From 4a36888bf576f72d0be8bb2208ce2ef0cf4ea378 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 12:54:55 -0500 Subject: [PATCH 1/9] java: checkstyle for client module Signed-off-by: Ze'ev Klapow --- java/.gitignore | 1 + java/checkstyle-suppression.xml | 15 + .../main/java/io/vitess/client/Context.java | 54 +-- .../src/main/java/io/vitess/client/Proto.java | 70 +-- .../client/RefreshableVTGateConnection.java | 53 +-- .../main/java/io/vitess/client/RpcClient.java | 39 +- .../io/vitess/client/RpcClientFactory.java | 6 +- .../main/java/io/vitess/client/SQLFuture.java | 63 ++- .../java/io/vitess/client/StreamIterator.java | 35 +- .../io/vitess/client/VTGateBlockingConn.java | 78 ++-- .../client/VTGateBlockingConnection.java | 239 ++++++----- .../io/vitess/client/VTGateBlockingTx.java | 31 +- .../java/io/vitess/client/VTGateConn.java | 135 +++--- .../io/vitess/client/VTGateConnection.java | 398 +++++++++--------- .../main/java/io/vitess/client/VTGateTx.java | 93 ++-- .../main/java/io/vitess/client/VTSession.java | 205 ++++----- .../java/io/vitess/client/cursor/Cursor.java | 30 +- .../vitess/client/cursor/CursorWithError.java | 40 +- .../io/vitess/client/cursor/FieldMap.java | 7 +- .../java/io/vitess/client/cursor/Row.java | 308 +++++++------- .../io/vitess/client/cursor/SimpleCursor.java | 16 +- .../io/vitess/client/cursor/StreamCursor.java | 26 +- .../io/vitess/client/grpc/tls/TlsOptions.java | 11 +- .../main/java/io/vitess/mysql/DateTime.java | 24 +- .../java/io/vitess/client/BindVarTest.java | 25 +- .../java/io/vitess/client/EntityIdTest.java | 148 +++---- .../test/java/io/vitess/client/ProtoTest.java | 9 +- .../java/io/vitess/client/RpcClientTest.java | 103 +++-- .../test/java/io/vitess/client/TestEnv.java | 8 +- .../test/java/io/vitess/client/TestUtil.java | 26 +- .../io/vitess/client/cursor/CursorTest.java | 55 ++- .../java/io/vitess/mysql/DateTimeTest.java | 9 +- java/pom.xml | 23 + 33 files changed, 1282 insertions(+), 1101 deletions(-) create mode 100644 java/.gitignore create mode 100644 java/checkstyle-suppression.xml diff --git a/java/.gitignore b/java/.gitignore new file mode 100644 index 00000000000..2f7896d1d13 --- /dev/null +++ b/java/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/java/checkstyle-suppression.xml b/java/checkstyle-suppression.xml new file mode 100644 index 00000000000..77906f6572a --- /dev/null +++ b/java/checkstyle-suppression.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/client/src/main/java/io/vitess/client/Context.java b/java/client/src/main/java/io/vitess/client/Context.java index b701820f635..c2a2bffcd98 100644 --- a/java/client/src/main/java/io/vitess/client/Context.java +++ b/java/client/src/main/java/io/vitess/client/Context.java @@ -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. * *

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. * *

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 Context withDeadline(Instant deadline) { } /** - * 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 Duration getTimeout() { 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; - } } diff --git a/java/client/src/main/java/io/vitess/client/Proto.java b/java/client/src/main/java/io/vitess/client/Proto.java index 2f15ccb4baa..2706a06fda4 100644 --- a/java/client/src/main/java/io/vitess/client/Proto.java +++ b/java/client/src/main/java/io/vitess/client/Proto.java @@ -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,19 @@ import com.google.common.collect.Iterables; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; + +import io.vitess.client.cursor.Cursor; +import io.vitess.client.cursor.CursorWithError; +import io.vitess.client.cursor.SimpleCursor; +import io.vitess.proto.Query; +import io.vitess.proto.Query.BindVariable; +import io.vitess.proto.Query.BoundQuery; +import io.vitess.proto.Query.QueryResult; +import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery; +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; @@ -34,25 +47,28 @@ 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; -import io.vitess.client.cursor.SimpleCursor; -import io.vitess.proto.Query; -import io.vitess.proto.Query.BindVariable; -import io.vitess.proto.Query.BoundQuery; -import io.vitess.proto.Query.QueryResult; -import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery; -import io.vitess.proto.Vtgate.BoundShardQuery; -import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId; -import io.vitess.proto.Vtrpc.RPCError; +import javax.annotation.Nullable; /** * Proto contains methods for working with Vitess protobuf messages. */ public class Proto { + public static final Function BYTE_ARRAY_TO_BYTE_STRING = + new Function() { + @Override + public ByteString apply(byte[] from) { + return ByteString.copyFrom(from); + } + }; + public static final Function, EntityId> MAP_ENTRY_TO_ENTITY_KEYSPACE_ID = + new Function, EntityId>() { + @Override + public EntityId apply(Map.Entry entry) { + return buildEntityId(entry.getKey(), entry.getValue()); + } + }; private static final int MAX_DECIMAL_UNIT = 30; /** @@ -133,7 +149,7 @@ public static int getErrno(@Nullable String errorMessage) { } try { return Integer.parseInt(errorMessage.substring(start, end)); - } catch (NumberFormatException e) { + } catch (NumberFormatException exc) { return 0; } } @@ -256,7 +272,8 @@ public static List toCursorList(List queryResults) { return builder.build(); } - public static List fromQueryResponsesToCursorList(List resultWithErrorList) { + public static List fromQueryResponsesToCursorList( + List resultWithErrorList) { ImmutableList.Builder builder = new ImmutableList.Builder(); for (Query.ResultWithError resultWithError : resultWithErrorList) { builder.add(new CursorWithError(resultWithError)); @@ -264,26 +281,11 @@ public static List fromQueryResponsesToCursorList(List BYTE_ARRAY_TO_BYTE_STRING = - new Function() { - @Override - public ByteString apply(byte[] from) { - return ByteString.copyFrom(from); - } - }; - - public static final Function, EntityId> MAP_ENTRY_TO_ENTITY_KEYSPACE_ID = - new Function, EntityId>() { - @Override - public EntityId apply(Map.Entry 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 @@ protected static class TypedValue { 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()); diff --git a/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java b/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java index 030062f6641..d1fb6d0621b 100644 --- a/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java +++ b/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java @@ -3,33 +3,34 @@ 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 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; + 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; + } } diff --git a/java/client/src/main/java/io/vitess/client/RpcClient.java b/java/client/src/main/java/io/vitess/client/RpcClient.java index 68015380044..31bd7e51689 100644 --- a/java/client/src/main/java/io/vitess/client/RpcClient.java +++ b/java/client/src/main/java/io/vitess/client/RpcClient.java @@ -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.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 @@ ListenableFuture executeEntityIds( * proto * definition for canonical documentation on this VTGate API. */ - ListenableFuture executeBatch(Context ctx, Vtgate.ExecuteBatchRequest request) + ListenableFuture executeBatch(Context ctx, + Vtgate.ExecuteBatchRequest request) throws SQLException; /** @@ -139,9 +142,9 @@ ListenableFuture executeBatchKeyspaceIds( * Starts stream queries with the VTGate V3 API. * *

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. * *

See the * proto @@ -154,9 +157,9 @@ StreamIterator streamExecute(Context ctx, StreamExecuteRequest requ * Starts stream queries with multiple shards. * *

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. * *

See the * proto @@ -169,9 +172,9 @@ StreamIterator streamExecuteShards(Context ctx, StreamExecuteShards * Starts a list of stream queries with keyspace ids as bind variables. * *

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. * *

See the * proto @@ -184,9 +187,9 @@ StreamIterator streamExecuteKeyspaceIds( * Starts stream query with a set of key ranges. * *

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. * *

See the * proto diff --git a/java/client/src/main/java/io/vitess/client/RpcClientFactory.java b/java/client/src/main/java/io/vitess/client/RpcClientFactory.java index 67e72d60aee..762f7105395 100644 --- a/java/client/src/main/java/io/vitess/client/RpcClientFactory.java +++ b/java/client/src/main/java/io/vitess/client/RpcClientFactory.java @@ -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. diff --git a/java/client/src/main/java/io/vitess/client/SQLFuture.java b/java/client/src/main/java/io/vitess/client/SQLFuture.java index 9c43c2c8bbb..0afef6fd0ed 100644 --- a/java/client/src/main/java/io/vitess/client/SQLFuture.java +++ b/java/client/src/main/java/io/vitess/client/SQLFuture.java @@ -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 @@ 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 @@ * *

* 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()}. * *

* 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. * *

* 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 + * not recommended for new projects. See the * CheckedFuture docs for more information. */ public class SQLFuture extends SimpleForwardingListenableFuture { + /** * Creates a SQLFuture that wraps the given ListenableFuture. */ @@ -64,13 +65,11 @@ public SQLFuture(ListenableFuture delegate) { 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 V checkedGet() throws SQLException { 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}. * *

- * 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 @@ protected SQLException mapException(Exception e) { .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 @@ protected SQLException mapException(Exception e) { } } - return new SQLException(e); + return new SQLException(exc); } } diff --git a/java/client/src/main/java/io/vitess/client/StreamIterator.java b/java/client/src/main/java/io/vitess/client/StreamIterator.java index 6550952329b..7d97da0779a 100644 --- a/java/client/src/main/java/io/vitess/client/StreamIterator.java +++ b/java/client/src/main/java/io/vitess/client/StreamIterator.java @@ -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.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. * *

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. * - *

The {@link #close()} method should be called when done to free up threads that may be blocking + *

The {@link #close()} method should be called when done to free up threads that may be + * blocking * on the streaming connection. * - * @param the type of result returned by the iterator, - * e.g. {@link io.vitess.proto.Query.QueryResult QueryResult} + * @param the type of result returned by the iterator, e.g. {@link + * io.vitess.proto.Query.QueryResult QueryResult} */ public interface StreamIterator extends AutoCloseable { + /** * hasNext returns true if next() would return a value. * *

If no value is available, hasNext() will block until either: *

*/ boolean hasNext() throws SQLException; @@ -52,9 +53,9 @@ public interface StreamIterator extends AutoCloseable { * *

If no value is available, next() will block until either: *

    - *
  • A value becomes available (returns the value), - *
  • The stream completes successfully (throws NoSuchElementException), - *
  • An error occurs (throws other exception). + *
  • A value becomes available (returns the value), + *
  • The stream completes successfully (throws NoSuchElementException), + *
  • An error occurs (throws other exception). *
*/ E next() throws NoSuchElementException, SQLException; diff --git a/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java b/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java index 03ca209bc0d..d2aee89e0a0 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java +++ b/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java @@ -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.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 @@ */ @Deprecated public class VTGateBlockingConn implements Closeable { + private final VTGateConn conn; /** @@ -76,15 +78,18 @@ public Cursor execute(Context ctx, String query, Map bindVars, Tablet } public Cursor executeShards(Context ctx, String query, String keyspace, Iterable shards, - Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields).checkedGet(); + Map 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 keyspaceIds, Map 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 Cursor executeKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, Map 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 entityKeyspaceIds, Map 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 List executeBatch(Context ctx, ArrayList queryLi public List executeBatch(Context ctx, ArrayList queryList, @Nullable ArrayList> 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 executeBatchShards(Context ctx, Iterable 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 executeBatchKeyspaceIds(Context ctx, Iterable 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 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 Cursor streamExecuteShards(Context ctx, String query, String keyspace, Iterable shards, Map 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 keyspaceIds, Map 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 keyRanges, Map 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 { diff --git a/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java b/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java index 183f17ac2a3..1d29492333c 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java +++ b/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java @@ -16,135 +16,162 @@ package io.vitess.client; +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; -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 javax.annotation.Nullable; /** * An asynchronous VTGate connection. *

*

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.

+ * 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.

*

*

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.

+ * complete before calling any other methods on that {@code VTGateConnection} instance. An {@link + * IllegalStateException} will be thrown if this constraint is violated.

*

- *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link VTGateBlockingConnection} if + *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link + * VTGateBlockingConnection} if * you want synchronous calls.

*/ public final class VTGateBlockingConnection implements Closeable { - private final VTGateConnection vtGateConnection; - /** - * Creates a VTGate connection with no specific parameters. - *

- *

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.

- * - * @param client RPC connection - */ - public VTGateBlockingConnection(RpcClient client) { - vtGateConnection = new VTGateConnection(client); - } + private final VTGateConnection vtGateConnection; + + /** + * Creates a VTGate connection with no specific parameters. + *

+ *

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.

+ * + * @param client RPC connection + */ + public VTGateBlockingConnection(RpcClient client) { + vtGateConnection = new VTGateConnection(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 Cursor - * @throws SQLException If anything fails on query execution. - */ - public Cursor execute(Context ctx, String query, @Nullable Map bindVars, final VTSession vtSession) throws SQLException { - return vtGateConnection.execute(ctx, query, bindVars, 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 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. - * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @param vtSession Session to be used with the call. - * @return List of Cursors - * @throws SQLException If anything fails on query execution. - */ - public List executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, final VTSession vtSession) throws SQLException { - return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, 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

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @param vtSession Session to be used with the call. + * @return List of Cursors + * @throws SQLException If anything fails on query execution. + */ + public List executeBatch(Context ctx, + List queryList, + @Nullable List> bindVarsList, + final VTSession vtSession) throws SQLException { + return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, vtSession).checkedGet(); + } - /** - * This method calls the VTGate to execute list of queries as a batch. - *

- *

If asTransaction is set to true then query execution will not change the session cookie. - * Otherwise, query execution will become part of the session.

- * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @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 executeBatch(Context ctx, List queryList, @Nullable List> 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. + *

+ *

If asTransaction is set to true then query execution will not change the + * session cookie. + * Otherwise, query execution will become part of the session.

+ * + * @param ctx Context on user and execution deadline if any. + * @param queryList List of sql queries to be executed. + * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @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 executeBatch(Context ctx, + List queryList, + @Nullable List> bindVarsList, + boolean asTransaction, + final VTSession vtSession) throws SQLException { + return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, asTransaction, 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 bindVars, VTSession vtSession) throws SQLException { - return vtGateConnection.streamExecute(ctx, query, bindVars, vtSession); - } + /** + * 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 bindVars, + VTSession vtSession) throws SQLException { + return vtGateConnection.streamExecute(ctx, query, bindVars, vtSession); + } - /** - * 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 splitQuery(Context ctx, String keyspace, String query, @Nullable Map bindVars, Iterable splitColumns, - int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException { - return vtGateConnection.splitQuery(ctx, keyspace, query, bindVars, splitColumns, splitCount, numRowsPerQueryPart, algorithm).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 splitQuery(Context ctx, + String keyspace, + String query, + @Nullable Map bindVars, + Iterable 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(); - } + /** + * @inheritDoc + */ + @Override + public void close() throws IOException { + vtGateConnection.close(); + } } diff --git a/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java b/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java index 18361bbcb6d..a44597e465c 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java +++ b/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java @@ -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.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 @@ */ @Deprecated public class VTGateBlockingTx { + private final VTGateTx tx; /** @@ -61,7 +63,8 @@ public Cursor executeShards( 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 Cursor executeKeyspaceIds( 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 Cursor executeKeyRanges( 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 Cursor executeEntityIds( 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(); } diff --git a/java/client/src/main/java/io/vitess/client/VTGateConn.java b/java/client/src/main/java/io/vitess/client/VTGateConn.java index 34f077944d5..6a810327701 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateConn.java +++ b/java/client/src/main/java/io/vitess/client/VTGateConn.java @@ -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.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.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. * *

- * See the VitessClientExample + * See the VitessClientExample * for a usage example. * *

@@ -84,6 +85,7 @@ */ @Deprecated public final class VTGateConn implements Closeable { + private final RpcClient client; private final String keyspace; @@ -107,8 +109,8 @@ public VTGateConn(RpcClient client) { * 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 VTGateConn(RpcClient client, String keyspace) { } public SQLFuture execute(Context ctx, String query, @Nullable Map 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 ListenableFuture apply(ExecuteKeyspaceIdsResponse response) public SQLFuture executeKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, @Nullable Map 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 ListenableFuture apply(ExecuteKeyRangesResponse response) public SQLFuture executeEntityIds(Context ctx, String query, String keyspace, String entityColumnName, Map entityKeyspaceIds, @Nullable Map 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 ListenableFuture apply(ExecuteEntityIdsResponse response) directExecutor())); } - public SQLFuture> executeBatch(Context ctx, List queryList, - @Nullable List> bindVarsList, TabletType tabletType, - Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return executeBatch(ctx, queryList, bindVarsList, tabletType, false, includedFields); + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, TabletType tabletType, + Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + return executeBatch(ctx, queryList, bindVarsList, tabletType, false, includedFields); + } + + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, TabletType tabletType, + boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { + List 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> executeBatch(Context ctx, List queryList, - @Nullable List> bindVarsList, TabletType tabletType, - boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - List 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)) - .setKeyspaceShard(keyspace) - .setTabletType(checkNotNull(tabletType)) - .setAsTransaction(asTransaction) - .setOptions(Query.ExecuteOptions.newBuilder() - .setIncludedFields(includedFields)); - - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + 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()); + } return new SQLFuture<>( transformAsync( @@ -310,13 +316,13 @@ public ListenableFuture> apply( } }, 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> executeBatchShards(Context ctx, Iterable queries, TabletType tabletType, boolean asTransaction, @@ -352,12 +358,13 @@ public ListenableFuture> apply(ExecuteBatchShardsResponse response) /** * 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> executeBatchKeyspaceIds(Context ctx, Iterable 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 ListenableFuture> apply(ExecuteBatchKeyspaceIdsResponse resp } public Cursor streamExecute(Context ctx, String query, @Nullable Map 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 Cursor streamExecuteKeyspaceIds(Context ctx, String query, String keyspac public Cursor streamExecuteKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, @Nullable Map 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)) diff --git a/java/client/src/main/java/io/vitess/client/VTGateConnection.java b/java/client/src/main/java/io/vitess/client/VTGateConnection.java index 485897f0da5..d22f01f5dc2 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateConnection.java +++ b/java/client/src/main/java/io/vitess/client/VTGateConnection.java @@ -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.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.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. *

*

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.

+ * 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.

*

*

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.

+ * complete before calling any other methods on that {@code VTGateConnection} instance. An {@link + * IllegalStateException} will be thrown if this constraint is violated.

*

- *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link VTGateBlockingConnection} if - * you want synchronous calls.

+ *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link + * VTGateBlockingConnection} if you want synchronous calls.

*/ public class VTGateConnection implements Closeable { - private final RpcClient client; - /** - * Creates a VTGate connection with no specific parameters. - *

- *

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.

- * - * @param client RPC connection - */ - public VTGateConnection(RpcClient client) { - this.client = checkNotNull(client); - } + private final RpcClient 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 execute(Context ctx, String query, @Nullable Map 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()); + /** + * Creates a VTGate connection with no specific parameters. + *

+ *

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.

+ * + * @param client RPC connection + */ + public VTGateConnection(RpcClient client) { + this.client = checkNotNull(client); + } - 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 execute(Context ctx, String query, @Nullable Map 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()); - SQLFuture call = new SQLFuture<>( - transformAsync(client.execute(ctx, requestBuilder.build()), - new AsyncFunction() { - @Override - public ListenableFuture apply(ExecuteResponse response) throws Exception { - vtSession.setSession(response.getSession()); - Proto.checkError(response.getError()); - return Futures.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

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @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> executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, final VTSession vtSession) throws SQLException { - return executeBatch(ctx, queryList, bindVarsList, false, vtSession); + SQLFuture call = new SQLFuture<>( + transformAsync(client.execute(ctx, requestBuilder.build()), + new AsyncFunction() { + @Override + public ListenableFuture apply(ExecuteResponse response) throws Exception { + vtSession.setSession(response.getSession()); + Proto.checkError(response.getError()); + return Futures.immediateFuture(new SimpleCursor(response.getResult())); + } + }, directExecutor())); + vtSession.setLastCall(call); + return call; } + } - /** - * This method calls the VTGate to execute list of queries as a batch. - *

- *

If asTransaction is set to true then query execution will not change the session cookie. - * Otherwise, query execution will become part of the session.

- * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @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> executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, boolean asTransaction, final VTSession vtSession) throws SQLException { - synchronized (this) { - vtSession.checkCallIsAllowed("executeBatch"); - List queries = new ArrayList<>(); + /** + * 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

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @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> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, final VTSession vtSession) throws SQLException { + return executeBatch(ctx, queryList, bindVarsList, false, vtSession); + } - if (null != bindVarsList && bindVarsList.size() != queryList.size()) { - throw new SQLDataException( - "Size of SQL Query list does not match the bind variables list"); - } + /** + * This method calls the VTGate to execute list of queries as a batch. + *

+ *

If asTransaction is set to true then query execution will not change the + * session cookie. Otherwise, query execution will become part of the session.

+ * + * @param ctx Context on user and execution deadline if any. + * @param queryList List of sql queries to be executed. + * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @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> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, boolean asTransaction, final VTSession vtSession) + throws SQLException { + synchronized (this) { + vtSession.checkCallIsAllowed("executeBatch"); + List 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)) - .setSession(vtSession.getSession()) - .setAsTransaction(asTransaction); + for (int i = 0; i < queryList.size(); ++i) { + queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), + bindVarsList == null ? null : bindVarsList.get(i))); + } - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + Vtgate.ExecuteBatchRequest.Builder requestBuilder = + Vtgate.ExecuteBatchRequest.newBuilder() + .addAllQueries(checkNotNull(queries)) + .setSession(vtSession.getSession()) + .setAsTransaction(asTransaction); - SQLFuture> call = new SQLFuture<>( - transformAsync(client.executeBatch(ctx, requestBuilder.build()), - new AsyncFunction>() { - @Override - public ListenableFuture> 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; - } - } + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); + } - /** - * - * @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 bindVars, VTSession vtSession) throws SQLException { - StreamExecuteRequest.Builder requestBuilder = - StreamExecuteRequest.newBuilder() - .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) - .setSession(vtSession.getSession()); + SQLFuture> call = new SQLFuture<>( + transformAsync(client.executeBatch(ctx, requestBuilder.build()), + new AsyncFunction>() { + @Override + public ListenableFuture> 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; + } + } - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + /** + * @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 bindVars, + VTSession vtSession) throws SQLException { + StreamExecuteRequest.Builder requestBuilder = + StreamExecuteRequest.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> splitQuery(Context ctx, String keyspace, String query, @Nullable Map bindVars, Iterable 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 StreamCursor(client.streamExecute(ctx, requestBuilder.build())); + } - return new SQLFuture<>( - transformAsync(client.splitQuery(ctx, requestBuilder.build()), - new AsyncFunction>() { - @Override - public ListenableFuture> apply(SplitQueryResponse response) throws Exception { - return Futures.immediateFuture(response.getSplitsList()); - } - }, directExecutor())); - } + /** + * 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> splitQuery(Context ctx, String keyspace, + String query, @Nullable Map bindVars, Iterable 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); - /** - * @inheritDoc - */ - @Override - public void close() throws IOException { - client.close(); + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); } - @Override - public String toString() { - return String.format("[VTGateConnection-%s client=%s]", - Integer.toHexString(this.hashCode()), - client.toString() - ); - } + return new SQLFuture<>( + transformAsync(client.splitQuery(ctx, requestBuilder.build()), + new AsyncFunction>() { + @Override + public ListenableFuture> 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() + ); + } } diff --git a/java/client/src/main/java/io/vitess/client/VTGateTx.java b/java/client/src/main/java/io/vitess/client/VTGateTx.java index 4e330790383..4028bde21fa 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateTx.java +++ b/java/client/src/main/java/io/vitess/client/VTGateTx.java @@ -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.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.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 @@ */ @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 execute(Context ctx, String query, Map 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 ListenableFuture apply(ExecuteKeyRangesResponse response) public synchronized SQLFuture executeEntityIds(Context ctx, String query, String keyspace, String entityColumnName, Map entityKeyspaceIds, Map 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 ListenableFuture apply(ExecuteEntityIdsResponse response) return call; } - public SQLFuture> executeBatch(Context ctx, List queryList, - @Nullable List> bindVarsList, TabletType tabletType, - Query.ExecuteOptions.IncludedFields includedFields) - throws SQLException { - List 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)) - .setKeyspaceShard(keyspace) - .setTabletType(checkNotNull(tabletType)) - .setSession(session) - .setOptions(Query.ExecuteOptions.newBuilder() - .setIncludedFields(includedFields)); - - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, TabletType tabletType, + Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { + List 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)) + .setKeyspaceShard(keyspace) + .setTabletType(checkNotNull(tabletType)) + .setSession(session) + .setOptions(Query.ExecuteOptions.newBuilder() + .setIncludedFields(includedFields)); + + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); + } return new SQLFuture<>( transformAsync( @@ -313,7 +318,7 @@ public ListenableFuture> apply( } }, directExecutor())); - } + } public synchronized SQLFuture> executeBatchShards(Context ctx, Iterable queries, TabletType tabletType, @@ -384,14 +389,14 @@ public ListenableFuture> apply( return call; } - public synchronized SQLFuture commit(Context ctx) throws SQLException { - return commit(ctx, false); - } + public synchronized SQLFuture commit(Context ctx) throws SQLException { + return commit(ctx, false); + } public synchronized SQLFuture 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()); } diff --git a/java/client/src/main/java/io/vitess/client/VTSession.java b/java/client/src/main/java/io/vitess/client/VTSession.java index d4d724cae16..69978a12db5 100644 --- a/java/client/src/main/java/io/vitess/client/VTSession.java +++ b/java/client/src/main/java/io/vitess/client/VTSession.java @@ -21,119 +21,122 @@ /** * 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. - *

- *

This method is not synchronized as the callee function is synchronized.

- * - * @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. + *

+ *

This method is not synchronized as the callee function is synchronized.

+ * + * @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(); + } + + /** + * 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. - *

- *

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.

- * - * @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."); - } + /** + * This method checks if the last SQLFuture call is complete or not. + *

+ *

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.

+ * + * @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."); } + } } diff --git a/java/client/src/main/java/io/vitess/client/cursor/Cursor.java b/java/client/src/main/java/io/vitess/client/cursor/Cursor.java index d7f479bb21c..f810bf99fd6 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/Cursor.java +++ b/java/client/src/main/java/io/vitess/client/cursor/Cursor.java @@ -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 @@ 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. * *

{@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. * *

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 @@ * should be called to free resources when done, regardless of whether all the rows were processed. * *

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}. * *

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; diff --git a/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java b/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java index 3fe52c451c6..4051a0f7a79 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java +++ b/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java @@ -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 @@ */ 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; + } } diff --git a/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java b/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java index 3826d0782a7..d34c13ab623 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java +++ b/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java @@ -20,11 +20,15 @@ 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 @@ * index is also used to find the value in a separate list. */ public class FieldMap { + private final List fields; private final Map labelMap; private final Map nameMap; diff --git a/java/client/src/main/java/io/vitess/client/cursor/Row.java b/java/client/src/main/java/io/vitess/client/cursor/Row.java index 20c079cbefc..b232fb6d8aa 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/Row.java +++ b/java/client/src/main/java/io/vitess/client/cursor/Row.java @@ -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 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.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. * *

- * 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}. * *

* 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 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}. * *

* {@link Cursor} uses this to share a {@link FieldMap} among multiple rows. @@ -95,9 +98,9 @@ public Row(List fields, Query.Row rawRow) { * Construct a Row manually (not from proto). * *

- * 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. * *

* Note that {@link #getRowProto()} will return null in this case, so a Row created in this way @@ -110,6 +113,102 @@ public Row(List fields, List values) { 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. + * + *

+ * See the docs for the {@code Row} message in {@code query.proto}. + */ + private static List extractValues(List lengths, ByteString buf) { + List list = new ArrayList(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 InputStream getBinaryInputStream(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 int getInt(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 UnsignedLong getULong(String columnLabel) throws SQLException { * @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 String getString(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 long getLong(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 long getLong(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 double getDouble(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 double getDouble(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 float getFloat(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 Date getDate(int columnIndex, Calendar cal) throws SQLException { } 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 Time getTime(int columnIndex, Calendar cal) throws SQLException { } 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 Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException } 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 BigDecimal getBigDecimal(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 short getShort(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * 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 short getShort(int columnIndex) throws SQLException { */ @SuppressWarnings("unchecked") // by runtime check public T getObject(int columnIndex, Class 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 T getObject(String columnLabel, Class type) throws SQLException { * {@code wasNull()}. * *

- * 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 boolean wasNull() throws SQLException { // 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. - * - *

- * See the docs for the {@code Row} message in {@code query.proto}. - */ - private static List extractValues(List lengths, ByteString buf) { - List list = new ArrayList(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; - } } diff --git a/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java b/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java index bc1c447ac63..69fe26d14e9 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java +++ b/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java @@ -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 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; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.QueryResult; +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 rowIterator; diff --git a/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java b/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java index 4ab56eea654..1ef5971ad73 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java +++ b/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java @@ -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 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; -import io.vitess.client.StreamIterator; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.QueryResult; +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 streamIterator; private Iterator rowIterator; @@ -103,8 +105,8 @@ public Row next() throws SQLException { * *

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. * *

If {@link #fields} is null, we assume the next {@link QueryResult} must contain the fields, * and set {@link #fields} from it. diff --git a/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java b/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java index e56dcce8329..a97fa3151ec 100644 --- a/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java +++ b/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java @@ -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 @@ /** *

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.

+ * {@link io.vitess.client.RpcClientFactory#createTls(InetSocketAddress, TlsOptions)} method, so + * that this method won't have an unwieldy number of direct parameters.

* *

This path uses a builder pattern style:

* @@ -39,6 +39,7 @@ * */ public class TlsOptions { + private File keyStore; private String keyStorePassword; private String keyAlias; diff --git a/java/client/src/main/java/io/vitess/mysql/DateTime.java b/java/client/src/main/java/io/vitess/mysql/DateTime.java index 1d2d9ae9cd7..e5f9ef13e4d 100644 --- a/java/client/src/main/java/io/vitess/mysql/DateTime.java +++ b/java/client/src/main/java/io/vitess/mysql/DateTime.java @@ -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 @@ * Utility methods for processing MySQL TIME, DATE, DATETIME, and TIMESTAMP. * *

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 static Time parseTime(String value, Calendar cal) throws ParseException { } } } - } catch (NumberFormatException e) { + } catch (NumberFormatException exc) { throw new ParseException("Invalid MYSQL TIME format: " + value, 0); } @@ -165,8 +167,8 @@ public static Time parseTime(String value, Calendar cal) throws ParseException { * Format a {@link Time} as a MySQL TIME with the default time zone. * *

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 static String formatTime(Time value) { * *

The range for TIME values is '-838:59:59.000000' to '838:59:59.000000' * [1]. - * 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 static Timestamp parseTimestamp(String value, Calendar cal) throws ParseE } 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); } } diff --git a/java/client/src/test/java/io/vitess/client/BindVarTest.java b/java/client/src/test/java/io/vitess/client/BindVarTest.java index 28bcee59f23..dee81b8ea66 100644 --- a/java/client/src/test/java/io/vitess/client/BindVarTest.java +++ b/java/client/src/test/java/io/vitess/client/BindVarTest.java @@ -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 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 static Collection testParams() { 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 static Collection testParams() { 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, diff --git a/java/client/src/test/java/io/vitess/client/EntityIdTest.java b/java/client/src/test/java/io/vitess/client/EntityIdTest.java index 82a5064dc49..1359d487904 100644 --- a/java/client/src/test/java/io/vitess/client/EntityIdTest.java +++ b/java/client/src/test/java/io/vitess/client/EntityIdTest.java @@ -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 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 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); } diff --git a/java/client/src/test/java/io/vitess/client/ProtoTest.java b/java/client/src/test/java/io/vitess/client/ProtoTest.java index 27f6ab1142b..d52d6551971 100644 --- a/java/client/src/test/java/io/vitess/client/ProtoTest.java +++ b/java/client/src/test/java/io/vitess/client/ProtoTest.java @@ -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 @@ @RunWith(JUnit4.class) public class ProtoTest { + @Test public void testGetErrno() { final Map testValues = diff --git a/java/client/src/test/java/io/vitess/client/RpcClientTest.java b/java/client/src/test/java/io/vitess/client/RpcClientTest.java index 97301296a3d..67e69c93552 100644 --- a/java/client/src/test/java/io/vitess/client/RpcClientTest.java +++ b/java/client/src/test/java/io/vitess/client/RpcClientTest.java @@ -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,21 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.ByteString; + +import io.vitess.client.cursor.Cursor; +import io.vitess.client.cursor.Row; +import io.vitess.proto.Query; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.SplitQueryRequest.Algorithm; +import io.vitess.proto.Topodata.KeyRange; +import io.vitess.proto.Topodata.KeyspaceIdType; +import io.vitess.proto.Topodata.ShardReference; +import io.vitess.proto.Topodata.SrvKeyspace; +import io.vitess.proto.Topodata.SrvKeyspace.KeyspacePartition; +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; @@ -34,7 +49,7 @@ 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; @@ -42,20 +57,6 @@ import org.junit.BeforeClass; import org.junit.Test; -import io.vitess.client.cursor.Cursor; -import io.vitess.client.cursor.Row; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import io.vitess.proto.Topodata.KeyRange; -import io.vitess.proto.Topodata.KeyspaceIdType; -import io.vitess.proto.Topodata.ShardReference; -import io.vitess.proto.Topodata.SrvKeyspace; -import io.vitess.proto.Topodata.SrvKeyspace.KeyspacePartition; -import io.vitess.proto.Topodata.TabletType; -import io.vitess.proto.Vtgate.SplitQueryResponse; -import io.vitess.proto.Vtrpc.CallerID; - /** * RpcClientTest tests a given implementation of RpcClient against a mock vtgate server * (go/cmd/vtgateclienttest). @@ -64,6 +65,7 @@ * 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 void setUp() throws SQLException, InterruptedException { // 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 void setUp() throws SQLException, InterruptedException { private static final String SHARDS_ECHO = "[-80 80-]"; private static final List 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 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 ENTITY_KEYSPACE_IDS = new ImmutableMap.Builder() - .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 void setUp() throws SQLException, InterruptedException { 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 BIND_VARS = new ImmutableMap.Builder() .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 @@ private static Map getEcho(Cursor cursor) throws Exception { * * 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 @@ private void waitForVtgateclienttest() throws SQLException, InterruptedException 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 @@ private void waitForVtgateclienttest() throws SQLException, InterruptedException 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 void testEchoExecute() throws Exception { 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 void testEchoExecute() throws Exception { public void testEchoStreamExecute() throws Exception { Map 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 void testEchoTransactionExecute() throws Exception { 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 void testEchoSplitQuery() throws Exception { 123, 1000, Algorithm.FULL_SCAN) - .get(0); + .get(0); Assert.assertEquals(expected, actual); } @@ -471,8 +478,8 @@ public void testGetSrvKeyspace() throws Exception { 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 void testGetSrvKeyspace() throws Exception { } abstract static class Executable { + abstract void execute(String query) throws Exception; } @@ -521,6 +529,7 @@ void checkStreamExecuteErrors(Executable exe) { } abstract static class TransactionExecutable { + abstract void execute(VTGateBlockingTx tx, String query) throws Exception; } @@ -602,7 +611,8 @@ void execute(String query) throws Exception { 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 @@ void execute(String query) throws Exception { checkStreamExecuteErrors(new Executable() { @Override void execute(String query) throws Exception { - conn.streamExecuteShards(ctx, query, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS).next(); + 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.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) + conn.streamExecuteKeyRanges(ctx, query, KEYSPACE, KEY_RANGES, BIND_VARS, TABLET_TYPE, + ALL_FIELDS) .next(); } }); @@ -683,7 +696,8 @@ void execute(VTGateBlockingTx tx, String query) throws Exception { 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 @@ void execute(VTGateBlockingTx tx, String query) throws Exception { @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() { diff --git a/java/client/src/test/java/io/vitess/client/TestEnv.java b/java/client/src/test/java/io/vitess/client/TestEnv.java index 1c5012eab9b..f9b9d0dabd3 100644 --- a/java/client/src/test/java/io/vitess/client/TestEnv.java +++ b/java/client/src/test/java/io/vitess/client/TestEnv.java @@ -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.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 @@ * 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; diff --git a/java/client/src/test/java/io/vitess/client/TestUtil.java b/java/client/src/test/java/io/vitess/client/TestUtil.java index 395abc4817f..563874f47b4 100644 --- a/java/client/src/test/java/io/vitess/client/TestUtil.java +++ b/java/client/src/test/java/io/vitess/client/TestUtil.java @@ -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 @@ 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 static void setupTestEnv(TestEnv testEnv) throws Exception { continue; } try { - Type mapType = new TypeToken>() {}.getType(); + Type mapType = new TypeToken>() { + }.getType(); Map 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 static VTGateBlockingConn getBlockingConn(TestEnv testEnv) { // 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 static void insertRows(TestEnv testEnv, int startId, int count) throws Ex 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); } diff --git a/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java b/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java index 0534cf72b4c..809607e00a9 100644 --- a/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java +++ b/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java @@ -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 @@ 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.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 void testFindColumn() throws Exception { @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 void testGetULong() throws Exception { 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 void testGetBigInteger() throws Exception { 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 void testGetDate() throws Exception { .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 void testGetBytes() throws Exception { .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 void testGetBigDecimal() throws Exception { .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 void testNull() throws Exception { 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); diff --git a/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java b/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java index 9a544f1001b..59bd0c7ea19 100644 --- a/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java +++ b/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java @@ -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 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.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")); diff --git a/java/pom.xml b/java/pom.xml index e5b2fbd7b45..ac05378c605 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -70,6 +70,7 @@ 1.16.0 3.6.1 3.6.1 + 3.0.0 @@ -253,6 +254,28 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + google_checks.xml + checkstyle-suppression.xml + true + false + true + warning + + + + validate + validate + + check + + + + From 4e1d20a3b40660e365dd75a982e0b122af006bc0 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 13:19:10 -0500 Subject: [PATCH 2/9] grpc-client: checkstyle Signed-off-by: Ze'ev Klapow --- .../java/io/vitess/client/grpc/Constants.java | 12 +- .../io/vitess/client/grpc/GrpcClient.java | 43 ++- .../vitess/client/grpc/GrpcClientFactory.java | 252 +++++++------- .../vitess/client/grpc/GrpcStreamAdapter.java | 36 +- .../client/grpc/RetryingInterceptor.java | 39 ++- .../grpc/RetryingInterceptorConfig.java | 24 +- .../client/grpc/StaticAuthCredentials.java | 5 +- .../client/grpc/GrpcClientStaticAuthTest.java | 10 +- .../java/io/client/grpc/GrpcClientTest.java | 32 +- .../grpc/GrpcClientTlsClientAuthTest.java | 313 +++++++++--------- .../io/client/grpc/GrpcClientTlsTest.java | 256 +++++++------- .../grpc/GrpcClientWithRetriesTest.java | 15 +- .../client/grpc/RetryingInterceptorTest.java | 49 ++- 13 files changed, 577 insertions(+), 509 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java index e8dd4319421..950c9d351ad 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java @@ -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,9 +21,9 @@ */ public class Constants { - public static final String KEYSTORE_TYPE = "JKS"; + public static final String KEYSTORE_TYPE = "JKS"; - private Constants() { + private Constants() { - } + } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index feb50bcdeca..a25784df223 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -20,10 +20,11 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; + import io.grpc.CallCredentials; +import io.grpc.InternalWithLogId; import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; -import io.grpc.InternalWithLogId; import io.vitess.client.Context; import io.vitess.client.Proto; import io.vitess.client.RpcClient; @@ -65,6 +66,9 @@ import io.vitess.proto.grpc.VitessGrpc; import io.vitess.proto.grpc.VitessGrpc.VitessFutureStub; import io.vitess.proto.grpc.VitessGrpc.VitessStub; + +import org.joda.time.Duration; + import java.io.IOException; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; @@ -75,12 +79,12 @@ import java.sql.SQLTimeoutException; import java.sql.SQLTransientException; import java.util.concurrent.TimeUnit; -import org.joda.time.Duration; /** * GrpcClient is a gRPC-based implementation of Vitess RpcClient. */ public class GrpcClient implements RpcClient { + private final ManagedChannel channel; private final String channelId; private final VitessStub asyncStub; @@ -101,8 +105,8 @@ public GrpcClient(ManagedChannel channel, CallCredentials credentials) { } private String toChannelId(ManagedChannel channel) { - return channel instanceof InternalWithLogId ? - ((InternalWithLogId) channel).getLogId().toString() : channel.toString(); + return channel instanceof InternalWithLogId + ? ((InternalWithLogId) channel).getLogId().toString() : channel.toString(); } @Override @@ -145,7 +149,8 @@ public ListenableFuture executeEntityIds(Context ctx, new ExceptionConverter(), MoreExecutors.directExecutor()); } - @Override public ListenableFuture executeBatch(Context ctx, + @Override + public ListenableFuture executeBatch(Context ctx, Vtgate.ExecuteBatchRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).executeBatch(request), Exception.class, new ExceptionConverter(), MoreExecutors.directExecutor()); @@ -260,9 +265,9 @@ public ListenableFuture getSrvKeyspace(Context ctx, /** * Converts an exception from the gRPC framework into the appropriate {@link SQLException}. */ - static SQLException convertGrpcError(Throwable e) { - if (e instanceof StatusRuntimeException) { - StatusRuntimeException sre = (StatusRuntimeException) e; + static SQLException convertGrpcError(Throwable exc) { + if (exc instanceof StatusRuntimeException) { + StatusRuntimeException sre = (StatusRuntimeException) exc; int errno = Proto.getErrno(sre.getMessage()); String sqlState = Proto.getSQLState(sre.getMessage()); @@ -282,21 +287,23 @@ static SQLException convertGrpcError(Throwable e) { return new SQLRecoverableException(sre.toString(), sqlState, errno, sre); default: // Covers e.g. UNKNOWN. String advice = ""; - if (e.getCause() instanceof java.nio.channels.ClosedChannelException) { + if (exc.getCause() instanceof java.nio.channels.ClosedChannelException) { advice = - "Failed to connect to vtgate. Make sure that vtgate is running and you are using the correct address. Details: "; + "Failed to connect to vtgate. Make sure that vtgate is running and you are using " + + "the correct address. Details: "; } return new SQLNonTransientException( - "gRPC StatusRuntimeException: " + advice + e.toString(), sqlState, errno, e); + "gRPC StatusRuntimeException: " + advice + exc.toString(), sqlState, errno, exc); } } - return new SQLNonTransientException("gRPC error: " + e.toString(), e); + return new SQLNonTransientException("gRPC error: " + exc.toString(), exc); } static class ExceptionConverter implements AsyncFunction { + @Override - public ListenableFuture apply(Exception e) throws Exception { - throw convertGrpcError(e); + public ListenableFuture apply(Exception exc) throws Exception { + throw convertGrpcError(exc); } } @@ -318,9 +325,9 @@ private VitessFutureStub getFutureStub(Context ctx) { @Override public String toString() { - return String.format("[GrpcClient-%s channel=%s]", - Integer.toHexString(this.hashCode()), - channelId - ); + return String.format("[GrpcClient-%s channel=%s]", + Integer.toHexString(this.hashCode()), + channelId + ); } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 928c29334ee..19524061faa 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -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,6 +19,16 @@ import io.grpc.CallCredentials; import io.grpc.LoadBalancer; import io.grpc.NameResolver; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NegotiationType; +import io.grpc.netty.NettyChannelBuilder; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.vitess.client.Context; +import io.vitess.client.RpcClient; +import io.vitess.client.RpcClientFactory; +import io.vitess.client.grpc.tls.TlsOptions; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -35,16 +45,6 @@ import javax.net.ssl.SSLException; -import io.grpc.netty.GrpcSslContexts; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.vitess.client.Context; -import io.vitess.client.RpcClient; -import io.vitess.client.RpcClientFactory; -import io.vitess.client.grpc.tls.TlsOptions; - /** * GrpcClientFactory creates RpcClients with the gRPC implementation. */ @@ -81,30 +81,32 @@ public GrpcClientFactory setNameResolverFactory(NameResolver.Factory value) { /** * Factory method to construct a gRPC client connection with no transport-layer security. * - * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that timeout duration and caller ID settings aren't discarded - * @param target - * target is passed to NettyChannelBuilder which will resolve based on scheme, by default dns. - * @return + * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that + * timeout duration and caller ID settings aren't discarded + * @param target target is passed to NettyChannelBuilder which will resolve based on scheme, + * by default dns. */ @Override public RpcClient create(Context ctx, String target) { NettyChannelBuilder channel = channelBuilder(target) - .negotiationType(NegotiationType.PLAINTEXT) - .intercept(new RetryingInterceptor(config)); + .negotiationType(NegotiationType.PLAINTEXT) + .intercept(new RetryingInterceptor(config)); if (loadBalancerFactory != null) { channel.loadBalancerFactory(loadBalancerFactory); } if (nameResolverFactory != null) { channel.nameResolverFactory(nameResolverFactory); } - return callCredentials != null ? - new GrpcClient(channel.build(), callCredentials) : new GrpcClient(channel.build()); + return callCredentials != null + ? new GrpcClient(channel.build(), callCredentials) : new GrpcClient(channel.build()); } /** - *

This method constructs NettyChannelBuilder object that will be used to create RpcClient.

- *

Subclasses may override this method to make adjustments to the builder

+ *

This method constructs NettyChannelBuilder object that will be used to create + * RpcClient.

+ *

Subclasses may override this method to make adjustments to the builder

* for example: + * * * @Override * protected NettyChannelBuilder channelBuilder(String target) { @@ -112,83 +114,81 @@ public RpcClient create(Context ctx, String target) { * .eventLoopGroup(new EpollEventLoopGroup()) * .withOption(EpollChannelOption.TCP_USER_TIMEOUT,30); * } - * * * - * @param target - * target is passed to NettyChannelBuilder which will resolve based on scheme, by default dns. - * @return + * @param target target is passed to NettyChannelBuilder which will resolve based on scheme, + * by default dns. */ - protected NettyChannelBuilder channelBuilder(String target){ + protected NettyChannelBuilder channelBuilder(String target) { return NettyChannelBuilder.forTarget(target); } /** *

Factory method to construct a gRPC client connection with transport-layer security.

* - *

Within the tlsOptions parameter value, the trustStore field should + *

Within the tlsOptions parameter value, the trustStore field + * should * always be populated. All other fields are optional.

* - * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that timeout duration and caller ID settings aren't discarded - * @param target - * target is passed to NettyChannelBuilder which will resolve based on scheme, by default dns. - * @param tlsOptions - * @return + * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that + * timeout duration and caller ID settings aren't discarded + * @param target target is passed to NettyChannelBuilder which will resolve based on scheme, + * by default dns. */ @Override public RpcClient createTls(Context ctx, String target, TlsOptions tlsOptions) { final SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient(); // trustManager should always be set - final KeyStore trustStore = loadKeyStore(tlsOptions.getTrustStore(), tlsOptions.getTrustStorePassword()); + final KeyStore trustStore = loadKeyStore(tlsOptions.getTrustStore(), + tlsOptions.getTrustStorePassword()); if (trustStore == null) { throw new RuntimeException("Could not load trustStore"); } final X509Certificate[] trustCertCollection = tlsOptions.getTrustAlias() == null - ? loadCertCollection(trustStore) - : loadCertCollectionForAlias(trustStore, tlsOptions.getTrustAlias()); + ? loadCertCollection(trustStore) + : loadCertCollectionForAlias(trustStore, tlsOptions.getTrustAlias()); sslContextBuilder.trustManager(trustCertCollection); - // keyManager should only be set if a keyStore is specified (meaning that client authentication is enabled) - final KeyStore keyStore = loadKeyStore(tlsOptions.getKeyStore(), tlsOptions.getKeyStorePassword()); + // keyManager should only be set if a keyStore is specified (meaning that client authentication + // is enabled) + final KeyStore keyStore = loadKeyStore(tlsOptions.getKeyStore(), + tlsOptions.getKeyStorePassword()); if (keyStore != null) { final PrivateKeyWrapper privateKeyWrapper = tlsOptions.getKeyAlias() == null - ? loadPrivateKeyEntry(keyStore, tlsOptions.getKeyStorePassword(), tlsOptions.getKeyPassword()) - : loadPrivateKeyEntryForAlias(keyStore, tlsOptions.getKeyAlias(), tlsOptions.getKeyStorePassword(), tlsOptions.getKeyPassword()); + ? loadPrivateKeyEntry(keyStore, tlsOptions.getKeyStorePassword(), + tlsOptions.getKeyPassword()) + : loadPrivateKeyEntryForAlias(keyStore, tlsOptions.getKeyAlias(), + tlsOptions.getKeyStorePassword(), tlsOptions.getKeyPassword()); if (privateKeyWrapper == null) { - throw new RuntimeException("Could not retrieve private key and certificate chain from keyStore"); + throw new RuntimeException( + "Could not retrieve private key and certificate chain from keyStore"); } sslContextBuilder.keyManager( - privateKeyWrapper.getPrivateKey(), - privateKeyWrapper.getPassword(), - privateKeyWrapper.getCertificateChain() + privateKeyWrapper.getPrivateKey(), + privateKeyWrapper.getPassword(), + privateKeyWrapper.getCertificateChain() ); } final SslContext sslContext; try { sslContext = sslContextBuilder.build(); - } catch (SSLException e) { - throw new RuntimeException(e); + } catch (SSLException exc) { + throw new RuntimeException(exc); } return new GrpcClient( - channelBuilder(target).negotiationType(NegotiationType.TLS).sslContext(sslContext).intercept(new RetryingInterceptor(config)).build()); + channelBuilder(target).negotiationType(NegotiationType.TLS).sslContext(sslContext) + .intercept(new RetryingInterceptor(config)).build()); } /** *

Opens a JKS keystore file from the filesystem.

* - *

Returns null if the file is inaccessible for any reason, or if the password fails to unlock it.

- * - * @param keyStoreFile - * @param keyStorePassword - * @return - * @throws KeyStoreException - * @throws IOException - * @throws CertificateException - * @throws NoSuchAlgorithmException + *

Returns null if the file is inaccessible for any reason, or if the password + * fails to unlock it.

*/ private KeyStore loadKeyStore(final File keyStoreFile, String keyStorePassword) { if (keyStoreFile == null) { @@ -202,45 +202,46 @@ private KeyStore loadKeyStore(final File keyStoreFile, String keyStorePassword) keyStore.load(fis, password); } return keyStore; - } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) { + } catch (KeyStoreException + | CertificateException + | NoSuchAlgorithmException + | IOException exc) { return null; } } /** - *

Loads an X509 certificate from a keystore using a given alias, and returns it as a one-element + *

Loads an X509 certificate from a keystore using a given alias, and returns it as a + * one-element * array so that it can be passed to {@link SslContextBuilder#trustManager(File)}.

* - *

Returns null if there is any problem accessing the keystore, or if the alias does + *

Returns null if there is any problem accessing the keystore, or if the alias + * does * not match an X509 certificate.

- * - * @param keyStore - * @param alias - * @return */ - private X509Certificate[] loadCertCollectionForAlias(final KeyStore keyStore, final String alias) { + private X509Certificate[] loadCertCollectionForAlias(final KeyStore keyStore, + final String alias) { if (keyStore == null) { return null; } try { - return new X509Certificate[] { - (X509Certificate) keyStore.getCertificate(alias) + return new X509Certificate[]{ + (X509Certificate) keyStore.getCertificate(alias) }; - } catch (KeyStoreException | ClassCastException e) { + } catch (KeyStoreException | ClassCastException exc) { return null; } } /** - *

Loads the first valid X509 certificate found in the keystore, and returns it as a one-element + *

Loads the first valid X509 certificate found in the keystore, and returns it as a + * one-element * array so that it can be passed to {@link SslContextBuilder#trustManager(File)}.

* - *

Returns null if there is any problem accessing the keystore, or if no X509 certificates + *

Returns null if there is any problem accessing the keystore, or if no X509 + * certificates * are found at all.

- * - * @param keyStore - * @return */ private X509Certificate[] loadCertCollection(final KeyStore keyStore) { if (keyStore == null) { @@ -250,7 +251,7 @@ private X509Certificate[] loadCertCollection(final KeyStore keyStore) { final Enumeration aliases; try { aliases = keyStore.aliases(); - } catch (KeyStoreException e) { + } catch (KeyStoreException exc) { return null; } @@ -266,29 +267,25 @@ private X509Certificate[] loadCertCollection(final KeyStore keyStore) { } /** - *

Loads from a keystore the private key entry matching a given alias, and returns it parsed and - * ready to be passed to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}.

+ *

Loads from a keystore the private key entry matching a given alias, and returns it parsed + * and + * ready to be passed to {@link SslContextBuilder#keyManager(PrivateKey, String, + * X509Certificate...)}.

* - *

To access the private key, this method will first try using the keyPassword parameter - * value (this parameter can be set to null to explicitly indicate that there is no password). - * If that fails, then this method will then try using the keyStorePassword parameter value - * as the key value too.

+ *

To access the private key, this method will first try using the keyPassword + * parameter + * value (this parameter can be set to null to explicitly indicate that there is no + * password). If that fails, then this method will then try using the + * keyStorePassword parameter value as the key value too.

* - *

Returns null if there is any problem accessing the keystore, if neither keyPassword - * or keyStorePassword can unlock the private key, or if no private key entry matches + *

Returns null if there is any problem accessing the keystore, if neither + * keyPassword + * or keyStorePassword can unlock the private key, or if no private key entry + * matches * alias.

- * - * @param keyStore - * @param alias - * @param keyStorePassword - * @param keyPassword - * @return - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws UnrecoverableEntryException */ private PrivateKeyWrapper loadPrivateKeyEntryForAlias(final KeyStore keyStore, final String alias, - final String keyStorePassword, final String keyPassword) { + final String keyStorePassword, final String keyPassword) { if (keyStore == null || alias == null) { return null; } @@ -298,52 +295,53 @@ private PrivateKeyWrapper loadPrivateKeyEntryForAlias(final KeyStore keyStore, f // There is no private key matching this alias return null; } - } catch (KeyStoreException e) { + } catch (KeyStoreException exc) { return null; } // Try loading the private key with the key password (which can be null) try { final char[] pass = keyPassword == null ? null : keyPassword.toCharArray(); - final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pass)); + final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore + .getEntry(alias, new KeyStore.PasswordProtection(pass)); return new PrivateKeyWrapper(entry.getPrivateKey(), keyPassword, entry.getCertificateChain()); - } catch (KeyStoreException | NoSuchAlgorithmException e) { - return null; - } catch (UnrecoverableEntryException e) { + } catch (KeyStoreException | NoSuchAlgorithmException exc) { + return null; + } catch (UnrecoverableEntryException exc) { // The key password didn't work (or just wasn't set). Try using the keystore password. final char[] pass = keyStorePassword == null ? null : keyStorePassword.toCharArray(); try { - final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pass)); - return new PrivateKeyWrapper(entry.getPrivateKey(), keyPassword, entry.getCertificateChain()); + final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore + .getEntry(alias, new KeyStore.PasswordProtection(pass)); + return new PrivateKeyWrapper(entry.getPrivateKey(), keyPassword, + entry.getCertificateChain()); } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableEntryException e1) { - // Neither password worked. - return null; + // Neither password worked. + return null; } } } /** - *

Loads from a keystore the first valid private key entry found, and returns it parsed and ready to be + *

Loads from a keystore the first valid private key entry found, and returns it parsed and + * ready to be * passed to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}.

* - *

To access the private key, this method will first try using the keyPassword parameter - * value (this parameter can be set to null to explicitly indicate that there is no password). - * If that fails, then this method will then try using the keyStorePassword parameter value - * as the key value too.

+ *

To access the private key, this method will first try using the keyPassword + * parameter + * value (this parameter can be set to null to explicitly indicate that there is no + * password). If that fails, then this method will then try using the + * keyStorePassword parameter value as the key value too.

* - *

Returns null if there is any problem accessing the keystore, if neither keyPassword - * or keyStorePassword can unlock the private key, or if no private key entry matches + *

Returns null if there is any problem accessing the keystore, if neither + * keyPassword + * or keyStorePassword can unlock the private key, or if no private key entry + * matches * alias.

- * - * @param keyStore - * @param keyStorePassword - * @param keyPassword - * @return - * @throws KeyStoreException - * @throws NoSuchAlgorithmException */ - private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, final String keyStorePassword, - final String keyPassword) { + private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, + final String keyStorePassword, + final String keyPassword) { if (keyStore == null) { return null; } @@ -351,13 +349,14 @@ private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, final Str final Enumeration aliases; try { aliases = keyStore.aliases(); - } catch (KeyStoreException e) { + } catch (KeyStoreException exc) { return null; } while (aliases.hasMoreElements()) { final String alias = aliases.nextElement(); - final PrivateKeyWrapper privateKeyWrapper = loadPrivateKeyEntryForAlias(keyStore, alias, keyStorePassword, keyPassword); + final PrivateKeyWrapper privateKeyWrapper = loadPrivateKeyEntryForAlias(keyStore, alias, + keyStorePassword, keyPassword); if (privateKeyWrapper != null) { return privateKeyWrapper; } @@ -366,20 +365,23 @@ private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, final Str } /** - * A container for the values returned by {@link this#loadPrivateKeyEntry(KeyStore, String, String)} and - * {@link this#loadPrivateKeyEntryForAlias(KeyStore, String, String, String)}, and passed in turn - * to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}. Helpful since Java - * methods cannot return multiple values. + * A container for the values returned by {@link this#loadPrivateKeyEntry(KeyStore, String, + * String)} and {@link this#loadPrivateKeyEntryForAlias(KeyStore, String, String, String)}, and + * passed in turn to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}. + * Helpful since Java methods cannot return multiple values. */ private class PrivateKeyWrapper { + private PrivateKey privateKey; private String password; private X509Certificate[] certificateChain; - public PrivateKeyWrapper(final PrivateKey privateKey, final String password, final Certificate[] certificateChain) { + public PrivateKeyWrapper(final PrivateKey privateKey, final String password, + final Certificate[] certificateChain) { this.privateKey = privateKey; this.password = password; - this.certificateChain = Arrays.copyOf(certificateChain, certificateChain.length, X509Certificate[].class); + this.certificateChain = Arrays + .copyOf(certificateChain, certificateChain.length, X509Certificate[].class); } public PrivateKey getPrivateKey() { diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java index fe2b68b119c..d8b6b12aff7 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java @@ -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 @@ import io.grpc.stub.StreamObserver; import io.vitess.client.StreamIterator; + import java.sql.SQLDataException; import java.sql.SQLException; import java.util.NoSuchElementException; @@ -29,9 +30,9 @@ * gRPC {@code StreamObserver} interface. * *

This class is abstract because it needs to be told how to extract the result - * (e.g. {@link io.vitess.proto.Query.QueryResult QueryResult}) from a given RPC response - * (e.g. {@link io.vitess.proto.Vtgate.StreamExecuteResponse StreamExecuteResponse}). - * Callers must therefore implement {@link #getResult(Object)} when instantiating this class. + * (e.g. {@link io.vitess.proto.Query.QueryResult QueryResult}) from a given RPC response (e.g. + * {@link io.vitess.proto.Vtgate.StreamExecuteResponse StreamExecuteResponse}). Callers must + * therefore implement {@link #getResult(Object)} when instantiating this class. * *

The {@code StreamObserver} side will block until the result has been returned to the consumer * by the {@code StreamIterator} side. Therefore, the {@link #close()} method must be called when @@ -42,11 +43,12 @@ */ abstract class GrpcStreamAdapter implements StreamObserver, StreamIterator, AutoCloseable { + /** - * getResult must be implemented to tell the adapter how to convert from - * the StreamObserver value type (V) to the StreamIterator value type (E). - * Before converting, getResult() should check for application-level errors - * in the RPC response and throw the appropriate SQLException. + * getResult must be implemented to tell the adapter how to convert from the StreamObserver value + * type (V) to the StreamIterator value type (E). Before converting, getResult() should check for + * application-level errors in the RPC response and throw the appropriate SQLException. + * * @param value The RPC response object. * @return The result object to pass to the iterator consumer. * @throws SQLException For errors originating within the Vitess server. @@ -75,10 +77,10 @@ public void onNext(V value) { nextValue = getResult(value); notifyAll(); - } catch (InterruptedException e) { - onError(e); - } catch (SQLException e) { - onError(e); + } catch (InterruptedException exc) { + onError(exc); + } catch (SQLException exc) { + onError(exc); } } } @@ -117,9 +119,9 @@ public boolean hasNext() throws SQLException { } return true; - } catch (InterruptedException e) { - onError(e); - throw new SQLDataException("gRPC StreamIterator interrupted while waiting for value", e); + } catch (InterruptedException exc) { + onError(exc); + throw new SQLDataException("gRPC StreamIterator interrupted while waiting for value", exc); } } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java index 0127e876a66..1991772df35 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java @@ -3,15 +3,6 @@ import static com.google.common.base.Preconditions.checkState; import static io.grpc.internal.GrpcUtil.TIMER_SERVICE; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import javax.annotation.Nullable; - import io.grpc.CallOptions; import io.grpc.Channel; import io.grpc.ClientCall; @@ -22,14 +13,24 @@ import io.grpc.Status; import io.grpc.internal.SharedResourceHolder; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + /** - * RetryingInterceptor is used for retrying certain classes of failed requests in the underlying gRPC connection. - * At this time it handles {@link MethodDescriptor.MethodType.UNARY} requests with status {@link Status.Code.UNAVAILABLE}, which is - * according to the spec meant to be a transient error. This class can be configured with {@link RetryingInterceptorConfig} to - * determine what level of exponential backoff to apply to the handled types of failing requests. + * RetryingInterceptor is used for retrying certain classes of failed requests in the underlying + * gRPC connection. At this time it handles {@link MethodDescriptor.MethodType.UNARY} requests with + * status {@link Status.Code.UNAVAILABLE}, which is according to the spec meant to be a transient + * error. This class can be configured with {@link RetryingInterceptorConfig} to determine what + * level of exponential backoff to apply to the handled types of failing requests. * - * When enabled, this interceptor will retry valid requests with an exponentially increasing backoff time up to the maximum - * time defined by the {@link io.grpc.Deadline} in the call's {@link CallOptions}. + * When enabled, this interceptor will retry valid requests with an exponentially increasing backoff + * time up to the maximum time defined by the {@link io.grpc.Deadline} in the call's {@link + * CallOptions}. */ public class RetryingInterceptor implements ClientInterceptor { @@ -52,6 +53,7 @@ public ClientCall interceptCall( } private class RetryingCall extends ClientCall { + private final MethodDescriptor method; private final CallOptions callOptions; private final Channel channel; @@ -71,8 +73,8 @@ private class RetryingCall extends ClientCall { private final double backoffMultiplier; RetryingCall(MethodDescriptor method, - CallOptions callOptions, Channel channel, Context context, - RetryingInterceptorConfig config) { + CallOptions callOptions, Channel channel, Context context, + RetryingInterceptorConfig config) { this.method = method; this.callOptions = callOptions; this.channel = channel; @@ -136,7 +138,7 @@ public void setMessageCompression(boolean enabled) { private long computeSleepTime() { long currentBackoff = nextBackoffMillis; - nextBackoffMillis = Math.min((long) ( currentBackoff * backoffMultiplier), maxBackoffMillis); + nextBackoffMillis = Math.min((long) (currentBackoff * backoffMultiplier), maxBackoffMillis); return currentBackoff; } @@ -194,6 +196,7 @@ private ClientCall lastCall() { } private class AttemptListener extends ClientCall.Listener { + final ClientCall call; Metadata responseHeaders; RespT responseMessage; diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java index 4e75c2ba60d..f3d3f0eeb76 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java @@ -1,8 +1,8 @@ package io.vitess.client.grpc; /** - * This class defines what level of exponential backoff to apply in the {@link RetryingInterceptor}. It can be - * disabled with the {@link #noOpConfig()}. + * This class defines what level of exponential backoff to apply in the {@link RetryingInterceptor}. + * It can be disabled with the {@link #noOpConfig()}. */ public class RetryingInterceptorConfig { @@ -12,7 +12,8 @@ public class RetryingInterceptorConfig { private final long maxBackoffMillis; private final double backoffMultiplier; - private RetryingInterceptorConfig(long initialBackoffMillis, long maxBackoffMillis, double backoffMultiplier) { + private RetryingInterceptorConfig(long initialBackoffMillis, long maxBackoffMillis, + double backoffMultiplier) { this.initialBackoffMillis = initialBackoffMillis; this.maxBackoffMillis = maxBackoffMillis; this.backoffMultiplier = backoffMultiplier; @@ -26,15 +27,16 @@ public static RetryingInterceptorConfig noOpConfig() { } /** - * Returns an exponential config with the given values to determine how aggressive of a backoff is needed - * @param initialBackoffMillis - * how long in millis to backoff off for the first attempt - * @param maxBackoffMillis - * the maximum value the backoff time can grow to, at which point all future retries will backoff at this amount - * @param backoffMultiplier - * how quickly the backoff time should grow + * Returns an exponential config with the given values to determine how aggressive of a backoff is + * needed + * + * @param initialBackoffMillis how long in millis to backoff off for the first attempt + * @param maxBackoffMillis the maximum value the backoff time can grow to, at which point all + * future retries will backoff at this amount + * @param backoffMultiplier how quickly the backoff time should grow */ - public static RetryingInterceptorConfig exponentialConfig(long initialBackoffMillis, long maxBackoffMillis, double backoffMultiplier) { + public static RetryingInterceptorConfig exponentialConfig(long initialBackoffMillis, + long maxBackoffMillis, double backoffMultiplier) { return new RetryingInterceptorConfig(initialBackoffMillis, maxBackoffMillis, backoffMultiplier); } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java index fbf5694b8c9..d04754ee5d8 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java @@ -5,6 +5,7 @@ import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.Status; + import java.util.Objects; import java.util.concurrent.Executor; @@ -35,8 +36,8 @@ public void applyRequestMetadata(MethodDescriptor method, Attributes attrs headers.put(USERNAME, username); headers.put(PASSWORD, password); applier.apply(headers); - } catch (Throwable e) { - applier.fail(Status.UNAUTHENTICATED.withCause(e)); + } catch (Throwable exc) { + applier.fail(Status.UNAUTHENTICATED.withCause(exc)); } }); } diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java index 8be2567535c..1148406412e 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java @@ -1,6 +1,7 @@ package io.client.grpc; import com.google.common.base.Throwables; + import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.vitess.client.Context; @@ -9,11 +10,14 @@ import io.vitess.client.grpc.GrpcClientFactory; import io.vitess.client.grpc.StaticAuthCredentials; import io.vitess.proto.Vtgate.GetSrvKeyspaceRequest; + +import org.joda.time.Duration; + import java.net.ServerSocket; import java.net.URI; import java.util.Arrays; import java.util.concurrent.ExecutionException; -import org.joda.time.Duration; + import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -23,6 +27,7 @@ @RunWith(JUnit4.class) public class GrpcClientStaticAuthTest extends RpcClientTest { + private static Process vtgateclienttest; private static int port; @@ -32,7 +37,8 @@ public static void setUpBeforeClass() throws Exception { if (vtRoot == null) { throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); } - URI staticAuthFile = GrpcClientStaticAuthTest.class.getResource("grpc_static_auth.json").toURI(); + URI staticAuthFile = GrpcClientStaticAuthTest.class.getResource("grpc_static_auth.json") + .toURI(); ServerSocket socket = new ServerSocket(0); port = socket.getLocalPort(); diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java index 00425e84a3e..18e69eaba21 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java @@ -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.client.grpc; +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; + +import org.joda.time.Duration; + import java.net.ServerSocket; import java.util.Arrays; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; - /** * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest). */ @RunWith(JUnit4.class) public class GrpcClientTest extends RpcClientTest { + private static Process vtgateclienttest; private static int port; @@ -50,13 +52,13 @@ public static void setUpBeforeClass() throws Exception { vtgateclienttest = new ProcessBuilder( - Arrays.asList( - vtRoot + "/bin/vtgateclienttest", - "-logtostderr", - "-grpc_port", - Integer.toString(port), - "-service_map", - "grpc-vtgateservice")) + Arrays.asList( + vtRoot + "/bin/vtgateclienttest", + "-logtostderr", + "-grpc_port", + Integer.toString(port), + "-service_map", + "grpc-vtgateservice")) .inheritIO() .start(); diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java index f37ed7467a2..19f2d4de91a 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java @@ -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,169 +16,186 @@ package io.client.grpc; +import com.google.common.io.Files; + +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; +import io.vitess.client.grpc.tls.TlsOptions; + +import org.joda.time.Duration; + import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.nio.file.Paths; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import com.google.common.io.Files; - -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; -import io.vitess.client.grpc.tls.TlsOptions; - /** - * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL connection with client - * authentication enabled. + * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL connection + * with client authentication enabled. */ @RunWith(JUnit4.class) public class GrpcClientTlsClientAuthTest extends RpcClientTest { - private static Process vtgateclienttest; - private static int port; - private static File certDirectory; - - private static String caConfig; - private static String caKey; - private static String caCert; - private static String caCertDer; - private static String trustStore; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - certDirectory = Files.createTempDir(); - System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); - - caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; - caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; - caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; - caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; - trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; - - createCA(); - createTrustStore(); - createSignedCert("01", "server"); - createSignedCert("02", "client"); - createKeyStore("client"); - - startVtgate(); - createClientConnection(); + private static Process vtgateclienttest; + private static int port; + private static File certDirectory; + + private static String caConfig; + private static String caKey; + private static String caCert; + private static String caCertDer; + private static String trustStore; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + certDirectory = Files.createTempDir(); + System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); + + caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; + caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; + caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; + caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; + trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; + + createCA(); + createTrustStore(); + createSignedCert("01", "server"); + createSignedCert("02", "client"); + createKeyStore("client"); + + startVtgate(); + createClientConnection(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + if (client != null) { + client.close(); } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - if (client != null) { - client.close(); - } - if (vtgateclienttest != null) { - vtgateclienttest.destroy(); - vtgateclienttest.waitFor(); - } + if (vtgateclienttest != null) { + vtgateclienttest.destroy(); + vtgateclienttest.waitFor(); } - - private static void runProcess(final String command) throws IOException, InterruptedException { - System.out.println("\nExecuting: " + command); - int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); - System.out.println("Exit code: " + exitCode + "\n"); + } + + private static void runProcess(final String command) throws IOException, InterruptedException { + System.out.println("\nExecuting: " + command); + int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); + System.out.println("Exit code: " + exitCode + "\n"); + } + + private static void createCA() throws Exception { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), + Paths.get(caConfig) + ); + + final String createKey = String.format("openssl genrsa -out %s 2048", caKey); + runProcess(createKey); + + final String createCert = String + .format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", + caConfig, caKey, caCert); + runProcess(createCert); + } + + private static void createTrustStore() throws Exception { + final String convertCaCert = String + .format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); + runProcess(convertCaCert); + + final String createTrustStore = String.format( + "keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", + trustStore, caCertDer); + runProcess(createTrustStore); + } + + private static void createSignedCert(final String serial, final String name) throws Exception { + final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; + if (!(new File(certConfig)).exists()) { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), + Paths.get(certConfig) + ); } - - private static void createCA() throws Exception { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), - Paths.get(caConfig) - ); - - final String createKey = String.format("openssl genrsa -out %s 2048", caKey); - runProcess(createKey); - - final String createCert = String.format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", caConfig, caKey, caCert); - runProcess(createCert); - } - - private static void createTrustStore() throws Exception { - final String convertCaCert = String.format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); - runProcess(convertCaCert); - - final String createTrustStore = String.format("keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", trustStore, caCertDer); - runProcess(createTrustStore); - } - - private static void createSignedCert(final String serial, final String name) throws Exception { - final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; - if (!(new File(certConfig)).exists()) { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), - Paths.get(certConfig) - ); - } - final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; - final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; - - final String createKeyAndCSR = String.format("openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", certConfig, key, req); - runProcess(createKeyAndCSR); - - final String signKey = String.format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, caCert, caKey, serial, cert); - runProcess(signKey); + final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; + final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; + + final String createKeyAndCSR = String.format( + "openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", + certConfig, key, req); + runProcess(createKeyAndCSR); + + final String signKey = String + .format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, + caCert, caKey, serial, cert); + runProcess(signKey); + } + + private static void createKeyStore(final String name) throws Exception { + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; + final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; + final String p12 = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.p12"; + final String keyStore = + certDirectory.getCanonicalPath() + File.separatorChar + name + "-keyStore.jks"; + + final String convertCert = String.format( + "openssl pkcs12 -export -in %s -inkey %s -out %s -name cert -CAfile %s -caname root -passout pass:passwd", + cert, key, p12, caCert); + System.out.println(convertCert); + new ProcessBuilder(convertCert.split(" ")).start().waitFor(); + + final String createKeyStore = String.format( + "keytool -importkeystore -deststorepass passwd -destkeystore %s -srckeystore %s -srcstoretype PKCS12 -alias cert -srcstorepass passwd", + keyStore, p12); + System.out.println(createKeyStore); + new ProcessBuilder(createKeyStore.split(" ")).start().waitFor(); + } + + private static void startVtgate() throws Exception { + final String vtRoot = System.getenv("VTROOT"); + if (vtRoot == null) { + throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); } - private static void createKeyStore(final String name) throws Exception { - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; - final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; - final String p12 = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.p12"; - final String keyStore = certDirectory.getCanonicalPath() + File.separatorChar + name + "-keyStore.jks"; - - final String convertCert = String.format("openssl pkcs12 -export -in %s -inkey %s -out %s -name cert -CAfile %s -caname root -passout pass:passwd", cert, key, p12, caCert); - System.out.println(convertCert); - new ProcessBuilder(convertCert.split(" ")).start().waitFor(); - - final String createKeyStore = String.format("keytool -importkeystore -deststorepass passwd -destkeystore %s -srckeystore %s -srcstoretype PKCS12 -alias cert -srcstorepass passwd", keyStore, p12); - System.out.println(createKeyStore); - new ProcessBuilder(createKeyStore.split(" ")).start().waitFor(); - } - - private static void startVtgate() throws Exception { - final String vtRoot = System.getenv("VTROOT"); - if (vtRoot == null) { - throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); - } - - final ServerSocket socket = new ServerSocket(0); - port = socket.getLocalPort(); - socket.close(); - - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; - final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; - - final String vtgateCommand = String.format("%s -grpc_cert %s -grpc_key %s -grpc_ca %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", - vtRoot + "/bin/vtgateclienttest", cert, key, caCert, Integer.toString(port)); - System.out.println(vtgateCommand); - vtgateclienttest = new ProcessBuilder(vtgateCommand.split(" ")).inheritIO().start(); - } - - private static void createClientConnection() throws Exception { - final String keyStore = certDirectory.getCanonicalPath() + File.separatorChar + "client-keyStore.jks"; - - final TlsOptions tlsOptions = new TlsOptions() - .keyStorePath(keyStore) - .keyStorePassword("passwd") - .keyAlias("cert") - .trustStorePath(trustStore) - .trustStorePassword("passwd") - .trustAlias("cacert"); - - client = new GrpcClientFactory() - .createTls( - Context.getDefault().withDeadlineAfter(Duration.millis(5000)), - "localhost:" + port, - tlsOptions - ); - } + final ServerSocket socket = new ServerSocket(0); + port = socket.getLocalPort(); + socket.close(); + + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; + final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; + + final String vtgateCommand = String.format( + "%s -grpc_cert %s -grpc_key %s -grpc_ca %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", + vtRoot + "/bin/vtgateclienttest", cert, key, caCert, Integer.toString(port)); + System.out.println(vtgateCommand); + vtgateclienttest = new ProcessBuilder(vtgateCommand.split(" ")).inheritIO().start(); + } + + private static void createClientConnection() throws Exception { + final String keyStore = + certDirectory.getCanonicalPath() + File.separatorChar + "client-keyStore.jks"; + + final TlsOptions tlsOptions = new TlsOptions() + .keyStorePath(keyStore) + .keyStorePassword("passwd") + .keyAlias("cert") + .trustStorePath(trustStore) + .trustStorePassword("passwd") + .trustAlias("cacert"); + + client = new GrpcClientFactory() + .createTls( + Context.getDefault().withDeadlineAfter(Duration.millis(5000)), + "localhost:" + port, + tlsOptions + ); + } } diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java index e326ea8f00f..f0c44616de4 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java @@ -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,153 +16,165 @@ package io.client.grpc; +import com.google.common.io.Files; + +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; +import io.vitess.client.grpc.tls.TlsOptions; + +import org.joda.time.Duration; + import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.nio.file.Paths; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import com.google.common.io.Files; - -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; -import io.vitess.client.grpc.tls.TlsOptions; - /** - * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL connection. + * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL + * connection. * * The SSL setup is adapted from "test/encrypted_transport.py" */ @RunWith(JUnit4.class) public class GrpcClientTlsTest extends RpcClientTest { - private static Process vtgateclienttest; - private static int port; - private static File certDirectory; + private static Process vtgateclienttest; + private static int port; + private static File certDirectory; - private static String caConfig; - private static String caKey; - private static String caCert; - private static String caCertDer; - private static String trustStore; + private static String caConfig; + private static String caKey; + private static String caCert; + private static String caCertDer; + private static String trustStore; - @BeforeClass - public static void setUpBeforeClass() throws Exception { - certDirectory = Files.createTempDir(); - System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); + @BeforeClass + public static void setUpBeforeClass() throws Exception { + certDirectory = Files.createTempDir(); + System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); - caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; - caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; - caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; - caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; - trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; + caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; + caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; + caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; + caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; + trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; - createCA(); - createTrustStore(); + createCA(); + createTrustStore(); - createSignedCert("01", "server"); + createSignedCert("01", "server"); - startVtgate(); - createClientConnection(); - } + startVtgate(); + createClientConnection(); + } - @AfterClass - public static void tearDownAfterClass() throws Exception { - if (client != null) { - client.close(); - } - if (vtgateclienttest != null) { - vtgateclienttest.destroy(); - vtgateclienttest.waitFor(); - } + @AfterClass + public static void tearDownAfterClass() throws Exception { + if (client != null) { + client.close(); } - - private static void runProcess(final String command) throws IOException, InterruptedException { - System.out.println("\nExecuting: " + command); - int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); - System.out.println("Exit code: " + exitCode + "\n"); + if (vtgateclienttest != null) { + vtgateclienttest.destroy(); + vtgateclienttest.waitFor(); } - - private static void createCA() throws Exception { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), - Paths.get(caConfig) - ); - - final String createKey = String.format("openssl genrsa -out %s 2048", caKey); - runProcess(createKey); - - final String createCert = String.format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", caConfig, caKey, caCert); - runProcess(createCert); + } + + private static void runProcess(final String command) throws IOException, InterruptedException { + System.out.println("\nExecuting: " + command); + int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); + System.out.println("Exit code: " + exitCode + "\n"); + } + + private static void createCA() throws Exception { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), + Paths.get(caConfig) + ); + + final String createKey = String.format("openssl genrsa -out %s 2048", caKey); + runProcess(createKey); + + final String createCert = String + .format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", + caConfig, caKey, caCert); + runProcess(createCert); + } + + private static void createTrustStore() throws Exception { + final String convertCaCert = String + .format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); + runProcess(convertCaCert); + + final String createTrustStore = String.format( + "keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", + trustStore, caCertDer); + runProcess(createTrustStore); + } + + private static void createSignedCert(final String serial, final String name) throws Exception { + final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; + if (!(new File(certConfig)).exists()) { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), + Paths.get(certConfig) + ); } - - private static void createTrustStore() throws Exception { - final String convertCaCert = String.format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); - runProcess(convertCaCert); - - final String createTrustStore = String.format("keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", trustStore, caCertDer); - runProcess(createTrustStore); - } - - private static void createSignedCert(final String serial, final String name) throws Exception { - final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; - if (!(new File(certConfig)).exists()) { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), - Paths.get(certConfig) - ); - } - final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; - final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; - - final String createKeyAndCSR = String.format("openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", certConfig, key, req); - runProcess(createKeyAndCSR); - - final String signKey = String.format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, caCert, caKey, serial, cert); - runProcess(signKey); + final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; + final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; + + final String createKeyAndCSR = String.format( + "openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", + certConfig, key, req); + runProcess(createKeyAndCSR); + + final String signKey = String + .format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, + caCert, caKey, serial, cert); + runProcess(signKey); + } + + private static void startVtgate() throws Exception { + final String vtRoot = System.getenv("VTROOT"); + if (vtRoot == null) { + throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); } - - private static void startVtgate() throws Exception { - final String vtRoot = System.getenv("VTROOT"); - if (vtRoot == null) { - throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); - } - final ServerSocket socket = new ServerSocket(0); - port = socket.getLocalPort(); - socket.close(); - - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; - final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; - - final String vtgate = String.format("%s -grpc_cert %s -grpc_key %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", - vtRoot + "/bin/vtgateclienttest", - cert, - key, - Integer.toString(port) + final ServerSocket socket = new ServerSocket(0); + port = socket.getLocalPort(); + socket.close(); + + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; + final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; + + final String vtgate = String.format( + "%s -grpc_cert %s -grpc_key %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", + vtRoot + "/bin/vtgateclienttest", + cert, + key, + Integer.toString(port) + ); + System.out.println(vtgate); + vtgateclienttest = new ProcessBuilder().inheritIO().command(vtgate.split(" ")).start(); + } + + private static void createClientConnection() throws Exception { + final TlsOptions tlsOptions = new TlsOptions() + .trustStorePath(trustStore) + .trustStorePassword("passwd") + .trustAlias("cacert"); + + client = new GrpcClientFactory() + .createTls( + Context.getDefault().withDeadlineAfter(Duration.millis(5000)), + "localhost:" + port, + tlsOptions ); - System.out.println(vtgate); - vtgateclienttest = new ProcessBuilder().inheritIO().command(vtgate.split(" ")).start(); - } - - private static void createClientConnection() throws Exception { - final TlsOptions tlsOptions = new TlsOptions() - .trustStorePath(trustStore) - .trustStorePassword("passwd") - .trustAlias("cacert"); - - client = new GrpcClientFactory() - .createTls( - Context.getDefault().withDeadlineAfter(Duration.millis(5000)), - "localhost:" + port, - tlsOptions - ); - } + } } diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java index ab66d6f9bdf..92164de28ac 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java @@ -1,18 +1,20 @@ package io.client.grpc; +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; +import io.vitess.client.grpc.RetryingInterceptorConfig; + +import org.joda.time.Duration; + import java.net.ServerSocket; import java.util.Arrays; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; -import io.vitess.client.grpc.RetryingInterceptorConfig; - public class GrpcClientWithRetriesTest extends RpcClientTest { + private static Process vtgateclienttest; private static int port; @@ -39,7 +41,6 @@ public static void setUpBeforeClass() throws Exception { .inheritIO() .start(); - client = new GrpcClientFactory(RetryingInterceptorConfig.exponentialConfig(5, 60, 2)) .create( diff --git a/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java b/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java index 757e77b1926..9e325c7de68 100644 --- a/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java +++ b/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java @@ -1,13 +1,5 @@ package io.vitess.client.grpc; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -import org.junit.Assert; -import org.junit.Test; - import com.google.common.util.concurrent.ListenableFuture; import io.grpc.CallOptions; @@ -22,15 +14,26 @@ import io.vitess.proto.Vtgate; import io.vitess.proto.grpc.VitessGrpc; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + +import org.junit.Assert; +import org.junit.Test; + public class RetryingInterceptorTest { @Test public void testNoopConfigPassesThrough() throws ExecutionException, InterruptedException { ForceRetryNTimesInterceptor forceRetryNTimesInterceptor = new ForceRetryNTimesInterceptor(3); - ManagedChannel channel = InProcessChannelBuilder.forName("foo").intercept(new RetryingInterceptor(RetryingInterceptorConfig.noOpConfig()), forceRetryNTimesInterceptor).build(); + ManagedChannel channel = InProcessChannelBuilder.forName("foo") + .intercept(new RetryingInterceptor(RetryingInterceptorConfig.noOpConfig()), + forceRetryNTimesInterceptor).build(); VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel); - ListenableFuture resp = stub.execute(Vtgate.ExecuteRequest.getDefaultInstance()); + ListenableFuture resp = stub + .execute(Vtgate.ExecuteRequest.getDefaultInstance()); try { resp.get(); Assert.fail("Should have failed after 1 attempt"); @@ -42,10 +45,14 @@ public void testNoopConfigPassesThrough() throws ExecutionException, Interrupted @Test public void testRetryAfterBackoff() throws ExecutionException, InterruptedException { ForceRetryNTimesInterceptor forceRetryNTimesInterceptor = new ForceRetryNTimesInterceptor(3); - RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig.exponentialConfig(5, 60, 2); - ManagedChannel channel = InProcessChannelBuilder.forName("foo").intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)).build(); + RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig + .exponentialConfig(5, 60, 2); + ManagedChannel channel = InProcessChannelBuilder.forName("foo") + .intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)) + .build(); VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel); - ListenableFuture resp = stub.execute(Vtgate.ExecuteRequest.getDefaultInstance()); + ListenableFuture resp = stub + .execute(Vtgate.ExecuteRequest.getDefaultInstance()); try { resp.get(); Assert.fail("Should have failed after 3 attempt"); @@ -58,10 +65,15 @@ public void testRetryAfterBackoff() throws ExecutionException, InterruptedExcept @Test public void testRetryDeadlineExceeded() throws ExecutionException, InterruptedException { ForceRetryNTimesInterceptor forceRetryNTimesInterceptor = new ForceRetryNTimesInterceptor(3); - RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig.exponentialConfig(5, 60, 2); - ManagedChannel channel = InProcessChannelBuilder.forName("foo").intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)).build(); - VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel).withDeadlineAfter(1, TimeUnit.MILLISECONDS); - ListenableFuture resp = stub.execute(Vtgate.ExecuteRequest.getDefaultInstance()); + RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig + .exponentialConfig(5, 60, 2); + ManagedChannel channel = InProcessChannelBuilder.forName("foo") + .intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)) + .build(); + VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel) + .withDeadlineAfter(1, TimeUnit.MILLISECONDS); + ListenableFuture resp = stub + .execute(Vtgate.ExecuteRequest.getDefaultInstance()); try { resp.get(); Assert.fail("Should have failed"); @@ -85,7 +97,8 @@ int getNumRetryableFailures() { } @Override - public ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) { + public ClientCall interceptCall(MethodDescriptor method, + CallOptions callOptions, Channel next) { System.out.println("Num failures: " + numRetryableFailures); if (numRetryableFailures < timesToForceRetry) { From 5ee78a5c0c27d655c30a9687916c2e1d79a8e8cf Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 13:25:45 -0500 Subject: [PATCH 3/9] vitess-hadoop: checkstyle Signed-off-by: Ze'ev Klapow --- .../vitess/client/grpc/GrpcClientFactory.java | 6 +-- .../java/io/vitess/hadoop/RowWritable.java | 19 +++++--- .../java/io/vitess/hadoop/VitessConf.java | 15 ++++--- .../io/vitess/hadoop/VitessInputFormat.java | 39 ++++++++-------- .../io/vitess/hadoop/VitessInputSplit.java | 14 +++--- .../io/vitess/hadoop/VitessRecordReader.java | 44 ++++++++++--------- .../java/io/vitess/hadoop/MapReduceIT.java | 35 ++++++++------- 7 files changed, 97 insertions(+), 75 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 19524061faa..92847bde42f 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -102,9 +102,9 @@ public RpcClient create(Context ctx, String target) { } /** - *

This method constructs NettyChannelBuilder object that will be used to create - * RpcClient.

- *

Subclasses may override this method to make adjustments to the builder

+ * This method constructs NettyChannelBuilder object that will be used to create + * RpcClient. + * Subclasses may override this method to make adjustments to the builder * for example: * * diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java b/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java index d8377fcb3d2..d349d8ae550 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java @@ -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,9 +19,13 @@ import com.google.common.collect.Lists; import com.google.common.io.BaseEncoding; import com.google.gson.Gson; + import io.vitess.client.cursor.Row; import io.vitess.proto.Query; import io.vitess.proto.Query.Field; + +import org.apache.hadoop.io.Writable; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -29,12 +33,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.hadoop.io.Writable; public class RowWritable implements Writable { + private Row row; - public RowWritable() {} + public RowWritable() { + } public RowWritable(Row row) { this.row = row; @@ -76,8 +81,8 @@ public String toString() { if (!map.containsKey(key)) { try { map.put(key, row.getRawValue(i + 1).toStringUtf8()); - } catch (SQLException e) { - map.put(key, e.toString()); + } catch (SQLException exc) { + map.put(key, exc.toString()); } } } diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java index 19cf26e81e4..c70c4b22f01 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java @@ -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,13 +19,16 @@ import io.vitess.client.RpcClientFactory; import io.vitess.proto.Query; import io.vitess.proto.Query.SplitQueryRequest; -import java.util.Collection; + import org.apache.hadoop.conf.Configuration; +import java.util.Collection; + /** * Collection of configuration properties used for {@link VitessInputFormat} */ public class VitessConf { + public static final String HOSTS = "vitess.client.hosts"; public static final String CONN_TIMEOUT_MS = "vitess.client.conn_timeout_ms"; public static final String INPUT_KEYSPACE = "vitess.client.keyspace"; @@ -108,7 +111,9 @@ public void setAlgorithm(SplitQueryRequest.Algorithm algorithm) { conf.setEnum(ALGORITHM, algorithm); } - public String getRpcFactoryClass() { return conf.get(RPC_FACTORY_CLASS); } + public String getRpcFactoryClass() { + return conf.get(RPC_FACTORY_CLASS); + } public void setRpcFactoryClass(Class clz) { conf.set(RPC_FACTORY_CLASS, clz.getName()); diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java index 62cd1ca4b12..97d06b845a1 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java @@ -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,12 +18,14 @@ import static com.google.common.base.Preconditions.checkNotNull; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Random; +import com.google.common.collect.Lists; + +import io.vitess.client.Context; +import io.vitess.client.RpcClient; +import io.vitess.client.RpcClientFactory; +import io.vitess.client.VTGateBlockingConn; +import io.vitess.proto.Query.SplitQueryRequest.Algorithm; +import io.vitess.proto.Vtgate.SplitQueryResponse; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.mapreduce.InputFormat; @@ -32,16 +34,15 @@ import org.apache.hadoop.mapreduce.JobContext; import org.apache.hadoop.mapreduce.RecordReader; import org.apache.hadoop.mapreduce.TaskAttemptContext; -import org.joda.time.Duration; -import com.google.common.collect.Lists; +import org.joda.time.Duration; -import io.vitess.client.Context; -import io.vitess.client.RpcClient; -import io.vitess.client.RpcClientFactory; -import io.vitess.client.VTGateBlockingConn; -import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import io.vitess.proto.Vtgate.SplitQueryResponse; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Random; /** * {@link VitessInputFormat} is the {@link org.apache.hadoop.mapreduce.InputFormat} for tables in @@ -77,8 +78,8 @@ public List getSplits(JobContext context) { conf.getAlgorithm()); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException - | IOException e) { - throw new RuntimeException(e); + | IOException exc) { + throw new RuntimeException(exc); } List splits = Lists.newArrayList(); diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java index 1dbf0d40caa..e32edf4c9fc 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java @@ -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,14 +17,18 @@ package io.vitess.hadoop; import com.google.common.io.BaseEncoding; + import io.vitess.proto.Vtgate.SplitQueryResponse; + +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapreduce.InputSplit; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import org.apache.hadoop.io.Writable; -import org.apache.hadoop.mapreduce.InputSplit; public class VitessInputSplit extends InputSplit implements Writable { + private String[] locations; private SplitQueryResponse.Part split; diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java index 221f7f1e14d..e8b83d9d6ce 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java @@ -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,18 +16,6 @@ package io.vitess.hadoop; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -import org.apache.hadoop.io.NullWritable; -import org.apache.hadoop.mapreduce.InputSplit; -import org.apache.hadoop.mapreduce.RecordReader; -import org.apache.hadoop.mapreduce.TaskAttemptContext; -import org.joda.time.Duration; - import io.vitess.client.Context; import io.vitess.client.RpcClient; import io.vitess.client.RpcClientFactory; @@ -39,7 +27,21 @@ import io.vitess.proto.Topodata.TabletType; import io.vitess.proto.Vtgate.SplitQueryResponse; +import org.apache.hadoop.io.NullWritable; +import org.apache.hadoop.mapreduce.InputSplit; +import org.apache.hadoop.mapreduce.RecordReader; +import org.apache.hadoop.mapreduce.TaskAttemptContext; + +import org.joda.time.Duration; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + public class VitessRecordReader extends RecordReader { + private VitessInputSplit split; private VTGateBlockingConn vtgate; private VitessConf conf; @@ -68,8 +70,8 @@ public void initialize(InputSplit split, TaskAttemptContext context) addressList.get(index)); vtgate = new VTGateBlockingConn(rpcClient); includedFields = conf.getIncludedFields(); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException exc) { + throw new RuntimeException(exc); } } @@ -79,8 +81,8 @@ public void close() throws IOException { try { vtgate.close(); vtgate = null; - } catch (IOException e) { - throw new RuntimeException(e); + } catch (IOException exc) { + throw new RuntimeException(exc); } } } @@ -134,8 +136,8 @@ public boolean nextKeyValue() throws IOException, InterruptedException { } else { currentRow = new RowWritable(row); } - } catch (SQLException e) { - throw new RuntimeException(e); + } catch (SQLException exc) { + throw new RuntimeException(exc); } if (currentRow == null) { diff --git a/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java b/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java index 36ebe85c69b..5ee19911543 100644 --- a/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java +++ b/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java @@ -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,18 +19,11 @@ import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; + import io.vitess.client.TestEnv; import io.vitess.client.TestUtil; import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import java.io.IOException; -import java.lang.reflect.Type; -import java.sql.SQLException; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import junit.extensions.TestSetup; -import junit.framework.TestSuite; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; @@ -43,17 +36,26 @@ import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import junit.extensions.TestSetup; +import junit.framework.TestSuite; import vttest.Vttest.Keyspace; import vttest.Vttest.Shard; import vttest.Vttest.VTTestTopology; - /** * Integration tests for MapReductions in Vitess. These tests use an in-process Hadoop cluster via * {@link HadoopTestCase}. These tests are JUnit3 style because of this dependency. Vitess setup for * these tests require at least one rdonly instance per shard. - * */ public class MapReduceIT extends HadoopTestCase { @@ -114,7 +116,8 @@ public void testDumpTableToHDFS() throws Exception { // Rows are written as JSON since this is TextOutputFormat. String rowJson = parts[1]; - Type mapType = new TypeToken>() {}.getType(); + Type mapType = new TypeToken>() { + }.getType(); @SuppressWarnings("unchecked") Map map = (Map) gson.fromJson(rowJson, mapType); actualNames.add(map.get("name")); @@ -185,6 +188,7 @@ public void testReducerAggregateRows() throws Exception { public static class TableMapper extends Mapper { + @Override public void map(NullWritable key, RowWritable value, Context context) throws IOException, InterruptedException { @@ -199,6 +203,7 @@ public void map(NullWritable key, RowWritable value, Context context) public static class CountReducer extends Reducer { + @Override public void reduce(IntWritable key, Iterable values, Context context) throws IOException, InterruptedException { From fb4a797e61c61002725bb32a69f6773e7f1a44b8 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 17:20:47 -0500 Subject: [PATCH 4/9] jdbc: parial checkstyle conversion Signed-off-by: Ze'ev Klapow --- java/checkstyle-suppression.xml | 6 +- .../vitess/client/grpc/GrpcClientFactory.java | 10 +- .../io/vitess/jdbc/ConnectionProperties.java | 1421 ++++---- .../java/io/vitess/jdbc/DBProperties.java | 74 +- .../io/vitess/jdbc/FieldWithMetadata.java | 1086 +++--- .../java/io/vitess/jdbc/VitessConnection.java | 1541 ++++---- .../vitess/jdbc/VitessDatabaseMetaData.java | 1044 +++--- .../java/io/vitess/jdbc/VitessDriver.java | 174 +- .../java/io/vitess/jdbc/VitessJDBCUrl.java | 396 +- .../jdbc/VitessMariaDBDatabaseMetadata.java | 986 +++-- .../jdbc/VitessMySQLDatabaseMetadata.java | 3233 ++++++++--------- .../vitess/jdbc/VitessParameterMetaData.java | 159 +- .../vitess/jdbc/VitessPreparedStatement.java | 1610 ++++---- .../java/io/vitess/jdbc/VitessResultSet.java | 2760 +++++++------- .../vitess/jdbc/VitessResultSetMetaData.java | 619 ++-- .../java/io/vitess/jdbc/VitessStatement.java | 1330 ++++--- .../io/vitess/jdbc/VitessVTGateManager.java | 358 +- .../main/java/io/vitess/util/CommonUtils.java | 50 +- .../main/java/io/vitess/util/Constants.java | 305 +- .../main/java/io/vitess/util/MysqlDefs.java | 894 ++--- .../main/java/io/vitess/util/StringUtils.java | 1653 +++++---- .../vitess/util/charset/CharsetMapping.java | 1068 +++--- .../io/vitess/util/charset/Collation.java | 50 +- .../io/vitess/util/charset/MysqlCharset.java | 193 +- .../test/java/io/vitess/jdbc/BaseTest.java | 43 +- .../vitess/jdbc/ConnectionPropertiesTest.java | 537 +-- .../io/vitess/jdbc/FieldWithMetadataTest.java | 1291 +++---- .../io/vitess/jdbc/VitessConnectionTest.java | 462 +-- .../jdbc/VitessDatabaseMetadataTest.java | 2804 +++++++------- .../java/io/vitess/jdbc/VitessDriverTest.java | 157 +- .../io/vitess/jdbc/VitessJDBCUrlTest.java | 461 +-- .../jdbc/VitessParameterMetaDataTest.java | 113 +- .../jdbc/VitessPreparedStatementTest.java | 1368 ++++--- .../jdbc/VitessResultSetMetadataTest.java | 1112 +++--- .../io/vitess/jdbc/VitessResultSetTest.java | 1348 +++---- .../io/vitess/jdbc/VitessStatementTest.java | 1286 ++++--- .../vitess/jdbc/VitessVTGateManagerTest.java | 125 +- .../java/io/vitess/util/StringUtilsTest.java | 88 +- 38 files changed, 16157 insertions(+), 16058 deletions(-) diff --git a/java/checkstyle-suppression.xml b/java/checkstyle-suppression.xml index 77906f6572a..ac41584523c 100644 --- a/java/checkstyle-suppression.xml +++ b/java/checkstyle-suppression.xml @@ -6,10 +6,14 @@ - + + + + + \ No newline at end of file diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 92847bde42f..25427c1b977 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -102,13 +102,13 @@ public RpcClient create(Context ctx, String target) { } /** - * This method constructs NettyChannelBuilder object that will be used to create - * RpcClient. - * Subclasses may override this method to make adjustments to the builder - * for example: + *

This method constructs NettyChannelBuilder object that will be used to create + * RpcClient.

+ *

Subclasses may override this method to make adjustments to the builder + * for example:

* * - * @Override + * {@literal @}Override * protected NettyChannelBuilder channelBuilder(String target) { * return super.channelBuilder(target) * .eventLoopGroup(new EpollEventLoopGroup()) diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java index f978311831e..5d172808395 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java @@ -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. @@ -34,797 +34,800 @@ public class ConnectionProperties { - private static final ArrayList PROPERTY_LIST = new ArrayList<>(); - - static { - try { - // Generate property list for use in dynamically filling out values from Properties objects in - // #initializeProperties below - java.lang.reflect.Field[] declaredFields = ConnectionProperties.class.getDeclaredFields(); - for (Field declaredField : declaredFields) { - if (ConnectionProperty.class.isAssignableFrom(declaredField.getType())) { - PROPERTY_LIST.add(declaredField); - } - } - Collections.sort(PROPERTY_LIST, new Comparator() { - @Override public int compare(Field o1, Field o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - // Configs for handling deserialization of blobs - private BooleanConnectionProperty blobsAreStrings = new BooleanConnectionProperty( - "blobsAreStrings", - "Should the driver always treat BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?", - false); - private BooleanConnectionProperty functionsNeverReturnBlobs = new BooleanConnectionProperty( - "functionsNeverReturnBlobs", - "Should the driver always treat data from functions returning BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?", - false); - - // Configs for handing tinyint(1) - private BooleanConnectionProperty tinyInt1isBit = new BooleanConnectionProperty( - "tinyInt1isBit", - "Should the driver treat the datatype TINYINT(1) as the BIT type (because the server silently converts BIT -> TINYINT(1) when creating tables)?", - true); - private BooleanConnectionProperty yearIsDateType = new BooleanConnectionProperty( - "yearIsDateType", - "Should the JDBC driver treat the MySQL type \"YEAR\" as a java.sql.Date, or as a SHORT?", - true); - - private EnumConnectionProperty zeroDateTimeBehavior = new EnumConnectionProperty<>( - "zeroDateTimeBehavior", - "How should timestamps with format \"0000-00-00 00:00:00.0000\" be treated", - Constants.ZeroDateTimeBehavior.GARBLE); - - // Configs for handling irregular blobs, those with characters outside the typical 4-byte encodings - private BooleanConnectionProperty useBlobToStoreUTF8OutsideBMP = new BooleanConnectionProperty( - "useBlobToStoreUTF8OutsideBMP", - "Tells the driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR columns holding text encoded in UTF-8 that has characters outside the BMP (4-byte encodings), which MySQL server can't handle natively.", - false); - private StringConnectionProperty utf8OutsideBmpIncludedColumnNamePattern = new StringConnectionProperty( - "utf8OutsideBmpIncludedColumnNamePattern", - "Used to specify exclusion rules to \"utf8OutsideBmpExcludedColumnNamePattern\". The regex must follow the patterns used for the java.util.regex package.", - null, - null); - private StringConnectionProperty utf8OutsideBmpExcludedColumnNamePattern = new StringConnectionProperty( - "utf8OutsideBmpExcludedColumnNamePattern", - "When \"useBlobToStoreUTF8OutsideBMP\" is set to \"true\", column names matching the given regex will still be treated as BLOBs unless they match the regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\". The regex must follow the patterns used for the java.util.regex package.", - null, - null); - - // Default encodings, for when one cannot be determined from field metadata - private StringConnectionProperty characterEncoding = new StringConnectionProperty( - "characterEncoding", - "If a character encoding cannot be detected, which fallback should be used when dealing with strings? (defaults is to 'autodetect')", - null, - null); - - // Vitess-specific configs - private StringConnectionProperty userName = new StringConnectionProperty( - Constants.Property.USERNAME, - "query will be executed via this user", - Constants.DEFAULT_USERNAME, - null); - private StringConnectionProperty target = new StringConnectionProperty( - Constants.Property.TARGET, - "Represents keyspace:shard@tabletType to be used to VTGates. keyspace, keyspace:shard, @tabletType all are optional.", - Constants.DEFAULT_TARGET, - null); - private StringConnectionProperty keyspace = new StringConnectionProperty( - Constants.Property.KEYSPACE, - "Targeted keyspace to execute queries on", - Constants.DEFAULT_KEYSPACE, - null); - private StringConnectionProperty catalog = new StringConnectionProperty( - Constants.Property.DBNAME, - "Database name in the keyspace", - Constants.DEFAULT_CATALOG, - null); - private StringConnectionProperty shard = new StringConnectionProperty( - Constants.Property.SHARD, - "Targeted shard in a given keyspace", - Constants.DEFAULT_SHARD, - null); - private EnumConnectionProperty tabletType = new EnumConnectionProperty<>( - Constants.Property.TABLET_TYPE, - "Tablet Type to which Vitess will connect(master, replica, rdonly)", - Constants.DEFAULT_TABLET_TYPE); - private EnumConnectionProperty oldTabletType = new EnumConnectionProperty<>( - Constants.Property.OLD_TABLET_TYPE, - "Deprecated Tablet Type to which Vitess will connect(master, replica, rdonly)", - Constants.DEFAULT_TABLET_TYPE); - private EnumConnectionProperty executeType = new EnumConnectionProperty<>( - Constants.Property.EXECUTE_TYPE, - "Query execution type: simple or stream", - Constants.DEFAULT_EXECUTE_TYPE); - private BooleanConnectionProperty twopcEnabled = new BooleanConnectionProperty( - Constants.Property.TWOPC_ENABLED, - "Whether to enable two-phased commit, for atomic distributed commits. See http://vitess.io/user-guide/twopc/", - false); - private EnumConnectionProperty includedFields = new EnumConnectionProperty<>( - Constants.Property.INCLUDED_FIELDS, - "What fields to return from MySQL to the Driver. Limiting the fields returned can improve performance, but ALL is required for maximum JDBC API support", - Constants.DEFAULT_INCLUDED_FIELDS); - private EnumConnectionProperty workload = new EnumConnectionProperty<>( - "workload", - "The workload type to use when executing queries", - Query.ExecuteOptions.Workload.UNSPECIFIED - ); - private BooleanConnectionProperty useAffectedRows = new BooleanConnectionProperty( - "useAffectedRows", - "Don't set the CLIENT_FOUND_ROWS flag when connecting to the server. The vitess default (useAffectedRows=true) is the opposite of mysql-connector-j.", - true); - - private BooleanConnectionProperty grpcRetriesEnabled = new BooleanConnectionProperty( - "grpcRetriesEnabled", - "If enabled, a gRPC interceptor will ensure retries happen in the case of TRANSIENT gRPC errors.", - true - ); - private LongConnectionProperty grpcRetryInitialBackoffMillis = new LongConnectionProperty( - "grpcRetriesInitialBackoffMillis", - "If grpcRetriesEnabled is set, what is the initial backoff time in milliseconds for exponential retry backoff.", - 10 - ); - private LongConnectionProperty grpcRetryMaxBackoffMillis = new LongConnectionProperty( - "grpcRetriesMaxBackoffMillis", - "If grpcRetriesEnabled is set, what is the maximum backoff time in milliseconds for exponential retry backoff. After this threshold, failures will propagate.", - TimeUnit.MINUTES.toMillis(2) - ); - private DoubleConnectionProperty grpcRetryBackoffMultiplier = new DoubleConnectionProperty( - "grpcRetriesBackoffMultiplier", - "If grpcRetriesEnabled is set, what multiplier should be used to increase exponential backoff on each retry.", - 1.6 - ); - // TLS-related configs - private BooleanConnectionProperty useSSL = new BooleanConnectionProperty( - Constants.Property.USE_SSL, - "Whether this connection should use transport-layer security", - false); - private BooleanConnectionProperty refreshConnection = new BooleanConnectionProperty( - "refreshConnection", - "When enabled, the driver will monitor for changes to the keystore and truststore files. If any are detected, SSL-enabled connections will be recreated.", - false); - private LongConnectionProperty refreshSeconds = new LongConnectionProperty( - "refreshSeconds", - "How often in seconds the driver will monitor for changes to the keystore and truststore files, when refreshConnection is enabled.", - 60); - private BooleanConnectionProperty refreshClosureDelayed = new BooleanConnectionProperty( - "refreshClosureDelayed", - "When enabled, the closing of the old connections will be delayed instead of happening instantly.", - false); - private LongConnectionProperty refreshClosureDelaySeconds = new LongConnectionProperty( - "refreshClosureDelaySeconds", - "How often in seconds the grace period before closing the old connections that had been recreated.", - 300); - private StringConnectionProperty keyStore = new StringConnectionProperty( - Constants.Property.KEYSTORE, - "The Java .JKS keystore file to use when TLS is enabled", - null, - null); - private StringConnectionProperty keyStorePassword = new StringConnectionProperty( - Constants.Property.KEYSTORE_PASSWORD, - "The password protecting the keystore file (if a password is set)", - null, - null); - private StringConnectionProperty keyAlias = new StringConnectionProperty( - Constants.Property.KEY_ALIAS, - "Alias under which the private key is stored in the keystore file (if not specified, then the " - + "first valid `PrivateKeyEntry` will be used)", - null, - null); - private StringConnectionProperty keyPassword = new StringConnectionProperty( - Constants.Property.KEY_PASSWORD, - "The additional password protecting the private key entry within the keystore file (if not " - + "specified, then the logic will fallback to the keystore password and then to no password at all)", - null, - null); - private StringConnectionProperty trustStore = new StringConnectionProperty( - Constants.Property.TRUSTSTORE, - "The Java .JKS truststore file to use when TLS is enabled", - null, - null); - private StringConnectionProperty trustStorePassword = new StringConnectionProperty( - Constants.Property.TRUSTSTORE_PASSWORD, - "The password protecting the truststore file (if a password is set)", - null, - null); - private StringConnectionProperty trustAlias = new StringConnectionProperty( - Constants.Property.TRUST_ALIAS, - "Alias under which the certficate chain is stored in the truststore file (if not specified, then " - + "the first valid `X509Certificate` will be used)", - null, - null); - - private BooleanConnectionProperty treatUtilDateAsTimestamp = new BooleanConnectionProperty( - "treatUtilDateAsTimestamp", - "Should the driver treat java.util.Date as a TIMESTAMP for the purposes of PreparedStatement.setObject()", - true); - - private LongConnectionProperty timeout = new LongConnectionProperty( - "timeout", - "The default timeout, in millis, to use for queries, connections, and transaction commit/rollback. Query timeout can be overridden by explicitly calling setQueryTimeout", - Constants.DEFAULT_TIMEOUT - ); - - // Caching of some hot properties to avoid casting over and over - private Topodata.TabletType tabletTypeCache; - private Query.ExecuteOptions.IncludedFields includedFieldsCache; - private Query.ExecuteOptions executeOptionsCache; - private boolean includeAllFieldsCache = true; - private boolean twopcEnabledCache = false; - private boolean simpleExecuteTypeCache = true; - private String characterEncodingAsString = null; - private String userNameCache; - - void initializeProperties(Properties props) throws SQLException { - Properties propsCopy = (Properties) props.clone(); - for (Field propertyField : PROPERTY_LIST) { - try { - ConnectionProperty propToSet = (ConnectionProperty) propertyField.get(this); - propToSet.initializeFrom(propsCopy); - } catch (IllegalAccessException iae) { - throw new SQLException("Unable to initialize driver properties due to " + iae.toString()); - } - } - postInitialization(); - checkConfiguredEncodingSupport(); - } - - private void postInitialization() { - this.tabletTypeCache = this.tabletType.getValueAsEnum(); - this.includedFieldsCache = this.includedFields.getValueAsEnum(); - this.includeAllFieldsCache = this.includedFieldsCache == Query.ExecuteOptions.IncludedFields.ALL; - this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); - this.simpleExecuteTypeCache = this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; - this.characterEncodingAsString = this.characterEncoding.getValueAsString(); - this.userNameCache = this.userName.getValueAsString(); - - setExecuteOptions(); - } - - /** - * Attempt to use the encoding, and bail out if it can't be used - * @throws SQLException if exception occurs while attempting to use the encoding - */ - private void checkConfiguredEncodingSupport() throws SQLException { - if (characterEncodingAsString != null) { - try { - String testString = "abc"; - StringUtils.getBytes(testString, characterEncodingAsString); - } catch (UnsupportedEncodingException UE) { - throw new SQLException("Unsupported character encoding: " + characterEncodingAsString); - } - } - } - - static DriverPropertyInfo[] exposeAsDriverPropertyInfo(Properties info, int slotsToReserve) throws SQLException { - return new ConnectionProperties().exposeAsDriverPropertyInfoInternal(info, slotsToReserve); - } + private static final ArrayList PROPERTY_LIST = new ArrayList<>(); - private DriverPropertyInfo[] exposeAsDriverPropertyInfoInternal(Properties info, int slotsToReserve) throws SQLException { - initializeProperties(info); - int numProperties = PROPERTY_LIST.size(); - int listSize = numProperties + slotsToReserve; - DriverPropertyInfo[] driverProperties = new DriverPropertyInfo[listSize]; - - for (int i = slotsToReserve; i < listSize; i++) { - java.lang.reflect.Field propertyField = PROPERTY_LIST.get(i - slotsToReserve); - try { - ConnectionProperty propToExpose = (ConnectionProperty) propertyField.get(this); - if (info != null) { - propToExpose.initializeFrom(info); - } - driverProperties[i] = propToExpose.getAsDriverPropertyInfo(); - } catch (IllegalAccessException iae) { - throw new SQLException("Internal properties failure", iae); - } + static { + try { + // Generate property list for use in dynamically filling out values from Properties objects in + // #initializeProperties below + java.lang.reflect.Field[] declaredFields = ConnectionProperties.class.getDeclaredFields(); + for (Field declaredField : declaredFields) { + if (ConnectionProperty.class.isAssignableFrom(declaredField.getType())) { + PROPERTY_LIST.add(declaredField); } - return driverProperties; - } - - public boolean getBlobsAreStrings() { - return blobsAreStrings.getValueAsBoolean(); - } - - public void setBlobsAreStrings(boolean blobsAreStrings) { - this.blobsAreStrings.setValue(blobsAreStrings); - } - - public boolean getUseBlobToStoreUTF8OutsideBMP() { - return useBlobToStoreUTF8OutsideBMP.getValueAsBoolean(); - } - - public void setUseBlobToStoreUTF8OutsideBMP(boolean useBlobToStoreUTF8OutsideBMP) { - this.useBlobToStoreUTF8OutsideBMP.setValue(useBlobToStoreUTF8OutsideBMP); - } - - public boolean getTinyInt1isBit() { - return tinyInt1isBit.getValueAsBoolean(); - } - - public void setTinyInt1isBit(boolean tinyInt1isBit) { - this.tinyInt1isBit.setValue(tinyInt1isBit); - } - - public boolean getFunctionsNeverReturnBlobs() { - return functionsNeverReturnBlobs.getValueAsBoolean(); - } - - public void setFunctionsNeverReturnBlobs(boolean functionsNeverReturnBlobs) { - this.functionsNeverReturnBlobs.setValue(functionsNeverReturnBlobs); - } - - public String getUtf8OutsideBmpIncludedColumnNamePattern() { - return utf8OutsideBmpIncludedColumnNamePattern.getValueAsString(); - } - - public void setUtf8OutsideBmpIncludedColumnNamePattern(String pattern) { - this.utf8OutsideBmpIncludedColumnNamePattern.setValue(pattern); - } - - public String getUtf8OutsideBmpExcludedColumnNamePattern() { - return utf8OutsideBmpExcludedColumnNamePattern.getValueAsString(); - } - - public void setUtf8OutsideBmpExcludedColumnNamePattern(String pattern) { - this.utf8OutsideBmpExcludedColumnNamePattern.setValue(pattern); - } - - public Constants.ZeroDateTimeBehavior getZeroDateTimeBehavior() { - return zeroDateTimeBehavior.getValueAsEnum(); - } - - public boolean getYearIsDateType() { - return yearIsDateType.getValueAsBoolean(); - } + } + Collections.sort(PROPERTY_LIST, new Comparator() { + @Override + public int compare(Field o1, Field o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // Configs for handling deserialization of blobs + private BooleanConnectionProperty blobsAreStrings = new BooleanConnectionProperty( + "blobsAreStrings", + "Should the driver always treat BLOBs as Strings - specifically to work around dubious " + + "metadata returned by the server for GROUP BY clauses?", + false); + private BooleanConnectionProperty functionsNeverReturnBlobs = new BooleanConnectionProperty( + "functionsNeverReturnBlobs", + "Should the driver always treat data from functions returning BLOBs as Strings - " + + "specifically to work around dubious metadata returned by the server for GROUP BY " + + "clauses?", + false); + + // Configs for handing tinyint(1) + private BooleanConnectionProperty tinyInt1isBit = new BooleanConnectionProperty("tinyInt1isBit", + "Should the driver treat the datatype TINYINT(1) as the BIT type (because the server " + + "silently converts BIT -> TINYINT(1) when creating tables)?", + true); + private BooleanConnectionProperty yearIsDateType = new BooleanConnectionProperty("yearIsDateType", + "Should the JDBC driver treat the MySQL type \"YEAR\" as a java.sql.Date, or as a SHORT?", + true); + + private EnumConnectionProperty zeroDateTimeBehavior = + new EnumConnectionProperty<>( + "zeroDateTimeBehavior", + "How should timestamps with format \"0000-00-00 00:00:00.0000\" be treated", + Constants.ZeroDateTimeBehavior.GARBLE); + + // Configs for handling irregular blobs, those with characters outside the typical 4-byte + // encodings + private BooleanConnectionProperty useBlobToStoreUTF8OutsideBMP = new BooleanConnectionProperty( + "useBlobToStoreUTF8OutsideBMP", + "Tells the driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR columns holding text " + + "encoded in UTF-8 that has characters outside the BMP (4-byte encodings), which MySQL" + + " server can't handle natively.", + false); + private StringConnectionProperty utf8OutsideBmpIncludedColumnNamePattern = + new StringConnectionProperty( + "utf8OutsideBmpIncludedColumnNamePattern", + "Used to specify exclusion rules to \"utf8OutsideBmpExcludedColumnNamePattern\". The regex " + + "must follow the patterns used for the java.util.regex package.", + null, null); + private StringConnectionProperty utf8OutsideBmpExcludedColumnNamePattern = + new StringConnectionProperty( + "utf8OutsideBmpExcludedColumnNamePattern", + "When \"useBlobToStoreUTF8OutsideBMP\" is set to \"true\", column names matching the given " + + "regex will still be treated as BLOBs unless they match the regex specified for " + + "\"utf8OutsideBmpIncludedColumnNamePattern\". The regex must follow the patterns used" + + " for the java.util.regex package.", + null, null); + + // Default encodings, for when one cannot be determined from field metadata + private StringConnectionProperty characterEncoding = new StringConnectionProperty( + "characterEncoding", + "If a character encoding cannot be detected, which fallback should be used when dealing " + + "with strings? (defaults is to 'autodetect')", + null, null); + + // Vitess-specific configs + private StringConnectionProperty userName = new StringConnectionProperty( + Constants.Property.USERNAME, "query will be executed via this user", + Constants.DEFAULT_USERNAME, null); + private StringConnectionProperty target = new StringConnectionProperty(Constants.Property.TARGET, + "Represents keyspace:shard@tabletType to be used to VTGates. keyspace, keyspace:shard, " + + "@tabletType all are optional.", + Constants.DEFAULT_TARGET, null); + private StringConnectionProperty keyspace = new StringConnectionProperty( + Constants.Property.KEYSPACE, "Targeted keyspace to execute queries on", + Constants.DEFAULT_KEYSPACE, null); + private StringConnectionProperty catalog = new StringConnectionProperty(Constants.Property.DBNAME, + "Database name in the keyspace", Constants.DEFAULT_CATALOG, null); + private StringConnectionProperty shard = new StringConnectionProperty(Constants.Property.SHARD, + "Targeted shard in a given keyspace", Constants.DEFAULT_SHARD, null); + private EnumConnectionProperty tabletType = new EnumConnectionProperty<>( + Constants.Property.TABLET_TYPE, + "Tablet Type to which Vitess will connect(master, replica, rdonly)", + Constants.DEFAULT_TABLET_TYPE); + private EnumConnectionProperty oldTabletType = new EnumConnectionProperty<>( + Constants.Property.OLD_TABLET_TYPE, + "Deprecated Tablet Type to which Vitess will connect(master, replica, rdonly)", + Constants.DEFAULT_TABLET_TYPE); + private EnumConnectionProperty executeType = + new EnumConnectionProperty<>( + Constants.Property.EXECUTE_TYPE, "Query execution type: simple or stream", + Constants.DEFAULT_EXECUTE_TYPE); + private BooleanConnectionProperty twopcEnabled = new BooleanConnectionProperty( + Constants.Property.TWOPC_ENABLED, + "Whether to enable two-phased commit, for atomic distributed commits. See http://vitess" + + ".io/user-guide/twopc/", + false); + private EnumConnectionProperty includedFields = + new EnumConnectionProperty<>( + Constants.Property.INCLUDED_FIELDS, + "What fields to return from MySQL to the Driver. Limiting the fields returned can improve " + + "performance, but ALL is required for maximum JDBC API support", + Constants.DEFAULT_INCLUDED_FIELDS); + private EnumConnectionProperty workload = + new EnumConnectionProperty<>( + "workload", "The workload type to use when executing queries", + Query.ExecuteOptions.Workload.UNSPECIFIED); + private BooleanConnectionProperty useAffectedRows = new BooleanConnectionProperty( + "useAffectedRows", + "Don't set the CLIENT_FOUND_ROWS flag when connecting to the server. The vitess default " + + "(useAffectedRows=true) is the opposite of mysql-connector-j.", + true); + + private BooleanConnectionProperty grpcRetriesEnabled = new BooleanConnectionProperty( + "grpcRetriesEnabled", + "If enabled, a gRPC interceptor will ensure retries happen in the case of TRANSIENT gRPC " + + "errors.", + true); + private LongConnectionProperty grpcRetryInitialBackoffMillis = new LongConnectionProperty( + "grpcRetriesInitialBackoffMillis", + "If grpcRetriesEnabled is set, what is the initial backoff time in milliseconds for " + + "exponential retry backoff.", + 10); + private LongConnectionProperty grpcRetryMaxBackoffMillis = new LongConnectionProperty( + "grpcRetriesMaxBackoffMillis", + "If grpcRetriesEnabled is set, what is the maximum backoff time in milliseconds for " + + "exponential retry backoff. After this threshold, failures will propagate.", + TimeUnit.MINUTES.toMillis(2)); + private DoubleConnectionProperty grpcRetryBackoffMultiplier = new DoubleConnectionProperty( + "grpcRetriesBackoffMultiplier", + "If grpcRetriesEnabled is set, what multiplier should be used to increase exponential " + + "backoff on each retry.", + 1.6); + // TLS-related configs + private BooleanConnectionProperty useSSL = new BooleanConnectionProperty( + Constants.Property.USE_SSL, "Whether this connection should use transport-layer security", + false); + private BooleanConnectionProperty refreshConnection = new BooleanConnectionProperty( + "refreshConnection", + "When enabled, the driver will monitor for changes to the keystore and truststore files. If" + + " any are detected, SSL-enabled connections will be recreated.", + false); + private LongConnectionProperty refreshSeconds = new LongConnectionProperty("refreshSeconds", + "How often in seconds the driver will monitor for changes to the keystore and truststore " + + "files, when refreshConnection is enabled.", + 60); + private BooleanConnectionProperty refreshClosureDelayed = new BooleanConnectionProperty( + "refreshClosureDelayed", + "When enabled, the closing of the old connections will be delayed instead of happening " + + "instantly.", + false); + private LongConnectionProperty refreshClosureDelaySeconds = new LongConnectionProperty( + "refreshClosureDelaySeconds", + "How often in seconds the grace period before closing the old connections that had been " + + "recreated.", + 300); + private StringConnectionProperty keyStore = new StringConnectionProperty( + Constants.Property.KEYSTORE, "The Java .JKS keystore file to use when TLS is enabled", null, + null); + private StringConnectionProperty keyStorePassword = new StringConnectionProperty( + Constants.Property.KEYSTORE_PASSWORD, + "The password protecting the keystore file (if a password is set)", null, null); + private StringConnectionProperty keyAlias = new StringConnectionProperty( + Constants.Property.KEY_ALIAS, + "Alias under which the private key is stored in the keystore file (if not specified, then " + + "the " + + "first valid `PrivateKeyEntry` will be used)", null, null); + private StringConnectionProperty keyPassword = new StringConnectionProperty( + Constants.Property.KEY_PASSWORD, + "The additional password protecting the private key entry within the keystore file (if not " + + "specified, then the logic will fallback to the keystore password and then to no " + + "password at all)", + null, null); + private StringConnectionProperty trustStore = new StringConnectionProperty( + Constants.Property.TRUSTSTORE, "The Java .JKS truststore file to use when TLS is enabled", + null, null); + private StringConnectionProperty trustStorePassword = new StringConnectionProperty( + Constants.Property.TRUSTSTORE_PASSWORD, + "The password protecting the truststore file (if a password is set)", null, null); + private StringConnectionProperty trustAlias = new StringConnectionProperty( + Constants.Property.TRUST_ALIAS, + "Alias under which the certficate chain is stored in the truststore file (if not specified," + + " then " + + "the first valid `X509Certificate` will be used)", null, null); + + private BooleanConnectionProperty treatUtilDateAsTimestamp = new BooleanConnectionProperty( + "treatUtilDateAsTimestamp", + "Should the driver treat java.util.Date as a TIMESTAMP for the purposes of " + + "PreparedStatement.setObject()", + true); + + private LongConnectionProperty timeout = new LongConnectionProperty("timeout", + "The default timeout, in millis, to use for queries, connections, and transaction " + + "commit/rollback. Query timeout can be overridden by explicitly calling " + + "setQueryTimeout", + Constants.DEFAULT_TIMEOUT); + + // Caching of some hot properties to avoid casting over and over + private Topodata.TabletType tabletTypeCache; + private Query.ExecuteOptions.IncludedFields includedFieldsCache; + private Query.ExecuteOptions executeOptionsCache; + private boolean includeAllFieldsCache = true; + private boolean twopcEnabledCache = false; + private boolean simpleExecuteTypeCache = true; + private String characterEncodingAsString = null; + private String userNameCache; + + void initializeProperties(Properties props) throws SQLException { + Properties propsCopy = (Properties) props.clone(); + for (Field propertyField : PROPERTY_LIST) { + try { + ConnectionProperty propToSet = (ConnectionProperty) propertyField.get(this); + propToSet.initializeFrom(propsCopy); + } catch (IllegalAccessException iae) { + throw new SQLException("Unable to initialize driver properties due to " + iae.toString()); + } + } + postInitialization(); + checkConfiguredEncodingSupport(); + } + + private void postInitialization() { + this.tabletTypeCache = this.tabletType.getValueAsEnum(); + this.includedFieldsCache = this.includedFields.getValueAsEnum(); + this.includeAllFieldsCache = + this.includedFieldsCache == Query.ExecuteOptions.IncludedFields.ALL; + this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); + this.simpleExecuteTypeCache = + this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; + this.characterEncodingAsString = this.characterEncoding.getValueAsString(); + this.userNameCache = this.userName.getValueAsString(); + + setExecuteOptions(); + } + + /** + * Attempt to use the encoding, and bail out if it can't be used + * + * @throws SQLException if exception occurs while attempting to use the encoding + */ + private void checkConfiguredEncodingSupport() throws SQLException { + if (characterEncodingAsString != null) { + try { + String testString = "abc"; + StringUtils.getBytes(testString, characterEncodingAsString); + } catch (UnsupportedEncodingException UE) { + throw new SQLException("Unsupported character encoding: " + characterEncodingAsString); + } + } + } + + static DriverPropertyInfo[] exposeAsDriverPropertyInfo(Properties info, int slotsToReserve) + throws SQLException { + return new ConnectionProperties().exposeAsDriverPropertyInfoInternal(info, slotsToReserve); + } + + private DriverPropertyInfo[] exposeAsDriverPropertyInfoInternal(Properties info, + int slotsToReserve) throws SQLException { + initializeProperties(info); + int numProperties = PROPERTY_LIST.size(); + int listSize = numProperties + slotsToReserve; + DriverPropertyInfo[] driverProperties = new DriverPropertyInfo[listSize]; + + for (int i = slotsToReserve; i < listSize; i++) { + java.lang.reflect.Field propertyField = PROPERTY_LIST.get(i - slotsToReserve); + try { + ConnectionProperty propToExpose = (ConnectionProperty) propertyField.get(this); + if (info != null) { + propToExpose.initializeFrom(info); + } + driverProperties[i] = propToExpose.getAsDriverPropertyInfo(); + } catch (IllegalAccessException iae) { + throw new SQLException("Internal properties failure", iae); + } + } + return driverProperties; + } + + public boolean getBlobsAreStrings() { + return blobsAreStrings.getValueAsBoolean(); + } + + public void setBlobsAreStrings(boolean blobsAreStrings) { + this.blobsAreStrings.setValue(blobsAreStrings); + } + + public boolean getUseBlobToStoreUTF8OutsideBMP() { + return useBlobToStoreUTF8OutsideBMP.getValueAsBoolean(); + } + + public void setUseBlobToStoreUTF8OutsideBMP(boolean useBlobToStoreUTF8OutsideBMP) { + this.useBlobToStoreUTF8OutsideBMP.setValue(useBlobToStoreUTF8OutsideBMP); + } + + public boolean getTinyInt1isBit() { + return tinyInt1isBit.getValueAsBoolean(); + } + + public void setTinyInt1isBit(boolean tinyInt1isBit) { + this.tinyInt1isBit.setValue(tinyInt1isBit); + } + + public boolean getFunctionsNeverReturnBlobs() { + return functionsNeverReturnBlobs.getValueAsBoolean(); + } + + public void setFunctionsNeverReturnBlobs(boolean functionsNeverReturnBlobs) { + this.functionsNeverReturnBlobs.setValue(functionsNeverReturnBlobs); + } + + public String getUtf8OutsideBmpIncludedColumnNamePattern() { + return utf8OutsideBmpIncludedColumnNamePattern.getValueAsString(); + } + + public void setUtf8OutsideBmpIncludedColumnNamePattern(String pattern) { + this.utf8OutsideBmpIncludedColumnNamePattern.setValue(pattern); + } + + public String getUtf8OutsideBmpExcludedColumnNamePattern() { + return utf8OutsideBmpExcludedColumnNamePattern.getValueAsString(); + } + + public void setUtf8OutsideBmpExcludedColumnNamePattern(String pattern) { + this.utf8OutsideBmpExcludedColumnNamePattern.setValue(pattern); + } + + public Constants.ZeroDateTimeBehavior getZeroDateTimeBehavior() { + return zeroDateTimeBehavior.getValueAsEnum(); + } + + public boolean getYearIsDateType() { + return yearIsDateType.getValueAsBoolean(); + } + + public void setYearIsDateType(boolean yearIsDateType) { + this.yearIsDateType.setValue(yearIsDateType); + } + + public String getEncoding() { + return characterEncodingAsString; + } + + public void setEncoding(String encoding) { + this.characterEncoding.setValue(encoding); + this.characterEncodingAsString = this.characterEncoding.getValueAsString(); + } + + public Query.ExecuteOptions.IncludedFields getIncludedFields() { + return this.includedFieldsCache; + } + + public boolean isIncludeAllFields() { + return this.includeAllFieldsCache; + } + + public void setIncludedFields(Query.ExecuteOptions.IncludedFields includedFields) { + this.includedFields.setValue(includedFields); + this.includedFieldsCache = includedFields; + this.includeAllFieldsCache = includedFields == Query.ExecuteOptions.IncludedFields.ALL; + this.setExecuteOptions(); + } + + public Query.ExecuteOptions.Workload getWorkload() { + return this.workload.getValueAsEnum(); + } + + public void setWorkload(Query.ExecuteOptions.Workload workload) { + this.workload.setValue(workload); + setExecuteOptions(); + } + + public boolean getUseAffectedRows() { + return useAffectedRows.getValueAsBoolean(); + } + + public void setUseAffectedRows(boolean useAffectedRows) { + this.useAffectedRows.setValue(useAffectedRows); + setExecuteOptions(); + } + + private void setExecuteOptions() { + this.executeOptionsCache = Query.ExecuteOptions.newBuilder() + .setIncludedFields(getIncludedFields()).setWorkload(getWorkload()) + .setClientFoundRows(!getUseAffectedRows()).build(); + } + + public Query.ExecuteOptions getExecuteOptions() { + return this.executeOptionsCache; + } + + public boolean getTwopcEnabled() { + return twopcEnabledCache; + } + + public void setTwopcEnabled(boolean twopcEnabled) { + this.twopcEnabled.setValue(twopcEnabled); + this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); + } + + public Constants.QueryExecuteType getExecuteType() { + return executeType.getValueAsEnum(); + } + + public boolean isSimpleExecute() { + return simpleExecuteTypeCache; + } + + public void setExecuteType(Constants.QueryExecuteType executeType) { + this.executeType.setValue(executeType); + this.simpleExecuteTypeCache = + this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; + } + + public Topodata.TabletType getTabletType() { + return tabletTypeCache; + } + + public void setTabletType(Topodata.TabletType tabletType) { + this.tabletType.setValue(tabletType); + this.tabletTypeCache = this.tabletType.getValueAsEnum(); + } + + public Boolean getGrpcRetriesEnabled() { + return grpcRetriesEnabled.getValueAsBoolean(); + } + + public void setGrpcRetriesEnabled(Boolean grpcRetriesEnabled) { + this.grpcRetriesEnabled.setValue(grpcRetriesEnabled); + } + + public Long getGrpcRetryInitialBackoffMillis() { + return grpcRetryInitialBackoffMillis.getValueAsLong(); + } + + public void setGrpcRetryInitialBackoffMillis(Long grpcRetryInitialBackoffMillis) { + this.grpcRetryInitialBackoffMillis.setValue(grpcRetryInitialBackoffMillis); + } + + public Long getGrpcRetryMaxBackoffMillis() { + return grpcRetryMaxBackoffMillis.getValueAsLong(); + } + + public void setGrpcRetryMaxBackoffMillis(Long grpcRetryMaxBackoffMillis) { + this.grpcRetryMaxBackoffMillis.setValue(grpcRetryMaxBackoffMillis); + } + + public Double getGrpcRetryBackoffMultiplier() { + return grpcRetryBackoffMultiplier.getValueAsDouble(); + } + + public void setGrpcRetryBackoffMultiplier(DoubleConnectionProperty grpcRetryBackoffMultiplier) { + this.grpcRetryBackoffMultiplier = grpcRetryBackoffMultiplier; + } + + public boolean getUseSSL() { + return useSSL.getValueAsBoolean(); + } + + public boolean getRefreshConnection() { + return refreshConnection.getValueAsBoolean(); + } + + public void setRefreshConnection(boolean refreshConnection) { + this.refreshConnection.setValue(refreshConnection); + } + + public long getRefreshSeconds() { + return refreshSeconds.getValueAsLong(); + } + + public void setRefreshSeconds(long refreshSeconds) { + this.refreshSeconds.setValue(refreshSeconds); + } + + public boolean getRefreshClosureDelayed() { + return refreshClosureDelayed.getValueAsBoolean(); + } + + public void setRefreshClosureDelayed(boolean refreshClosureDelayed) { + this.refreshClosureDelayed.setValue(refreshClosureDelayed); + } + + public long getRefreshClosureDelaySeconds() { + return refreshClosureDelaySeconds.getValueAsLong(); + } + + public void setRefreshClosureDelaySeconds(long refreshClosureDelaySeconds) { + this.refreshClosureDelaySeconds.setValue(refreshClosureDelaySeconds); + } + + public String getKeyStore() { + return keyStore.getValueAsString(); + } + + public String getKeyStorePassword() { + return keyStorePassword.getValueAsString(); + } + + public String getKeyAlias() { + return keyAlias.getValueAsString(); + } + + public String getKeyPassword() { + return keyPassword.getValueAsString(); + } - public void setYearIsDateType(boolean yearIsDateType) { - this.yearIsDateType.setValue(yearIsDateType); - } + public String getTrustStore() { + return trustStore.getValueAsString(); + } - public String getEncoding() { - return characterEncodingAsString; - } + public String getTrustStorePassword() { + return trustStorePassword.getValueAsString(); + } - public void setEncoding(String encoding) { - this.characterEncoding.setValue(encoding); - this.characterEncodingAsString = this.characterEncoding.getValueAsString(); - } + public String getTrustAlias() { + return trustAlias.getValueAsString(); + } - public Query.ExecuteOptions.IncludedFields getIncludedFields() { - return this.includedFieldsCache; - } + public boolean getTreatUtilDateAsTimestamp() { + return treatUtilDateAsTimestamp.getValueAsBoolean(); + } - public boolean isIncludeAllFields() { - return this.includeAllFieldsCache; - } + public void setTreatUtilDateAsTimestamp(boolean treatUtilDateAsTimestamp) { + this.treatUtilDateAsTimestamp.setValue(treatUtilDateAsTimestamp); + } - public void setIncludedFields(Query.ExecuteOptions.IncludedFields includedFields) { - this.includedFields.setValue(includedFields); - this.includedFieldsCache = includedFields; - this.includeAllFieldsCache = includedFields == Query.ExecuteOptions.IncludedFields.ALL; - this.setExecuteOptions(); - } + public long getTimeout() { + return timeout.getValueAsLong(); + } - public Query.ExecuteOptions.Workload getWorkload() { - return this.workload.getValueAsEnum(); - } + public void setTimeout(long timeout) { + this.timeout.setValue(timeout); + } - public void setWorkload(Query.ExecuteOptions.Workload workload) { - this.workload.setValue(workload); - setExecuteOptions(); + public String getTarget() { + if (!StringUtils.isNullOrEmptyWithoutWS(target.getValueAsString())) { + return target.getValueAsString(); } - - public boolean getUseAffectedRows() { - return useAffectedRows.getValueAsBoolean(); + String targetString = ""; + String keyspace = this.keyspace.getValueAsString(); + if (!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { + targetString += keyspace; + String shard = this.shard.getValueAsString(); + if (!StringUtils.isNullOrEmptyWithoutWS(shard)) { + targetString += ":" + shard; + } } - - public void setUseAffectedRows(boolean useAffectedRows) { - this.useAffectedRows.setValue(useAffectedRows); - setExecuteOptions(); + String tabletType = this.tabletType.getValueAsEnum().name(); + if (!StringUtils.isNullOrEmptyWithoutWS(tabletType)) { + targetString += "@" + tabletType.toLowerCase(); } + return targetString; + } - private void setExecuteOptions() { - this.executeOptionsCache = Query.ExecuteOptions.newBuilder() - .setIncludedFields(getIncludedFields()) - .setWorkload(getWorkload()) - .setClientFoundRows(!getUseAffectedRows()) - .build(); - } + @Deprecated + protected String getKeyspace() { + return this.keyspace.getValueAsString(); + } - public Query.ExecuteOptions getExecuteOptions() { - return this.executeOptionsCache; - } + protected void setCatalog(String catalog) throws SQLException { + this.catalog.setValue(catalog); + } - public boolean getTwopcEnabled() { - return twopcEnabledCache; - } + protected String getCatalog() throws SQLException { + return this.catalog.getValueAsString(); + } - public void setTwopcEnabled(boolean twopcEnabled) { - this.twopcEnabled.setValue(twopcEnabled); - this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); - } + protected String getUsername() { + return this.userNameCache; + } - public Constants.QueryExecuteType getExecuteType() { - return executeType.getValueAsEnum(); - } - - public boolean isSimpleExecute() { - return simpleExecuteTypeCache; - } + abstract static class ConnectionProperty { - public void setExecuteType(Constants.QueryExecuteType executeType) { - this.executeType.setValue(executeType); - this.simpleExecuteTypeCache = this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; - } + private final String name; + private final boolean required = false; + private final String description; + final Object defaultValue; + Object valueAsObject; - public Topodata.TabletType getTabletType() { - return tabletTypeCache; + private ConnectionProperty(String name, String description, Object defaultValue) { + this.name = name; + this.description = description; + this.defaultValue = defaultValue; } - public void setTabletType(Topodata.TabletType tabletType) { - this.tabletType.setValue(tabletType); - this.tabletTypeCache = this.tabletType.getValueAsEnum(); - } - - public Boolean getGrpcRetriesEnabled() { - return grpcRetriesEnabled.getValueAsBoolean(); - } - - public void setGrpcRetriesEnabled(Boolean grpcRetriesEnabled) { - this.grpcRetriesEnabled.setValue(grpcRetriesEnabled); - } - - public Long getGrpcRetryInitialBackoffMillis() { - return grpcRetryInitialBackoffMillis.getValueAsLong(); - } - - public void setGrpcRetryInitialBackoffMillis(Long grpcRetryInitialBackoffMillis) { - this.grpcRetryInitialBackoffMillis.setValue(grpcRetryInitialBackoffMillis); + void initializeFrom(Properties extractFrom) { + String extractedValue = extractFrom.getProperty(getPropertyName()); + String[] allowable = getAllowableValues(); + if (allowable != null && extractedValue != null) { + boolean found = false; + for (String value : allowable) { + found |= value.equalsIgnoreCase(extractedValue); + } + if (!found) { + throw new IllegalArgumentException("Property '" + name + "' Value '" + extractedValue + + "' not in the list of allowable values: " + Arrays.toString(allowable)); + } + } + extractFrom.remove(getPropertyName()); + initializeFrom(extractedValue); } - public Long getGrpcRetryMaxBackoffMillis() { - return grpcRetryMaxBackoffMillis.getValueAsLong(); - } + abstract void initializeFrom(String extractedValue); - public void setGrpcRetryMaxBackoffMillis(Long grpcRetryMaxBackoffMillis) { - this.grpcRetryMaxBackoffMillis.setValue(grpcRetryMaxBackoffMillis); - } + abstract String[] getAllowableValues(); - public Double getGrpcRetryBackoffMultiplier() { - return grpcRetryBackoffMultiplier.getValueAsDouble(); + public String getPropertyName() { + return name; } - public void setGrpcRetryBackoffMultiplier(DoubleConnectionProperty grpcRetryBackoffMultiplier) { - this.grpcRetryBackoffMultiplier = grpcRetryBackoffMultiplier; + DriverPropertyInfo getAsDriverPropertyInfo() { + DriverPropertyInfo dpi = new DriverPropertyInfo(this.name, null); + dpi.choices = getAllowableValues(); + dpi.value = (this.valueAsObject != null) ? this.valueAsObject.toString() : null; + dpi.required = this.required; + dpi.description = this.description; + return dpi; } + } - public boolean getUseSSL() { - return useSSL.getValueAsBoolean(); - } + private static class BooleanConnectionProperty extends ConnectionProperty { - public boolean getRefreshConnection() { - return refreshConnection.getValueAsBoolean(); + private BooleanConnectionProperty(String name, String description, Boolean defaultValue) { + super(name, description, defaultValue); } - public void setRefreshConnection(boolean refreshConnection) { - this.refreshConnection.setValue(refreshConnection); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(extractedValue.equalsIgnoreCase("TRUE") || extractedValue.equalsIgnoreCase("YES")); + } else { + this.valueAsObject = this.defaultValue; + } } - public long getRefreshSeconds() { - return refreshSeconds.getValueAsLong(); + public void setValue(boolean value) { + this.valueAsObject = value; } - public void setRefreshSeconds(long refreshSeconds) { - this.refreshSeconds.setValue(refreshSeconds); + @Override + String[] getAllowableValues() { + return new String[]{Boolean.toString(true), Boolean.toString(false), "yes", "no"}; } - public boolean getRefreshClosureDelayed() { - return refreshClosureDelayed.getValueAsBoolean(); + boolean getValueAsBoolean() { + return (boolean) valueAsObject; } + } - public void setRefreshClosureDelayed(boolean refreshClosureDelayed) { - this.refreshClosureDelayed.setValue(refreshClosureDelayed); - } + private static class StringConnectionProperty extends ConnectionProperty { - public long getRefreshClosureDelaySeconds() { - return refreshClosureDelaySeconds.getValueAsLong(); - } + private final String[] allowableValues; - public void setRefreshClosureDelaySeconds(long refreshClosureDelaySeconds) { - this.refreshClosureDelaySeconds.setValue(refreshClosureDelaySeconds); + private StringConnectionProperty(String name, String description, String defaultValue, + String[] allowableValuesToSet) { + super(name, description, defaultValue); + allowableValues = allowableValuesToSet; } - public String getKeyStore() { - return keyStore.getValueAsString(); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(extractedValue); + } else { + this.valueAsObject = this.defaultValue; + } } - public String getKeyStorePassword() { - return keyStorePassword.getValueAsString(); + @Override + String[] getAllowableValues() { + return allowableValues; } - public String getKeyAlias() { - return keyAlias.getValueAsString(); + public void setValue(String value) { + this.valueAsObject = value; } - public String getKeyPassword() { - return keyPassword.getValueAsString(); + String getValueAsString() { + return valueAsObject == null ? null : valueAsObject.toString(); } + } - public String getTrustStore() { - return trustStore.getValueAsString(); - } + private static class LongConnectionProperty extends ConnectionProperty { - public String getTrustStorePassword() { - return trustStorePassword.getValueAsString(); + private LongConnectionProperty(String name, String description, long defaultValue) { + super(name, description, defaultValue); } - public String getTrustAlias() { - return trustAlias.getValueAsString(); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(Long.parseLong(extractedValue)); + } else { + this.valueAsObject = this.defaultValue; + } } - public boolean getTreatUtilDateAsTimestamp() { - return treatUtilDateAsTimestamp.getValueAsBoolean(); + @Override + String[] getAllowableValues() { + return null; } - public void setTreatUtilDateAsTimestamp(boolean treatUtilDateAsTimestamp) { - this.treatUtilDateAsTimestamp.setValue(treatUtilDateAsTimestamp); + public void setValue(Long value) { + this.valueAsObject = value; } - public long getTimeout() { - return timeout.getValueAsLong(); + Long getValueAsLong() { + return valueAsObject == null ? null : (Long) valueAsObject; } + } - public void setTimeout(long timeout) { - this.timeout.setValue(timeout); - } + private static class DoubleConnectionProperty extends ConnectionProperty { - public String getTarget() { - if(!StringUtils.isNullOrEmptyWithoutWS(target.getValueAsString())) { - return target.getValueAsString(); - } - String targetString = ""; - String keyspace = this.keyspace.getValueAsString(); - if(!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { - targetString += keyspace; - String shard = this.shard.getValueAsString(); - if(!StringUtils.isNullOrEmptyWithoutWS(shard)) { - targetString += ":" + shard; - } - } - String tabletType = this.tabletType.getValueAsEnum().name(); - if(!StringUtils.isNullOrEmptyWithoutWS(tabletType)) { - targetString += "@" + tabletType.toLowerCase(); - } - return targetString; + private DoubleConnectionProperty(String name, String description, double defaultValue) { + super(name, description, defaultValue); } - @Deprecated - protected String getKeyspace() { - return this.keyspace.getValueAsString(); - } - protected void setCatalog(String catalog) throws SQLException { - this.catalog.setValue(catalog); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(Double.parseDouble(extractedValue)); + } else { + this.valueAsObject = this.defaultValue; + } } - protected String getCatalog() throws SQLException{ - return this.catalog.getValueAsString(); + @Override + String[] getAllowableValues() { + return null; } - protected String getUsername() { - return this.userNameCache; + public void setValue(Double value) { + this.valueAsObject = value; } - abstract static class ConnectionProperty { - - private final String name; - private final boolean required = false; - private final String description; - final Object defaultValue; - Object valueAsObject; - - private ConnectionProperty(String name, String description, Object defaultValue) { - this.name = name; - this.description = description; - this.defaultValue = defaultValue; - } - - void initializeFrom(Properties extractFrom) { - String extractedValue = extractFrom.getProperty(getPropertyName()); - String[] allowable = getAllowableValues(); - if (allowable != null && extractedValue != null) { - boolean found = false; - for (String value : allowable) { - found |= value.equalsIgnoreCase(extractedValue); - } - if (!found) { - throw new IllegalArgumentException("Property '" + name + "' Value '" + extractedValue + "' not in the list of allowable values: " + Arrays.toString(allowable)); - } - } - extractFrom.remove(getPropertyName()); - initializeFrom(extractedValue); - } - - abstract void initializeFrom(String extractedValue); - - abstract String[] getAllowableValues(); - - public String getPropertyName() { - return name; - } - - DriverPropertyInfo getAsDriverPropertyInfo() { - DriverPropertyInfo dpi = new DriverPropertyInfo(this.name, null); - dpi.choices = getAllowableValues(); - dpi.value = (this.valueAsObject != null) ? this.valueAsObject.toString() : null; - dpi.required = this.required; - dpi.description = this.description; - return dpi; - } + Double getValueAsDouble() { + return valueAsObject == null ? null : (Double) valueAsObject; } + } - private static class BooleanConnectionProperty extends ConnectionProperty { + private static class EnumConnectionProperty> extends ConnectionProperty { - private BooleanConnectionProperty(String name, String description, Boolean defaultValue) { - super(name, description, defaultValue); - } + private final Class clazz; - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(extractedValue.equalsIgnoreCase("TRUE") || extractedValue.equalsIgnoreCase("YES")); - } else { - this.valueAsObject = this.defaultValue; - } - } - - public void setValue(boolean value) { - this.valueAsObject = value; - } - - @Override - String[] getAllowableValues() { - return new String[]{Boolean.toString(true), Boolean.toString(false), "yes", "no"}; - } - - boolean getValueAsBoolean() { - return (boolean) valueAsObject; - } + private EnumConnectionProperty(String name, String description, Enum defaultValue) { + super(name, description, defaultValue); + this.clazz = defaultValue.getDeclaringClass(); + if (!clazz.isEnum()) { + throw new IllegalArgumentException("EnumConnectionProperty types should be enums"); + } } - private static class StringConnectionProperty extends ConnectionProperty { - - private final String[] allowableValues; - - private StringConnectionProperty(String name, String description, String defaultValue, String[] allowableValuesToSet) { - super(name, description, defaultValue); - allowableValues = allowableValuesToSet; - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(extractedValue); - } else { - this.valueAsObject = this.defaultValue; - } - } - - @Override - String[] getAllowableValues() { - return allowableValues; - } - - public void setValue(String value) { - this.valueAsObject = value; - } - - String getValueAsString() { - return valueAsObject == null ? null : valueAsObject.toString(); - } + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(Enum.valueOf(clazz, extractedValue.toUpperCase())); + } else { + this.valueAsObject = this.defaultValue; + } } - private static class LongConnectionProperty extends ConnectionProperty { - - private LongConnectionProperty(String name, String description, long defaultValue) { - super(name, description, defaultValue); - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(Long.parseLong(extractedValue)); - } else { - this.valueAsObject = this.defaultValue; - } - } - - @Override - String[] getAllowableValues() { - return null; - } - - public void setValue(Long value) { - this.valueAsObject = value; - } - - Long getValueAsLong() { - return valueAsObject == null ? null : (Long) valueAsObject; - } + public void setValue(T value) { + this.valueAsObject = value; } - private static class DoubleConnectionProperty extends ConnectionProperty { - - private DoubleConnectionProperty(String name, String description, double defaultValue) { - super(name, description, defaultValue); - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(Double.parseDouble(extractedValue)); - } else { - this.valueAsObject = this.defaultValue; - } - } - - @Override - String[] getAllowableValues() { - return null; - } - - public void setValue(Double value) { - this.valueAsObject = value; - } - - Double getValueAsDouble() { - return valueAsObject == null ? null : (Double) valueAsObject; - } + @Override + String[] getAllowableValues() { + T[] enumConstants = clazz.getEnumConstants(); + String[] allowed = new String[enumConstants.length]; + for (int i = 0; i < enumConstants.length; i++) { + allowed[i] = enumConstants[i].toString(); + } + return allowed; } - private static class EnumConnectionProperty> extends ConnectionProperty { - - private final Class clazz; - - private EnumConnectionProperty(String name, String description, Enum defaultValue) { - super(name, description, defaultValue); - this.clazz = defaultValue.getDeclaringClass(); - if (!clazz.isEnum()) { - throw new IllegalArgumentException("EnumConnectionProperty types should be enums"); - } - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(Enum.valueOf(clazz, extractedValue.toUpperCase())); - } else { - this.valueAsObject = this.defaultValue; - } - } - - public void setValue(T value) { - this.valueAsObject = value; - } - - @Override - String[] getAllowableValues() { - T[] enumConstants = clazz.getEnumConstants(); - String[] allowed = new String[enumConstants.length]; - for (int i = 0; i < enumConstants.length; i++) { - allowed[i] = enumConstants[i].toString(); - } - return allowed; - } - - T getValueAsEnum() { - return (T) valueAsObject; - } + T getValueAsEnum() { + return (T) valueAsObject; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java index 6c64ebb5be3..e510df6bd65 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java @@ -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,45 +20,47 @@ * Created by ashudeep.sharma on 10/03/16. */ public class DBProperties { - private final String productVersion; - private final String majorVersion; - private final String minorVersion; - private final int isolationLevel; - private final boolean caseInsensitiveComparison; - private final boolean storesLowerCaseTableName; - public DBProperties(String productVersion, String majorVersion, String minorVersion, - int isolationLevel, String lowerCaseTableNames) { + private final String productVersion; + private final String majorVersion; + private final String minorVersion; + private final int isolationLevel; + private final boolean caseInsensitiveComparison; + private final boolean storesLowerCaseTableName; - this.productVersion = productVersion; - this.majorVersion = majorVersion; - this.minorVersion = minorVersion; - this.isolationLevel = isolationLevel; - this.caseInsensitiveComparison = "1".equalsIgnoreCase(lowerCaseTableNames) || "2".equalsIgnoreCase(lowerCaseTableNames); - this.storesLowerCaseTableName = "1".equalsIgnoreCase(lowerCaseTableNames); - } + public DBProperties(String productVersion, String majorVersion, String minorVersion, + int isolationLevel, String lowerCaseTableNames) { - public String getProductVersion() { - return this.productVersion; - } + this.productVersion = productVersion; + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.isolationLevel = isolationLevel; + this.caseInsensitiveComparison = + "1".equalsIgnoreCase(lowerCaseTableNames) || "2".equalsIgnoreCase(lowerCaseTableNames); + this.storesLowerCaseTableName = "1".equalsIgnoreCase(lowerCaseTableNames); + } - public String getMajorVersion() { - return this.majorVersion; - } + public String getProductVersion() { + return this.productVersion; + } - public String getMinorVersion() { - return this.minorVersion; - } + public String getMajorVersion() { + return this.majorVersion; + } - public int getIsolationLevel() { - return this.isolationLevel; - } + public String getMinorVersion() { + return this.minorVersion; + } - public boolean getUseCaseInsensitiveComparisons() { - return caseInsensitiveComparison; - } + public int getIsolationLevel() { + return this.isolationLevel; + } - public boolean getStoresLowerCaseTableName() { - return storesLowerCaseTableName; - } + public boolean getUseCaseInsensitiveComparisons() { + return caseInsensitiveComparison; + } + + public boolean getStoresLowerCaseTableName() { + return storesLowerCaseTableName; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java index 910c83825e3..b86b2dd893e 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java @@ -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. @@ -30,553 +30,573 @@ public class FieldWithMetadata { - private final ConnectionProperties connectionProperties; - private final Query.Field field; - private final Query.Type vitessType; - private final boolean isImplicitTempTable; - private final boolean isSingleBit; - private final int precisionAdjustFactor; - - private int javaType; - private int colFlag; - private String encoding; - private String collationName; - private int collationIndex; - private int maxBytesPerChar; - - public FieldWithMetadata(ConnectionProperties connectionProperties, Query.Field field) throws SQLException { - this.connectionProperties = connectionProperties; - this.field = field; - this.colFlag = field.getFlags(); - this.vitessType = field.getType(); - this.collationIndex = field.getCharset(); - - // Map MySqlTypes to an initial java.sql Type - // Afterwards, below we will sometimes re-map the javaType based on other - // information we receive from the server, such as flags and encodings. - if (MysqlDefs.vitesstoMySqlType.containsKey(vitessType)) { - this.javaType = MysqlDefs.vitesstoMySqlType.get(vitessType); - } else if (field.getType().equals(Query.Type.TUPLE)) { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE); - } else { - throw new SQLException(Constants.SQLExceptionMessages.UNKNOWN_COLUMN_TYPE); - } - - // All of the below remapping and metadata fields require the extra - // fields included when includeFields=IncludedFields.ALL - if (connectionProperties != null && connectionProperties.isIncludeAllFields()) { - this.isImplicitTempTable = checkForImplicitTemporaryTable(); - // Re-map BLOB to 'real' blob type - if (this.javaType == Types.BLOB) { - boolean isFromFunction = field.getOrgTable().isEmpty(); - if (connectionProperties.getBlobsAreStrings() || (connectionProperties.getFunctionsNeverReturnBlobs() && isFromFunction)) { - this.javaType = Types.VARCHAR; - } else if (collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary) { - if (connectionProperties.getUseBlobToStoreUTF8OutsideBMP() && shouldSetupForUtf8StringInBlob()) { - if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB || this.getColumnLength() == MysqlDefs.LENGTH_BLOB) { - this.javaType = Types.VARCHAR; - } else { - this.javaType = Types.LONGVARCHAR; - } - this.collationIndex = CharsetMapping.MYSQL_COLLATION_INDEX_utf8; - } else { - if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB) { - this.javaType = Types.VARBINARY; - } else if (this.getColumnLength() == MysqlDefs.LENGTH_BLOB || this.getColumnLength() == MysqlDefs.LENGTH_MEDIUMBLOB - || this.getColumnLength() == MysqlDefs.LENGTH_LONGBLOB) { - this.javaType = Types.LONGVARBINARY; - } - } - } else { - // *TEXT masquerading as blob - this.javaType = Types.LONGVARCHAR; - } - } - - // Re-map TINYINT(1) as bit or pseudo-boolean - if (this.javaType == Types.TINYINT && this.field.getColumnLength() == 1 && connectionProperties.getTinyInt1isBit()) { - this.javaType = Types.BIT; - } - - if (!isNativeNumericType() && !isNativeDateTimeType()) { - // For non-numeric types, try to pull the encoding from the passed collationIndex - // We will do some fixup afterwards - this.encoding = getEncodingForIndex(this.collationIndex); - // ucs2, utf16, and utf32 cannot be used as a client character set, but if it was received from server - // under some circumstances we can parse them as utf16 - if ("UnicodeBig".equals(this.encoding)) { - this.encoding = "UTF-16"; - } - // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the type is JSON - if (vitessType == Query.Type.JSON) { - this.encoding = "UTF-8"; - } - this.isSingleBit = this.javaType == Types.BIT && (field.getColumnLength() == 0 || field.getColumnLength() == 1); - - // The server sends back a BINARY/VARBINARY field whenever varchar/text data is stored on disk as binary, but - // that doesn't mean the data is actually binary. For instance, a field with collation ascii_bin - // gets stored on disk as bytes for case-sensitive comparison, but is still an ascii string. - // Re-map these BINARY/VARBINARY types to CHAR/VARCHAR when the data is not actually - // binary encoded - boolean isBinaryEncoded = isBinary() && collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary; - if (javaType == Types.VARBINARY && !isBinaryEncoded) { - this.javaType = Types.VARCHAR; - } - if (javaType == Types.BINARY && !isBinaryEncoded) { - this.javaType = Types.CHAR; - } + private final ConnectionProperties connectionProperties; + private final Query.Field field; + private final Query.Type vitessType; + private final boolean isImplicitTempTable; + private final boolean isSingleBit; + private final int precisionAdjustFactor; + + private int javaType; + private int colFlag; + private String encoding; + private String collationName; + private int collationIndex; + private int maxBytesPerChar; + + public FieldWithMetadata(ConnectionProperties connectionProperties, Query.Field field) + throws SQLException { + this.connectionProperties = connectionProperties; + this.field = field; + this.colFlag = field.getFlags(); + this.vitessType = field.getType(); + this.collationIndex = field.getCharset(); + + // Map MySqlTypes to an initial java.sql Type + // Afterwards, below we will sometimes re-map the javaType based on other + // information we receive from the server, such as flags and encodings. + if (MysqlDefs.vitesstoMySqlType.containsKey(vitessType)) { + this.javaType = MysqlDefs.vitesstoMySqlType.get(vitessType); + } else if (field.getType().equals(Query.Type.TUPLE)) { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE); + } else { + throw new SQLException(Constants.SQLExceptionMessages.UNKNOWN_COLUMN_TYPE); + } + + // All of the below remapping and metadata fields require the extra + // fields included when includeFields=IncludedFields.ALL + if (connectionProperties != null && connectionProperties.isIncludeAllFields()) { + this.isImplicitTempTable = checkForImplicitTemporaryTable(); + // Re-map BLOB to 'real' blob type + if (this.javaType == Types.BLOB) { + boolean isFromFunction = field.getOrgTable().isEmpty(); + if (connectionProperties.getBlobsAreStrings() || ( + connectionProperties.getFunctionsNeverReturnBlobs() && isFromFunction)) { + this.javaType = Types.VARCHAR; + } else if (collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary) { + if (connectionProperties.getUseBlobToStoreUTF8OutsideBMP() + && shouldSetupForUtf8StringInBlob()) { + if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB + || this.getColumnLength() == MysqlDefs.LENGTH_BLOB) { + this.javaType = Types.VARCHAR; } else { - // Default encoding for number-types and date-types - // We keep the default javaType as passed from the server, and just set the encoding - this.encoding = "US-ASCII"; - this.isSingleBit = false; + this.javaType = Types.LONGVARCHAR; } - - // Precision can be calculated from column length, but needs - // to be adjusted for the extra bytes used by the negative sign - // and decimal points, where appropriate. - if (isSigned()) { - switch (javaType) { - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.BIT: - // float/real/double are the same regardless of sign/decimal - // bit values can't actually be signed - this.precisionAdjustFactor = 0; - break; - default: - // other types we adjust for the negative symbol, and decimal - // symbol if there are decimals - this.precisionAdjustFactor = getDecimals() > 0 ? -2 : -1; - } - } else { - switch (javaType) { - case Types.DECIMAL: - case Types.NUMERIC: - // adjust for the decimal - this.precisionAdjustFactor = -1; - break; - default: - // all other types need no adjustment - this.precisionAdjustFactor = 0; - } + this.collationIndex = CharsetMapping.MYSQL_COLLATION_INDEX_utf8; + } else { + if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB) { + this.javaType = Types.VARBINARY; + } else if (this.getColumnLength() == MysqlDefs.LENGTH_BLOB + || this.getColumnLength() == MysqlDefs.LENGTH_MEDIUMBLOB + || this.getColumnLength() == MysqlDefs.LENGTH_LONGBLOB) { + this.javaType = Types.LONGVARBINARY; } + } } else { - // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the type is JSON - if (vitessType == Query.Type.JSON) { - this.encoding = "UTF-8"; - } - // Defaults to appease final variables when not including all fields - this.isImplicitTempTable = false; - this.isSingleBit = false; + // *TEXT masquerading as blob + this.javaType = Types.LONGVARCHAR; + } + } + + // Re-map TINYINT(1) as bit or pseudo-boolean + if (this.javaType == Types.TINYINT && this.field.getColumnLength() == 1 + && connectionProperties.getTinyInt1isBit()) { + this.javaType = Types.BIT; + } + + if (!isNativeNumericType() && !isNativeDateTimeType()) { + // For non-numeric types, try to pull the encoding from the passed collationIndex + // We will do some fixup afterwards + this.encoding = getEncodingForIndex(this.collationIndex); + // ucs2, utf16, and utf32 cannot be used as a client character set, but if it was + // received from server + // under some circumstances we can parse them as utf16 + if ("UnicodeBig".equals(this.encoding)) { + this.encoding = "UTF-16"; + } + // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the + // type is JSON + if (vitessType == Query.Type.JSON) { + this.encoding = "UTF-8"; + } + this.isSingleBit = this.javaType == Types.BIT && (field.getColumnLength() == 0 + || field.getColumnLength() == 1); + + // The server sends back a BINARY/VARBINARY field whenever varchar/text data is stored on + // disk as binary, but + // that doesn't mean the data is actually binary. For instance, a field with collation + // ascii_bin + // gets stored on disk as bytes for case-sensitive comparison, but is still an ascii string. + // Re-map these BINARY/VARBINARY types to CHAR/VARCHAR when the data is not actually + // binary encoded + boolean isBinaryEncoded = + isBinary() && collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary; + if (javaType == Types.VARBINARY && !isBinaryEncoded) { + this.javaType = Types.VARCHAR; + } + if (javaType == Types.BINARY && !isBinaryEncoded) { + this.javaType = Types.CHAR; + } + } else { + // Default encoding for number-types and date-types + // We keep the default javaType as passed from the server, and just set the encoding + this.encoding = "US-ASCII"; + this.isSingleBit = false; + } + + // Precision can be calculated from column length, but needs + // to be adjusted for the extra bytes used by the negative sign + // and decimal points, where appropriate. + if (isSigned()) { + switch (javaType) { + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.BIT: + // float/real/double are the same regardless of sign/decimal + // bit values can't actually be signed + this.precisionAdjustFactor = 0; + break; + default: + // other types we adjust for the negative symbol, and decimal + // symbol if there are decimals + this.precisionAdjustFactor = getDecimals() > 0 ? -2 : -1; + } + } else { + switch (javaType) { + case Types.DECIMAL: + case Types.NUMERIC: + // adjust for the decimal + this.precisionAdjustFactor = -1; + break; + default: + // all other types need no adjustment this.precisionAdjustFactor = 0; } - } - - /** - * Implicit temp tables are temporary tables created internally by MySQL for certain operations. - * For those types of tables, the table name is always prefixed with #sql_, typically followed by a numeric - * or other unique identifier. - */ - private boolean checkForImplicitTemporaryTable() { - return field.getTable().length() > 5 && field.getTable().startsWith("#sql_"); - } - - private boolean isNativeNumericType() { - switch (this.javaType) { - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.DOUBLE: - case Types.REAL: - case Types.DECIMAL: - return true; - default: - return false; - } - } - - private boolean isNativeDateTimeType() { - switch (this.javaType) { - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: - return true; - default: - return false; - } - } - - @VisibleForTesting - String getEncodingForIndex(int charsetIndex) { - String javaEncoding = null; - if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) { - javaEncoding = CharsetMapping.getJavaEncodingForCollationIndex(charsetIndex, connectionProperties.getEncoding()); - } - // If nothing, get default based on configuration, may still be null - if (javaEncoding == null) { - javaEncoding = connectionProperties.getEncoding(); - } - return javaEncoding; - } - - public ConnectionProperties getConnectionProperties() throws SQLException { - checkConnectionProperties(); - return connectionProperties; - } - - public boolean hasConnectionProperties() { - return connectionProperties != null; - } - - private void checkConnectionProperties() throws SQLException { - if (!hasConnectionProperties()) { - throw new SQLException(Constants.SQLExceptionMessages.CONN_UNAVAILABLE); - } - } - - private boolean shouldSetupForUtf8StringInBlob() throws SQLException { - String includePattern = connectionProperties.getUtf8OutsideBmpIncludedColumnNamePattern(); - String excludePattern = connectionProperties.getUtf8OutsideBmpExcludedColumnNamePattern(); - - // When UseBlobToStoreUTF8OutsideBMP is set, we by default set blobs to UTF-8. So we first - // look for fields to exclude from that remapping (blacklist) - if (excludePattern != null && !StringUtils.isNullOrEmptyWithoutWS(excludePattern)) { - try { - if (getOrgName().matches(excludePattern)) { - // If we want to include more specific patters that were inadvertently covered by the exclude pattern, - // we set the includePattern (whitelist) - if (includePattern != null && !StringUtils.isNullOrEmptyWithoutWS(includePattern)) { - try { - if (getOrgName().matches(includePattern)) { - return true; - } - } catch (PatternSyntaxException pse) { - throw new SQLException("Illegal regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\"", pse); - } - } - return false; - } - } catch (PatternSyntaxException pse) { - throw new SQLException("Illegal regex specified for \"utf8OutsideBmpExcludedColumnNamePattern\"", pse); - } - } - + } + } else { + // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the + // type is JSON + if (vitessType == Query.Type.JSON) { + this.encoding = "UTF-8"; + } + // Defaults to appease final variables when not including all fields + this.isImplicitTempTable = false; + this.isSingleBit = false; + this.precisionAdjustFactor = 0; + } + } + + /** + * Implicit temp tables are temporary tables created internally by MySQL for certain operations. + * For those types of tables, the table name is always prefixed with #sql_, typically followed by + * a numeric or other unique identifier. + */ + private boolean checkForImplicitTemporaryTable() { + return field.getTable().length() > 5 && field.getTable().startsWith("#sql_"); + } + + private boolean isNativeNumericType() { + switch (this.javaType) { + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.DOUBLE: + case Types.REAL: + case Types.DECIMAL: return true; + default: + return false; } + } - public boolean isAutoIncrement() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE) > 0); - } - - public boolean isBinary() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.BINARY_FLAG_VALUE) > 0); - } - - public boolean isBlob() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.BLOB_FLAG_VALUE) > 0); - } - - public boolean isMultipleKey() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE) > 0); - } - - boolean isNotNull() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return true; - } - return ((this.colFlag & Query.MySqlFlag.NOT_NULL_FLAG_VALUE) > 0); - } - - public boolean isZeroFill() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.ZEROFILL_FLAG_VALUE) > 0); - } - - public boolean isPrimaryKey() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.PRI_KEY_FLAG_VALUE) > 0); - } - - public boolean isUniqueKey() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE) > 0); - } - - public boolean isUnsigned() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return true; - } - return ((this.colFlag & Query.MySqlFlag.UNSIGNED_FLAG_VALUE) > 0); - } - - public boolean isSigned() throws SQLException { - checkConnectionProperties(); - return !isUnsigned(); - } - - boolean isOpaqueBinary() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - - // Detect CHAR(n) CHARACTER SET BINARY which is a synonym for fixed-length binary types - if (this.collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary && isBinary() - && (this.vitessType == Query.Type.CHAR || this.vitessType == Query.Type.VARCHAR)) { - // Okay, queries resolved by temp tables also have this 'signature', check for that - return !isImplicitTemporaryTable(); - } - - // this is basically always false unless a valid charset is not found and someone explicitly sets a fallback - // using ConnectionProperties, as binary defaults to ISO8859-1 per mysql-connector-j implementation - return "binary".equalsIgnoreCase(getEncoding()); - } - - /** - * Is this field _definitely_ not writable? - * - * @return true if this field can not be written to in an INSERT/UPDATE - * statement. - */ - boolean isReadOnly() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - String orgColumnName = getOrgName(); - String orgTableName = getOrgTable(); - return !(orgColumnName != null && orgColumnName.length() > 0 && orgTableName != null && orgTableName.length() > 0); - } - - public synchronized String getCollation() throws SQLException { - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - - if (this.collationName == null) { - int collationIndex = getCollationIndex(); + private boolean isNativeDateTimeType() { + switch (this.javaType) { + case Types.DATE: + case Types.TIME: + case Types.TIMESTAMP: + return true; + default: + return false; + } + } + + @VisibleForTesting + String getEncodingForIndex(int charsetIndex) { + String javaEncoding = null; + if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) { + javaEncoding = CharsetMapping + .getJavaEncodingForCollationIndex(charsetIndex, connectionProperties.getEncoding()); + } + // If nothing, get default based on configuration, may still be null + if (javaEncoding == null) { + javaEncoding = connectionProperties.getEncoding(); + } + return javaEncoding; + } + + public ConnectionProperties getConnectionProperties() throws SQLException { + checkConnectionProperties(); + return connectionProperties; + } + + public boolean hasConnectionProperties() { + return connectionProperties != null; + } + + private void checkConnectionProperties() throws SQLException { + if (!hasConnectionProperties()) { + throw new SQLException(Constants.SQLExceptionMessages.CONN_UNAVAILABLE); + } + } + + private boolean shouldSetupForUtf8StringInBlob() throws SQLException { + String includePattern = connectionProperties.getUtf8OutsideBmpIncludedColumnNamePattern(); + String excludePattern = connectionProperties.getUtf8OutsideBmpExcludedColumnNamePattern(); + + // When UseBlobToStoreUTF8OutsideBMP is set, we by default set blobs to UTF-8. So we first + // look for fields to exclude from that remapping (blacklist) + if (excludePattern != null && !StringUtils.isNullOrEmptyWithoutWS(excludePattern)) { + try { + if (getOrgName().matches(excludePattern)) { + // If we want to include more specific patters that were inadvertently covered by the + // exclude pattern, + // we set the includePattern (whitelist) + if (includePattern != null && !StringUtils.isNullOrEmptyWithoutWS(includePattern)) { try { - this.collationName = CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[collationIndex]; - } catch (ArrayIndexOutOfBoundsException ex) { - throw new SQLException("CollationIndex '" + collationIndex + "' out of bounds for collationName lookup, should be within 0 and " + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, ex); + if (getOrgName().matches(includePattern)) { + return true; + } + } catch (PatternSyntaxException pse) { + throw new SQLException( + "Illegal regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\"", pse); } + } + return false; } - return this.collationName; - } - - - public synchronized int getMaxBytesPerCharacter() { - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - - if (this.maxBytesPerChar == 0) { - this.maxBytesPerChar = getMaxBytesPerChar(getCollationIndex(), getEncoding()); - } - return this.maxBytesPerChar; - } - - @VisibleForTesting - int getMaxBytesPerChar(Integer charsetIndex, String javaCharsetName) { - // if we can get it by charsetIndex just doing it - String charset = CharsetMapping.getMysqlCharsetNameForCollationIndex(charsetIndex); - // if we didn't find charset name by its full name - if (charset == null) { - charset = CharsetMapping.getMysqlCharsetForJavaEncoding(javaCharsetName); - } - // checking against static maps - return CharsetMapping.getMblen(charset); - } - - public String getName() { - return field.getName(); - } - - public String getTable() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getTable(); - } - - public String getOrgTable() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getOrgTable(); + } catch (PatternSyntaxException pse) { + throw new SQLException( + "Illegal regex specified for \"utf8OutsideBmpExcludedColumnNamePattern\"", pse); + } } - public String getDatabase() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getDatabase(); - } - - public String getOrgName() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getOrgName(); - } - - public int getColumnLength() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - return field.getColumnLength(); - } - - public int getDecimals() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - return field.getDecimals(); - } - - public int getJavaType() { - return javaType; - } - - private Query.Type getVitessType() { - return vitessType; - } - - public int getVitessTypeValue() { - return field.getTypeValue(); - } + return true; + } - boolean isImplicitTemporaryTable() { - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return isImplicitTempTable; + public boolean isAutoIncrement() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE) > 0); + } + + public boolean isBinary() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.BINARY_FLAG_VALUE) > 0); + } + + public boolean isBlob() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.BLOB_FLAG_VALUE) > 0); + } + + public boolean isMultipleKey() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE) > 0); + } + + boolean isNotNull() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return true; } + return ((this.colFlag & Query.MySqlFlag.NOT_NULL_FLAG_VALUE) > 0); + } - public String getEncoding() { - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return encoding; - } - - /** - * Precision can be calculated from column length, but needs - * to be adjusted for the extra values that can be included for the various - * numeric types - */ - public int getPrecisionAdjustFactor() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - return precisionAdjustFactor; + public boolean isZeroFill() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.ZEROFILL_FLAG_VALUE) > 0); + } + + public boolean isPrimaryKey() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.PRI_KEY_FLAG_VALUE) > 0); + } + + public boolean isUniqueKey() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE) > 0); + } + + public boolean isUnsigned() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return true; + } + return ((this.colFlag & Query.MySqlFlag.UNSIGNED_FLAG_VALUE) > 0); + } + + public boolean isSigned() throws SQLException { + checkConnectionProperties(); + return !isUnsigned(); + } + + boolean isOpaqueBinary() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; } - public boolean isSingleBit() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return isSingleBit; - } - - private int getCollationIndex() { - return collationIndex; - } - - @Override - public String toString() { - try { - StringBuilder asString = new StringBuilder(); - asString.append(getClass().getCanonicalName()); - asString.append("["); - asString.append("catalog="); - asString.append(this.getDatabase()); - asString.append(",tableName="); - asString.append(this.getTable()); - asString.append(",originalTableName="); - asString.append(this.getOrgTable()); - asString.append(",columnName="); - asString.append(this.getName()); - asString.append(",originalColumnName="); - asString.append(this.getOrgName()); - asString.append(",vitessType="); - asString.append(getVitessType()); - asString.append("("); - asString.append(getJavaType()); - asString.append(")"); - asString.append(",flags="); - if (isAutoIncrement()) { - asString.append("AUTO_INCREMENT"); - } - if (isPrimaryKey()) { - asString.append(" PRIMARY_KEY"); - } - if (isUniqueKey()) { - asString.append(" UNIQUE_KEY"); - } - if (isBinary()) { - asString.append(" BINARY"); - } - if (isBlob()) { - asString.append(" BLOB"); - } - if (isMultipleKey()) { - asString.append(" MULTI_KEY"); - } - if (isUnsigned()) { - asString.append(" UNSIGNED"); - } - if (isZeroFill()) { - asString.append(" ZEROFILL"); - } - - asString.append(", charsetIndex="); - asString.append(this.collationIndex); - asString.append(", charsetName="); - asString.append(this.encoding); - asString.append("]"); - return asString.toString(); - } catch (Throwable t) { - return super.toString(); - } - } + // Detect CHAR(n) CHARACTER SET BINARY which is a synonym for fixed-length binary types + if (this.collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary && isBinary() && ( + this.vitessType == Query.Type.CHAR || this.vitessType == Query.Type.VARCHAR)) { + // Okay, queries resolved by temp tables also have this 'signature', check for that + return !isImplicitTemporaryTable(); + } + + // this is basically always false unless a valid charset is not found and someone explicitly + // sets a fallback + // using ConnectionProperties, as binary defaults to ISO8859-1 per mysql-connector-j + // implementation + return "binary".equalsIgnoreCase(getEncoding()); + } + + /** + * Is this field _definitely_ not writable? + * + * @return true if this field can not be written to in an INSERT/UPDATE statement. + */ + boolean isReadOnly() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + String orgColumnName = getOrgName(); + String orgTableName = getOrgTable(); + return !(orgColumnName != null && orgColumnName.length() > 0 && orgTableName != null + && orgTableName.length() > 0); + } + + public synchronized String getCollation() throws SQLException { + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + + if (this.collationName == null) { + int collationIndex = getCollationIndex(); + try { + this.collationName = CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[collationIndex]; + } catch (ArrayIndexOutOfBoundsException ex) { + throw new SQLException("CollationIndex '" + collationIndex + + "' out of bounds for collationName lookup, should be within 0 and " + + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, ex); + } + } + return this.collationName; + } + + + public synchronized int getMaxBytesPerCharacter() { + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + + if (this.maxBytesPerChar == 0) { + this.maxBytesPerChar = getMaxBytesPerChar(getCollationIndex(), getEncoding()); + } + return this.maxBytesPerChar; + } + + @VisibleForTesting + int getMaxBytesPerChar(Integer charsetIndex, String javaCharsetName) { + // if we can get it by charsetIndex just doing it + String charset = CharsetMapping.getMysqlCharsetNameForCollationIndex(charsetIndex); + // if we didn't find charset name by its full name + if (charset == null) { + charset = CharsetMapping.getMysqlCharsetForJavaEncoding(javaCharsetName); + } + // checking against static maps + return CharsetMapping.getMblen(charset); + } + + public String getName() { + return field.getName(); + } + + public String getTable() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getTable(); + } + + public String getOrgTable() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getOrgTable(); + } + + public String getDatabase() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getDatabase(); + } + + public String getOrgName() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getOrgName(); + } + + public int getColumnLength() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + return field.getColumnLength(); + } + + public int getDecimals() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + return field.getDecimals(); + } + + public int getJavaType() { + return javaType; + } + + private Query.Type getVitessType() { + return vitessType; + } + + public int getVitessTypeValue() { + return field.getTypeValue(); + } + + boolean isImplicitTemporaryTable() { + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return isImplicitTempTable; + } + + public String getEncoding() { + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return encoding; + } + + /** + * Precision can be calculated from column length, but needs to be adjusted for the extra values + * that can be included for the various numeric types + */ + public int getPrecisionAdjustFactor() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + return precisionAdjustFactor; + } + + public boolean isSingleBit() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return isSingleBit; + } + + private int getCollationIndex() { + return collationIndex; + } + + @Override + public String toString() { + try { + StringBuilder asString = new StringBuilder(); + asString.append(getClass().getCanonicalName()); + asString.append("["); + asString.append("catalog="); + asString.append(this.getDatabase()); + asString.append(",tableName="); + asString.append(this.getTable()); + asString.append(",originalTableName="); + asString.append(this.getOrgTable()); + asString.append(",columnName="); + asString.append(this.getName()); + asString.append(",originalColumnName="); + asString.append(this.getOrgName()); + asString.append(",vitessType="); + asString.append(getVitessType()); + asString.append("("); + asString.append(getJavaType()); + asString.append(")"); + asString.append(",flags="); + if (isAutoIncrement()) { + asString.append("AUTO_INCREMENT"); + } + if (isPrimaryKey()) { + asString.append(" PRIMARY_KEY"); + } + if (isUniqueKey()) { + asString.append(" UNIQUE_KEY"); + } + if (isBinary()) { + asString.append(" BINARY"); + } + if (isBlob()) { + asString.append(" BLOB"); + } + if (isMultipleKey()) { + asString.append(" MULTI_KEY"); + } + if (isUnsigned()) { + asString.append(" UNSIGNED"); + } + if (isZeroFill()) { + asString.append(" ZEROFILL"); + } + + asString.append(", charsetIndex="); + asString.append(this.collationIndex); + asString.append(", charsetName="); + asString.append(this.encoding); + asString.append("]"); + return asString.toString(); + } catch (Throwable t) { + return super.toString(); + } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java index 9fcd3d947be..88bf7e1eae3 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java @@ -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. @@ -55,811 +55,752 @@ */ public class VitessConnection extends ConnectionProperties implements Connection { - /* Get actual class name to be printed on */ - private static DatabaseMetaData databaseMetaData = null; - - /** - * A Map of currently open statements - */ - private Set openStatements = new HashSet<>(); - private VitessVTGateManager.VTGateConnections vTGateConnections; - private boolean closed = true; - private boolean readOnly = false; - private DBProperties dbProperties; - private final VitessJDBCUrl vitessJDBCUrl; - private final VTSession vtSession; - - - /** - * Constructor to Create Connection Object - * - * @param url - Connection url - * @param connectionProperties - property for the connection - * @throws SQLException - */ - public VitessConnection(String url, Properties connectionProperties) throws SQLException { - try { - this.vitessJDBCUrl = new VitessJDBCUrl(url, connectionProperties); - this.closed = false; - this.dbProperties = null; - initializeProperties(vitessJDBCUrl.getProperties()); - this.vtSession = new VTSession(this.getTarget(), this.getExecuteOptions()); - } catch (Exception e) { - throw new SQLException( - Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + e.getMessage(), e); + /* Get actual class name to be printed on */ + private static DatabaseMetaData databaseMetaData = null; + + /** + * A Map of currently open statements + */ + private Set openStatements = new HashSet<>(); + private VitessVTGateManager.VTGateConnections vtGateConnections; + private boolean closed = true; + private boolean readOnly = false; + private DBProperties dbProperties; + private final VitessJDBCUrl vitessJDBCUrl; + private final VTSession vtSession; + + + /** + * Constructor to Create Connection Object + * + * @param url - Connection url + * @param connectionProperties - property for the connection + */ + public VitessConnection(String url, Properties connectionProperties) throws SQLException { + try { + this.vitessJDBCUrl = new VitessJDBCUrl(url, connectionProperties); + this.closed = false; + this.dbProperties = null; + initializeProperties(vitessJDBCUrl.getProperties()); + this.vtSession = new VTSession(this.getTarget(), this.getExecuteOptions()); + } catch (Exception exc) { + throw new SQLException( + Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + e.getMessage(), exc); + } + } + + public void connect() { + this.vtGateConnections = new VitessVTGateManager.VTGateConnections(this); + } + + /** + * Creates statement for the given connection + * + * @return Statement Object + */ + public Statement createStatement() throws SQLException { + checkOpen(); + + return new VitessStatement(this); + } + + /** + * Create PreparedStatement for the given connection & sql + * + * @param sql - Sql Statement + * @return PreparedStatement Object + */ + public PreparedStatement prepareStatement(String sql) throws SQLException { + checkOpen(); + return new VitessPreparedStatement(this, sql); + } + + /** + * This method returns the sql form which the driver will sent to database + * + * @param sql - Sql Statement + * @return Form of the sql that the driver will sent to the underlying database + */ + public String nativeSQL(String sql) throws SQLException { + checkOpen(); + return sql; + } + + /** + * Return Auto commit status + * + * @return autoCommit + */ + public boolean getAutoCommit() throws SQLException { + checkOpen(); + return this.vtSession.isAutoCommit(); + } + + /** + * Sets this connection's auto-commit mode to the given state. + * + * @param autoCommit - true or false + */ + public void setAutoCommit(boolean autoCommit) throws SQLException { + checkOpen(); + if (this.vtSession.isAutoCommit() != autoCommit) { //If same then no-op + //Old Transaction Needs to be committed as per JDBC 4.1 Spec. + if (isInTransaction()) { + this.commit(); + } + this.vtSession.setAutoCommit(autoCommit); + } + } + + /** + * Commit on existing transaction and closed the transaction + */ + public void commit() throws SQLException { + checkOpen(); + checkAutoCommit(Constants.SQLExceptionMessages.COMMIT_WHEN_AUTO_COMMIT_TRUE); + if (isInTransaction()) { + commitTx(); + } + } + + private void commitTx() throws SQLException { + executeCommand("commit"); + } + + /** + * Rollback on existing transaction and closed the transaction + */ + public void rollback() throws SQLException { + checkOpen(); + checkAutoCommit(Constants.SQLExceptionMessages.ROLLBACK_WHEN_AUTO_COMMIT_TRUE); + if (isInTransaction()) { + rollbackTx(); + } + } + + private void rollbackTx() throws SQLException { + executeCommand("rollback"); + } + + private void executeCommand(String sql) throws SQLException { + try (Statement statement = this.createStatement()) { + statement.executeUpdate(sql); + } + } + + /** + * Closes an existing connection + */ + public void close() throws SQLException { + if (!this.closed) { //no-op when Connection already closed + try { + if (isInTransaction()) { //Rolling back active transaction on close + this.rollback(); } - } - - public void connect() { - this.vTGateConnections = new VitessVTGateManager.VTGateConnections(this); - } - - /** - * Creates statement for the given connection - * - * @return Statement Object - * @throws SQLException - */ - public Statement createStatement() throws SQLException { - checkOpen(); - - return new VitessStatement(this); - } - - /** - * Create PreparedStatement for the given connection & sql - * - * @param sql - Sql Statement - * @return PreparedStatement Object - * @throws SQLException - */ - public PreparedStatement prepareStatement(String sql) throws SQLException { - checkOpen(); - return new VitessPreparedStatement(this, sql); - } - - /** - * This method returns the sql form which the driver will sent to database - * - * @param sql - Sql Statement - * @return Form of the sql that the driver will sent to the underlying database - * @throws SQLException - */ - public String nativeSQL(String sql) throws SQLException { - checkOpen(); - return sql; - } - - /** - * Return Auto commit status - * - * @return autoCommit - * @throws SQLException - */ - public boolean getAutoCommit() throws SQLException { - checkOpen(); - return this.vtSession.isAutoCommit(); - } - - /** - * Sets this connection's auto-commit mode to the given state. - * - * @param autoCommit - true or false - * @throws SQLException - */ - public void setAutoCommit(boolean autoCommit) throws SQLException { - checkOpen(); - if (this.vtSession.isAutoCommit() != autoCommit) { //If same then no-op - //Old Transaction Needs to be committed as per JDBC 4.1 Spec. - if (isInTransaction()) { - this.commit(); - } - this.vtSession.setAutoCommit(autoCommit); - } - } - - /** - * Commit on existing transaction and closed the transaction - * - * @throws SQLException - */ - public void commit() throws SQLException { - checkOpen(); - checkAutoCommit(Constants.SQLExceptionMessages.COMMIT_WHEN_AUTO_COMMIT_TRUE); - if (isInTransaction()) { - commitTx(); - } - } - - private void commitTx() throws SQLException { - executeCommand("commit"); - } - - /** - * Rollback on existing transaction and closed the transaction - * - * @throws SQLException - */ - public void rollback() throws SQLException { - checkOpen(); - checkAutoCommit(Constants.SQLExceptionMessages.ROLLBACK_WHEN_AUTO_COMMIT_TRUE); - if (isInTransaction()) { - rollbackTx(); - } - } - - private void rollbackTx() throws SQLException{ - executeCommand("rollback"); - } - - private void executeCommand(String sql) throws SQLException { - try (Statement statement = this.createStatement()){ - statement.executeUpdate(sql); - } - } - - /** - * Closes an existing connection - * - * @throws SQLException - */ - public void close() throws SQLException { - if (!this.closed) { //no-op when Connection already closed - try { - if (isInTransaction()) { //Rolling back active transaction on close - this.rollback(); - } - closeAllOpenStatements(); - } finally { - this.closed = true; - } - } - } - - /** - * Return Connection state - * - * @return DatabaseMetadata Object - */ - public boolean isClosed() { - return this.closed; - } - - public DatabaseMetaData getMetaData() throws SQLException { - checkOpen(); - if (!metadataNullOrClosed()) { - return databaseMetaData; - } else { - synchronized (VitessConnection.class) { - if (metadataNullOrClosed()) { - String dbEngine = initializeDBProperties(); - if (dbEngine.equals("mariadb")) { - databaseMetaData = new VitessMariaDBDatabaseMetadata(this); - } else { - databaseMetaData = new VitessMySQLDatabaseMetadata(this); - } - } - } - return databaseMetaData; - } - } - - private boolean metadataNullOrClosed() throws SQLException { - return null == databaseMetaData || null == databaseMetaData.getConnection() || databaseMetaData.getConnection().isClosed(); - } - - public boolean isReadOnly() throws SQLException { - checkOpen(); - return readOnly; - } - - /** - * Set ReadOnly for the connection - * - * @param readOnly - true or false - * @throws SQLException - */ - public void setReadOnly(boolean readOnly) throws SQLException { - checkOpen(); - - if (isInTransaction()) { - throw new SQLException( - Constants.SQLExceptionMessages.METHOD_CALLED_ON_OPEN_TRANSACTION); - } - - // TODO implement read only properly - this.readOnly = readOnly; - } - - /** - * Return Catalog - * - * @return catalog string - * @throws SQLException - */ - public String getCatalog() throws SQLException { - checkOpen(); - return super.getCatalog(); - } - - /** - * As per JDBC 4.1 specs, if database does not support catalog, then silently ignore the call - * - * @param catalog - Catalog value - * @throws SQLException - */ - public void setCatalog(String catalog) throws SQLException { - checkOpen(); - super.setCatalog(catalog); //Ignoring any affect - } - - /** - * Get the Isolation Level - * - * @return Isolation Level of the Database - * @throws SQLException - */ - public int getTransactionIsolation() throws SQLException { - checkOpen(); - switch (this.vtSession.getTransactionIsolation()) { - case DEFAULT: - return this.getMetaData().getDefaultTransactionIsolation(); - case READ_COMMITTED: - return Connection.TRANSACTION_READ_COMMITTED; - case READ_UNCOMMITTED: - return Connection.TRANSACTION_READ_UNCOMMITTED; - case REPEATABLE_READ: - return Connection.TRANSACTION_REPEATABLE_READ; - case SERIALIZABLE: - return Connection.TRANSACTION_SERIALIZABLE; - default: - throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); - } - } - - /** - * TODO: Currently it will not allow to change the isolation level - * - * @param level - Isolation Level - * @throws SQLException - */ - public void setTransactionIsolation(int level) throws SQLException { - checkOpen(); - if (isInTransaction()) { - rollbackTx(); - } - if (Connection.TRANSACTION_NONE == level || !getMetaData() - .supportsTransactionIsolationLevel(level)) { - throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); - } - - Query.ExecuteOptions.TransactionIsolation isolation; - switch (level) { - case Connection.TRANSACTION_READ_COMMITTED: - isolation = Query.ExecuteOptions.TransactionIsolation.READ_COMMITTED; - break; - case Connection.TRANSACTION_READ_UNCOMMITTED: - isolation = Query.ExecuteOptions.TransactionIsolation.READ_UNCOMMITTED; - break; - case Connection.TRANSACTION_REPEATABLE_READ: - isolation = Query.ExecuteOptions.TransactionIsolation.REPEATABLE_READ; - break; - case Connection.TRANSACTION_SERIALIZABLE: - isolation = Query.ExecuteOptions.TransactionIsolation.SERIALIZABLE; - break; - default: - throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); - } - this.vtSession.setTransactionIsolation(isolation); - } - - /** - * Return Warnings - *

- * TODO: Not implementing as Error is Thrown when occured - * - * @return SQLWarning or null - * @throws SQLException - */ - public SQLWarning getWarnings() throws SQLException { - checkOpen(); - return null; - } - - /** - * Clear the warnings - Not saving Warnings - * - * @throws SQLException - */ - public void clearWarnings() throws SQLException { - checkOpen(); - } - - /** - * Create Statement object with ResultSet properties - * - * @param resultSetType - ResultSet Type - * @param resultSetConcurrency - ResultSet Concurrency - * @return Statement Object - * @throws SQLException - */ - public Statement createStatement(int resultSetType, int resultSetConcurrency) - throws SQLException { - VitessStatement vitessStatement; - - checkOpen(); - if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); - } - if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); - } - vitessStatement = new VitessStatement(this, resultSetType, resultSetConcurrency); - - return vitessStatement; - } - - /** - * Create PreparedStatement object with ResultSet properties - * - * @param sql - Sql Statement - * @param resultSetType - ResultSet Type - * @param resultSetConcurrency - ResultSet Concurrency - * @return PreparedStatement Object - * @throws SQLException - */ - public PreparedStatement prepareStatement(String sql, int resultSetType, - int resultSetConcurrency) throws SQLException { - VitessPreparedStatement vitessPreparedStatement; - - checkOpen(); - if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); - } - if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); - } - vitessPreparedStatement = - new VitessPreparedStatement(this, sql, resultSetType, resultSetConcurrency); - - return vitessPreparedStatement; - } - - /** - * Return ResultSet Holdability - * - * @return ResetSet Holdability Type - * @throws SQLException - */ - public int getHoldability() throws SQLException { - checkOpen(); - return this.getMetaData().getResultSetHoldability(); - } - - /** - * Feature is not Supported - * - * @param holdability - ResetSet Holdability Type - * @throws SQLException - */ - public void setHoldability(int holdability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * TODO : This method should actually validate the connection. - * - * @param timeout - * @return - * @throws SQLException - */ - public boolean isValid(int timeout) throws SQLException { - if (timeout < 0) { - throw new SQLException(Constants.SQLExceptionMessages.TIMEOUT_NEGATIVE); - } - return closed ? Boolean.FALSE : Boolean.TRUE; - } - - /** - * TODO: For Implementation Possibility - * - * @param name - Property Name - * @param value - Property Value - * @throws SQLClientInfoException - */ - public void setClientInfo(String name, String value) throws SQLClientInfoException { - Map errorMap = new HashMap<>(); - ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; - errorMap.put(name, clientInfoStatus); - - throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, - errorMap); - } - - /** - * TODO: For Implementation Possibility - * - * @param name - Property Name - * @return Property Value - */ - public String getClientInfo(String name) { - return null; - } - - /** - * TODO: For Implementation Possibility - * - * @return - Property Object - */ - public Properties getClientInfo() { - return null; - } - - /** - * TODO: For Implementation Possibility - * - * @param properties - Property Object - * @throws SQLClientInfoException - */ - public void setClientInfo(Properties properties) throws SQLClientInfoException { - Map errorMap = new HashMap<>(); - ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; - for (String name : properties.stringPropertyNames()) { - errorMap.put(name, clientInfoStatus); - } - - throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, - errorMap); - } - - /** - * No-op for now - * - * @return Schema - * @throws SQLException - */ - public String getSchema() throws SQLException { - checkOpen(); - return null; - } - - /** - * No-op for now - * - * @param schema - Schema - * @throws SQLException - */ - public void setSchema(String schema) throws SQLException { - checkOpen(); - } - - /** - * Abort the Connection - * - * @param executor - Executor - * @throws SQLException - */ - public void abort(Executor executor) throws SQLException { - if (!closed) { //no-op on closed - if (null == executor) { - throw new SQLException(Constants.SQLExceptionMessages.EXECUTOR_NULL); - } - - executor.execute(new Runnable() { - @Override public void run() { - try { - close(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - }); + closeAllOpenStatements(); + } finally { + this.closed = true; + } + } + } + + /** + * Return Connection state + * + * @return DatabaseMetadata Object + */ + public boolean isClosed() { + return this.closed; + } + + public DatabaseMetaData getMetaData() throws SQLException { + checkOpen(); + if (!metadataNullOrClosed()) { + return databaseMetaData; + } else { + synchronized (VitessConnection.class) { + if (metadataNullOrClosed()) { + String dbEngine = initializeDBProperties(); + if (dbEngine.equals("mariadb")) { + databaseMetaData = new VitessMariaDBDatabaseMetadata(this); + } else { + databaseMetaData = new VitessMySQLDatabaseMetadata(this); + } } - } - - /** - * Unwrap a class - * - * @param iface - A Class defining an interface that the result must implement. - * @param - the type of the class modeled by this Class object - * @return an object that implements the interface. May be a proxy for the actual implementing object. - * @throws SQLException - */ - public T unwrap(Class iface) throws SQLException { - try { - return iface.cast(this); - } catch (ClassCastException cce) { - throw new SQLException( - Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), cce); + } + return databaseMetaData; + } + } + + private boolean metadataNullOrClosed() throws SQLException { + return null == databaseMetaData || null == databaseMetaData.getConnection() || databaseMetaData + .getConnection().isClosed(); + } + + public boolean isReadOnly() throws SQLException { + checkOpen(); + return readOnly; + } + + /** + * Set ReadOnly for the connection + * + * @param readOnly - true or false + */ + public void setReadOnly(boolean readOnly) throws SQLException { + checkOpen(); + + if (isInTransaction()) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALLED_ON_OPEN_TRANSACTION); + } + + // TODO implement read only properly + this.readOnly = readOnly; + } + + /** + * Return Catalog + * + * @return catalog string + */ + public String getCatalog() throws SQLException { + checkOpen(); + return super.getCatalog(); + } + + /** + * As per JDBC 4.1 specs, if database does not support catalog, then silently ignore the call + * + * @param catalog - Catalog value + */ + public void setCatalog(String catalog) throws SQLException { + checkOpen(); + super.setCatalog(catalog); //Ignoring any affect + } + + /** + * Get the Isolation Level + * + * @return Isolation Level of the Database + */ + public int getTransactionIsolation() throws SQLException { + checkOpen(); + switch (this.vtSession.getTransactionIsolation()) { + case DEFAULT: + return this.getMetaData().getDefaultTransactionIsolation(); + case READ_COMMITTED: + return Connection.TRANSACTION_READ_COMMITTED; + case READ_UNCOMMITTED: + return Connection.TRANSACTION_READ_UNCOMMITTED; + case REPEATABLE_READ: + return Connection.TRANSACTION_REPEATABLE_READ; + case SERIALIZABLE: + return Connection.TRANSACTION_SERIALIZABLE; + default: + throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); + } + } + + /** + * TODO: Currently it will not allow to change the isolation level + * + * @param level - Isolation Level + */ + public void setTransactionIsolation(int level) throws SQLException { + checkOpen(); + if (isInTransaction()) { + rollbackTx(); + } + if (Connection.TRANSACTION_NONE == level || !getMetaData() + .supportsTransactionIsolationLevel(level)) { + throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); + } + + Query.ExecuteOptions.TransactionIsolation isolation; + switch (level) { + case Connection.TRANSACTION_READ_COMMITTED: + isolation = Query.ExecuteOptions.TransactionIsolation.READ_COMMITTED; + break; + case Connection.TRANSACTION_READ_UNCOMMITTED: + isolation = Query.ExecuteOptions.TransactionIsolation.READ_UNCOMMITTED; + break; + case Connection.TRANSACTION_REPEATABLE_READ: + isolation = Query.ExecuteOptions.TransactionIsolation.REPEATABLE_READ; + break; + case Connection.TRANSACTION_SERIALIZABLE: + isolation = Query.ExecuteOptions.TransactionIsolation.SERIALIZABLE; + break; + default: + throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); + } + this.vtSession.setTransactionIsolation(isolation); + } + + /** + * Return Warnings + *

+ * TODO: Not implementing as Error is Thrown when occured + * + * @return SQLWarning or null + */ + public SQLWarning getWarnings() throws SQLException { + checkOpen(); + return null; + } + + /** + * Clear the warnings - Not saving Warnings + */ + public void clearWarnings() throws SQLException { + checkOpen(); + } + + /** + * Create Statement object with ResultSet properties + * + * @param resultSetType - ResultSet Type + * @param resultSetConcurrency - ResultSet Concurrency + * @return Statement Object + */ + public Statement createStatement(int resultSetType, int resultSetConcurrency) + throws SQLException { + + checkOpen(); + if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); + } + if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); + } + + return new VitessStatement(this, resultSetType, resultSetConcurrency); + } + + /** + * Create PreparedStatement object with ResultSet properties + * + * @param sql - Sql Statement + * @param resultSetType - ResultSet Type + * @param resultSetConcurrency - ResultSet Concurrency + * @return PreparedStatement Object + */ + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + + checkOpen(); + if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); + } + if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); + } + return new VitessPreparedStatement(this, sql, resultSetType, + resultSetConcurrency); + } + + /** + * Return ResultSet Holdability + * + * @return ResetSet Holdability Type + */ + public int getHoldability() throws SQLException { + checkOpen(); + return this.getMetaData().getResultSetHoldability(); + } + + /** + * Feature is not Supported + * + * @param holdability - ResetSet Holdability Type + */ + public void setHoldability(int holdability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * TODO : This method should actually validate the connection. + */ + public boolean isValid(int timeout) throws SQLException { + if (timeout < 0) { + throw new SQLException(Constants.SQLExceptionMessages.TIMEOUT_NEGATIVE); + } + return closed ? Boolean.FALSE : Boolean.TRUE; + } + + /** + * TODO: For Implementation Possibility + * + * @param name - Property Name + * @param value - Property Value + */ + public void setClientInfo(String name, String value) throws SQLClientInfoException { + Map errorMap = new HashMap<>(); + ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; + errorMap.put(name, clientInfoStatus); + + throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, + errorMap); + } + + /** + * TODO: For Implementation Possibility + * + * @param name - Property Name + * @return Property Value + */ + public String getClientInfo(String name) { + return null; + } + + /** + * TODO: For Implementation Possibility + * + * @return - Property Object + */ + public Properties getClientInfo() { + return null; + } + + /** + * TODO: For Implementation Possibility + * + * @param properties - Property Object + */ + public void setClientInfo(Properties properties) throws SQLClientInfoException { + Map errorMap = new HashMap<>(); + ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; + for (String name : properties.stringPropertyNames()) { + errorMap.put(name, clientInfoStatus); + } + + throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, + errorMap); + } + + /** + * No-op for now + * + * @return Schema + */ + public String getSchema() throws SQLException { + checkOpen(); + return null; + } + + /** + * No-op for now + * + * @param schema - Schema + */ + public void setSchema(String schema) throws SQLException { + checkOpen(); + } + + /** + * Abort the Connection + * + * @param executor - Executor + */ + public void abort(Executor executor) throws SQLException { + if (!closed) { //no-op on closed + if (null == executor) { + throw new SQLException(Constants.SQLExceptionMessages.EXECUTOR_NULL); + } + + executor.execute(new Runnable() { + @Override + public void run() { + try { + close(); + } catch (SQLException exc) { + throw new RuntimeException(exc); + } } - } - - /** - * Checking Wrapper - * - * @param iface - A Class defining an interface that the result must implement. - * @return true if this implements the interface or directly or indirectly wraps an object that does. - * @throws SQLException - */ - public boolean isWrapperFor(Class iface) throws SQLException { - checkOpen(); - return iface.isInstance(this); - } - - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) - throws SQLException { - checkOpen(); - return new VitessPreparedStatement(this, sql, autoGeneratedKeys); - } - - //Methods created for this class - - private void checkOpen() throws SQLException { - if (this.closed) { - throw new SQLException(Constants.SQLExceptionMessages.CONN_CLOSED); + }); + } + } + + /** + * Unwrap a class + * + * @param iface - A Class defining an interface that the result must implement. + * @param - the type of the class modeled by this Class object + * @return an object that implements the interface. May be a proxy for the actual implementing + * object. + */ + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException ccexc) { + throw new SQLException(Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), + ccexc); + } + } + + /** + * Checking Wrapper + * + * @param iface - A Class defining an interface that the result must implement. + * @return true if this implements the interface or directly or indirectly wraps an object that + * does. + */ + public boolean isWrapperFor(Class iface) throws SQLException { + checkOpen(); + return iface.isInstance(this); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + checkOpen(); + return new VitessPreparedStatement(this, sql, autoGeneratedKeys); + } + + //Methods created for this class + + private void checkOpen() throws SQLException { + if (this.closed) { + throw new SQLException(Constants.SQLExceptionMessages.CONN_CLOSED); + } + } + + private void checkAutoCommit(String exception) throws SQLException { + if (this.vtSession.isAutoCommit()) { + throw new SQLException(exception); + } + } + + public boolean isInTransaction() { + return this.vtSession.isInTransaction(); + } + + public VTGateConnection getVtGateConn() { + return vtGateConnections.getVtGateConnInstance(); + } + + public VTSession getVtSession() { + return this.vtSession; + } + + public VitessJDBCUrl getUrl() { + return this.vitessJDBCUrl; + } + + /** + * Register a Statement instance as open. + * + * @param statement the Statement instance to remove + */ + public void registerStatement(Statement statement) { + this.openStatements.add(statement); + } + + /** + * Remove the given statement from the list of open statements + * + * @param statement the Statement instance to remove + */ + public void unregisterStatement(Statement statement) { + this.openStatements.remove(statement); + } + + /** + * Closes all currently open statements. + */ + private void closeAllOpenStatements() throws SQLException { + SQLException postponedException = null; + + // Copy openStatements, since VitessStatement.close() + // deregisters itself, modifying the original set. + for (Statement statement : new ArrayList<>(this.openStatements)) { + try { + VitessStatement vitessStatement = (VitessStatement) statement; + vitessStatement.close(); + } catch (SQLException sqlEx) { + postponedException = sqlEx; // throw it later, cleanup all statements first + } + } + + this.openStatements.clear(); + + if (postponedException != null) { + throw postponedException; + } + + } + + // UnSupported Feature List + + /** + * TODO: To support Stored Procedure + */ + public CallableStatement prepareCall(String sql) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * TODO: To support Stored Procedure + */ + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Map> getTypeMap() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setTypeMap(Map> map) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Savepoint setSavepoint() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Savepoint setSavepoint(String namexc) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void rollback(Savepoint savepoint) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * TODO: To support Stored Procedure + */ + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Clob createClob() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Blob createBlob() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public NClob createNClob() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public SQLXML createSQLXML() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getNetworkTimeout() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + private String initializeDBProperties() throws SQLException { + HashMap dbVariables = new HashMap<>(); + String dbEngine = null; + + if (metadataNullOrClosed()) { + String versionValue; + + try (VitessStatement vitessStatement = new VitessStatement( + this); ResultSet resultSet = vitessStatement.executeQuery( + "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', " + + "\'lower_case_table_names\')")) { + while (resultSet.next()) { + dbVariables.put(resultSet.getString(1), resultSet.getString(2)); } - } - - private void checkAutoCommit(String exception) throws SQLException { - if (this.vtSession.isAutoCommit()) { - throw new SQLException(exception); + versionValue = dbVariables.get("innodb_version"); + String transactionIsolation = dbVariables.get("tx_isolation"); + String lowerCaseTables = dbVariables.get("lower_case_table_names"); + String productVersion = ""; + String majorVersion = ""; + String minorVersion = ""; + int isolationLevel = 0; + if (MysqlDefs.mysqlConnectionTransactionMapping.containsKey(transactionIsolation)) { + isolationLevel = MysqlDefs.mysqlConnectionTransactionMapping.get(transactionIsolation); } - } - - public boolean isInTransaction() { - return this.vtSession.isInTransaction(); - } - - public VTGateConnection getVtGateConn() { - return vTGateConnections.getVtGateConnInstance(); - } - - public VTSession getVtSession() { - return this.vtSession; - } - - public VitessJDBCUrl getUrl() { - return this.vitessJDBCUrl; - } - - /** - * Register a Statement instance as open. - * - * @param statement the Statement instance to remove - */ - public void registerStatement(Statement statement) { - this.openStatements.add(statement); - } - - /** - * Remove the given statement from the list of open statements - * - * @param statement the Statement instance to remove - */ - public void unregisterStatement(Statement statement) { - this.openStatements.remove(statement); - } - - /** - * Closes all currently open statements. - * - * @throws SQLException - */ - private void closeAllOpenStatements() throws SQLException { - SQLException postponedException = null; - - // Copy openStatements, since VitessStatement.close() - // deregisters itself, modifying the original set. - for (Statement statement : new ArrayList<>(this.openStatements)) { - try { - VitessStatement vitessStatement = (VitessStatement) statement; - vitessStatement.close(); - } catch (SQLException sqlEx) { - postponedException = sqlEx; // throw it later, cleanup all statements first - } - } - - this.openStatements.clear(); - - if (postponedException != null) { - throw postponedException; - } - - } - - // UnSupported Feature List - - /** - * TODO: To support Stored Procedure - * - * @param sql - * @return - * @throws SQLException - */ - public CallableStatement prepareCall(String sql) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * TODO: To support Stored Procedure - * - * @param sql - * @param resultSetType - * @param resultSetConcurrency - * @return - * @throws SQLException - */ - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Map> getTypeMap() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setTypeMap(Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Savepoint setSavepoint() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Savepoint setSavepoint(String name) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void rollback(Savepoint savepoint) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void releaseSavepoint(Savepoint savepoint) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Statement createStatement(int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public PreparedStatement prepareStatement(String sql, int resultSetType, - int resultSetConcurrency, int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * TODO: To support Stored Procedure - * - * @param sql - * @param resultSetType - * @param resultSetConcurrency - * @param resultSetHoldability - * @return - * @throws SQLException - */ - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public PreparedStatement prepareStatement(String sql, String[] columnNames) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Clob createClob() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Blob createBlob() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public NClob createNClob() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public SQLXML createSQLXML() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Array createArrayOf(String typeName, Object[] elements) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Struct createStruct(String typeName, Object[] attributes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getNetworkTimeout() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - private String initializeDBProperties() throws SQLException { - HashMap dbVariables = new HashMap<>(); - String dbEngine = null; - - if (metadataNullOrClosed()) { - String versionValue; - - try(VitessStatement vitessStatement = new VitessStatement(this); - ResultSet resultSet = vitessStatement.executeQuery( - "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', \'lower_case_table_names\')") - ) { - while (resultSet.next()) { - dbVariables.put(resultSet.getString(1), resultSet.getString(2)); - } - versionValue = dbVariables.get("innodb_version"); - String transactionIsolation = dbVariables.get("tx_isolation"); - String lowerCaseTables = dbVariables.get("lower_case_table_names"); - String productVersion = ""; - String majorVersion = ""; - String minorVersion = ""; - int isolationLevel = 0; - if (MysqlDefs.mysqlConnectionTransactionMapping.containsKey(transactionIsolation)) { - isolationLevel = - MysqlDefs.mysqlConnectionTransactionMapping.get(transactionIsolation); - } - if (null != versionValue) { - if (versionValue.toLowerCase().contains("mariadb")) { - dbEngine = "mariadb"; - } else { - dbEngine = "mysql"; - } - if (versionValue.contains("-")) { - String[] versions = versionValue.split("-"); - productVersion = versions[0]; - } else { - productVersion = versionValue; - } - String[] dbVersions = productVersion.split("\\.", 3); - majorVersion = dbVersions[0]; - minorVersion = dbVersions[1]; - } - this.dbProperties = - new DBProperties(productVersion, majorVersion, minorVersion, isolationLevel, lowerCaseTables); - } + if (null != versionValue) { + if (versionValue.toLowerCase().contains("mariadb")) { + dbEngine = "mariadb"; + } else { + dbEngine = "mysql"; + } + if (versionValue.contains("-")) { + String[] versions = versionValue.split("-"); + productVersion = versions[0]; + } else { + productVersion = versionValue; + } + String[] dbVersions = productVersion.split("\\.", 3); + majorVersion = dbVersions[0]; + minorVersion = dbVersions[1]; } - return dbEngine; + this.dbProperties = new DBProperties(productVersion, majorVersion, minorVersion, + isolationLevel, lowerCaseTables); + } } + return dbEngine; + } - public DBProperties getDbProperties() { - return this.dbProperties; - } + public DBProperties getDbProperties() { + return this.dbProperties; + } - public Context createContext(long deadlineAfter) { - return CommonUtils.createContext(getUsername(), deadlineAfter); - } + public Context createContext(long deadlineAfter) { + return CommonUtils.createContext(getUsername(), deadlineAfter); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java index 61942951a15..a037ab5ce35 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java @@ -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. @@ -29,587 +29,589 @@ */ public abstract class VitessDatabaseMetaData implements DatabaseMetaData { - private static final String SEARCH_STRING_ESCAPE = "\\"; - private static final String EXTRA_NAME_CHARS = "#@"; - private static final String SCHEMA_TERM = ""; - private static final String CATALOG_SEPARATOR = "."; - private static final String PROCEDURE_TERM = "procedure"; - private static final String CATALOG_TERM = "database"; - private static final String DATABASE_PRODUCT_NAME = "MySQL"; - /* Get actual class name to be printed on */ - private static Logger logger = Logger.getLogger(VitessDatabaseMetaData.class.getName()); - protected final String quotedId = "`"; - protected VitessConnection connection = null; - - public String getURL() throws SQLException { - if (this.connection == null || this.connection.getUrl() == null) { - return null; - } - return this.connection.getUrl().getUrl(); - } - - public String getUserName() throws SQLException { - return this.connection.getUsername(); - } - - public boolean isReadOnly() throws SQLException { - return this.connection.isReadOnly(); - } - - public boolean allProceduresAreCallable() throws SQLException { - return false; - } - - public boolean allTablesAreSelectable() throws SQLException { - return false; - } - - public boolean nullsAreSortedHigh() throws SQLException { - return false; - } - - public boolean nullsAreSortedLow() throws SQLException { - return !this.nullsAreSortedHigh(); - } - - public String getDatabaseProductName() throws SQLException { - return DATABASE_PRODUCT_NAME; - } - - public String getDatabaseProductVersion() throws SQLException { - return this.connection.getDbProperties().getProductVersion(); - } - - public String getDriverVersion() throws SQLException { - return Constants.DRIVER_MAJOR_VERSION + "." + Constants.DRIVER_MINOR_VERSION; - } - - public int getDriverMajorVersion() { - return Constants.DRIVER_MAJOR_VERSION; - } - - public int getDriverMinorVersion() { - return Constants.DRIVER_MINOR_VERSION; - } - - public boolean usesLocalFiles() throws SQLException { - return false; - } - - public boolean usesLocalFilePerTable() throws SQLException { - return false; - } - - public boolean supportsMixedCaseIdentifiers() throws SQLException { - return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); - } - - public boolean storesUpperCaseIdentifiers() throws SQLException { - return false; - } - - public boolean storesLowerCaseIdentifiers() throws SQLException { - return connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public boolean storesMixedCaseIdentifiers() throws SQLException { - return !connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { - return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); - } - - public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { - return false; - } - - public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { - return connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { - return !connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public String getNumericFunctions() throws SQLException { - return - "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW," - + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; - } - - public String getStringFunctions() throws SQLException { - return - "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD," - + - "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,LTRIM,MAKE_SET,MATCH," - + - "MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SPACE,STRCMP," - + - "SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER"; - } - - public String getSystemFunctions() throws SQLException { - return "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION"; - } - - public String getTimeDateFunctions() throws SQLException { - return - "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND," - + - "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME," - + - "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,SEC_TO_TIME,TIME_TO_SEC"; - } - - public String getSearchStringEscape() throws SQLException { - return SEARCH_STRING_ESCAPE; - } - - public String getExtraNameCharacters() throws SQLException { - return EXTRA_NAME_CHARS; - } - - public boolean supportsAlterTableWithAddColumn() throws SQLException { - return false; - } - - public boolean supportsAlterTableWithDropColumn() throws SQLException { - return false; - } - - public boolean supportsColumnAliasing() throws SQLException { - return true; - } - - public boolean nullPlusNonNullIsNull() throws SQLException { - return true; - } - - public boolean supportsConvert() throws SQLException { - return false; - } - - public boolean supportsConvert(int fromType, int toType) throws SQLException { - return false; - } - - public boolean supportsTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsExpressionsInOrderBy() throws SQLException { - return false; - } - - public boolean supportsOrderByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupBy() throws SQLException { - return false; - } - - public boolean supportsGroupByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupByBeyondSelect() throws SQLException { - return false; - } - - public boolean supportsLikeEscapeClause() throws SQLException { - return true; - } - - public boolean supportsMultipleResultSets() throws SQLException { - return false; - } - - public boolean supportsMultipleTransactions() throws SQLException { - return true; - } - - public boolean supportsNonNullableColumns() throws SQLException { - return true; - } - - public boolean supportsMinimumSQLGrammar() throws SQLException { - return true; - } - - public boolean supportsCoreSQLGrammar() throws SQLException { - return false; - } - - public boolean supportsExtendedSQLGrammar() throws SQLException { - return false; - } - - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92IntermediateSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92FullSQL() throws SQLException { - return false; - } - - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - return false; - } - - public boolean supportsOuterJoins() throws SQLException { - return false; - } + private static final String SEARCH_STRING_ESCAPE = "\\"; + private static final String EXTRA_NAME_CHARS = "#@"; + private static final String SCHEMA_TERM = ""; + private static final String CATALOG_SEPARATOR = "."; + private static final String PROCEDURE_TERM = "procedure"; + private static final String CATALOG_TERM = "database"; + private static final String DATABASE_PRODUCT_NAME = "MySQL"; + /* Get actual class name to be printed on */ + private static Logger logger = Logger.getLogger(VitessDatabaseMetaData.class.getName()); + protected final String quotedId = "`"; + protected VitessConnection connection = null; + + public String getURL() throws SQLException { + if (this.connection == null || this.connection.getUrl() == null) { + return null; + } + return this.connection.getUrl().getUrl(); + } + + public String getUserName() throws SQLException { + return this.connection.getUsername(); + } + + public boolean isReadOnly() throws SQLException { + return this.connection.isReadOnly(); + } + + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + public boolean allTablesAreSelectable() throws SQLException { + return false; + } + + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + public boolean nullsAreSortedLow() throws SQLException { + return !this.nullsAreSortedHigh(); + } + + public String getDatabaseProductName() throws SQLException { + return DATABASE_PRODUCT_NAME; + } + + public String getDatabaseProductVersion() throws SQLException { + return this.connection.getDbProperties().getProductVersion(); + } + + public String getDriverVersion() throws SQLException { + return Constants.DRIVER_MAJOR_VERSION + "." + Constants.DRIVER_MINOR_VERSION; + } + + public int getDriverMajorVersion() { + return Constants.DRIVER_MAJOR_VERSION; + } + + public int getDriverMinorVersion() { + return Constants.DRIVER_MINOR_VERSION; + } + + public boolean usesLocalFiles() throws SQLException { + return false; + } + + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); + } + + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseIdentifiers() throws SQLException { + return connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public boolean storesMixedCaseIdentifiers() throws SQLException { + return !connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); + } + + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return !connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public String getNumericFunctions() throws SQLException { + return + "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN," + + "MOD,PI,POW," + + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; + } + + public String getStringFunctions() throws SQLException { + return + "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT," + + "EXPORT_SET,FIELD," + + "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + + "LTRIM,MAKE_SET,MATCH," + + "MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM," + + "SOUNDEX,SPACE,STRCMP," + + "SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER"; + } + + public String getSystemFunctions() throws SQLException { + return "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION"; + } + + public String getTimeDateFunctions() throws SQLException { + return + "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR," + + "MINUTE,SECOND," + + "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE," + + "CURRENT_DATE,CURTIME," + + "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + + "SEC_TO_TIME,TIME_TO_SEC"; + } + + public String getSearchStringEscape() throws SQLException { + return SEARCH_STRING_ESCAPE; + } + + public String getExtraNameCharacters() throws SQLException { + return EXTRA_NAME_CHARS; + } + + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + public boolean supportsColumnAliasing() throws SQLException { + return true; + } + + public boolean nullPlusNonNullIsNull() throws SQLException { + return true; + } + + public boolean supportsConvert() throws SQLException { + return false; + } + + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupBy() throws SQLException { + return false; + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + public boolean supportsLikeEscapeClause() throws SQLException { + return true; + } + + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + public boolean supportsMultipleTransactions() throws SQLException { + return true; + } + + public boolean supportsNonNullableColumns() throws SQLException { + return true; + } + + public boolean supportsMinimumSQLGrammar() throws SQLException { + return true; + } + + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } - public boolean supportsFullOuterJoins() throws SQLException { - return false; - } + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } - public boolean supportsLimitedOuterJoins() throws SQLException { - return false; - } + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } - public String getSchemaTerm() throws SQLException { - return SCHEMA_TERM; - } + public boolean supportsOuterJoins() throws SQLException { + return false; + } - public String getProcedureTerm() throws SQLException { - return PROCEDURE_TERM; - } + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } - public String getCatalogTerm() throws SQLException { - return CATALOG_TERM; - } + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } - public boolean isCatalogAtStart() throws SQLException { - return true; - } + public String getSchemaTerm() throws SQLException { + return SCHEMA_TERM; + } - public String getCatalogSeparator() throws SQLException { - return CATALOG_SEPARATOR; - } + public String getProcedureTerm() throws SQLException { + return PROCEDURE_TERM; + } - public VitessConnection getConnection() throws SQLException { - return this.connection; - } + public String getCatalogTerm() throws SQLException { + return CATALOG_TERM; + } - public void setConnection(VitessConnection vitessConnection) throws SQLException { - this.connection = vitessConnection; - } + public boolean isCatalogAtStart() throws SQLException { + return true; + } - public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; - } + public String getCatalogSeparator() throws SQLException { + return CATALOG_SEPARATOR; + } - public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; - } + public VitessConnection getConnection() throws SQLException { + return this.connection; + } - public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; - } + public void setConnection(VitessConnection vitessConnection) throws SQLException { + this.connection = vitessConnection; + } - public boolean supportsSchemasInIndexDefinitions() throws SQLException { - return false; - } + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; - } + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } - public boolean supportsCatalogsInDataManipulation() throws SQLException { - return false; - } + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - return false; - } + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return false; - } + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return false; - } + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - return false; - } + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } - public boolean supportsPositionedDelete() throws SQLException { - return false; - } + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } - public boolean supportsPositionedUpdate() throws SQLException { - return false; - } + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } - public boolean supportsSelectForUpdate() throws SQLException { - return false; - } + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsStoredProcedures() throws SQLException { - return false; - } + public boolean supportsPositionedDelete() throws SQLException { + return false; + } - public boolean supportsSubqueriesInComparisons() throws SQLException { - return false; - } + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } - public boolean supportsSubqueriesInExists() throws SQLException { - return false; - } + public boolean supportsSelectForUpdate() throws SQLException { + return false; + } - public boolean supportsSubqueriesInIns() throws SQLException { - return false; - } + public boolean supportsStoredProcedures() throws SQLException { + return false; + } - public boolean supportsSubqueriesInQuantifieds() throws SQLException { - return false; - } + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } - public boolean supportsCorrelatedSubqueries() throws SQLException { - return false; - } + public boolean supportsSubqueriesInExists() throws SQLException { + return false; + } - public boolean supportsUnion() throws SQLException { - return false; - } + public boolean supportsSubqueriesInIns() throws SQLException { + return false; + } - public boolean supportsUnionAll() throws SQLException { - return false; - } + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } - public boolean supportsOpenCursorsAcrossCommit() throws SQLException { - return false; - } + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } - public boolean supportsOpenCursorsAcrossRollback() throws SQLException { - return false; - } + public boolean supportsUnion() throws SQLException { + return false; + } - public boolean supportsOpenStatementsAcrossCommit() throws SQLException { - return false; - } + public boolean supportsUnionAll() throws SQLException { + return false; + } - public boolean supportsOpenStatementsAcrossRollback() throws SQLException { - return false; - } + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } - public int getMaxBinaryLiteralLength() throws SQLException { - return 16777208; - } + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } - public int getMaxCharLiteralLength() throws SQLException { - return 16777208; - } + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } - public int getMaxColumnNameLength() throws SQLException { - return 64; - } + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } - public int getMaxColumnsInGroupBy() throws SQLException { - return 64; - } + public int getMaxBinaryLiteralLength() throws SQLException { + return 16777208; + } - public int getMaxColumnsInIndex() throws SQLException { - return 16; - } + public int getMaxCharLiteralLength() throws SQLException { + return 16777208; + } - public int getMaxColumnsInOrderBy() throws SQLException { - return 64; - } + public int getMaxColumnNameLength() throws SQLException { + return 64; + } - public int getMaxColumnsInSelect() throws SQLException { - return 256; - } + public int getMaxColumnsInGroupBy() throws SQLException { + return 64; + } - public int getMaxConnections() throws SQLException { - return 0; - } + public int getMaxColumnsInIndex() throws SQLException { + return 16; + } - public int getMaxCursorNameLength() throws SQLException { - return 0; - } + public int getMaxColumnsInOrderBy() throws SQLException { + return 64; + } - public int getMaxIndexLength() throws SQLException { - return 256; - } + public int getMaxColumnsInSelect() throws SQLException { + return 256; + } - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { - return false; - } + public int getMaxConnections() throws SQLException { + return 0; + } - public int getMaxStatements() throws SQLException { - return 0; - } + public int getMaxCursorNameLength() throws SQLException { + return 0; + } - public int getMaxTableNameLength() throws SQLException { - return 64; - } + public int getMaxIndexLength() throws SQLException { + return 256; + } - public int getMaxTablesInSelect() throws SQLException { - return 256; - } + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } - public int getMaxUserNameLength() throws SQLException { - return 16; - } + public int getMaxStatements() throws SQLException { + return 0; + } - public int getMaxProcedureNameLength() throws SQLException { - return 256; - } + public int getMaxTableNameLength() throws SQLException { + return 64; + } - public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { - return false; - } + public int getMaxTablesInSelect() throws SQLException { + return 256; + } - public boolean supportsDataManipulationTransactionsOnly() throws SQLException { - return false; - } + public int getMaxUserNameLength() throws SQLException { + return 16; + } - public boolean dataDefinitionCausesTransactionCommit() throws SQLException { - return false; - } + public int getMaxProcedureNameLength() throws SQLException { + return 256; + } - public boolean dataDefinitionIgnoredInTransactions() throws SQLException { - return false; - } - - public String getIdentifierQuoteString() throws SQLException { - return this.quotedId; - } - - public ResultSet getProcedures(String catalog, String schemaPattern, - String procedureNamePattern) throws SQLException { - return null; - } - - public ResultSet getProcedureColumns(String catalog, String schemaPattern, - String procedureNamePattern, String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean supportsResultSetType(int type) throws SQLException { - return type == ResultSet.TYPE_FORWARD_ONLY; - } - - public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { - return (type == ResultSet.TYPE_FORWARD_ONLY && concurrency == ResultSet.CONCUR_READ_ONLY); - } - - public boolean ownUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean updatesAreDetected(int type) throws SQLException { - return false; - } - - public boolean deletesAreDetected(int type) throws SQLException { - return false; - } - - public boolean insertsAreDetected(int type) throws SQLException { - return false; - } - - public boolean supportsBatchUpdates() throws SQLException { - return true; - } - - public boolean supportsSavepoints() throws SQLException { - return false; - } - - public boolean supportsNamedParameters() throws SQLException { - return false; - } - - public boolean supportsMultipleOpenResults() throws SQLException { - return false; - } - - public boolean supportsGetGeneratedKeys() throws SQLException { - return true; - } + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } - public boolean supportsResultSetHoldability(int holdability) throws SQLException { - return false; - } + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } - public int getResultSetHoldability() throws SQLException { - return 0; - } + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } - public int getDatabaseMajorVersion() throws SQLException { - return Integer.valueOf(this.connection.getDbProperties().getMajorVersion()); - } + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } - public int getDatabaseMinorVersion() throws SQLException { - return Integer.valueOf(this.connection.getDbProperties().getMinorVersion()); - } + public String getIdentifierQuoteString() throws SQLException { + return this.quotedId; + } - public int getJDBCMajorVersion() throws SQLException { - return 1; - } + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) + throws SQLException { + return null; + } + + public ResultSet getProcedureColumns(String catalog, String schemaPattern, + String procedureNamePattern, String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - public int getJDBCMinorVersion() throws SQLException { - return 0; - } + public boolean supportsResultSetType(int type) throws SQLException { + return type == ResultSet.TYPE_FORWARD_ONLY; + } - public boolean supportsStatementPooling() throws SQLException { - return false; - } + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return (type == ResultSet.TYPE_FORWARD_ONLY && concurrency == ResultSet.CONCUR_READ_ONLY); + } - public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { - return false; - } - - public boolean autoCommitFailureClosesAllResultSets() throws SQLException { - return false; - } + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + public boolean supportsBatchUpdates() throws SQLException { + return true; + } + + public boolean supportsSavepoints() throws SQLException { + return false; + } + + public boolean supportsNamedParameters() throws SQLException { + return false; + } + + public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + public boolean supportsGetGeneratedKeys() throws SQLException { + return true; + } + + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return false; + } + + public int getResultSetHoldability() throws SQLException { + return 0; + } + + public int getDatabaseMajorVersion() throws SQLException { + return Integer.valueOf(this.connection.getDbProperties().getMajorVersion()); + } + + public int getDatabaseMinorVersion() throws SQLException { + return Integer.valueOf(this.connection.getDbProperties().getMinorVersion()); + } + + public int getJDBCMajorVersion() throws SQLException { + return 1; + } + + public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + public boolean supportsStatementPooling() throws SQLException { + return false; + } + + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } - public boolean generatedKeyAlwaysReturned() throws SQLException { - return true; - } + public boolean generatedKeyAlwaysReturned() throws SQLException { + return true; + } - public T unwrap(Class iface) throws SQLException { - return null; - } + public T unwrap(Class iface) throws SQLException { + return null; + } - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java index a06f7df9904..0cb46209e1d 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java @@ -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. @@ -38,101 +38,97 @@ */ public class VitessDriver implements Driver { - static { - try { - DriverManager.registerDriver(new VitessDriver()); - } catch (SQLException e) { - throw new RuntimeException( - Constants.SQLExceptionMessages.INIT_FAILED + " : " + e.getErrorCode() + " - " + e - .getMessage()); - } + static { + try { + DriverManager.registerDriver(new VitessDriver()); + } catch (SQLException e) { + throw new RuntimeException( + Constants.SQLExceptionMessages.INIT_FAILED + " : " + e.getErrorCode() + " - " + e + .getMessage()); } + } - @Override - public Connection connect(String url, Properties info) throws SQLException { - if (!acceptsURL(url)) { - return null; - } - final VitessConnection connection = new VitessConnection(url, info); - connection.connect(); - return connection; + @Override + public Connection connect(String url, Properties info) throws SQLException { + if (!acceptsURL(url)) { + return null; } - - /** - * Checks whether a given url is in a valid format. - *

- * The current uri format is: jdbc:vitess://[host]:[port] - * - * @param url the URL of the database - * @return true, if this driver understands the given URL; - * false, otherwise - *

- * TODO: Write a better regex - */ - @Override - public boolean acceptsURL(String url) { - return null != url && url.startsWith(Constants.URL_PREFIX); + final VitessConnection connection = new VitessConnection(url, info); + connection.connect(); + return connection; + } + + /** + * Checks whether a given url is in a valid format. + *

+ * The current uri format is: jdbc:vitess://[host]:[port] + * + * @param url the URL of the database + * @return true, if this driver understands the given URL; false, otherwise + *

+ * TODO: Write a better regex + */ + @Override + public boolean acceptsURL(String url) { + return null != url && url.startsWith(Constants.URL_PREFIX); + } + + /** + * Given a String URL and a Properties object, computes the expected and required parameters for + * the driver. Parameters can be set in either the URL or Properties. + * + * @param url - Connection Url A vitess-compatible URL, per {@link VitessJDBCUrl} i.e. + * jdbc:vitess://locahost:9000/vt_keyspace?TABLET_TYPE=master + * @param info - Property for the connection May contain additional properties to configure + * this driver with + * @return DriverPropertyInfo Array Object + */ + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + if (null == info) { + info = new Properties(); } - /** - * Given a String URL and a Properties object, computes the expected and - * required parameters for the driver. Parameters can be set in either the URL - * or Properties. - * - * @param url - Connection Url - * A vitess-compatible URL, per {@link VitessJDBCUrl} - * i.e. jdbc:vitess://locahost:9000/vt_keyspace?TABLET_TYPE=master - * @param info - Property for the connection - * May contain additional properties to configure this driver with - * @return DriverPropertyInfo Array Object - * @throws SQLException - */ - @Override - public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { - if (null == info) { - info = new Properties(); - } - - DriverPropertyInfo[] dpi = ConnectionProperties.exposeAsDriverPropertyInfo(info, 2); - if (acceptsURL(url)) { - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl(url, info); - - dpi[0] = new DriverPropertyInfo(Constants.Property.HOST, - vitessJDBCUrl.getHostInfos().get(0).getHostname()); - dpi[0].required = true; - dpi[0].description = Constants.VITESS_HOST; - - dpi[1] = new DriverPropertyInfo(Constants.Property.PORT, - (new Integer(vitessJDBCUrl.getHostInfos().get(0).getPort())).toString()); - dpi[1].required = false; - dpi[1].description = Constants.VITESS_PORT; - - } else { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_CONN_URL + " : " + url); - } - - return dpi; - } + DriverPropertyInfo[] dpi = ConnectionProperties.exposeAsDriverPropertyInfo(info, 2); + if (acceptsURL(url)) { + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl(url, info); - @Override - public int getMajorVersion() { - return Constants.DRIVER_MAJOR_VERSION; - } + dpi[0] = new DriverPropertyInfo(Constants.Property.HOST, + vitessJDBCUrl.getHostInfos().get(0).getHostname()); + dpi[0].required = true; + dpi[0].description = Constants.VITESS_HOST; - @Override - public int getMinorVersion() { - return Constants.DRIVER_MINOR_VERSION; - } + dpi[1] = new DriverPropertyInfo(Constants.Property.PORT, + (new Integer(vitessJDBCUrl.getHostInfos().get(0).getPort())).toString()); + dpi[1].required = false; + dpi[1].description = Constants.VITESS_PORT; - @Override - public boolean jdbcCompliant() { - return Constants.JDBC_COMPLIANT; + } else { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_CONN_URL + " : " + url); } - @Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + return dpi; + } + + @Override + public int getMajorVersion() { + return Constants.DRIVER_MAJOR_VERSION; + } + + @Override + public int getMinorVersion() { + return Constants.DRIVER_MINOR_VERSION; + } + + @Override + public boolean jdbcCompliant() { + return Constants.JDBC_COMPLIANT; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java index 416a76734a6..44814416bc5 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java @@ -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. @@ -30,12 +30,11 @@ import java.util.regex.Pattern; /** - * VitessJDBCUrl is responsible for parsing a driver URL and Properties object, - * returning a new Properties object with configuration from the URL and passed in Properties - * merged. + * VitessJDBCUrl is responsible for parsing a driver URL and Properties object, returning a new + * Properties object with configuration from the URL and passed in Properties merged. *

- * Parameters passed in through the Properties object take precedence over the parameters - * in the URL, where there are conflicts. + * Parameters passed in through the Properties object take precedence over the parameters in the + * URL, where there are conflicts. *

* The Passed in URL is expected to conform to the following basic format: *

@@ -43,83 +42,80 @@ */ public class VitessJDBCUrl { - private final String url; - private final List hostInfos; - private final Properties info; + private final String url; + private final List hostInfos; + private final Properties info; - /* - Assuming List of vtGate ips could be given in url, separated by "," - */ - public static class HostInfo { - private String hostname; - private int port; + /* + Assuming List of vtGate ips could be given in url, separated by "," + */ + public static class HostInfo { - public HostInfo(String hostname, int port) { - this.hostname = hostname; - this.port = port; - } + private String hostname; + private int port; - public String getHostname() { - return hostname; - } + public HostInfo(String hostname, int port) { + this.hostname = hostname; + this.port = port; + } - public int getPort() { - return port; - } + public String getHostname() { + return hostname; + } - @Override - public String toString() { - return hostname + ":" + port; - } + public int getPort() { + return port; } - /** - *

Create VitessJDBC url object for given urls and properties.

- *

- *

To indicate that SSL should be used, URL's follow the MySQL and MariaDB convention of including - * the property useSSL=true. To use a keyStore and trustStore other than the JRE - * default, you can add the following URL properties:

- *

- *

- *

    - *
  • keyStore=path_to_keystore_file
  • - *
  • keyStorePassword=password (if set)
  • - *
  • keyPassword=password (only needed if the private key password differs from - * the keyStore password)
  • - *
  • keyAlias=alias_under_which_private_key_is_stored (if not set, then the - * first valid PrivateKeyEntry found in the keyStore will be used)
  • - *
  • trustStore=path_to_truststore_file
  • - *
  • trustStorePassword=password (if set)
  • - *
  • trustAlias=alias_under_which_certificate_chain_is_stored (if not set, - * then the first valid X509Certificate found in the trustStore will be used)
  • - *
- *

- *

- *

If useSSL=true, and any of these additional properties are not set on the JDBC URL, - * then the driver will look to see if these corresponding property was set at JVM startup time:

- *

- *

- *

    - *
  • -Djavax.net.ssl.keyStore
  • - *
  • -Djavax.net.ssl.keyStorePassword
  • - *
  • -Djavax.net.ssl.keyPassword
  • - *
  • -Djavax.net.ssl.keyAlias
  • - *
  • -Djavax.net.ssl.trustStore
  • - *
  • -Djavax.net.ssl.trustStorePassword
  • - *
  • -Djavax.net.ssl.trustStoreAlias
  • - *
- *

- *

- *

See:

- *

https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/#tls-ssl

- *

https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-using-ssl.html

- * - * @param url - * @param info - * @return - * @throws SQLException - */ - public VitessJDBCUrl(String url, Properties info) throws SQLException { + @Override + public String toString() { + return hostname + ":" + port; + } + } + + /** + *

Create VitessJDBC url object for given urls and properties.

+ *

+ *

To indicate that SSL should be used, URL's follow the MySQL and MariaDB convention of + * including the property useSSL=true. To use a keyStore and trustStore other than + * the JRE default, you can add the following URL properties:

+ *

+ *

+ *

    + *
  • keyStore=path_to_keystore_file
  • + *
  • keyStorePassword=password (if set)
  • + *
  • keyPassword=password (only needed if the private key password differs from + * the keyStore password)
  • + *
  • keyAlias=alias_under_which_private_key_is_stored (if not set, then the + * first valid PrivateKeyEntry found in the keyStore will be used)
  • + *
  • trustStore=path_to_truststore_file
  • + *
  • trustStorePassword=password (if set)
  • + *
  • trustAlias=alias_under_which_certificate_chain_is_stored (if not set, + * then the first valid X509Certificate found in the trustStore will be used)
  • + *
+ *

+ *

+ *

If useSSL=true, and any of these additional properties are not set on the JDBC + * URL, then the driver will look to see if these corresponding property was set at JVM startup + * time:

+ *

+ *

+ *

    + *
  • -Djavax.net.ssl.keyStore
  • + *
  • -Djavax.net.ssl.keyStorePassword
  • + *
  • -Djavax.net.ssl.keyPassword
  • + *
  • -Djavax.net.ssl.keyAlias
  • + *
  • -Djavax.net.ssl.trustStore
  • + *
  • -Djavax.net.ssl.trustStorePassword
  • + *
  • -Djavax.net.ssl.trustStoreAlias
  • + *
+ *

+ *

+ *

See:

+ *

https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/#tls-ssl

+ *

https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-using-ssl.html

+ */ + public VitessJDBCUrl(String url, Properties info) throws SQLException { /* URL pattern e.g. jdbc:vitess://username:password@ip1:port1,ip2:port2/keyspace/catalog? property1=value1.. @@ -137,146 +133,144 @@ public VitessJDBCUrl(String url, Properties info) throws SQLException { m.group(12) = "property1=value1.." */ - final Pattern p = Pattern.compile(Constants.URL_PATTERN); - final Matcher m = p.matcher(url); - if (!m.find()) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - - info = getURLParamProperties(m.group(12), info); - - // Will add password property once its supported from vitess - // this.password = (m.group(5) == null ? info.getProperty("password") : m.group(5)); - String postUrl = m.group(6); - if (null == postUrl) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - - this.hostInfos = getURLHostInfos(postUrl); - this.url = url; + final Pattern p = Pattern.compile(Constants.URL_PATTERN); + final Matcher m = p.matcher(url); + if (!m.find()) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } - // For Backward Compatibility of username in connection url. - String userName = m.group(3); - if (!StringUtils.isNullOrEmptyWithoutWS(userName)) { - info.setProperty(Constants.Property.USERNAME, userName); - } + info = getURLParamProperties(m.group(12), info); - // For Backward Compatibility of keyspace & catalog/database/schema name in connection url. - String keyspace = m.group(8); - if (!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { - info.setProperty(Constants.Property.KEYSPACE, keyspace); - String catalog = m.group(10); - if (!StringUtils.isNullOrEmptyWithoutWS(catalog)) { - info.setProperty(Constants.Property.DBNAME, catalog); - } else { - info.setProperty(Constants.Property.DBNAME, keyspace); - } - } + // Will add password property once its supported from vitess + // this.password = (m.group(5) == null ? info.getProperty("password") : m.group(5)); + String postUrl = m.group(6); + if (null == postUrl) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } - // For Backward Compatibility of old tablet type. - String oldTabletType = info.getProperty(Constants.Property.OLD_TABLET_TYPE); - String tabletType = info.getProperty(Constants.Property.TABLET_TYPE); - if (null != tabletType) { - info.setProperty(Constants.Property.OLD_TABLET_TYPE, tabletType); - } else if (null != oldTabletType) { - info.setProperty(Constants.Property.TABLET_TYPE, oldTabletType); - } + this.hostInfos = getURLHostInfos(postUrl); + this.url = url; - this.info = info; + // For Backward Compatibility of username in connection url. + String userName = m.group(3); + if (!StringUtils.isNullOrEmptyWithoutWS(userName)) { + info.setProperty(Constants.Property.USERNAME, userName); } - public String getUrl() { - return url; + // For Backward Compatibility of keyspace & catalog/database/schema name in connection url. + String keyspace = m.group(8); + if (!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { + info.setProperty(Constants.Property.KEYSPACE, keyspace); + String catalog = m.group(10); + if (!StringUtils.isNullOrEmptyWithoutWS(catalog)) { + info.setProperty(Constants.Property.DBNAME, catalog); + } else { + info.setProperty(Constants.Property.DBNAME, keyspace); + } } - public List getHostInfos() { - return hostInfos; + // For Backward Compatibility of old tablet type. + String oldTabletType = info.getProperty(Constants.Property.OLD_TABLET_TYPE); + String tabletType = info.getProperty(Constants.Property.TABLET_TYPE); + if (null != tabletType) { + info.setProperty(Constants.Property.OLD_TABLET_TYPE, tabletType); + } else if (null != oldTabletType) { + info.setProperty(Constants.Property.TABLET_TYPE, oldTabletType); } - /** - * Get Properties object for params after ? in url. - * - * @param paramString Parameter String in the url - * @param info passed in the connection - * @return Properties updated with parameters - */ - - private static Properties getURLParamProperties(String paramString, Properties info) - throws SQLException { - // If passed in, don't use info properties directly so we don't act upon it accidentally. - // instead use as defaults for a new properties object - info = (info == null) ? new Properties() : new Properties(info); - - if (!StringUtils.isNullOrEmptyWithoutWS(paramString)) { - StringTokenizer queryParams = new StringTokenizer(paramString, "&"); //$NON-NLS-1$ - while (queryParams.hasMoreTokens()) { - String parameterValuePair = queryParams.nextToken(); - int indexOfEquals = parameterValuePair.indexOf('='); - - String parameter = null; - String value = null; - - if (indexOfEquals != -1) { - parameter = parameterValuePair.substring(0, indexOfEquals); - - if (indexOfEquals + 1 < parameterValuePair.length()) { - value = parameterValuePair.substring(indexOfEquals + 1); - } - } - - // Per the mysql-connector-java docs, passed in Properties values should take precedence over - // those in the URL. See javadoc for NonRegisteringDriver#connect - if ((null != value && value.length() > 0) && (parameter.length() > 0) && null == info.getProperty(parameter)) { - try { - info.put(parameter, URLDecoder.decode(value, "UTF-8")); - } catch (UnsupportedEncodingException | NoSuchMethodError badEncoding) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - } - } + this.info = info; + } + + public String getUrl() { + return url; + } + + public List getHostInfos() { + return hostInfos; + } + + /** + * Get Properties object for params after ? in url. + * + * @param paramString Parameter String in the url + * @param info passed in the connection + * @return Properties updated with parameters + */ + + private static Properties getURLParamProperties(String paramString, Properties info) + throws SQLException { + // If passed in, don't use info properties directly so we don't act upon it accidentally. + // instead use as defaults for a new properties object + info = (info == null) ? new Properties() : new Properties(info); + + if (!StringUtils.isNullOrEmptyWithoutWS(paramString)) { + StringTokenizer queryParams = new StringTokenizer(paramString, "&"); //$NON-NLS-1$ + while (queryParams.hasMoreTokens()) { + String parameterValuePair = queryParams.nextToken(); + int indexOfEquals = parameterValuePair.indexOf('='); + + String parameter = null; + String value = null; + + if (indexOfEquals != -1) { + parameter = parameterValuePair.substring(0, indexOfEquals); + + if (indexOfEquals + 1 < parameterValuePair.length()) { + value = parameterValuePair.substring(indexOfEquals + 1); + } } - return info; + // Per the mysql-connector-java docs, passed in Properties values should take precedence + // over + // those in the URL. See javadoc for NonRegisteringDriver#connect + if ((null != value && value.length() > 0) && (parameter.length() > 0) && null == info + .getProperty(parameter)) { + try { + info.put(parameter, URLDecoder.decode(value, "UTF-8")); + } catch (UnsupportedEncodingException | NoSuchMethodError badEncoding) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } + } + } } - /** - * Get List of Hosts for url separated by commas - * - * @param hostURLs - * @return - * @throws SQLException - */ - private static List getURLHostInfos(String hostURLs) throws SQLException { - List hostInfos = new ArrayList<>(); - - StringTokenizer stringTokenizer = new StringTokenizer(hostURLs, ","); - while (stringTokenizer.hasMoreTokens()) { - String hostString = stringTokenizer.nextToken(); + return info; + } + + /** + * Get List of Hosts for url separated by commas + */ + private static List getURLHostInfos(String hostURLs) throws SQLException { + List hostInfos = new ArrayList<>(); + + StringTokenizer stringTokenizer = new StringTokenizer(hostURLs, ","); + while (stringTokenizer.hasMoreTokens()) { + String hostString = stringTokenizer.nextToken(); /* pattern = ip:port */ - final Pattern p = Pattern.compile("([^/:]+):(\\d+)?"); - final Matcher m = p.matcher(hostString); - if (!m.find()) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - String hostname = m.group(1); - int port; - if (m.group(2) != null) { - port = Integer.parseInt(m.group(2)); - } else { - port = Integer.parseInt(Constants.DEFAULT_PORT); - } - HostInfo hostInfo = new HostInfo(hostname, port); - hostInfos.add(hostInfo); - } - if (hostInfos.size() == 0) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - return hostInfos; + final Pattern p = Pattern.compile("([^/:]+):(\\d+)?"); + final Matcher m = p.matcher(hostString); + if (!m.find()) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } + String hostname = m.group(1); + int port; + if (m.group(2) != null) { + port = Integer.parseInt(m.group(2)); + } else { + port = Integer.parseInt(Constants.DEFAULT_PORT); + } + HostInfo hostInfo = new HostInfo(hostname, port); + hostInfos.add(hostInfo); } - - public Properties getProperties() { - return info; + if (hostInfos.size() == 0) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); } + return hostInfos; + } + + public Properties getProperties() { + return info; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java index 5b0f47f7e07..e372f150996 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java @@ -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. @@ -30,511 +30,499 @@ /** * Created by ashudeep.sharma on 15/02/16. */ -public class VitessMariaDBDatabaseMetadata extends VitessDatabaseMetaData - implements DatabaseMetaData { +public class VitessMariaDBDatabaseMetadata extends VitessDatabaseMetaData implements + DatabaseMetaData { + + private static final String DRIVER_NAME = "Vitess MariaDB JDBC Driver"; + private static Logger logger = Logger.getLogger(VitessMariaDBDatabaseMetadata.class.getName()); + + public VitessMariaDBDatabaseMetadata(VitessConnection connection) throws SQLException { + this.setConnection(connection); + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return !this.nullsAreSortedAtStart(); + } + + public String getDatabaseProductVersion() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public String getDriverName() throws SQLException { + return DRIVER_NAME; + } + + public String getSQLKeywords() throws SQLException { + return "ACCESSIBLE," + "ANALYZE," + "ASENSITIVE," + "BEFORE," + "BIGINT," + "BINARY," + "BLOB," + + "CALL," + "CHANGE," + "CONDITION," + "DATABASE," + "DATABASES," + "DAY_HOUR," + + "DAY_MICROSECOND," + "DAY_MINUTE," + "DAY_SECOND," + "DELAYED," + "DETERMINISTIC," + + "DISTINCTROW," + "DIV," + "DUAL," + "EACH," + "ELSEIF," + "ENCLOSED," + "ESCAPED," + + "EXIT," + "EXPLAIN," + "FLOAT4," + "FLOAT8," + "FORCE," + "FULLTEXT," + "HIGH_PRIORITY," + + "HOUR_MICROSECOND," + "HOUR_MINUTE," + "HOUR_SECOND," + "IF," + "IGNORE," + "INFILE," + + "INOUT," + "INT1," + "INT2," + "INT3," + "INT4," + "INT8," + "ITERATE," + "KEY," + "KEYS," + + "KILL," + "LEAVE," + "LIMIT," + "LINEAR," + "LINES," + "LOAD," + "LOCALTIME," + + "LOCALTIMESTAMP," + "LOCK," + "LONG," + "LONGBLOB," + "LONGTEXT," + "LOOP," + + "LOW_PRIORITY," + "MEDIUMBLOB," + "MEDIUMINT," + "MEDIUMTEXT," + "MIDDLEINT," + + "MINUTE_MICROSECOND," + "MINUTE_SECOND," + "MOD," + "MODIFIES," + "NO_WRITE_TO_BINLOG," + + "OPTIMIZE," + "OPTIONALLY," + "OUT," + "OUTFILE," + "PURGE," + "RANGE," + "READS," + "" + + "READ_ONLY," + "READ_WRITE," + "REGEXP," + "RELEASE," + "RENAME," + "REPEAT," + "REPLACE," + + "REQUIRE," + "RETURN," + "RLIKE," + "SCHEMAS," + "SECOND_MICROSECOND," + "SENSITIVE," + + "SEPARATOR," + "SHOW," + "SPATIAL," + "SPECIFIC," + "SQLEXCEPTION," + "SQL_BIG_RESULT," + + "SQL_CALC_FOUND_ROWS," + "SQL_SMALL_RESULT," + "SSL," + "STARTING," + "STRAIGHT_JOIN," + + "TERMINATED," + "TINYBLOB," + "TINYINT," + "TINYTEXT," + "TRIGGER," + "UNDO," + "UNLOCK," + + "UNSIGNED," + "USE," + "UTC_DATE," + "UTC_TIME," + "UTC_TIMESTAMP," + "VARBINARY," + + "VARCHARACTER," + "WHILE," + "X509," + "XOR," + "YEAR_MONTH," + "ZEROFILL," + "GENERAL," + + "IGNORE_SERVER_IDS," + "MASTER_HEARTBEAT_PERIOD," + "MAXVALUE," + "RESIGNAL," + "SIGNAL" + + "SLOW"; + } + + public boolean supportsConvert() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupBy() throws SQLException { + return false; + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } - private static final String DRIVER_NAME = "Vitess MariaDB JDBC Driver"; - private static Logger logger = Logger.getLogger(VitessMariaDBDatabaseMetadata.class.getName()); + public int getMaxColumnsInTable() throws SQLException { + return 512; + } - public VitessMariaDBDatabaseMetadata(VitessConnection connection) throws SQLException { - this.setConnection(connection); - } - - public boolean nullsAreSortedAtStart() throws SQLException { - return false; - } - - public boolean nullsAreSortedAtEnd() throws SQLException { - return !this.nullsAreSortedAtStart(); - } - - public String getDatabaseProductVersion() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public String getDriverName() throws SQLException { - return DRIVER_NAME; - } - - public String getSQLKeywords() throws SQLException { - return "ACCESSIBLE," + "ANALYZE," + "ASENSITIVE," + "BEFORE," + "BIGINT," + "BINARY," - + "BLOB," + "CALL," + - "CHANGE," + "CONDITION," + "DATABASE," + "DATABASES," + "DAY_HOUR," + "DAY_MICROSECOND," - + "DAY_MINUTE," + "DAY_SECOND," + "DELAYED," + "DETERMINISTIC," + "DISTINCTROW," - + "DIV," + "DUAL," + "EACH," + "ELSEIF," + "ENCLOSED," + "ESCAPED," + "EXIT," - + "EXPLAIN," + "FLOAT4," + "FLOAT8," + "FORCE," + "FULLTEXT," + - "HIGH_PRIORITY," + "HOUR_MICROSECOND," + "HOUR_MINUTE," + "HOUR_SECOND," + "IF," - + "IGNORE," + "INFILE," + "INOUT," + "INT1," + "INT2," + "INT3," + "INT4," + "INT8," - + "ITERATE," + "KEY," + "KEYS," + "KILL," + - "LEAVE," + "LIMIT," + "LINEAR," + "LINES," + "LOAD," + "LOCALTIME," + "LOCALTIMESTAMP," - + "LOCK," + - "LONG," + "LONGBLOB," + "LONGTEXT," + "LOOP," + "LOW_PRIORITY," + "MEDIUMBLOB," - + "MEDIUMINT," + - "MEDIUMTEXT," + "MIDDLEINT," + "MINUTE_MICROSECOND," + "MINUTE_SECOND," + "MOD," - + "MODIFIES," + - "NO_WRITE_TO_BINLOG," + "OPTIMIZE," + "OPTIONALLY," + "OUT," + "OUTFILE," + "PURGE," - + "RANGE," + "READS," + - "" + "READ_ONLY," + "READ_WRITE," + "REGEXP," + "RELEASE," + "RENAME," + "REPEAT," - + "REPLACE," + - "REQUIRE," + "RETURN," + "RLIKE," + "SCHEMAS," + "SECOND_MICROSECOND," + "SENSITIVE," - + "SEPARATOR," + - "SHOW," + "SPATIAL," + "SPECIFIC," + "SQLEXCEPTION," + "SQL_BIG_RESULT," - + "SQL_CALC_FOUND_ROWS," + - "SQL_SMALL_RESULT," + "SSL," + "STARTING," + "STRAIGHT_JOIN," + "TERMINATED," - + "TINYBLOB," + "TINYINT," + "TINYTEXT," + "TRIGGER," + "UNDO," + "UNLOCK," - + "UNSIGNED," + "USE," + "UTC_DATE," + "UTC_TIME," + - "UTC_TIMESTAMP," + "VARBINARY," + "VARCHARACTER," + "WHILE," + "X509," + "XOR," - + "YEAR_MONTH," + - "ZEROFILL," + "GENERAL," + "IGNORE_SERVER_IDS," + "MASTER_HEARTBEAT_PERIOD," - + "MAXVALUE," + "RESIGNAL," + "SIGNAL" + "SLOW"; - } - - public boolean supportsConvert() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean supportsConvert(int fromType, int toType) throws SQLException { - return false; - } - - public boolean supportsTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsExpressionsInOrderBy() throws SQLException { - return false; - } - - public boolean supportsOrderByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupBy() throws SQLException { - return false; - } - - public boolean supportsGroupByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupByBeyondSelect() throws SQLException { - return false; - } - - public boolean supportsMultipleResultSets() throws SQLException { - return false; - } - - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92IntermediateSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92FullSQL() throws SQLException { - return false; - } - - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - return false; - } - - public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; - } - - public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInDataManipulation() throws SQLException { - return false; - } - - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsPositionedDelete() throws SQLException { - return false; - } - - public boolean supportsPositionedUpdate() throws SQLException { - return false; - } + public int getMaxCursorNameLength() throws SQLException { + return 0; + } - public boolean supportsSubqueriesInComparisons() throws SQLException { - return false; - } + public int getMaxSchemaNameLength() throws SQLException { + return 32; + } - public int getMaxColumnsInTable() throws SQLException { - return 512; - } + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } - public int getMaxCursorNameLength() throws SQLException { - return 0; - } + public int getMaxRowSize() throws SQLException { + return 0; + } - public int getMaxSchemaNameLength() throws SQLException { - return 32; - } + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } - public int getMaxCatalogNameLength() throws SQLException { - return 0; - } + public int getMaxStatementLength() throws SQLException { + return 0; + } - public int getMaxRowSize() throws SQLException { - return 0; - } + public int getDefaultTransactionIsolation() throws SQLException { + return this.connection.TRANSACTION_REPEATABLE_READ; + } - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { - return false; - } + public boolean supportsTransactions() throws SQLException { + return true; + } - public int getMaxStatementLength() throws SQLException { - return 0; - } - - public int getDefaultTransactionIsolation() throws SQLException { - return this.connection.TRANSACTION_REPEATABLE_READ; - } - - public boolean supportsTransactions() throws SQLException { + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + switch (level) { + case Connection.TRANSACTION_READ_UNCOMMITTED: + case Connection.TRANSACTION_READ_COMMITTED: + case Connection.TRANSACTION_REPEATABLE_READ: + case Connection.TRANSACTION_SERIALIZABLE: return true; - } - - public boolean supportsTransactionIsolationLevel(int level) throws SQLException { - switch (level) { - case Connection.TRANSACTION_READ_UNCOMMITTED: - case Connection.TRANSACTION_READ_COMMITTED: - case Connection.TRANSACTION_REPEATABLE_READ: - case Connection.TRANSACTION_SERIALIZABLE: - return true; - default: - return false; - } - } - - public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, - String[] types) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getSchemas() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getCatalogs() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTableTypes() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getColumnPrivileges(String catalog, String schema, String table, - String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTablePrivileges(String catalog, String schemaPattern, - String tableNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, - boolean nullable) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getVersionColumns(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getPrimaryKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getImportedKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getExportedKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getCrossReference(String parentCatalog, String parentSchema, - String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTypeInfo() throws SQLException { - String[] columnNames = - {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", "LITERAL_SUFFIX", - "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", - "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", - "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; - Query.Type[] columnTypes = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.BIT, - Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, - Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32}; - - String[][] data = - {{"BIT", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BIT", "0", "0", "0", "0", - "10"}, - {"BOOL", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BOOL", "0", "0", "0", - "0", "10"}, - {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "TINYINT", "0", "0", "0", "0", "10"}, - {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", - "3", "1", "0", "1", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "BIGINT", "0", "0", "0", "0", "10"}, - {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", - "LONG VARBINARY", "0", "0", "0", "0", "10"}, - {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", - "MEDIUMBLOB", "0", "0", "0", "0", "10"}, - {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "1", "3", "0", "0", "0", - "LONGBLOB", "0", "0", "0", "0", "10"}, - {"BLOB", "-4", "65535", "'", "'", "", "1", "1", "3", "0", "0", "0", "BLOB", "0", - "0", "0", "0", "10"}, - {"TINYBLOB", "-4", "255", "'", "'", "", "1", "1", "3", "0", "0", "0", "TINYBLOB", - "0", "0", "0", "0", "10"}, - {"VARBINARY", "-3", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", - "VARBINARY", "0", "0", "0", "0", "10"}, - {"BINARY", "-2", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "BINARY", - "0", "0", "0", "0", "10"}, - {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", - "LONG VARCHAR", "0", "0", "0", "0", "10"}, - {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", - "MEDIUMTEXT", "0", "0", "0", "0", "10"}, - {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "0", "3", "0", "0", "0", - "LONGTEXT", "0", "0", "0", "0", "10"}, - {"TEXT", "-1", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "TEXT", "0", - "0", "0", "0", "10"}, - {"TINYTEXT", "-1", "255", "'", "'", "", "1", "0", "3", "0", "0", "0", "TINYTEXT", - "0", "0", "0", "0", "10"}, - {"CHAR", "1", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "CHAR", "0", - "0", "0", "0", "10"}, - {"NUMERIC", "2", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "NUMERIC", "-308", "308", "0", "0", "10"}, - {"DECIMAL", "3", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "DECIMAL", "-308", "308", "0", "0", "10"}, - {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "INTEGER", "0", "0", "0", "0", "10"}, - {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, - {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "INT", "0", "0", "0", "0", "10"}, - {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "INT UNSIGNED", "0", "0", "0", "0", "10"}, - {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "MEDIUMINT", "0", "0", "0", "0", "10"}, - {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "SMALLINT", "0", "0", "0", "0", "10"}, - {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"FLOAT", "7", "10", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "FLOAT", "-38", "38", "0", "0", "10"}, - {"DOUBLE", "8", "17", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "DOUBLE", "-308", "308", "0", "0", "10"}, - {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", - "0", "1", "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, - {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "REAL", "-308", "308", "0", "0", "10"}, - {"VARCHAR", "12", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "VARCHAR", - "0", "0", "0", "0", "10"}, - {"ENUM", "12", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "ENUM", "0", - "0", "0", "0", "10"}, - {"SET", "12", "64", "'", "'", "", "1", "0", "3", "0", "0", "0", "SET", "0", "0", - "0", "0", "10"}, - {"DATE", "91", "10", "'", "'", "", "1", "0", "3", "0", "0", "0", "DATE", "0", "0", - "0", "0", "10"}, - {"TIME", "92", "18", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIME", "0", - "0", "0", "0", "10"}, - {"DATETIME", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", - "DATETIME", "0", "0", "0", "0", "10"}, - {"TIMESTAMP", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", - "TIMESTAMP", "0", "0", "0", "0", "10"}}; - - return new VitessResultSet(columnNames, columnTypes, data, this.connection); - } - - public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, - boolean approximate) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean ownUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean updatesAreDetected(int type) throws SQLException { - return false; - } - - public boolean deletesAreDetected(int type) throws SQLException { - return false; - } - - public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, - int[] types) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public VitessConnection getConnection() throws SQLException { - return connection; - } - - public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, - String attributeNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getSQLStateType() throws SQLException { - return DatabaseMetaData.sqlStateSQL; - } - - public boolean locatorsUpdateCopy() throws SQLException { - return false; - } - - public RowIdLifetime getRowIdLifetime() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean autoCommitFailureClosesAllResultSets() throws SQLException { - return false; - } - - public ResultSet getClientInfoProperties() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - return connection.createStatement().executeQuery("SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," - + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," - + "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE, ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' IS_NULLABLE FROM DUAL " - + "WHERE 1=0"); - } - - public T unwrap(Class iface) throws SQLException { - return null; - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + default: + return false; + } + } + + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, + String[] types) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSchemas() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getCatalogs() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTableTypes() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getColumnPrivileges(String catalog, String schema, String table, + String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, + boolean nullable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getVersionColumns(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getImportedKeys(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getExportedKeys(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, + String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTypeInfo() throws SQLException { + String[] columnNames = {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", + "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", + "MINIMUM_SCALE", "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; + Query.Type[] columnTypes = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, + Query.Type.BIT, Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, + Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32}; + + String[][] data = { + {"BIT", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BIT", "0", "0", "0", "0", + "10"}, + {"BOOL", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BOOL", "0", "0", "0", "0", + "10"}, + {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "TINYINT", "0", "0", "0", "0", "10"}, + {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", + "0", "1", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "BIGINT", "0", "0", "0", "0", "10"}, + {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", + "LONG VARBINARY", "0", "0", "0", "0", "10"}, + {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", "MEDIUMBLOB", + "0", "0", "0", "0", "10"}, + {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "1", "3", "0", "0", "0", "LONGBLOB", + "0", "0", "0", "0", "10"}, + {"BLOB", "-4", "65535", "'", "'", "", "1", "1", "3", "0", "0", "0", "BLOB", "0", "0", "0", + "0", "10"}, + {"TINYBLOB", "-4", "255", "'", "'", "", "1", "1", "3", "0", "0", "0", "TINYBLOB", "0", "0", + "0", "0", "10"}, + {"VARBINARY", "-3", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "VARBINARY", "0", + "0", "0", "0", "10"}, + {"BINARY", "-2", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "BINARY", "0", "0", + "0", "0", "10"}, + {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", + "LONG VARCHAR", "0", "0", "0", "0", "10"}, + {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", "MEDIUMTEXT", + "0", "0", "0", "0", "10"}, + {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "0", "3", "0", "0", "0", "LONGTEXT", + "0", "0", "0", "0", "10"}, + {"TEXT", "-1", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "TEXT", "0", "0", "0", + "0", "10"}, + {"TINYTEXT", "-1", "255", "'", "'", "", "1", "0", "3", "0", "0", "0", "TINYTEXT", "0", "0", + "0", "0", "10"}, + {"CHAR", "1", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "CHAR", "0", "0", "0", + "0", "10"}, + {"NUMERIC", "2", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", + "NUMERIC", "-308", "308", "0", "0", "10"}, + {"DECIMAL", "3", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", + "DECIMAL", "-308", "308", "0", "0", "10"}, + {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INTEGER", "0", "0", "0", "0", "10"}, + {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, + {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INT", "0", "0", "0", "0", "10"}, + {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INT UNSIGNED", "0", "0", "0", "0", "10"}, + {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "MEDIUMINT", "0", "0", "0", "0", "10"}, + {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "SMALLINT", "0", "0", "0", "0", "10"}, + {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"FLOAT", "7", "10", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "FLOAT", + "-38", "38", "0", "0", "10"}, + {"DOUBLE", "8", "17", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "DOUBLE", + "-308", "308", "0", "0", "10"}, + {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", + "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, + {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "REAL", + "-308", "308", "0", "0", "10"}, + {"VARCHAR", "12", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "VARCHAR", "0", "0", + "0", "0", "10"}, + {"ENUM", "12", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "ENUM", "0", "0", "0", + "0", "10"}, + {"SET", "12", "64", "'", "'", "", "1", "0", "3", "0", "0", "0", "SET", "0", "0", "0", "0", + "10"}, + {"DATE", "91", "10", "'", "'", "", "1", "0", "3", "0", "0", "0", "DATE", "0", "0", "0", "0", + "10"}, + {"TIME", "92", "18", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIME", "0", "0", "0", + "0", "10"}, + {"DATETIME", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "DATETIME", "0", + "0", "0", "0", "10"}, + {"TIMESTAMP", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIMESTAMP", "0", + "0", "0", "0", "10"}}; + + return new VitessResultSet(columnNames, columnTypes, data, this.connection); + } + + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, + boolean approximate) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, + int[] types) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public VitessConnection getConnection() throws SQLException { + return connection; + } + + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, + String attributeNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getSQLStateType() throws SQLException { + return DatabaseMetaData.sqlStateSQL; + } + + public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + public RowIdLifetime getRowIdLifetime() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + public ResultSet getClientInfoProperties() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getFunctionColumns(String catalog, String schemaPattern, + String functionNamePattern, String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + return connection.createStatement().executeQuery("SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," + + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," + + "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE, ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' " + + "IS_NULLABLE FROM DUAL " + + "WHERE 1=0"); + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java index e94541dacde..0c87ff34d0e 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java @@ -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,12 +17,13 @@ package io.vitess.jdbc; import com.google.common.annotations.VisibleForTesting; -import org.apache.commons.lang.StringUtils; import io.vitess.proto.Query; import io.vitess.util.Constants; import io.vitess.util.MysqlDefs; +import org.apache.commons.lang.StringUtils; + import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -45,1774 +46,1738 @@ /** * Created by ashudeep.sharma on 15/02/16. */ -public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData - implements DatabaseMetaData { - - private static final String DRIVER_NAME = "Vitess MySQL JDBC Driver"; - private static Logger logger = Logger.getLogger(VitessMySQLDatabaseMetadata.class.getName()); - private static String mysqlKeywordsThatArentSQL92; - - static { - - String[] allMySQLKeywords = - new String[] {"ACCESSIBLE", "ADD", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", - "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BLOB", "BOTH", "BY", "CALL", - "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", "CHECK", "COLLATE", "COLUMN", - "CONDITION", "CONNECTION", "CONSTRAINT", "CONTINUE", "CONVERT", "CREATE", "CROSS", - "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", - "DATABASE", "DATABASES", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", - "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", - "DETERMINISTIC", "DISTINCT", "DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", - "ELSE", "ELSEIF", "ENCLOSED", "ESCAPED", "EXISTS", "EXIT", "EXPLAIN", "FALSE", - "FETCH", "FLOAT", "FLOAT4", "FLOAT8", "FOR", "FORCE", "FOREIGN", "FROM", "FULLTEXT", - "GRANT", "GROUP", "HAVING", "HIGH_PRIORITY", "HOUR_MICROSECOND", "HOUR_MINUTE", - "HOUR_SECOND", "IF", "IGNORE", "IN", "INDEX", "INFILE", "INNER", "INOUT", - "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER", - "INTERVAL", "INTO", "IS", "ITERATE", "JOIN", "KEY", "KEYS", "KILL", "LEADING", - "LEAVE", "LEFT", "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", - "LOCALTIMESTAMP", "LOCK", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", - "MATCH", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND", - "MINUTE_SECOND", "MOD", "MODIFIES", "NATURAL", "NOT", "NO_WRITE_TO_BINLOG", "NULL", - "NUMERIC", "ON", "OPTIMIZE", "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", - "OUTFILE", "PRECISION", "PRIMARY", "PROCEDURE", "PURGE", "RANGE", "READ", "READS", - "READ_ONLY", "READ_WRITE", "REAL", "REFERENCES", "REGEXP", "RELEASE", "RENAME", - "REPEAT", "REPLACE", "REQUIRE", "RESTRICT", "RETURN", "REVOKE", "RIGHT", "RLIKE", - "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT", "SENSITIVE", "SEPARATOR", - "SET", "SHOW", "SMALLINT", "SPATIAL", "SPECIFIC", "SQL", "SQLEXCEPTION", "SQLSTATE", - "SQLWARNING", "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS", "SQL_SMALL_RESULT", "SSL", - "STARTING", "STRAIGHT_JOIN", "TABLE", "TERMINATED", "THEN", "TINYBLOB", "TINYINT", - "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", "UNIQUE", - "UNLOCK", "UNSIGNED", "UPDATE", "USAGE", "USE", "USING", "UTC_DATE", "UTC_TIME", - "UTC_TIMESTAMP", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", - "WHEN", "WHERE", "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH", "ZEROFILL"}; - String[] sql92Keywords = - new String[] {"ABSOLUTE", "EXEC", "OVERLAPS", "ACTION", "EXECUTE", "PAD", "ADA", - "EXISTS", "PARTIAL", "ADD", "EXTERNAL", "PASCAL", "ALL", "EXTRACT", "POSITION", - "ALLOCATE", "FALSE", "PRECISION", "ALTER", "FETCH", "PREPARE", "AND", "FIRST", - "PRESERVE", "ANY", "FLOAT", "PRIMARY", "ARE", "FOR", "PRIOR", "AS", "FOREIGN", - "PRIVILEGES", "ASC", "FORTRAN", "PROCEDURE", "ASSERTION", "FOUND", "PUBLIC", "AT", - "FROM", "READ", "AUTHORIZATION", "FULL", "REAL", "AVG", "GET", "REFERENCES", - "BEGIN", "GLOBAL", "RELATIVE", "BETWEEN", "GO", "RESTRICT", "BIT", "GOTO", "REVOKE", - "BIT_LENGTH", "GRANT", "RIGHT", "BOTH", "GROUP", "ROLLBACK", "BY", "HAVING", "ROWS", - "CASCADE", "HOUR", "SCHEMA", "CASCADED", "IDENTITY", "SCROLL", "CASE", "IMMEDIATE", - "SECOND", "CAST", "IN", "SECTION", "CATALOG", "INCLUDE", "SELECT", "CHAR", "INDEX", - "SESSION", "CHAR_LENGTH", "INDICATOR", "SESSION_USER", "CHARACTER", "INITIALLY", - "SET", "CHARACTER_LENGTH", "INNER", "SIZE", "CHECK", "INPUT", "SMALLINT", "CLOSE", - "INSENSITIVE", "SOME", "COALESCE", "INSERT", "SPACE", "COLLATE", "INT", "SQL", - "COLLATION", "INTEGER", "SQLCA", "COLUMN", "INTERSECT", "SQLCODE", "COMMIT", - "INTERVAL", "SQLERROR", "CONNECT", "INTO", "SQLSTATE", "CONNECTION", "IS", - "SQLWARNING", "CONSTRAINT", "ISOLATION", "SUBSTRING", "CONSTRAINTS", "JOIN", "SUM", - "CONTINUE", "KEY", "SYSTEM_USER", "CONVERT", "LANGUAGE", "TABLE", "CORRESPONDING", - "LAST", "TEMPORARY", "COUNT", "LEADING", "THEN", "CREATE", "LEFT", "TIME", "CROSS", - "LEVEL", "TIMESTAMP", "CURRENT", "LIKE", "TIMEZONE_HOUR", "CURRENT_DATE", "LOCAL", - "TIMEZONE_MINUTE", "CURRENT_TIME", "LOWER", "TO", "CURRENT_TIMESTAMP", "MATCH", - "TRAILING", "CURRENT_USER", "MAX", "TRANSACTION", "CURSOR", "MIN", "TRANSLATE", - "DATE", "MINUTE", "TRANSLATION", "DAY", "MODULE", "TRIM", "DEALLOCATE", "MONTH", - "TRUE", "DEC", "NAMES", "UNION", "DECIMAL", "NATIONAL", "UNIQUE", "DECLARE", - "NATURAL", "UNKNOWN", "DEFAULT", "NCHAR", "UPDATE", "DEFERRABLE", "NEXT", "UPPER", - "DEFERRED", "NO", "USAGE", "DELETE", "NONE", "USER", "DESC", "NOT", "USING", - "DESCRIBE", "NULL", "VALUE", "DESCRIPTOR", "NULLIF", "VALUES", "DIAGNOSTICS", - "NUMERIC", "VARCHAR", "DISCONNECT", "OCTET_LENGTH", "VARYING", "DISTINCT", "OF", - "VIEW", "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", - "WHERE", "ELSE", "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", - "WRITE", "ESCAPE", "OUTER", "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"}; - TreeMap mySQLKeywordMap = new TreeMap(); - - for (String allMySQLKeyword : allMySQLKeywords) { - mySQLKeywordMap.put(allMySQLKeyword, null); - } - - HashMap sql92KeywordMap = new HashMap(sql92Keywords.length); +public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData implements + DatabaseMetaData { + + private static final String DRIVER_NAME = "Vitess MySQL JDBC Driver"; + private static Logger logger = Logger.getLogger(VitessMySQLDatabaseMetadata.class.getName()); + private static String mysqlKeywordsThatArentSQL92; + + static { + + String[] allMySQLKeywords = new String[]{"ACCESSIBLE", "ADD", "ALL", "ALTER", "ANALYZE", "AND", + "AS", "ASC", "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BLOB", "BOTH", "BY", + "CALL", "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", "CHECK", "COLLATE", "COLUMN", + "CONDITION", "CONNECTION", "CONSTRAINT", "CONTINUE", "CONVERT", "CREATE", "CROSS", + "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "DATABASE", + "DATABASES", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DEC", "DECIMAL", + "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", "DETERMINISTIC", "DISTINCT", + "DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", "ELSE", "ELSEIF", "ENCLOSED", + "ESCAPED", "EXISTS", "EXIT", "EXPLAIN", "FALSE", "FETCH", "FLOAT", "FLOAT4", "FLOAT8", + "FOR", "FORCE", "FOREIGN", "FROM", "FULLTEXT", "GRANT", "GROUP", "HAVING", "HIGH_PRIORITY", + "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IF", "IGNORE", "IN", "INDEX", "INFILE", + "INNER", "INOUT", "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", + "INTEGER", "INTERVAL", "INTO", "IS", "ITERATE", "JOIN", "KEY", "KEYS", "KILL", "LEADING", + "LEAVE", "LEFT", "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", "LOCALTIMESTAMP", + "LOCK", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "MATCH", "MEDIUMBLOB", + "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MOD", + "MODIFIES", "NATURAL", "NOT", "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", "ON", "OPTIMIZE", + "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", "OUTFILE", "PRECISION", "PRIMARY", + "PROCEDURE", "PURGE", "RANGE", "READ", "READS", "READ_ONLY", "READ_WRITE", "REAL", + "REFERENCES", "REGEXP", "RELEASE", "RENAME", "REPEAT", "REPLACE", "REQUIRE", "RESTRICT", + "RETURN", "REVOKE", "RIGHT", "RLIKE", "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT", + "SENSITIVE", "SEPARATOR", "SET", "SHOW", "SMALLINT", "SPATIAL", "SPECIFIC", "SQL", + "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS", + "SQL_SMALL_RESULT", "SSL", "STARTING", "STRAIGHT_JOIN", "TABLE", "TERMINATED", "THEN", + "TINYBLOB", "TINYINT", "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", + "UNIQUE", "UNLOCK", "UNSIGNED", "UPDATE", "USAGE", "USE", "USING", "UTC_DATE", "UTC_TIME", + "UTC_TIMESTAMP", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", "WHEN", + "WHERE", "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH", "ZEROFILL"}; + String[] sql92Keywords = new String[]{"ABSOLUTE", "EXEC", "OVERLAPS", "ACTION", "EXECUTE", + "PAD", "ADA", "EXISTS", "PARTIAL", "ADD", "EXTERNAL", "PASCAL", "ALL", "EXTRACT", + "POSITION", "ALLOCATE", "FALSE", "PRECISION", "ALTER", "FETCH", "PREPARE", "AND", "FIRST", + "PRESERVE", "ANY", "FLOAT", "PRIMARY", "ARE", "FOR", "PRIOR", "AS", "FOREIGN", "PRIVILEGES", + "ASC", "FORTRAN", "PROCEDURE", "ASSERTION", "FOUND", "PUBLIC", "AT", "FROM", "READ", + "AUTHORIZATION", "FULL", "REAL", "AVG", "GET", "REFERENCES", "BEGIN", "GLOBAL", "RELATIVE", + "BETWEEN", "GO", "RESTRICT", "BIT", "GOTO", "REVOKE", "BIT_LENGTH", "GRANT", "RIGHT", + "BOTH", "GROUP", "ROLLBACK", "BY", "HAVING", "ROWS", "CASCADE", "HOUR", "SCHEMA", + "CASCADED", "IDENTITY", "SCROLL", "CASE", "IMMEDIATE", "SECOND", "CAST", "IN", "SECTION", + "CATALOG", "INCLUDE", "SELECT", "CHAR", "INDEX", "SESSION", "CHAR_LENGTH", "INDICATOR", + "SESSION_USER", "CHARACTER", "INITIALLY", "SET", "CHARACTER_LENGTH", "INNER", "SIZE", + "CHECK", "INPUT", "SMALLINT", "CLOSE", "INSENSITIVE", "SOME", "COALESCE", "INSERT", "SPACE", + "COLLATE", "INT", "SQL", "COLLATION", "INTEGER", "SQLCA", "COLUMN", "INTERSECT", "SQLCODE", + "COMMIT", "INTERVAL", "SQLERROR", "CONNECT", "INTO", "SQLSTATE", "CONNECTION", "IS", + "SQLWARNING", "CONSTRAINT", "ISOLATION", "SUBSTRING", "CONSTRAINTS", "JOIN", "SUM", + "CONTINUE", "KEY", "SYSTEM_USER", "CONVERT", "LANGUAGE", "TABLE", "CORRESPONDING", "LAST", + "TEMPORARY", "COUNT", "LEADING", "THEN", "CREATE", "LEFT", "TIME", "CROSS", "LEVEL", + "TIMESTAMP", "CURRENT", "LIKE", "TIMEZONE_HOUR", "CURRENT_DATE", "LOCAL", "TIMEZONE_MINUTE", + "CURRENT_TIME", "LOWER", "TO", "CURRENT_TIMESTAMP", "MATCH", "TRAILING", "CURRENT_USER", + "MAX", "TRANSACTION", "CURSOR", "MIN", "TRANSLATE", "DATE", "MINUTE", "TRANSLATION", "DAY", + "MODULE", "TRIM", "DEALLOCATE", "MONTH", "TRUE", "DEC", "NAMES", "UNION", "DECIMAL", + "NATIONAL", "UNIQUE", "DECLARE", "NATURAL", "UNKNOWN", "DEFAULT", "NCHAR", "UPDATE", + "DEFERRABLE", "NEXT", "UPPER", "DEFERRED", "NO", "USAGE", "DELETE", "NONE", "USER", "DESC", + "NOT", "USING", "DESCRIBE", "NULL", "VALUE", "DESCRIPTOR", "NULLIF", "VALUES", + "DIAGNOSTICS", "NUMERIC", "VARCHAR", "DISCONNECT", "OCTET_LENGTH", "VARYING", "DISTINCT", + "OF", "VIEW", "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", "WHERE", + "ELSE", "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", "WRITE", "ESCAPE", + "OUTER", "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"}; + TreeMap mySQLKeywordMap = new TreeMap(); + + for (String allMySQLKeyword : allMySQLKeywords) { + mySQLKeywordMap.put(allMySQLKeyword, null); + } + + HashMap sql92KeywordMap = new HashMap(sql92Keywords.length); + + for (String sql92Keyword : sql92Keywords) { + sql92KeywordMap.put(sql92Keyword, null); + } + + Iterator sql92KeywordIterator = sql92KeywordMap.keySet().iterator(); + + while (sql92KeywordIterator.hasNext()) { + mySQLKeywordMap.remove(sql92KeywordIterator.next()); + } + + StringBuffer keywordBuf = new StringBuffer(); + sql92KeywordIterator = mySQLKeywordMap.keySet().iterator(); + if (sql92KeywordIterator.hasNext()) { + keywordBuf.append(sql92KeywordIterator.next().toString()); + } + + while (sql92KeywordIterator.hasNext()) { + keywordBuf.append(","); + keywordBuf.append(sql92KeywordIterator.next().toString()); + } + + mysqlKeywordsThatArentSQL92 = keywordBuf.toString(); + } + + private int maxBufferSize = '\uffff'; + + public VitessMySQLDatabaseMetadata(VitessConnection connection) throws SQLException { + this.setConnection(connection); + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + public String getDriverName() throws SQLException { + return DRIVER_NAME; + } + + public String getSQLKeywords() throws SQLException { + return mysqlKeywordsThatArentSQL92; + } + + public String getSystemFunctions() throws SQLException { + return super.getSystemFunctions() + ",PASSWORD,ENCRYPT"; + } + + public boolean supportsConvert() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } - for (String sql92Keyword : sql92Keywords) { - sql92KeywordMap.put(sql92Keyword, null); - } + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } - Iterator sql92KeywordIterator = sql92KeywordMap.keySet().iterator(); + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } - while (sql92KeywordIterator.hasNext()) { - mySQLKeywordMap.remove(sql92KeywordIterator.next()); - } - - StringBuffer keywordBuf = new StringBuffer(); - sql92KeywordIterator = mySQLKeywordMap.keySet().iterator(); - if (sql92KeywordIterator.hasNext()) { - keywordBuf.append(sql92KeywordIterator.next().toString()); - } - - while (sql92KeywordIterator.hasNext()) { - keywordBuf.append(","); - keywordBuf.append(sql92KeywordIterator.next().toString()); - } + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } - mysqlKeywordsThatArentSQL92 = keywordBuf.toString(); - } - - private int maxBufferSize = '\uffff'; - - public VitessMySQLDatabaseMetadata(VitessConnection connection) throws SQLException { - this.setConnection(connection); - } - - public boolean nullsAreSortedAtStart() throws SQLException { - return false; - } - - public boolean nullsAreSortedAtEnd() throws SQLException { - return false; - } + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } - public String getDriverName() throws SQLException { - return DRIVER_NAME; - } + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } - public String getSQLKeywords() throws SQLException { - return mysqlKeywordsThatArentSQL92; - } + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } - public String getSystemFunctions() throws SQLException { - return super.getSystemFunctions() + ",PASSWORD,ENCRYPT"; - } + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsConvert() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } - public boolean supportsConvert(int fromType, int toType) throws SQLException { - return false; - } + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } - public boolean supportsTableCorrelationNames() throws SQLException { - return false; - } + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - return false; - } + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - return false; - } + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsANSI92IntermediateSQL() throws SQLException { - return false; - } + public boolean supportsPositionedDelete() throws SQLException { + return false; + } - public boolean supportsANSI92FullSQL() throws SQLException { - return false; - } + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + public int getMaxCursorNameLength() throws SQLException { + return 64; + } + + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + public int getMaxCatalogNameLength() throws SQLException { + return 32; + } + + public int getMaxRowSize() throws SQLException { + return 2147483639; + } + + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + public int getMaxStatementLength() throws SQLException { + return 65531; + } - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - return false; - } + public int getDefaultTransactionIsolation() throws SQLException { + return this.connection.getDbProperties().getIsolationLevel(); + } - public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; - } + public boolean supportsTransactions() throws SQLException { + return true; + } - public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInDataManipulation() throws SQLException { - return false; - } - - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsPositionedDelete() throws SQLException { - return false; - } - - public boolean supportsPositionedUpdate() throws SQLException { - return false; - } - - public int getMaxColumnsInTable() throws SQLException { - return 0; - } - - public int getMaxCursorNameLength() throws SQLException { - return 64; - } - - public int getMaxSchemaNameLength() throws SQLException { - return 0; - } - - public int getMaxCatalogNameLength() throws SQLException { - return 32; - } - - public int getMaxRowSize() throws SQLException { - return 2147483639; - } + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + switch (level) { + case Connection.TRANSACTION_READ_COMMITTED: + case Connection.TRANSACTION_READ_UNCOMMITTED: + case Connection.TRANSACTION_REPEATABLE_READ: + case Connection.TRANSACTION_SERIALIZABLE: + return true; - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + default: return false; } + } + + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, + String[] types) throws SQLException { + ResultSet resultSet = null; + VitessStatement vitessStatement = null; + boolean reportTables = false; + boolean reportViews = false; + boolean reportSystemTables = false; + boolean reportSystemViews = false; + boolean reportLocalTemporaries = false; + final SortedMap> sortedRows = new TreeMap<>(); + + if (null == tableNamePattern) { + tableNamePattern = "%"; + } + if (null == catalog || catalog.length() == 0) { + catalog = this.connection.getCatalog(); + } + ArrayList> data = new ArrayList<>(); + try { + vitessStatement = new VitessStatement(this.connection); + resultSet = vitessStatement.executeQuery( + "SHOW FULL TABLES FROM " + this.quotedId + catalog + this.quotedId + " LIKE \'" + + tableNamePattern + "\'"); + + if (null == types || types.length == 0) { + reportTables = reportViews = reportSystemTables = reportSystemViews = + reportLocalTemporaries = true; + } else { + for (String type : types) { + if (TableType.TABLE.equalsTo(type)) { + reportTables = true; + + } else if (TableType.VIEW.equalsTo(type)) { + reportViews = true; + + } else if (TableType.SYSTEM_TABLE.equalsTo(type)) { + reportSystemTables = true; + + } else if (TableType.SYSTEM_VIEW.equalsTo(type)) { + reportSystemViews = true; + + } else if (TableType.LOCAL_TEMPORARY.equalsTo(type)) { + reportLocalTemporaries = true; + } + } + } + + int typeColumnIndex = 0; + boolean hasTableTypes; + try { + typeColumnIndex = resultSet.findColumn("table_type"); + hasTableTypes = true; + } catch (SQLException sqlEx) { + try { + typeColumnIndex = resultSet.findColumn("Type"); + hasTableTypes = true; + } catch (SQLException sqlEx2) { + hasTableTypes = false; + } + } - public int getMaxStatementLength() throws SQLException { - return 65531; - } - - public int getDefaultTransactionIsolation() throws SQLException { - return this.connection.getDbProperties().getIsolationLevel(); - } - - public boolean supportsTransactions() throws SQLException { - return true; - } - - public boolean supportsTransactionIsolationLevel(int level) throws SQLException { - switch (level) { - case Connection.TRANSACTION_READ_COMMITTED: - case Connection.TRANSACTION_READ_UNCOMMITTED: - case Connection.TRANSACTION_REPEATABLE_READ: - case Connection.TRANSACTION_SERIALIZABLE: - return true; + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + row.add(0, catalog); + row.add(1, null); + row.add(2, resultSet.getString(1)); + row.add(3, ""); + row.add(4, null); + row.add(5, null); + row.add(6, null); + row.add(7, null); + row.add(8, null); + row.add(9, null); + + if (hasTableTypes) { + String tableType = resultSet.getString(typeColumnIndex); + switch (TableType.getTableTypeCompliantWith(tableType)) { + case TABLE: + boolean reportTable = false; + TableMetaDataKey tablesKey = null; + if (reportSystemTables) { + row.add(3, TableType.TABLE.toString()); + tablesKey = new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, + resultSet.getString(1)); + reportTable = true; + } + if (reportTable) { + sortedRows.put(tablesKey, row); + } + break; + + case VIEW: + if (reportViews) { + row.add(3, TableType.VIEW.toString()); + sortedRows.put(new TableMetaDataKey(TableType.VIEW.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; + + case SYSTEM_TABLE: + if (reportSystemTables) { + row.add(3, TableType.SYSTEM_TABLE.toString()); + sortedRows.put(new TableMetaDataKey(TableType.SYSTEM_TABLE.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; + + case SYSTEM_VIEW: + if (reportSystemViews) { + row.add(3, TableType.SYSTEM_VIEW.toString()); + sortedRows.put(new TableMetaDataKey(TableType.SYSTEM_VIEW.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; + + case LOCAL_TEMPORARY: + if (reportLocalTemporaries) { + row.add(3, TableType.LOCAL_TEMPORARY.toString()); + sortedRows.put( + new TableMetaDataKey(TableType.LOCAL_TEMPORARY.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; default: - return false; + row.add(3, TableType.TABLE.toString()); + sortedRows.put(new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, + resultSet.getString(1)), row); + break; + } + } else { + if (reportTables) { + // Pre-MySQL-5.0.1, tables only + row.add(3, TableType.TABLE.toString()); + sortedRows.put(new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, + resultSet.getString(1)), row); + } } - } - - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getTables(String catalog, - String schemaPattern, String tableNamePattern, String[] types) throws SQLException { - ResultSet resultSet = null; - VitessStatement vitessStatement = null; - boolean reportTables = false; - boolean reportViews = false; - boolean reportSystemTables = false; - boolean reportSystemViews = false; - boolean reportLocalTemporaries = false; - final SortedMap> sortedRows = new TreeMap<>(); - - if (null == tableNamePattern) { - tableNamePattern = "%"; + data.add(row); + } + } finally { + if (null != resultSet) { + resultSet.close(); + } + if (null != vitessStatement) { + vitessStatement.close(); + } + } + String[] columnNames = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", + "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", + "REF_GENERATION"}; + Query.Type[] columnTypes = new Query.Type[]{Query.Type.VARCHAR, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR}; + + return new VitessResultSet(columnNames, columnTypes, data, this.connection); + } + + public ResultSet getSchemas() throws SQLException { + String[] columnNames = {"TABLE_SCHEM", "TABLE_CATALOG"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getCatalogs() throws SQLException { + ResultSet resultSet; + VitessStatement vitessStatement; + String getCatalogQB = "SHOW DATABASES"; + + vitessStatement = new VitessStatement(this.connection); + resultSet = vitessStatement.executeQuery(getCatalogQB); + + ArrayList row = new ArrayList<>(); + ArrayList> data = new ArrayList<>(); + while (resultSet.next()) { + row.add(resultSet.getString(1)); + } + Collections.sort(row); + + for (String result : row) { + ArrayList resultAsList = new ArrayList<>(); + resultAsList.add(result); + data.add(resultAsList); + } + resultSet.close(); + vitessStatement.close(); + String[] columnName = new String[]{"TABLE_CAT"}; + Query.Type[] columntype = new Query.Type[]{Query.Type.CHAR}; + return new VitessResultSet(columnName, columntype, data, this.connection); + } + + public ResultSet getTableTypes() throws SQLException { + String[] columnNames = {"table_type"}; + Query.Type[] columnType = {Query.Type.VARCHAR}; + String[][] data = new String[][]{{"LOCAL TEMPORARY"}, {"SYSTEM TABLES"}, {"SYSTEM VIEW"}, + {"TABLE"}, {"VIEW"}}; + return new VitessResultSet(columnNames, columnType, data, this.connection); + } + + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); + ArrayList> data = new ArrayList<>(); + //Null Matches All + if (null == columnNamePattern) { + columnNamePattern = "%"; + } + if (null == catalog || catalog.length() == 0) { + catalog = this.connection.getCatalog(); + } + try { + ArrayList tableList = new ArrayList<>(); + ResultSet tables = null; + if (null == tableNamePattern) { + try { + tables = getTables(catalog, schemaPattern, "%", new String[0]); + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + tableList.add(tableName); + } + } finally { + if (null != tables) { + tables.close(); + } } - if (null == catalog || catalog.length() == 0) { - catalog = this.connection.getCatalog(); + } else { + try { + tables = getTables(catalog, schemaPattern, tableNamePattern, new String[0]); + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + tableList.add(tableName); + } + } finally { + if (null != tables) { + tables.close(); + } } - ArrayList> data = new ArrayList<>(); + } + for (String tableName : tableList) { + resultSet = null; try { + + // Return correct ordinals if column name pattern is not '%' + // Currently, MySQL doesn't show enough data to do this, so we do it the 'hard' way...Once + // _SYSTEM tables are in, this should be + // much easier + boolean fixUpOrdinalsRequired = false; + Map ordinalFixUpMap = null; + if (!columnNamePattern.equals("%")) { + fixUpOrdinalsRequired = true; vitessStatement = new VitessStatement(this.connection); resultSet = vitessStatement.executeQuery( - "SHOW FULL TABLES FROM " + this.quotedId + catalog + this.quotedId + " LIKE \'" - + tableNamePattern + "\'"); + "SHOW FULL COLUMNS FROM " + this.quotedId + tableName + this.quotedId + " FROM " + + this.quotedId + catalog + this.quotedId); + ordinalFixUpMap = new HashMap<>(); - if (null == types || types.length == 0) { - reportTables = reportViews = - reportSystemTables = reportSystemViews = reportLocalTemporaries = true; + int fullOrdinalPos = 1; + while (resultSet.next()) { + String fullOrdColName = resultSet.getString("Field"); + ordinalFixUpMap.put(fullOrdColName, fullOrdinalPos++); + } + } + resultSet = vitessStatement.executeQuery( + "SHOW FULL COLUMNS FROM " + this.quotedId + tableName + this.quotedId + " FROM " + + this.quotedId + catalog + this.quotedId + " LIKE " + + Constants.LITERAL_SINGLE_QUOTE + columnNamePattern + + Constants.LITERAL_SINGLE_QUOTE); + int ordPos = 1; + + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + row.add(0, catalog); + row.add(1, null); + row.add(2, tableName); + row.add(3, resultSet.getString("Field")); + TypeDescriptor typeDesc = new TypeDescriptor(resultSet.getString("Type"), + resultSet.getString("Null")); + + row.add(4, Short.toString(typeDesc.dataType)); + + // DATA_TYPE (jdbc) + row.add(5, typeDesc.typeName); // TYPE_NAME + // (native) + if (null == typeDesc.columnSize) { + row.add(6, null); } else { - for (String type : types) { - if (TableType.TABLE.equalsTo(type)) { - reportTables = true; - - } else if (TableType.VIEW.equalsTo(type)) { - reportViews = true; - - } else if (TableType.SYSTEM_TABLE.equalsTo(type)) { - reportSystemTables = true; - - } else if (TableType.SYSTEM_VIEW.equalsTo(type)) { - reportSystemViews = true; - - } else if (TableType.LOCAL_TEMPORARY.equalsTo(type)) { - reportLocalTemporaries = true; - } + String collation = resultSet.getString("Collation"); + int mbminlen = 1; + if (collation != null && ("TEXT".equals(typeDesc.typeName) || "TINYTEXT" + .equals(typeDesc.typeName) || "MEDIUMTEXT".equals(typeDesc.typeName))) { + if (collation.indexOf("ucs2") > -1 || collation.indexOf("utf16") > -1) { + mbminlen = 2; + } else if (collation.indexOf("utf32") > -1) { + mbminlen = 4; } + } + row.add(6, mbminlen == 1 ? typeDesc.columnSize.toString() + : Integer.toString(typeDesc.columnSize / mbminlen)); + } + row.add(7, Integer.toString(typeDesc.bufferLength)); + row.add(8, typeDesc.decimalDigits == null ? null : typeDesc.decimalDigits.toString()); + row.add(9, Integer.toString(typeDesc.numPrecRadix)); + row.add(10, Integer.toString(typeDesc.nullability)); + + // + // Doesn't always have this field, depending on version + // + // + // REMARK column + // + row.add(11, "Comment"); + + // COLUMN_DEF + row.add(12, + resultSet.getString("Default") == null ? null : resultSet.getString("Default")); + + row.add(13, Integer.toString(0));// SQL_DATA_TYPE + row.add(14, Integer.toString(0));// SQL_DATE_TIME_SUB + + if (StringUtils.indexOfIgnoreCase(typeDesc.typeName, "CHAR") != -1 + || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BLOB") != -1 + || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "TEXT") != -1 + || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BINARY") != -1) { + row.add(15, row.get(6)); // CHAR_OCTET_LENGTH + } else { + row.add(15, Integer.toString(0)); } - int typeColumnIndex = 0; - boolean hasTableTypes; - try { - typeColumnIndex = resultSet.findColumn("table_type"); - hasTableTypes = true; - } catch (SQLException sqlEx) { - try { - typeColumnIndex = resultSet.findColumn("Type"); - hasTableTypes = true; - } catch (SQLException sqlEx2) { - hasTableTypes = false; - } + // ORDINAL_POSITION + if (!fixUpOrdinalsRequired) { + row.add(16, Integer.toString(ordPos++)); + } else { + String origColName = resultSet.getString("Field"); + Integer realOrdinal = ordinalFixUpMap.get(origColName); + + if (realOrdinal != null) { + row.add(16, realOrdinal.toString()); + } else { + throw new SQLException( + "Can not find column in full column list to determine true ordinal position."); + } } - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - row.add(0, catalog); - row.add(1, null); - row.add(2, resultSet.getString(1)); - row.add(3, ""); - row.add(4, null); - row.add(5, null); - row.add(6, null); - row.add(7, null); - row.add(8, null); - row.add(9, null); - - if (hasTableTypes) { - String tableType = resultSet.getString(typeColumnIndex); - switch (TableType.getTableTypeCompliantWith(tableType)) { - case TABLE: - boolean reportTable = false; - TableMetaDataKey tablesKey = null; - if (reportSystemTables) { - row.add(3, TableType.TABLE.toString()); - tablesKey = - new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, - resultSet.getString(1)); - reportTable = true; - } - if (reportTable) { - sortedRows.put(tablesKey, row); - } - break; - - case VIEW: - if (reportViews) { - row.add(3, TableType.VIEW.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.VIEW.getName(), catalog, null, - resultSet.getString(1)), row); - } - break; - - case SYSTEM_TABLE: - if (reportSystemTables) { - row.add(3, TableType.SYSTEM_TABLE.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.SYSTEM_TABLE.getName(), catalog, - null, resultSet.getString(1)), row); - } - break; - - case SYSTEM_VIEW: - if (reportSystemViews) { - row.add(3, TableType.SYSTEM_VIEW.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.SYSTEM_VIEW.getName(), catalog, - null, resultSet.getString(1)), row); - } - break; - - case LOCAL_TEMPORARY: - if (reportLocalTemporaries) { - row.add(3, TableType.LOCAL_TEMPORARY.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.LOCAL_TEMPORARY.getName(), - catalog, null, resultSet.getString(1)), row); - } - break; - - default: - row.add(3, TableType.TABLE.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, - resultSet.getString(1)), row); - break; - } - } else { - if (reportTables) { - // Pre-MySQL-5.0.1, tables only - row.add(3, TableType.TABLE.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, - resultSet.getString(1)), row); - } - } - data.add(row); + row.add(17, typeDesc.isNullable); + + // We don't support REF or DISTINCT types + row.add(18, null); + row.add(19, null); + row.add(20, null); + row.add(21, null); + String extra = resultSet.getString("Extra"); + if (null != extra) { + row.add(22, + StringUtils.indexOfIgnoreCase(extra, "auto_increment") != -1 ? "YES" : "NO"); + row.add(23, StringUtils.indexOfIgnoreCase(extra, "generated") != -1 ? "YES" : "NO"); } + data.add(row); + } } finally { - if (null != resultSet) { - resultSet.close(); - } - if (null != vitessStatement) { - vitessStatement.close(); - } - } - String[] columnNames = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", - "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", - "REF_GENERATION"}; - Query.Type[] columnTypes = - new Query.Type[] {Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR}; - - return new VitessResultSet(columnNames, columnTypes, data, this.connection); - } - - public ResultSet getSchemas() throws SQLException { - String[] columnNames = {"TABLE_SCHEM", "TABLE_CATALOG"}; - Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } - - public ResultSet getCatalogs() throws SQLException { - ResultSet resultSet; - VitessStatement vitessStatement; - String getCatalogQB = "SHOW DATABASES"; - - vitessStatement = new VitessStatement(this.connection); - resultSet = vitessStatement.executeQuery(getCatalogQB); - - ArrayList row = new ArrayList<>(); - ArrayList> data = new ArrayList<>(); - while (resultSet.next()) { - row.add(resultSet.getString(1)); - } - Collections.sort(row); - - for (String result : row) { - ArrayList resultAsList = new ArrayList<>(); - resultAsList.add(result); - data.add(resultAsList); + if (null != resultSet) { + resultSet.close(); + } } + } + } finally { + if (null != resultSet) { resultSet.close(); - vitessStatement.close(); - String[] columnName = new String[] {"TABLE_CAT"}; - Query.Type[] columntype = new Query.Type[] {Query.Type.CHAR}; - return new VitessResultSet(columnName, columntype, data, this.connection); + } + vitessStatement.close(); } - public ResultSet getTableTypes() throws SQLException { - String[] columnNames = {"table_type"}; - Query.Type[] columnType = {Query.Type.VARCHAR}; - String[][] data = - new String[][] {{"LOCAL TEMPORARY"}, {"SYSTEM TABLES"}, {"SYSTEM VIEW"}, {"TABLE"}, - {"VIEW"}}; - return new VitessResultSet(columnNames, columnType, data, this.connection); - } + String[] columnNames = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", + "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", + "NUM_PREC_RADIX", "NULLABLE", "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", + "SCOPE_TABLE", "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", "IS_GENERATEDCOLUMN"}; - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getColumns(String catalog, - String schemaPattern, String tableNamePattern, String columnNamePattern) - throws SQLException { - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); - ArrayList> data = new ArrayList<>(); - //Null Matches All - if (null == columnNamePattern) { - columnNamePattern = "%"; - } - if (null == catalog || catalog.length() == 0) { - catalog = this.connection.getCatalog(); - } - try { - ArrayList tableList = new ArrayList<>(); - ResultSet tables = null; - if (null == tableNamePattern) { - try { - tables = getTables(catalog, schemaPattern, "%", new String[0]); - while (tables.next()) { - String tableName = tables.getString("TABLE_NAME"); - tableList.add(tableName); - } - } finally { - if (null != tables) { - tables.close(); - } - } - } else { - try { - tables = getTables(catalog, schemaPattern, tableNamePattern, new String[0]); - while (tables.next()) { - String tableName = tables.getString("TABLE_NAME"); - tableList.add(tableName); - } - } finally { - if (null != tables) { - tables.close(); - } - } - } - for (String tableName : tableList) { - resultSet = null; - try { - - // Return correct ordinals if column name pattern is not '%' - // Currently, MySQL doesn't show enough data to do this, so we do it the 'hard' way...Once - // _SYSTEM tables are in, this should be - // much easier - boolean fixUpOrdinalsRequired = false; - Map ordinalFixUpMap = null; - if (!columnNamePattern.equals("%")) { - fixUpOrdinalsRequired = true; - vitessStatement = new VitessStatement(this.connection); - resultSet = - vitessStatement.executeQuery("SHOW FULL COLUMNS FROM " + this.quotedId + - tableName + this.quotedId + " FROM " + this.quotedId + catalog - + this.quotedId); - ordinalFixUpMap = new HashMap<>(); - - int fullOrdinalPos = 1; - while (resultSet.next()) { - String fullOrdColName = resultSet.getString("Field"); - ordinalFixUpMap.put(fullOrdColName, fullOrdinalPos++); - } - } - resultSet = vitessStatement - .executeQuery("SHOW FULL COLUMNS FROM " + this.quotedId + tableName + - this.quotedId + " FROM " + this.quotedId + catalog + this.quotedId - + " LIKE " + Constants.LITERAL_SINGLE_QUOTE + columnNamePattern - + Constants.LITERAL_SINGLE_QUOTE); - int ordPos = 1; - - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - row.add(0, catalog); - row.add(1, null); - row.add(2, tableName); - row.add(3, resultSet.getString("Field")); - TypeDescriptor typeDesc = new TypeDescriptor(resultSet.getString("Type"), - resultSet.getString("Null")); - - row.add(4, Short.toString(typeDesc.dataType)); - - // DATA_TYPE (jdbc) - row.add(5, typeDesc.typeName); // TYPE_NAME - // (native) - if (null == typeDesc.columnSize) { - row.add(6, null); - } else { - String collation = resultSet.getString("Collation"); - int mbminlen = 1; - if (collation != null && ("TEXT".equals(typeDesc.typeName) || "TINYTEXT" - .equals(typeDesc.typeName) || "MEDIUMTEXT" - .equals(typeDesc.typeName))) { - if (collation.indexOf("ucs2") > -1 - || collation.indexOf("utf16") > -1) { - mbminlen = 2; - } else if (collation.indexOf("utf32") > -1) { - mbminlen = 4; - } - } - row.add(6, mbminlen == 1 ? - typeDesc.columnSize.toString() : - Integer.toString(typeDesc.columnSize / mbminlen)); - } - row.add(7, Integer.toString(typeDesc.bufferLength)); - row.add(8, typeDesc.decimalDigits == null ? - null : - typeDesc.decimalDigits.toString()); - row.add(9, Integer.toString(typeDesc.numPrecRadix)); - row.add(10, Integer.toString(typeDesc.nullability)); - - // - // Doesn't always have this field, depending on version - // - // - // REMARK column - // - row.add(11, "Comment"); - - // COLUMN_DEF - row.add(12, resultSet.getString("Default") == null ? - null : - resultSet.getString("Default")); - - row.add(13, Integer.toString(0));// SQL_DATA_TYPE - row.add(14, Integer.toString(0));// SQL_DATE_TIME_SUB - - if (StringUtils.indexOfIgnoreCase(typeDesc.typeName, "CHAR") != -1 - || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BLOB") != -1 - || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "TEXT") != -1 - || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BINARY") != -1) { - row.add(15, row.get(6)); // CHAR_OCTET_LENGTH - } else { - row.add(15, Integer.toString(0)); - } - - // ORDINAL_POSITION - if (!fixUpOrdinalsRequired) { - row.add(16, Integer.toString(ordPos++)); - } else { - String origColName = resultSet.getString("Field"); - Integer realOrdinal = ordinalFixUpMap.get(origColName); - - if (realOrdinal != null) { - row.add(16, realOrdinal.toString()); - } else { - throw new SQLException( - "Can not find column in full column list to determine true ordinal position."); - } - } - - row.add(17, typeDesc.isNullable); - - // We don't support REF or DISTINCT types - row.add(18, null); - row.add(19, null); - row.add(20, null); - row.add(21, null); - String extra = resultSet.getString("Extra"); - if (null != extra) { - row.add(22, - StringUtils.indexOfIgnoreCase(extra, "auto_increment") != -1 ? - "YES" : - "NO"); - row.add(23, StringUtils.indexOfIgnoreCase(extra, "generated") != -1 ? - "YES" : - "NO"); - } - data.add(row); - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - } - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - vitessStatement.close(); - } + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.INT32, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, Query.Type.CHAR, + Query.Type.CHAR}; - String[] columnNames = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", - "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX", - "NULLABLE", "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", - "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", - "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", - "IS_GENERATEDCOLUMN"}; - - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.INT32, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, - Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.INT16, Query.Type.CHAR, Query.Type.CHAR}; - - return new VitessResultSet(columnNames, columnType, data, this.connection); - } + return new VitessResultSet(columnNames, columnType, data, this.connection); + } - public ResultSet getColumnPrivileges(String catalog, String schema, String table, - String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public ResultSet getColumnPrivileges(String catalog, String schema, String table, + String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - public ResultSet getTablePrivileges(String catalog, String schemaPattern, - String tableNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getBestRowIdentifier( - String catalog, String schema, String table, int scope, boolean nullable) - throws SQLException { - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, + boolean nullable) throws SQLException { + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); - if (null == table) { - throw new SQLException("Table Parameter cannot be null in getBestRowIdentifier"); - } + if (null == table) { + throw new SQLException("Table Parameter cannot be null in getBestRowIdentifier"); + } - String[] columnName = - new String[] {"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", - "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; + String[] columnName = new String[]{"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; - Query.Type[] columnType = - new Query.Type[] {Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, Query.Type.CHAR, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; + Query.Type[] columnType = new Query.Type[]{Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, + Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; - ArrayList> data = new ArrayList<>(); + ArrayList> data = new ArrayList<>(); - try { - resultSet = vitessStatement - .executeQuery("SHOW COLUMNS FROM " + this.quotedId + table + this.quotedId + "" + - " FROM " + this.quotedId + catalog + this.quotedId); + try { + resultSet = vitessStatement.executeQuery( + "SHOW COLUMNS FROM " + this.quotedId + table + this.quotedId + "" + " FROM " + + this.quotedId + catalog + this.quotedId); - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - String keyType = resultSet.getString("Key"); - if (keyType != null && StringUtils.startsWithIgnoreCase(keyType, "PRI")) { - row.add(Integer.toString(DatabaseMetaData.bestRowSession)); - row.add(resultSet.getString("Field")); - String type = resultSet.getString("Type"); - int size = this.maxBufferSize; - int decimals = 0; - if (type.indexOf("enum") != -1) { - String temp = type.substring(type.indexOf("("), type.indexOf(")")); - StringTokenizer tokenizer = new StringTokenizer(temp, ","); - - int maxLength; - for ( - maxLength = 0; tokenizer.hasMoreTokens(); - maxLength = Math.max(maxLength, tokenizer.nextToken().length() - 2)) - ; - - size = maxLength; - decimals = 0; - type = "enum"; - } else if (type.indexOf("(") != -1) { - if (type.indexOf(",") != -1) { - size = Integer - .parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(","))); - decimals = Integer - .parseInt(type.substring(type.indexOf(",") + 1, type.indexOf(")"))); - } else { - size = Integer - .parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(")"))); - } - - type = type.substring(0, type.indexOf("(")); - } - - row.add(Integer.toString(MysqlDefs.mysqlToJavaType(type))); - row.add(type); - row.add(Integer.toString(size + decimals)); - row.add(Integer.toString(size + decimals)); - row.add(Integer.toString(decimals)); - row.add(Integer.toString(DatabaseMetaData.bestRowNotPseudo)); - data.add(row); - } + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + String keyType = resultSet.getString("Key"); + if (keyType != null && StringUtils.startsWithIgnoreCase(keyType, "PRI")) { + row.add(Integer.toString(DatabaseMetaData.bestRowSession)); + row.add(resultSet.getString("Field")); + String type = resultSet.getString("Type"); + int size = this.maxBufferSize; + int decimals = 0; + if (type.indexOf("enum") != -1) { + String temp = type.substring(type.indexOf("("), type.indexOf(")")); + StringTokenizer tokenizer = new StringTokenizer(temp, ","); + + int maxLength; + for (maxLength = 0; tokenizer.hasMoreTokens(); + maxLength = Math.max(maxLength, tokenizer.nextToken().length() - 2)) { + ; } - } finally { - if (resultSet != null) { - resultSet.close(); + + size = maxLength; + decimals = 0; + type = "enum"; + } else if (type.indexOf("(") != -1) { + if (type.indexOf(",") != -1) { + size = Integer.parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(","))); + decimals = Integer.parseInt(type.substring(type.indexOf(",") + 1, type.indexOf(")"))); + } else { + size = Integer.parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(")"))); } - vitessStatement.close(); - } - return new VitessResultSet(columnName, columnType, data, this.connection); - } - public ResultSet getVersionColumns(String catalog, String schema, String table) - throws SQLException { - if (null == table) { - throw new SQLException("Table cannot be null"); - } - ResultSet resultSet = null; - VitessStatement vitessStatement = null; - ArrayList> data = new ArrayList<>(); - - StringBuilder getVersionColumnsQB = new StringBuilder(); - getVersionColumnsQB.append("SHOW COLUMNS FROM "); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(table); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(" FROM "); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(catalog); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(" WHERE Extra LIKE '%on update CURRENT_TIMESTAMP%'"); + type = type.substring(0, type.indexOf("(")); + } - try { - vitessStatement = new VitessStatement(this.connection); - resultSet = vitessStatement.executeQuery(getVersionColumnsQB.toString()); - ArrayList row; - while (resultSet.next()) { - row = new ArrayList<>(); - TypeDescriptor typeDesc = - new TypeDescriptor(resultSet.getString("Type"), resultSet.getString("Null")); - row.add(0, null); - row.add(1, resultSet.getString("Field")); - row.add(2, Short.toString(typeDesc.dataType)); - row.add(3, typeDesc.typeName); - row.add(4, typeDesc.columnSize == null ? null : typeDesc.columnSize.toString()); - row.add(5, Integer.toString(typeDesc.bufferLength)); - row.add(6, - typeDesc.decimalDigits == null ? null : typeDesc.decimalDigits.toString()); - row.add(7, Integer.toString(java.sql.DatabaseMetaData.versionColumnNotPseudo)); - data.add(row); - } - } finally { - if (null != resultSet) { - resultSet.close(); - vitessStatement.close(); - } + row.add(Integer.toString(MysqlDefs.mysqlToJavaType(type))); + row.add(type); + row.add(Integer.toString(size + decimals)); + row.add(Integer.toString(size + decimals)); + row.add(Integer.toString(decimals)); + row.add(Integer.toString(DatabaseMetaData.bestRowNotPseudo)); + data.add(row); } - String[] columnNames = - new String[] {"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", - "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; - - Query.Type[] columnType = - new Query.Type[] {Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, Query.Type.CHAR, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, data, this.connection); + } + } finally { + if (resultSet != null) { + resultSet.close(); + } + vitessStatement.close(); + } + return new VitessResultSet(columnName, columnType, data, this.connection); + } + + public ResultSet getVersionColumns(String catalog, String schema, String table) + throws SQLException { + if (null == table) { + throw new SQLException("Table cannot be null"); + } + ResultSet resultSet = null; + VitessStatement vitessStatement = null; + ArrayList> data = new ArrayList<>(); + + StringBuilder getVersionColumnsQB = new StringBuilder(); + getVersionColumnsQB.append("SHOW COLUMNS FROM "); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(table); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(" FROM "); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(catalog); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(" WHERE Extra LIKE '%on update CURRENT_TIMESTAMP%'"); + + try { + vitessStatement = new VitessStatement(this.connection); + resultSet = vitessStatement.executeQuery(getVersionColumnsQB.toString()); + ArrayList row; + while (resultSet.next()) { + row = new ArrayList<>(); + TypeDescriptor typeDesc = new TypeDescriptor(resultSet.getString("Type"), + resultSet.getString("Null")); + row.add(0, null); + row.add(1, resultSet.getString("Field")); + row.add(2, Short.toString(typeDesc.dataType)); + row.add(3, typeDesc.typeName); + row.add(4, typeDesc.columnSize == null ? null : typeDesc.columnSize.toString()); + row.add(5, Integer.toString(typeDesc.bufferLength)); + row.add(6, typeDesc.decimalDigits == null ? null : typeDesc.decimalDigits.toString()); + row.add(7, Integer.toString(java.sql.DatabaseMetaData.versionColumnNotPseudo)); + data.add(row); + } + } finally { + if (null != resultSet) { + resultSet.close(); + vitessStatement.close(); + } } + String[] columnNames = new String[]{"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getPrimaryKeys( - String catalog, String schema, String table) throws SQLException { + Query.Type[] columnType = new Query.Type[]{Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, + Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, data, this.connection); + } - if (null == table) { - throw new SQLException("Table Name Cannot be Null"); - } - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); - ArrayList> sortedData = new ArrayList<>(); - try { + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { - resultSet = vitessStatement - .executeQuery("SHOW KEYS FROM " + this.quotedId + table + this.quotedId + " " + - "FROM " + this.quotedId + catalog + this.quotedId); + if (null == table) { + throw new SQLException("Table Name Cannot be Null"); + } + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); + ArrayList> sortedData = new ArrayList<>(); + try { - TreeMap> sortMap = new TreeMap<>(); + resultSet = vitessStatement.executeQuery( + "SHOW KEYS FROM " + this.quotedId + table + this.quotedId + " " + "FROM " + this.quotedId + + catalog + this.quotedId); - while (resultSet.next()) { - String keyType = resultSet.getString("Key_name"); - ArrayList row = new ArrayList<>(); - if (null != keyType) { - if (keyType.equalsIgnoreCase("PRIMARY") || keyType.equalsIgnoreCase("PRI")) { - row.add(0, (catalog == null) ? "" : catalog); - row.add(1, null); - row.add(2, table); - - String columnName = resultSet.getString("Column_name"); - row.add(3, columnName); - row.add(4, resultSet.getString("Seq_in_index")); - row.add(5, keyType); - sortMap.put(columnName, row); - } - } - } + TreeMap> sortMap = new TreeMap<>(); - // Now pull out in column name sorted order - for (ArrayList row : sortMap.values()) { - sortedData.add(row); - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - vitessStatement.close(); + while (resultSet.next()) { + String keyType = resultSet.getString("Key_name"); + ArrayList row = new ArrayList<>(); + if (null != keyType) { + if (keyType.equalsIgnoreCase("PRIMARY") || keyType.equalsIgnoreCase("PRI")) { + row.add(0, (catalog == null) ? "" : catalog); + row.add(1, null); + row.add(2, table); + + String columnName = resultSet.getString("Column_name"); + row.add(3, columnName); + row.add(4, resultSet.getString("Seq_in_index")); + row.add(5, keyType); + sortMap.put(columnName, row); + } } - - String[] columnNames = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", - "PK_NAME"}; - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.INT16, Query.Type.CHAR}; - - return new VitessResultSet(columnNames, columnType, sortedData, this.connection); - } - - public ResultSet getImportedKeys(String catalog, String schema, String table) - throws SQLException { - if (null == table) { - throw new SQLException("Table Name Cannot be Null"); + } + + // Now pull out in column name sorted order + for (ArrayList row : sortMap.values()) { + sortedData.add(row); + } + } finally { + if (null != resultSet) { + resultSet.close(); + } + vitessStatement.close(); + } + + String[] columnNames = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", + "KEY_SEQ", "PK_NAME"}; + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.INT16, Query.Type.CHAR}; + + return new VitessResultSet(columnNames, columnType, sortedData, this.connection); + } + + public ResultSet getImportedKeys(String catalog, String schema, String table) + throws SQLException { + if (null == table) { + throw new SQLException("Table Name Cannot be Null"); + } + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); + ArrayList> rows = new ArrayList<>(); + try { + resultSet = vitessStatement + .executeQuery("SHOW CREATE TABLE " + this.quotedId + table + this.quotedId); + while (resultSet.next()) { + extractForeignKeyForTable(rows, resultSet.getString(2), catalog, table); + } + } finally { + if (resultSet != null) { + resultSet.close(); + } + } + String[] columnNames = new String[]{"PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", "PK_NAME", "DEFERRABILITY"}; + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT16, Query.Type.INT16, Query.Type.INT16, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, rows, this.connection); + } + + @VisibleForTesting + void extractForeignKeyForTable(List> rows, String createTableString, + String catalog, String table) throws SQLException { + StringTokenizer lineTokenizer = new StringTokenizer(createTableString, "\n"); + + while (lineTokenizer.hasMoreTokens()) { + String line = lineTokenizer.nextToken().trim(); + String constraintName = null; + if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) { + boolean usingBackTicks = true; + int beginPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, this.quotedId, 0); + if (beginPos == -1) { + beginPos = line.indexOf("\""); + usingBackTicks = false; } - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); - ArrayList> rows = new ArrayList<>(); - try { - resultSet = vitessStatement.executeQuery("SHOW CREATE TABLE " + this.quotedId + table + this.quotedId); - while (resultSet.next()) { - extractForeignKeyForTable(rows, resultSet.getString(2), catalog, table); - } - } finally { - if (resultSet != null) { - resultSet.close(); - } + if (beginPos != -1) { + int endPos; + if (usingBackTicks) { + endPos = io.vitess.util.StringUtils + .indexOfQuoteDoubleAware(line, this.quotedId, beginPos + 1); + } else { + endPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, "\"", beginPos + 1); + } + if (endPos != -1) { + constraintName = line.substring(beginPos + 1, endPos); + line = line.substring(endPos + 1, line.length()).trim(); + } } - String[] columnNames = - new String[] {"PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT", - "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", "UPDATE_RULE", "DELETE_RULE", - "FK_NAME", "PK_NAME", "DEFERRABILITY"}; - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, - Query.Type.INT16, Query.Type.INT16, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, rows, this.connection); - } - - @VisibleForTesting - void extractForeignKeyForTable(List> rows, String createTableString, String catalog, String table) throws SQLException { - StringTokenizer lineTokenizer = new StringTokenizer(createTableString, "\n"); - - while (lineTokenizer.hasMoreTokens()) { - String line = lineTokenizer.nextToken().trim(); - String constraintName = null; - if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) { - boolean usingBackTicks = true; - int beginPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, this.quotedId, 0); - if (beginPos == -1) { - beginPos = line.indexOf("\""); - usingBackTicks = false; - } - if (beginPos != -1) { - int endPos; - if (usingBackTicks) { - endPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, this.quotedId, beginPos + 1); - } else { - endPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, "\"", beginPos + 1); - } - if (endPos != -1) { - constraintName = line.substring(beginPos + 1, endPos); - line = line.substring(endPos + 1, line.length()).trim(); - } - } - } + } - if (line.startsWith("FOREIGN KEY")) { - if (line.endsWith(",")) { - line = line.substring(0, line.length() - 1); - } - int indexOfFK = line.indexOf("FOREIGN KEY"); - String localColumnName = null; - String referencedCatalogName = io.vitess.util.StringUtils.quoteIdentifier(catalog, this.quotedId); - String referencedTableName = null; - String referencedColumnName = null; - if (indexOfFK != -1) { - int afterFk = indexOfFK + "FOREIGN KEY".length(); - - int indexOfRef = io.vitess.util.StringUtils.indexOfIgnoreCase(afterFk, line, "REFERENCES", this.quotedId, this.quotedId); - if (indexOfRef != -1) { - int indexOfParenOpen = line.indexOf('(', afterFk); - int indexOfParenClose = io.vitess.util.StringUtils.indexOfIgnoreCase(indexOfParenOpen, line, ")", this.quotedId, this.quotedId); - localColumnName = line.substring(indexOfParenOpen + 1, indexOfParenClose); - - int afterRef = indexOfRef + "REFERENCES".length(); - int referencedColumnBegin = io.vitess.util.StringUtils.indexOfIgnoreCase(afterRef, line, "(", this.quotedId, this.quotedId); - - if (referencedColumnBegin != -1) { - referencedTableName = line.substring(afterRef, referencedColumnBegin); - int referencedColumnEnd = io.vitess.util.StringUtils.indexOfIgnoreCase(referencedColumnBegin + 1, line, ")", this.quotedId, this.quotedId); - if (referencedColumnEnd != -1) { - referencedColumnName = line.substring(referencedColumnBegin + 1, referencedColumnEnd); - } - int indexOfCatalogSep = io.vitess.util.StringUtils.indexOfIgnoreCase(0, referencedTableName, ".", this.quotedId, this.quotedId); - if (indexOfCatalogSep != -1) { - referencedCatalogName = referencedTableName.substring(0, indexOfCatalogSep); - referencedTableName = referencedTableName.substring(indexOfCatalogSep + 1); - } - } - } - } - if (constraintName == null) { - constraintName = "not_available"; - } - List localColumnsList = io.vitess.util.StringUtils.split(localColumnName, ",", this.quotedId, this.quotedId); - List referColumnsList = io.vitess.util.StringUtils.split(referencedColumnName, ",", this.quotedId, this.quotedId); - if (localColumnsList.size() != referColumnsList.size()) { - throw new SQLException("Mismatch columns list for foreign key local and reference columns"); - } - // Report a separate row for each column in the foreign key. All values the same except the column name. - for (int i = 0; i < localColumnsList.size(); i++) { - String localColumn = localColumnsList.get(i); - String referColumn = referColumnsList.get(i); - ArrayList row = new ArrayList<>(14); - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(referencedCatalogName, this.quotedId)); // PKTABLE_CAT - row.add(null); // PKTABLE_SCHEM - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(referencedTableName, this.quotedId)); // PKTABLE_NAME - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(referColumn, this.quotedId)); // PKCOLUMN_NAME - row.add(catalog); // FKTABLE_CAT - row.add(null); // FKTABLE_SCHEM - row.add(table); // FKTABLE_NAME - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(localColumn, this.quotedId)); // FKCOLUMN_NAME - row.add(Integer.toString(i + 1)); // KEY_SEQ - int[] actions = getForeignKeyActions(line); - row.add(Integer.toString(actions[1])); // UPDATE_RULE - row.add(Integer.toString(actions[0])); // DELETE_RULE - row.add(constraintName); // FK_NAME - row.add(null); // PK_NAME - row.add(Integer.toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable)); // DEFERRABILITY - rows.add(row); - } + if (line.startsWith("FOREIGN KEY")) { + if (line.endsWith(",")) { + line = line.substring(0, line.length() - 1); + } + int indexOfFK = line.indexOf("FOREIGN KEY"); + String localColumnName = null; + String referencedCatalogName = io.vitess.util.StringUtils + .quoteIdentifier(catalog, this.quotedId); + String referencedTableName = null; + String referencedColumnName = null; + if (indexOfFK != -1) { + int afterFk = indexOfFK + "FOREIGN KEY".length(); + + int indexOfRef = io.vitess.util.StringUtils + .indexOfIgnoreCase(afterFk, line, "REFERENCES", this.quotedId, this.quotedId); + if (indexOfRef != -1) { + int indexOfParenOpen = line.indexOf('(', afterFk); + int indexOfParenClose = io.vitess.util.StringUtils + .indexOfIgnoreCase(indexOfParenOpen, line, ")", this.quotedId, this.quotedId); + localColumnName = line.substring(indexOfParenOpen + 1, indexOfParenClose); + + int afterRef = indexOfRef + "REFERENCES".length(); + int referencedColumnBegin = io.vitess.util.StringUtils + .indexOfIgnoreCase(afterRef, line, "(", this.quotedId, this.quotedId); + + if (referencedColumnBegin != -1) { + referencedTableName = line.substring(afterRef, referencedColumnBegin); + int referencedColumnEnd = io.vitess.util.StringUtils + .indexOfIgnoreCase(referencedColumnBegin + 1, line, ")", this.quotedId, + this.quotedId); + if (referencedColumnEnd != -1) { + referencedColumnName = line + .substring(referencedColumnBegin + 1, referencedColumnEnd); + } + int indexOfCatalogSep = io.vitess.util.StringUtils + .indexOfIgnoreCase(0, referencedTableName, ".", this.quotedId, this.quotedId); + if (indexOfCatalogSep != -1) { + referencedCatalogName = referencedTableName.substring(0, indexOfCatalogSep); + referencedTableName = referencedTableName.substring(indexOfCatalogSep + 1); + } } + } } - } - - - /** - * Parses the constraint to see what actions are taking for update and delete, such as cascade. - * @param constraint - * the constraint to parse - * @return the code from {@link DatabaseMetaData} corresponding to the foreign actions for the constraint - */ - private int[] getForeignKeyActions(String constraint) { - int[] actions = new int[] { java.sql.DatabaseMetaData.importedKeyNoAction, java.sql.DatabaseMetaData.importedKeyNoAction }; - int lastParenIndex = constraint.lastIndexOf(")"); - if (lastParenIndex != (constraint.length() - 1)) { - String cascadeOptions = constraint.substring(lastParenIndex + 1).trim().toUpperCase(Locale.ENGLISH); - actions[0] = getCascadeDeleteOption(cascadeOptions); - actions[1] = getCascadeUpdateOption(cascadeOptions); + if (constraintName == null) { + constraintName = "not_available"; } - return actions; - } - - /** - * Parses the cascade option string and returns the DBMD constant that - * represents it (for deletes) - * - * @param cascadeOptions - * the comment from 'SHOW TABLE STATUS' - * @return the DBMD constant that represents the cascade option - */ - private int getCascadeDeleteOption(String cascadeOptions) { - int onDeletePos = cascadeOptions.indexOf("ON DELETE"); - if (onDeletePos != -1) { - String deleteOptions = cascadeOptions.substring(onDeletePos, cascadeOptions.length()); - if (deleteOptions.startsWith("ON DELETE CASCADE")) { - return java.sql.DatabaseMetaData.importedKeyCascade; - } else if (deleteOptions.startsWith("ON DELETE SET NULL")) { - return java.sql.DatabaseMetaData.importedKeySetNull; - } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) { - return java.sql.DatabaseMetaData.importedKeyRestrict; - } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) { - return java.sql.DatabaseMetaData.importedKeyNoAction; - } + List localColumnsList = io.vitess.util.StringUtils + .split(localColumnName, ",", this.quotedId, this.quotedId); + List referColumnsList = io.vitess.util.StringUtils + .split(referencedColumnName, ",", this.quotedId, this.quotedId); + if (localColumnsList.size() != referColumnsList.size()) { + throw new SQLException( + "Mismatch columns list for foreign key local and reference columns"); } - return java.sql.DatabaseMetaData.importedKeyNoAction; - } - - /** - * Parses the cascade option string and returns the DBMD constant that - * represents it (for Updates) - * - * @param cascadeOptions - * the comment from 'SHOW TABLE STATUS' - * @return the DBMD constant that represents the cascade option - */ - private int getCascadeUpdateOption(String cascadeOptions) { - int onUpdatePos = cascadeOptions.indexOf("ON UPDATE"); - if (onUpdatePos != -1) { - String updateOptions = cascadeOptions.substring(onUpdatePos, cascadeOptions.length()); - if (updateOptions.startsWith("ON UPDATE CASCADE")) { - return java.sql.DatabaseMetaData.importedKeyCascade; - } else if (updateOptions.startsWith("ON UPDATE SET NULL")) { - return java.sql.DatabaseMetaData.importedKeySetNull; - } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) { - return java.sql.DatabaseMetaData.importedKeyRestrict; - } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) { - return java.sql.DatabaseMetaData.importedKeyNoAction; - } + // Report a separate row for each column in the foreign key. All values the same except + // the column name. + for (int i = 0; i < localColumnsList.size(); i++) { + String localColumn = localColumnsList.get(i); + String referColumn = referColumnsList.get(i); + ArrayList row = new ArrayList<>(14); + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(referencedCatalogName, this.quotedId)); // PKTABLE_CAT + row.add(null); // PKTABLE_SCHEM + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(referencedTableName, this.quotedId)); // PKTABLE_NAME + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(referColumn, this.quotedId)); // PKCOLUMN_NAME + row.add(catalog); // FKTABLE_CAT + row.add(null); // FKTABLE_SCHEM + row.add(table); // FKTABLE_NAME + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(localColumn, this.quotedId)); // FKCOLUMN_NAME + row.add(Integer.toString(i + 1)); // KEY_SEQ + int[] actions = getForeignKeyActions(line); + row.add(Integer.toString(actions[1])); // UPDATE_RULE + row.add(Integer.toString(actions[0])); // DELETE_RULE + row.add(constraintName); // FK_NAME + row.add(null); // PK_NAME + row.add(Integer + .toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable)); // DEFERRABILITY + rows.add(row); } + } + } + } + + + /** + * Parses the constraint to see what actions are taking for update and delete, such as cascade. + * + * @param constraint the constraint to parse + * @return the code from {@link DatabaseMetaData} corresponding to the foreign actions for the + * constraint + */ + private int[] getForeignKeyActions(String constraint) { + int[] actions = new int[]{java.sql.DatabaseMetaData.importedKeyNoAction, + java.sql.DatabaseMetaData.importedKeyNoAction}; + int lastParenIndex = constraint.lastIndexOf(")"); + if (lastParenIndex != (constraint.length() - 1)) { + String cascadeOptions = constraint.substring(lastParenIndex + 1).trim() + .toUpperCase(Locale.ENGLISH); + actions[0] = getCascadeDeleteOption(cascadeOptions); + actions[1] = getCascadeUpdateOption(cascadeOptions); + } + return actions; + } + + /** + * Parses the cascade option string and returns the DBMD constant that represents it (for + * deletes) + * + * @param cascadeOptions the comment from 'SHOW TABLE STATUS' + * @return the DBMD constant that represents the cascade option + */ + private int getCascadeDeleteOption(String cascadeOptions) { + int onDeletePos = cascadeOptions.indexOf("ON DELETE"); + if (onDeletePos != -1) { + String deleteOptions = cascadeOptions.substring(onDeletePos, cascadeOptions.length()); + if (deleteOptions.startsWith("ON DELETE CASCADE")) { + return java.sql.DatabaseMetaData.importedKeyCascade; + } else if (deleteOptions.startsWith("ON DELETE SET NULL")) { + return java.sql.DatabaseMetaData.importedKeySetNull; + } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) { + return java.sql.DatabaseMetaData.importedKeyRestrict; + } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) { return java.sql.DatabaseMetaData.importedKeyNoAction; - } - - public ResultSet getExportedKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getCrossReference(String parentCatalog, String parentSchema, - String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTypeInfo() throws SQLException { - String[] columnNames = - {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", "LITERAL_SUFFIX", - "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", - "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", - "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; - Query.Type[] columnTypes = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.BIT, - Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, - Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32}; - - String[][] data = - {{"BIT", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BIT", "0", - "0", "0", "0", "10"}, - {"BOOL", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BOOL", - "0", "0", "0", "0", "10"}, - {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "TINYINT", "0", "0", "0", "0", "10"}, - {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", - "3", "true", "false", "true", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "BIGINT", "0", "0", "0", "0", "10"}, - {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", - "false", "false", "LONG VARBINARY", "0", "0", "0", "0", "10"}, - {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", "false", - "false", "MEDIUMBLOB", "0", "0", "0", "0", "10"}, - {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "true", "3", "false", "false", - "false", "LONGBLOB", "0", "0", "0", "0", "10"}, - {"BLOB", "-4", "65535", "'", "'", "", "1", "true", "3", "false", "false", "false", - "BLOB", "0", "0", "0", "0", "10"}, - {"TINYBLOB", "-4", "255", "'", "'", "", "1", "true", "3", "false", "false", "false", - "TINYBLOB", "0", "0", "0", "0", "10"}, - {"VARBINARY", "-3", "65535", "'", "'", "(M)", "1", "true", "3", "false", "false", - "false", "VARBINARY", "0", "0", "0", "0", "10"}, - {"BINARY", "-2", "255", "'", "'", "(M)", "1", "true", "3", "false", "false", - "false", "BINARY", "0", "0", "0", "0", "10"}, - {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", - "false", "false", "LONG VARCHAR", "0", "0", "0", "0", "10"}, - {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", "false", - "false", "MEDIUMTEXT", "0", "0", "0", "0", "10"}, - {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "false", "3", "false", "false", - "false", "LONGTEXT", "0", "0", "0", "0", "10"}, - {"TEXT", "-1", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", - "TEXT", "0", "0", "0", "0", "10"}, - {"TINYTEXT", "-1", "255", "'", "'", "", "1", "false", "3", "false", "false", - "false", "TINYTEXT", "0", "0", "0", "0", "10"}, - {"CHAR", "1", "255", "'", "'", "(M)", "1", "false", "3", "false", "false", "false", - "CHAR", "0", "0", "0", "0", "10"}, - {"NUMERIC", "2", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "NUMERIC", "-308", "308", "0", "0", "10"}, - {"DECIMAL", "3", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "DECIMAL", "-308", "308", "0", "0", "10"}, - {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "INTEGER", "0", "0", "0", "0", "10"}, - {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, - {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", - "false", "true", "INT", "0", "0", "0", "0", "10"}, - {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", - "false", "true", "INT UNSIGNED", "0", "0", "0", "0", "10"}, - {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "MEDIUMINT", "0", "0", "0", "0", "10"}, - {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "SMALLINT", "0", "0", "0", "0", "10"}, - {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"FLOAT", "7", "10", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "FLOAT", "-38", "38", "0", "0", "10"}, - {"DOUBLE", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "DOUBLE", "-308", "308", "0", "0", "10"}, - {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", - "false", "false", "true", "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, - {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "REAL", "-308", "308", "0", "0", "10"}, - {"VARCHAR", "12", "65535", "'", "'", "(M)", "1", "false", "3", "false", "false", - "false", "VARCHAR", "0", "0", "0", "0", "10"}, - {"ENUM", "12", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", - "ENUM", "0", "0", "0", "0", "10"}, - {"SET", "12", "64", "'", "'", "", "1", "false", "3", "false", "false", "false", - "SET", "0", "0", "0", "0", "10"}, - {"DATE", "91", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", - "DATE", "0", "0", "0", "0", "10"}, - {"TIME", "92", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", - "TIME", "0", "0", "0", "0", "10"}, - {"DATETIME", "93", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", - "DATETIME", "0", "0", "0", "0", "10"}, - {"TIMESTAMP", "93", "0", "'", "'", "[(M)]", "1", "false", "3", "false", "false", - "false", "TIMESTAMP", "0", "0", "0", "0", "10"}}; - - return new VitessResultSet(columnNames, columnTypes, data, this.connection); - } - - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getIndexInfo( - String catalog, String schema, String table, boolean unique, boolean approximate) - throws SQLException { - - ArrayList> data = new ArrayList<>(); - final SortedMap> sortedRows = new TreeMap<>(); - VitessStatement vitessStatement = new VitessStatement(this.connection); - ResultSet resultSet = null; - try { - resultSet = vitessStatement - .executeQuery("SHOW INDEX FROM " + this.quotedId + table + this.quotedId + " " + - "FROM " + this.quotedId + catalog + this.quotedId); - - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - row.add(0, catalog); - row.add(1, null); - row.add(2, resultSet.getString("Table")); - - boolean indexIsUnique = resultSet.getInt("Non_unique") == 0; - - row.add(3, !indexIsUnique ? "true" : "false"); - row.add(4, ""); - row.add(5, resultSet.getString("Key_name")); - short indexType = DatabaseMetaData.tableIndexOther; - row.add(6, Integer.toString(indexType)); - row.add(7, resultSet.getString("Seq_in_index")); - row.add(8, resultSet.getString("Column_name")); - row.add(9, resultSet.getString("Collation")); - - long cardinality = resultSet.getLong("Cardinality"); - if (cardinality > Integer.MAX_VALUE) { - cardinality = Integer.MAX_VALUE; - } + } + } + return java.sql.DatabaseMetaData.importedKeyNoAction; + } + + /** + * Parses the cascade option string and returns the DBMD constant that represents it (for + * Updates) + * + * @param cascadeOptions the comment from 'SHOW TABLE STATUS' + * @return the DBMD constant that represents the cascade option + */ + private int getCascadeUpdateOption(String cascadeOptions) { + int onUpdatePos = cascadeOptions.indexOf("ON UPDATE"); + if (onUpdatePos != -1) { + String updateOptions = cascadeOptions.substring(onUpdatePos, cascadeOptions.length()); + if (updateOptions.startsWith("ON UPDATE CASCADE")) { + return java.sql.DatabaseMetaData.importedKeyCascade; + } else if (updateOptions.startsWith("ON UPDATE SET NULL")) { + return java.sql.DatabaseMetaData.importedKeySetNull; + } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) { + return java.sql.DatabaseMetaData.importedKeyRestrict; + } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) { + return java.sql.DatabaseMetaData.importedKeyNoAction; + } + } + return java.sql.DatabaseMetaData.importedKeyNoAction; + } + + public ResultSet getExportedKeys(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, + String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTypeInfo() throws SQLException { + String[] columnNames = {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", + "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", + "MINIMUM_SCALE", "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; + Query.Type[] columnTypes = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, + Query.Type.BIT, Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, + Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32}; + + String[][] data = { + {"BIT", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BIT", "0", "0", + "0", "0", "10"}, + {"BOOL", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BOOL", "0", + "0", "0", "0", "10"}, + {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "TINYINT", "0", "0", "0", "0", "10"}, + {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", + "true", "false", "true", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "BIGINT", "0", "0", "0", "0", "10"}, + {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", "false", + "false", "LONG VARBINARY", "0", "0", "0", "0", "10"}, + {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", "false", "false", + "MEDIUMBLOB", "0", "0", "0", "0", "10"}, + {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "true", "3", "false", "false", "false", + "LONGBLOB", "0", "0", "0", "0", "10"}, + {"BLOB", "-4", "65535", "'", "'", "", "1", "true", "3", "false", "false", "false", "BLOB", + "0", "0", "0", "0", "10"}, + {"TINYBLOB", "-4", "255", "'", "'", "", "1", "true", "3", "false", "false", "false", + "TINYBLOB", "0", "0", "0", "0", "10"}, + {"VARBINARY", "-3", "65535", "'", "'", "(M)", "1", "true", "3", "false", "false", "false", + "VARBINARY", "0", "0", "0", "0", "10"}, + {"BINARY", "-2", "255", "'", "'", "(M)", "1", "true", "3", "false", "false", "false", + "BINARY", "0", "0", "0", "0", "10"}, + {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", "false", + "false", "LONG VARCHAR", "0", "0", "0", "0", "10"}, + {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", "false", "false", + "MEDIUMTEXT", "0", "0", "0", "0", "10"}, + {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "false", "3", "false", "false", "false", + "LONGTEXT", "0", "0", "0", "0", "10"}, + {"TEXT", "-1", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", "TEXT", + "0", "0", "0", "0", "10"}, + {"TINYTEXT", "-1", "255", "'", "'", "", "1", "false", "3", "false", "false", "false", + "TINYTEXT", "0", "0", "0", "0", "10"}, + {"CHAR", "1", "255", "'", "'", "(M)", "1", "false", "3", "false", "false", "false", "CHAR", + "0", "0", "0", "0", "10"}, + {"NUMERIC", "2", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "NUMERIC", "-308", "308", "0", "0", "10"}, + {"DECIMAL", "3", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "DECIMAL", "-308", "308", "0", "0", "10"}, + {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "INTEGER", "0", "0", "0", "0", "10"}, + {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, + {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "INT", "0", "0", "0", "0", "10"}, + {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", "false", + "true", "INT UNSIGNED", "0", "0", "0", "0", "10"}, + {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "MEDIUMINT", "0", "0", "0", "0", "10"}, + {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "SMALLINT", "0", "0", "0", "0", "10"}, + {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"FLOAT", "7", "10", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "FLOAT", "-38", "38", "0", "0", "10"}, + {"DOUBLE", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "DOUBLE", "-308", "308", "0", "0", "10"}, + {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", + "false", "true", "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, + {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "REAL", "-308", "308", "0", "0", "10"}, + {"VARCHAR", "12", "65535", "'", "'", "(M)", "1", "false", "3", "false", "false", "false", + "VARCHAR", "0", "0", "0", "0", "10"}, + {"ENUM", "12", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", "ENUM", + "0", "0", "0", "0", "10"}, + {"SET", "12", "64", "'", "'", "", "1", "false", "3", "false", "false", "false", "SET", "0", + "0", "0", "0", "10"}, + {"DATE", "91", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", "DATE", "0", + "0", "0", "0", "10"}, + {"TIME", "92", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", "TIME", "0", + "0", "0", "0", "10"}, + {"DATETIME", "93", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", + "DATETIME", "0", "0", "0", "0", "10"}, + {"TIMESTAMP", "93", "0", "'", "'", "[(M)]", "1", "false", "3", "false", "false", "false", + "TIMESTAMP", "0", "0", "0", "0", "10"}}; + + return new VitessResultSet(columnNames, columnTypes, data, this.connection); + } + + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, + boolean approximate) throws SQLException { + + ArrayList> data = new ArrayList<>(); + final SortedMap> sortedRows = new TreeMap<>(); + VitessStatement vitessStatement = new VitessStatement(this.connection); + ResultSet resultSet = null; + try { + resultSet = vitessStatement.executeQuery( + "SHOW INDEX FROM " + this.quotedId + table + this.quotedId + " " + "FROM " + this.quotedId + + catalog + this.quotedId); + + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + row.add(0, catalog); + row.add(1, null); + row.add(2, resultSet.getString("Table")); + + boolean indexIsUnique = resultSet.getInt("Non_unique") == 0; + + row.add(3, !indexIsUnique ? "true" : "false"); + row.add(4, ""); + row.add(5, resultSet.getString("Key_name")); + short indexType = DatabaseMetaData.tableIndexOther; + row.add(6, Integer.toString(indexType)); + row.add(7, resultSet.getString("Seq_in_index")); + row.add(8, resultSet.getString("Column_name")); + row.add(9, resultSet.getString("Collation")); + + long cardinality = resultSet.getLong("Cardinality"); + if (cardinality > Integer.MAX_VALUE) { + cardinality = Integer.MAX_VALUE; + } - row.add(10, String.valueOf(cardinality)); - row.add(11, "0"); - row.add(12, null); + row.add(10, String.valueOf(cardinality)); + row.add(11, "0"); + row.add(12, null); - IndexMetaDataKey indexInfoKey = new IndexMetaDataKey(!indexIsUnique, indexType, - resultSet.getString("Key_name").toLowerCase(), - resultSet.getShort("Seq_in_index")); - sortedRows.put(indexInfoKey, row); - } + IndexMetaDataKey indexInfoKey = new IndexMetaDataKey(!indexIsUnique, indexType, + resultSet.getString("Key_name").toLowerCase(), resultSet.getShort("Seq_in_index")); + sortedRows.put(indexInfoKey, row); + } - for (ArrayList row : sortedRows.values()) { - data.add(row); - } + for (ArrayList row : sortedRows.values()) { + data.add(row); + } - } finally { - if (null != resultSet) { - resultSet.close(); - } - vitessStatement.close(); + } finally { + if (null != resultSet) { + resultSet.close(); + } + vitessStatement.close(); + } + String[] columnName = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "Non_unique", + "INDEX_QUALIFIER", "INDEX_NAME", "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", + "CARDINALITY", "PAGES", "FILTER_CONDITION"}; + + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.BIT, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, Query.Type.INT16, + Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR}; + + return new VitessResultSet(columnName, columnType, data, this.connection); + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, + int[] types) throws SQLException { + String[] columnNames = {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "CLASS_NAME", "DATA_TYPE", + "REMARKS", "BASE_TYPE"}; + Query.Type[] columnType = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) + throws SQLException { + String[] columnNames = {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SUPERTYPE_CAT", + "SUPERTYPE_SCHEM", "SUPERTYPE_NAME"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + String[] columnNames = {"TABLE_CAT", "TYPE_SCHEM", "TABLE_NAME", "SUPERTABLE_NAME"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, + String attributeNamePattern) throws SQLException { + + String[] columnNames = {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "ATTR_NAME", "DATA_TYPE", + "ATTR_TYPE_NAME", "ATTR_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS", + "ATTR_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", + "ISNULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public int getSQLStateType() throws SQLException { + return DatabaseMetaData.sqlStateSQL99; + } + + public boolean locatorsUpdateCopy() throws SQLException { + return true; + } + + public RowIdLifetime getRowIdLifetime() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + String[] columnNames = {"TABLE_CAT", "TABLE_CATALOG"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getClientInfoProperties() throws SQLException { + String[] columnNames = {"NAME", "MAX_LEN", "DEFAULT_VALUE", "DESCRIPTION"}; + Query.Type[] columnType = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, + Query.Type.VARCHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getFunctionColumns(String catalog, String schemaPattern, + String functionNamePattern, String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + String[] columnNames = {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", + "COLUMN_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "COLUMN_USAGE", "REMARKS", + "CHAR_OCTET_LENGTH", "IS_NULLABLE"}; + Query.Type[] columnType = {Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + /** + * Enumeration for Table Types + */ + protected enum TableType {LOCAL_TEMPORARY("LOCAL TEMPORARY"), SYSTEM_TABLE( + "SYSTEM TABLE"), SYSTEM_VIEW("SYSTEM VIEW"), TABLE("TABLE", new String[]{"BASE TABLE"}), VIEW( + "VIEW"), UNKNOWN("UNKNOWN"); + + private String name; + private byte[] nameAsBytes; + private String[] synonyms; + + TableType(String tableTypeName) { + this(tableTypeName, null); + } + + TableType(String tableTypeName, String[] tableTypeSynonyms) { + this.name = tableTypeName; + this.nameAsBytes = tableTypeName.getBytes(); + this.synonyms = tableTypeSynonyms; + } + + static TableType getTableTypeEqualTo(String tableTypeName) { + for (TableType tableType : TableType.values()) { + if (tableType.equalsTo(tableTypeName)) { + return tableType; } - String[] columnName = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "Non_unique", "INDEX_QUALIFIER", - "INDEX_NAME", "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", - "CARDINALITY", "PAGES", "FILTER_CONDITION"}; - - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.BIT, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, Query.Type.INT16, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, - Query.Type.CHAR}; - - return new VitessResultSet(columnName, columnType, data, this.connection); + } + return UNKNOWN; } - public boolean ownUpdatesAreVisible(int type) throws SQLException { - return false; + static TableType getTableTypeCompliantWith(String tableTypeName) { + for (TableType tableType : TableType.values()) { + if (tableType.compliesWith(tableTypeName)) { + return tableType; + } + } + return UNKNOWN; } - public boolean ownDeletesAreVisible(int type) throws SQLException { - return false; + String getName() { + return this.name; } - public boolean ownInsertsAreVisible(int type) throws SQLException { - return false; + boolean equalsTo(String tableTypeName) { + return this.name.equalsIgnoreCase(tableTypeName); } - public boolean othersUpdatesAreVisible(int type) throws SQLException { + boolean compliesWith(String tableTypeName) { + if (equalsTo(tableTypeName)) { + return true; + } + if (null != this.synonyms) { + for (String synonym : this.synonyms) { + if (synonym.equalsIgnoreCase(tableTypeName)) { + return true; + } + } + } + return false; + }} + + + /** + * Helper class to provide means of comparing tables by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and + * TABLE_NAME. + */ + protected class TableMetaDataKey implements Comparable { + + String tableType; + String tableCat; + String tableSchem; + String tableName; + + TableMetaDataKey(String tableType, String tableCat, String tableSchem, String tableName) { + this.tableType = tableType == null ? "" : tableType; + this.tableCat = tableCat == null ? "" : tableCat; + this.tableSchem = tableSchem == null ? "" : tableSchem; + this.tableName = tableName == null ? "" : tableName; + } + + public int compareTo(TableMetaDataKey tablesKey) { + int compareResult; + + if ((compareResult = this.tableType.compareTo(tablesKey.tableType)) != 0) { + return compareResult; + } + if ((compareResult = this.tableCat.compareTo(tablesKey.tableCat)) != 0) { + return compareResult; + } + if ((compareResult = this.tableSchem.compareTo(tablesKey.tableSchem)) != 0) { + return compareResult; + } + return this.tableName.compareTo(tablesKey.tableName); + } + + @Override + public boolean equals(Object obj) { + if (null == obj) { return false; - } + } - public boolean othersDeletesAreVisible(int type) throws SQLException { - return false; - } + if (obj == this) { + return true; + } - public boolean othersInsertsAreVisible(int type) throws SQLException { - return false; + return obj instanceof TableMetaDataKey && compareTo((TableMetaDataKey) obj) == 0; } + } - public boolean updatesAreDetected(int type) throws SQLException { - return false; - } - public boolean deletesAreDetected(int type) throws SQLException { - return false; - } + /** + * Helper class to provide means of comparing indexes by Non_unique, TYPE, INDEX_NAME, and + * ORDINAL_POSITION. + */ + protected class IndexMetaDataKey implements Comparable { - public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, - int[] types) throws SQLException { - String[] columnNames = - {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "CLASS_NAME", "DATA_TYPE", "REMARKS", - "BASE_TYPE"}; - Query.Type[] columnType = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.INT32, Query.Type.VARCHAR, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + Boolean columnNonUnique; + Short columnType; + String columnIndexName; + Short columnOrdinalPosition; - public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) - throws SQLException { - String[] columnNames = - {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SUPERTYPE_CAT", "SUPERTYPE_SCHEM", - "SUPERTYPE_NAME"}; - Query.Type[] columnType = - {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); + IndexMetaDataKey(boolean columnNonUnique, short columnType, String columnIndexName, + short columnOrdinalPosition) { + this.columnNonUnique = columnNonUnique; + this.columnType = columnType; + this.columnIndexName = columnIndexName; + this.columnOrdinalPosition = columnOrdinalPosition; } - public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) - throws SQLException { - String[] columnNames = {"TABLE_CAT", "TYPE_SCHEM", "TABLE_NAME", "SUPERTABLE_NAME"}; - Query.Type[] columnType = - {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + public int compareTo(IndexMetaDataKey indexInfoKey) { + int compareResult; - public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, - String attributeNamePattern) throws SQLException { - - String[] columnNames = - {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "ATTR_NAME", "DATA_TYPE", "ATTR_TYPE_NAME", - "ATTR_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS", "ATTR_DEF", - "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", - "ISNULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE"}; - Query.Type[] columnType = - {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, - Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, - Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); + if ((compareResult = this.columnNonUnique.compareTo(indexInfoKey.columnNonUnique)) != 0) { + return compareResult; + } + if ((compareResult = this.columnType.compareTo(indexInfoKey.columnType)) != 0) { + return compareResult; + } + if ((compareResult = this.columnIndexName.compareTo(indexInfoKey.columnIndexName)) != 0) { + return compareResult; + } + return this.columnOrdinalPosition.compareTo(indexInfoKey.columnOrdinalPosition); } - public int getSQLStateType() throws SQLException { - return DatabaseMetaData.sqlStateSQL99; - } + @Override + public boolean equals(Object obj) { + if (null == obj) { + return false; + } - public boolean locatorsUpdateCopy() throws SQLException { + if (obj == this) { return true; - } + } - public RowIdLifetime getRowIdLifetime() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + return obj instanceof IndexMetaDataKey && compareTo((IndexMetaDataKey) obj) == 0; } + } - public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { - String[] columnNames = {"TABLE_CAT", "TABLE_CATALOG"}; - Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } - public ResultSet getClientInfoProperties() throws SQLException { - String[] columnNames = {"NAME", "MAX_LEN", "DEFAULT_VALUE", "DESCRIPTION"}; - Query.Type[] columnType = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, Query.Type.VARCHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + /** + * Parses and represents common data type information used by various column/parameter methods. + */ + class TypeDescriptor { - public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + int bufferLength; - public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + int charOctetLength; - public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - String[] columnNames = - {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "COLUMN_SIZE", - "DECIMAL_DIGITS", "NUM_PREC_RADIX", "COLUMN_USAGE", "REMARKS", "CHAR_OCTET_LENGTH", - "IS_NULLABLE"}; - Query.Type[] columnType = - {Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + Integer columnSize; - public T unwrap(Class iface) throws SQLException { - return null; - } + short dataType; - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + Integer decimalDigits; - /** - * Enumeration for Table Types - */ - protected enum TableType { - LOCAL_TEMPORARY("LOCAL TEMPORARY"), SYSTEM_TABLE("SYSTEM TABLE"), SYSTEM_VIEW( - "SYSTEM VIEW"), TABLE("TABLE", new String[] {"BASE TABLE"}), VIEW("VIEW"), UNKNOWN( - "UNKNOWN"); + String isNullable; - private String name; - private byte[] nameAsBytes; - private String[] synonyms; + int nullability; - TableType(String tableTypeName) { - this(tableTypeName, null); - } + int numPrecRadix = 10; - TableType(String tableTypeName, String[] tableTypeSynonyms) { - this.name = tableTypeName; - this.nameAsBytes = tableTypeName.getBytes(); - this.synonyms = tableTypeSynonyms; - } + String typeName; - static TableType getTableTypeEqualTo(String tableTypeName) { - for (TableType tableType : TableType.values()) { - if (tableType.equalsTo(tableTypeName)) { - return tableType; - } - } - return UNKNOWN; - } + TypeDescriptor(String typeInfo, String nullabilityInfo) throws SQLException { + if (typeInfo == null) { + throw new SQLException("NULL typeinfo not supported."); + } - static TableType getTableTypeCompliantWith(String tableTypeName) { - for (TableType tableType : TableType.values()) { - if (tableType.compliesWith(tableTypeName)) { - return tableType; - } - } - return UNKNOWN; - } + String mysqlType; + String fullMysqlType; - String getName() { - return this.name; - } + if (typeInfo.indexOf("(") != -1) { + mysqlType = typeInfo.substring(0, typeInfo.indexOf("(")).trim(); + } else { + mysqlType = typeInfo; + } - boolean equalsTo(String tableTypeName) { - return this.name.equalsIgnoreCase(tableTypeName); - } + int indexOfUnsignedInMysqlType = StringUtils.indexOfIgnoreCase(mysqlType, "unsigned"); - boolean compliesWith(String tableTypeName) { - if (equalsTo(tableTypeName)) { - return true; - } - if (null != this.synonyms) { - for (String synonym : this.synonyms) { - if (synonym.equalsIgnoreCase(tableTypeName)) { - return true; - } - } - } - return false; - } - } + if (indexOfUnsignedInMysqlType != -1) { + mysqlType = mysqlType.substring(0, (indexOfUnsignedInMysqlType - 1)); + } + // Add unsigned to typename reported to enduser as 'native type', if present - /** - * Helper class to provide means of comparing tables by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and TABLE_NAME. - */ - protected class TableMetaDataKey implements Comparable { - String tableType; - String tableCat; - String tableSchem; - String tableName; - - TableMetaDataKey(String tableType, String tableCat, String tableSchem, String tableName) { - this.tableType = tableType == null ? "" : tableType; - this.tableCat = tableCat == null ? "" : tableCat; - this.tableSchem = tableSchem == null ? "" : tableSchem; - this.tableName = tableName == null ? "" : tableName; - } + boolean isUnsigned = false; - public int compareTo(TableMetaDataKey tablesKey) { - int compareResult; + if ((StringUtils.indexOfIgnoreCase(typeInfo, "unsigned") != -1) && ( + StringUtils.indexOfIgnoreCase(typeInfo, "set") != 0) && ( + StringUtils.indexOfIgnoreCase(typeInfo, "enum") != 0)) { + fullMysqlType = mysqlType + " unsigned"; + isUnsigned = true; + } else { + fullMysqlType = mysqlType; + } + fullMysqlType = fullMysqlType.toUpperCase(Locale.ENGLISH); - if ((compareResult = this.tableType.compareTo(tablesKey.tableType)) != 0) { - return compareResult; - } - if ((compareResult = this.tableCat.compareTo(tablesKey.tableCat)) != 0) { - return compareResult; - } - if ((compareResult = this.tableSchem.compareTo(tablesKey.tableSchem)) != 0) { - return compareResult; - } - return this.tableName.compareTo(tablesKey.tableName); - } - - @Override public boolean equals(Object obj) { - if (null == obj) { - return false; - } - - if (obj == this) { - return true; - } - - return obj instanceof TableMetaDataKey && compareTo((TableMetaDataKey) obj) == 0; - } - } + this.dataType = (short) MysqlDefs.mysqlToJavaType(mysqlType); + this.typeName = fullMysqlType; - /** - * Helper class to provide means of comparing indexes by Non_unique, TYPE, INDEX_NAME, and ORDINAL_POSITION. - */ - protected class IndexMetaDataKey implements Comparable { - Boolean columnNonUnique; - Short columnType; - String columnIndexName; - Short columnOrdinalPosition; - - IndexMetaDataKey(boolean columnNonUnique, short columnType, String columnIndexName, - short columnOrdinalPosition) { - this.columnNonUnique = columnNonUnique; - this.columnType = columnType; - this.columnIndexName = columnIndexName; - this.columnOrdinalPosition = columnOrdinalPosition; - } + // Figure Out the Size - public int compareTo(IndexMetaDataKey indexInfoKey) { - int compareResult; + if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { + String temp = typeInfo.substring(typeInfo.indexOf("("), typeInfo.lastIndexOf(")")); + StringTokenizer tokenizer = new StringTokenizer(temp, ","); + int maxLength = 0; - if ((compareResult = this.columnNonUnique.compareTo(indexInfoKey.columnNonUnique)) - != 0) { - return compareResult; - } - if ((compareResult = this.columnType.compareTo(indexInfoKey.columnType)) != 0) { - return compareResult; - } - if ((compareResult = this.columnIndexName.compareTo(indexInfoKey.columnIndexName)) - != 0) { - return compareResult; - } - return this.columnOrdinalPosition.compareTo(indexInfoKey.columnOrdinalPosition); + while (tokenizer.hasMoreTokens()) { + maxLength = Math.max(maxLength, (tokenizer.nextToken().length() - 2)); } - @Override public boolean equals(Object obj) { - if (null == obj) { - return false; - } + this.columnSize = maxLength; + this.decimalDigits = null; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { + String temp = typeInfo.substring(typeInfo.indexOf("(") + 1, typeInfo.lastIndexOf(")")); + StringTokenizer tokenizer = new StringTokenizer(temp, ","); + int maxLength = 0; - if (obj == this) { - return true; - } + int numElements = tokenizer.countTokens(); - return obj instanceof IndexMetaDataKey && compareTo((IndexMetaDataKey) obj) == 0; + if (numElements > 0) { + maxLength += (numElements - 1); } - } - - - /** - * Parses and represents common data type information used by various - * column/parameter methods. - */ - class TypeDescriptor { - int bufferLength; - int charOctetLength; + while (tokenizer.hasMoreTokens()) { + String setMember = tokenizer.nextToken().trim(); - Integer columnSize; - - short dataType; - - Integer decimalDigits; - - String isNullable; - - int nullability; - - int numPrecRadix = 10; - - String typeName; - - TypeDescriptor(String typeInfo, String nullabilityInfo) throws SQLException { - if (typeInfo == null) { - throw new SQLException("NULL typeinfo not supported."); - } - - String mysqlType; - String fullMysqlType; - - if (typeInfo.indexOf("(") != -1) { - mysqlType = typeInfo.substring(0, typeInfo.indexOf("(")).trim(); - } else { - mysqlType = typeInfo; - } - - int indexOfUnsignedInMysqlType = StringUtils.indexOfIgnoreCase(mysqlType, "unsigned"); - - if (indexOfUnsignedInMysqlType != -1) { - mysqlType = mysqlType.substring(0, (indexOfUnsignedInMysqlType - 1)); - } - - // Add unsigned to typename reported to enduser as 'native type', if present - - boolean isUnsigned = false; - - if ((StringUtils.indexOfIgnoreCase(typeInfo, "unsigned") != -1) && ( - StringUtils.indexOfIgnoreCase(typeInfo, "set") != 0) && ( - StringUtils.indexOfIgnoreCase(typeInfo, "enum") != 0)) { - fullMysqlType = mysqlType + " unsigned"; - isUnsigned = true; - } else { - fullMysqlType = mysqlType; - } - fullMysqlType = fullMysqlType.toUpperCase(Locale.ENGLISH); - - this.dataType = (short) MysqlDefs.mysqlToJavaType(mysqlType); - - this.typeName = fullMysqlType; - - // Figure Out the Size - - if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { - String temp = typeInfo.substring(typeInfo.indexOf("("), typeInfo.lastIndexOf(")")); - StringTokenizer tokenizer = new StringTokenizer(temp, ","); - int maxLength = 0; - - while (tokenizer.hasMoreTokens()) { - maxLength = Math.max(maxLength, (tokenizer.nextToken().length() - 2)); - } - - this.columnSize = maxLength; - this.decimalDigits = null; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { - String temp = - typeInfo.substring(typeInfo.indexOf("(") + 1, typeInfo.lastIndexOf(")")); - StringTokenizer tokenizer = new StringTokenizer(temp, ","); - int maxLength = 0; - - int numElements = tokenizer.countTokens(); - - if (numElements > 0) { - maxLength += (numElements - 1); - } - - while (tokenizer.hasMoreTokens()) { - String setMember = tokenizer.nextToken().trim(); - - if (setMember.startsWith(Constants.LITERAL_SINGLE_QUOTE) && setMember - .endsWith(Constants.LITERAL_SINGLE_QUOTE)) { - maxLength += setMember.length() - 2; - } else { - maxLength += setMember.length(); - } - } + if (setMember.startsWith(Constants.LITERAL_SINGLE_QUOTE) && setMember + .endsWith(Constants.LITERAL_SINGLE_QUOTE)) { + maxLength += setMember.length() - 2; + } else { + maxLength += setMember.length(); + } + } - this.columnSize = maxLength; - this.decimalDigits = null; - } else if (typeInfo.indexOf(",") != -1) { - // Numeric with decimals - this.columnSize = Integer.valueOf( - typeInfo.substring((typeInfo.indexOf("(") + 1), (typeInfo.indexOf(","))) - .trim()); - this.decimalDigits = Integer.valueOf( - typeInfo.substring((typeInfo.indexOf(",") + 1), (typeInfo.indexOf(")"))) - .trim()); - } else { - this.columnSize = null; - this.decimalDigits = null; - - /* If the size is specified with the DDL, use that */ - if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "text") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "blob") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "binary") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "bit") != -1) - && typeInfo.indexOf("(") != -1) { - int endParenIndex = typeInfo.indexOf(")"); - - if (endParenIndex == -1) { - endParenIndex = typeInfo.length(); - } - - this.columnSize = Integer.valueOf( - typeInfo.substring((typeInfo.indexOf("(") + 1), endParenIndex).trim()); - - // Adjust for pseudo-boolean - if (this.columnSize == 1 && StringUtils - .startsWithIgnoreCase(typeInfo, "tinyint")) { - this.dataType = Types.BIT; - this.typeName = "BIT"; - } - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyint")) { - if (typeInfo.indexOf("(1)") != -1) { - this.dataType = Types.BIT; - this.typeName = "BIT"; - - } else { - this.columnSize = 3; - this.decimalDigits = 0; - } - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "smallint")) { - this.columnSize = 5; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumint")) { - this.columnSize = isUnsigned ? 8 : 7; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int")) { - this.columnSize = 10; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "integer")) { - this.columnSize = 10; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "bigint")) { - this.dataType = Types.BIGINT; - this.columnSize = isUnsigned ? 20 : 19; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int24")) { - this.columnSize = 19; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "real")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "float")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "decimal")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "numeric")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "double")) { - this.columnSize = 22; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "char")) { - this.columnSize = 1; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "varchar")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "timestamp")) { - this.columnSize = 19; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "datetime")) { - this.columnSize = 19; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "date")) { - this.columnSize = 10; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "time")) { - this.columnSize = 8; - - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyblob")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "blob")) { - this.columnSize = 65535; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumblob")) { - this.columnSize = 16777215; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longblob")) { - this.columnSize = Integer.MAX_VALUE; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinytext")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "text")) { - this.columnSize = 65535; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumtext")) { - this.columnSize = 16777215; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longtext")) { - this.columnSize = Integer.MAX_VALUE; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { - this.columnSize = 255; - } + this.columnSize = maxLength; + this.decimalDigits = null; + } else if (typeInfo.indexOf(",") != -1) { + // Numeric with decimals + this.columnSize = Integer.valueOf( + typeInfo.substring((typeInfo.indexOf("(") + 1), (typeInfo.indexOf(","))).trim()); + this.decimalDigits = Integer.valueOf( + typeInfo.substring((typeInfo.indexOf(",") + 1), (typeInfo.indexOf(")"))).trim()); + } else { + this.columnSize = null; + this.decimalDigits = null; + + /* If the size is specified with the DDL, use that */ + if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "text") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "blob") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "binary") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "bit") != -1) + && typeInfo.indexOf("(") != -1) { + int endParenIndex = typeInfo.indexOf(")"); + + if (endParenIndex == -1) { + endParenIndex = typeInfo.length(); + } + + this.columnSize = Integer + .valueOf(typeInfo.substring((typeInfo.indexOf("(") + 1), endParenIndex).trim()); + + // Adjust for pseudo-boolean + if (this.columnSize == 1 && StringUtils.startsWithIgnoreCase(typeInfo, "tinyint")) { + this.dataType = Types.BIT; + this.typeName = "BIT"; + } + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyint")) { + if (typeInfo.indexOf("(1)") != -1) { + this.dataType = Types.BIT; + this.typeName = "BIT"; + + } else { + this.columnSize = 3; + this.decimalDigits = 0; + } + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "smallint")) { + this.columnSize = 5; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumint")) { + this.columnSize = isUnsigned ? 8 : 7; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int")) { + this.columnSize = 10; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "integer")) { + this.columnSize = 10; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "bigint")) { + this.dataType = Types.BIGINT; + this.columnSize = isUnsigned ? 20 : 19; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int24")) { + this.columnSize = 19; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "real")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "float")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "decimal")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "numeric")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "double")) { + this.columnSize = 22; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "char")) { + this.columnSize = 1; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "varchar")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "timestamp")) { + this.columnSize = 19; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "datetime")) { + this.columnSize = 19; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "date")) { + this.columnSize = 10; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "time")) { + this.columnSize = 8; + + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyblob")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "blob")) { + this.columnSize = 65535; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumblob")) { + this.columnSize = 16777215; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longblob")) { + this.columnSize = Integer.MAX_VALUE; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinytext")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "text")) { + this.columnSize = 65535; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumtext")) { + this.columnSize = 16777215; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longtext")) { + this.columnSize = Integer.MAX_VALUE; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { + this.columnSize = 255; + } - } - this.bufferLength = 65535; - this.numPrecRadix = 10; - - if (nullabilityInfo != null) { - switch (nullabilityInfo) { - case "YES": - this.nullability = DatabaseMetaData.columnNullable; - this.isNullable = "YES"; - - break; - case "UNKNOWN": - this.nullability = DatabaseMetaData.columnNullableUnknown; - this.isNullable = ""; - break; - default: - this.nullability = DatabaseMetaData.columnNoNulls; - this.isNullable = "NO"; - break; - } - } else { - this.nullability = DatabaseMetaData.columnNoNulls; - this.isNullable = "NO"; - } + } + this.bufferLength = 65535; + this.numPrecRadix = 10; + + if (nullabilityInfo != null) { + switch (nullabilityInfo) { + case "YES": + this.nullability = DatabaseMetaData.columnNullable; + this.isNullable = "YES"; + + break; + case "UNKNOWN": + this.nullability = DatabaseMetaData.columnNullableUnknown; + this.isNullable = ""; + break; + default: + this.nullability = DatabaseMetaData.columnNoNulls; + this.isNullable = "NO"; + break; } + } else { + this.nullability = DatabaseMetaData.columnNoNulls; + this.isNullable = "NO"; + } } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java index 48cdecf4640..d6c2b2a1340 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java @@ -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. @@ -22,86 +22,85 @@ public class VitessParameterMetaData implements ParameterMetaData { - private final int parameterCount; - - /** - * This implementation (and defaults below) is equivalent to - * mysql-connector-java's "simple" (non-server) - * statement metadata - */ - VitessParameterMetaData(int count) { - this.parameterCount = count; - } - - @Override - public int getParameterCount() throws SQLException { - return parameterCount; - } - - @Override - public int isNullable(int param) throws SQLException { - throw new SQLException("Parameter metadata not available for the given statement"); - } - - @Override - public boolean isSigned(int param) throws SQLException { - checkBounds(param); - return false; - } - - @Override - public int getPrecision(int param) throws SQLException { - checkBounds(param); - return 0; - } - - @Override - public int getScale(int param) throws SQLException { - checkBounds(param); - return 0; + private final int parameterCount; + + /** + * This implementation (and defaults below) is equivalent to mysql-connector-java's "simple" + * (non-server) statement metadata + */ + VitessParameterMetaData(int count) { + this.parameterCount = count; + } + + @Override + public int getParameterCount() throws SQLException { + return parameterCount; + } + + @Override + public int isNullable(int param) throws SQLException { + throw new SQLException("Parameter metadata not available for the given statement"); + } + + @Override + public boolean isSigned(int param) throws SQLException { + checkBounds(param); + return false; + } + + @Override + public int getPrecision(int param) throws SQLException { + checkBounds(param); + return 0; + } + + @Override + public int getScale(int param) throws SQLException { + checkBounds(param); + return 0; + } + + @Override + public int getParameterType(int param) throws SQLException { + checkBounds(param); + return Types.VARCHAR; + } + + @Override + public String getParameterTypeName(int param) throws SQLException { + checkBounds(param); + return "VARCHAR"; + } + + @Override + public String getParameterClassName(int param) throws SQLException { + checkBounds(param); + return "java.lang.String"; + } + + @Override + public int getParameterMode(int param) throws SQLException { + return ParameterMetaData.parameterModeIn; + } + + private void checkBounds(int paramNumber) throws SQLException { + if (paramNumber < 1) { + throw new SQLException("Parameter index of '" + paramNumber + "' is invalid."); } - @Override - public int getParameterType(int param) throws SQLException { - checkBounds(param); - return Types.VARCHAR; + if (paramNumber > this.parameterCount) { + throw new SQLException("Parameter index of '" + paramNumber + + "' is greater than number of parameters, which is '" + this.parameterCount + "'."); } + } - @Override - public String getParameterTypeName(int param) throws SQLException { - checkBounds(param); - return "VARCHAR"; - } - - @Override - public String getParameterClassName(int param) throws SQLException { - checkBounds(param); - return "java.lang.String"; - } - - @Override - public int getParameterMode(int param) throws SQLException { - return ParameterMetaData.parameterModeIn; - } - - private void checkBounds(int paramNumber) throws SQLException { - if (paramNumber < 1) { - throw new SQLException("Parameter index of '" + paramNumber + "' is invalid."); - } + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } - if (paramNumber > this.parameterCount) { - throw new SQLException( - "Parameter index of '" + paramNumber + "' is greater than number of parameters, which is '" + this.parameterCount + "'."); - } - } - - @Override - public T unwrap(Class iface) throws SQLException { - return null; - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java index d53d7c86ceb..eef8b6f2078 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java @@ -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. @@ -60,842 +60,832 @@ /** * Created by harshit.gangal on 25/01/16. *

- * This class expected for an sql query and a given set of parameters - * the DB Call can be made once with any of the following method - * execute, executeQuery, executeUpdate and executeBatch. - * After the call, the parameters will be reset - * and a new set of parameters needs to be provided before calling any of the above method. + * This class expected for an sql query and a given set of parameters the DB Call can be made once + * with any of the following method execute, executeQuery, executeUpdate and executeBatch. After the + * call, the parameters will be reset and a new set of parameters needs to be provided before + * calling any of the above method. */ public class VitessPreparedStatement extends VitessStatement implements PreparedStatement { - /* Get actual class name to be printed on */ - private final String sql; - private final Map bindVariables; - /** - * Holds batched commands - */ - private final List> batchedArgs; - private VitessParameterMetaData parameterMetadata; - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql) - throws SQLException { - this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - } - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, - int resultSetConcurrency) throws SQLException { - this(vitessConnection, sql, resultSetType, resultSetConcurrency, - Statement.NO_GENERATED_KEYS); - } - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql, - int autoGeneratedKeys) throws SQLException { - this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - autoGeneratedKeys); - } - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, - int resultSetConcurrency, int autoGeneratedKeys) throws SQLException { - super(vitessConnection, resultSetType, resultSetConcurrency); - checkSQLNullOrEmpty(sql); - this.bindVariables = new HashMap<>(); - this.sql = sql; - this.generatedId = -1; - this.retrieveGeneratedKeys = (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS); - this.batchedArgs = new ArrayList<>(); - } - - public ResultSet executeQuery() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - - checkOpen(); - closeOpenResultSetAndResetCount(); - - //Setting to default value - this.generatedId = -1; - - vtGateConn = this.vitessConnection.getVtGateConn(); - - try { - if (vitessConnection.isSimpleExecute() && this.fetchSize == 0) { - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()).checkedGet(); - } else { - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.streamExecute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()); + /* Get actual class name to be printed on */ + private final String sql; + private final Map bindVariables; + /** + * Holds batched commands + */ + private final List> batchedArgs; + private VitessParameterMetaData parameterMetadata; + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql) + throws SQLException { + this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, + int resultSetConcurrency) throws SQLException { + this(vitessConnection, sql, resultSetType, resultSetConcurrency, Statement.NO_GENERATED_KEYS); + } + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql, + int autoGeneratedKeys) throws SQLException { + this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + autoGeneratedKeys); + } + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, + int resultSetConcurrency, int autoGeneratedKeys) throws SQLException { + super(vitessConnection, resultSetType, resultSetConcurrency); + checkSQLNullOrEmpty(sql); + this.bindVariables = new HashMap<>(); + this.sql = sql; + this.generatedId = -1; + this.retrieveGeneratedKeys = (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS); + this.batchedArgs = new ArrayList<>(); + } + + public ResultSet executeQuery() throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + + checkOpen(); + closeOpenResultSetAndResetCount(); + + //Setting to default value + this.generatedId = -1; + + vtGateConn = this.vitessConnection.getVtGateConn(); + + try { + if (vitessConnection.isSimpleExecute() && this.fetchSize == 0) { + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn + .execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()) + .checkedGet(); + } else { + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn + .streamExecute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()); + } + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + this.vitessResultSet = new VitessResultSet(cursor, this); + } finally { + this.bindVariables.clear(); + } + return this.vitessResultSet; + } + + public int executeUpdate() throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + int truncatedUpdateCount; + + checkOpen(); + checkNotReadOnly(); + closeOpenResultSetAndResetCount(); + + vtGateConn = this.vitessConnection.getVtGateConn(); + + try { + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn + .execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()) + .checkedGet(); + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { + throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); + } + + if (this.retrieveGeneratedKeys) { + this.generatedId = cursor.getInsertId(); + } + + this.resultCount = cursor.getRowsAffected(); + + if (this.resultCount > Integer.MAX_VALUE) { + truncatedUpdateCount = Integer.MAX_VALUE; + } else { + truncatedUpdateCount = (int) this.resultCount; + } + } finally { + this.bindVariables.clear(); + } + return truncatedUpdateCount; + } + + public boolean execute() throws SQLException { + checkOpen(); + closeOpenResultSetAndResetCount(); + + if (!maybeSelect(this.sql)) { + this.executeUpdate(); + return false; + } else { + this.executeQuery(); + return true; + } + } + + public void clearParameters() throws SQLException { + checkOpen(); + this.bindVariables.clear(); + } + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, null); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte[] x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + checkOpen(); + String date = DateTime.formatDate(x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + checkOpen(); + String time = DateTime.formatTime(x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + checkOpen(); + String timeStamp = DateTime.formatTimestamp(x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + checkOpen(); + String date = DateTime.formatDate(x, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + checkOpen(); + String time = DateTime.formatTime(x, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + checkOpen(); + String timeStamp = DateTime.formatTimestamp(x, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + if (x == null) { + setNull(parameterIndex, Types.NULL); + } else if (x instanceof String) { + setString(parameterIndex, (String) x); + } else if (x instanceof Short) { + setShort(parameterIndex, (Short) x); + } else if (x instanceof Integer) { + setInt(parameterIndex, (Integer) x); + } else if (x instanceof Long) { + setLong(parameterIndex, (Long) x); + } else if (x instanceof Float) { + setFloat(parameterIndex, (Float) x); + } else if (x instanceof Double) { + setDouble(parameterIndex, (Double) x); + } else if (x instanceof Boolean) { + setBoolean(parameterIndex, (Boolean) x); + } else if (x instanceof Byte) { + setByte(parameterIndex, (Byte) x); + } else if (x instanceof Character) { + setString(parameterIndex, String.valueOf(x)); + } else if (x instanceof Date) { + setDate(parameterIndex, (Date) x); + } else if (x instanceof Time) { + setTime(parameterIndex, (Time) x); + } else if (x instanceof Timestamp) { + setTimestamp(parameterIndex, (Timestamp) x); + } else if (x instanceof BigDecimal) { + setBigDecimal(parameterIndex, (BigDecimal) x); + } else if (x instanceof BigInteger) { + setBigInteger(parameterIndex, (BigInteger) x); + } else if (x instanceof byte[]) { + setBytes(parameterIndex, (byte[]) x); + } else if (getConnection().getTreatUtilDateAsTimestamp() && x instanceof java.util.Date) { + setTimestamp(parameterIndex, new Timestamp(((java.util.Date) x).getTime())); + } else { + throw new SQLException( + Constants.SQLExceptionMessages.SQL_TYPE_INFER + x.getClass().getCanonicalName()); + } + } + + /** + * Add bindVariables to the batch and clear it to have new set of bindVariables. + */ + public void addBatch() throws SQLException { + checkOpen(); + this.batchedArgs.add(new HashMap<>(this.bindVariables)); + this.bindVariables.clear(); + } + + /** + * Clear all the batched bindVariables. + */ + @Override + public void clearBatch() throws SQLException { + checkOpen(); + this.batchedArgs.clear(); + } + + /** + * Submits a batch of commands to the database for execution and if all commands execute + * successfully, returns an array of update counts. The array returned is according to the order + * in which they were added to the batch. + *

+ * If one of the commands in a batch update fails to execute properly, this method throws a + * BatchUpdateException, and a JDBC driver may or may not continue to process the + * remaining commands in the batch. If the driver continues processing after a failure, the array + * returned by the method BatchUpdateException.getUpdateCounts will contain as many + * elements as there are commands in the batch. + * + * @return int[] of results corresponding to each command + */ + @Override + public int[] executeBatch() throws SQLException { + checkOpen(); + // An executeBatch can't contain SELECT statements as defined by the documentation: + // https://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html + // "This list may contain statements for updating, inserting, or deleting a row; and it may + // also contain DDL statements such as CREATE TABLE and DROP TABLE. It cannot, however, + // contain a statement that would produce a ResultSet object, such as a SELECT statement. + // In other words, the list can contain only statements that produce an update count." + checkNotReadOnly(); + + VTGateConnection vtGateConn; + List cursorWithErrorList; + List batchedQueries = new ArrayList<>(); + + if (0 == batchedArgs.size()) { + return new int[0]; + } + + try { + vtGateConn = this.vitessConnection.getVtGateConn(); + + this.retrieveGeneratedKeys = true; // mimicking mysql-connector-j + /* + * Current api does not support single query and multiple bindVariables list. + * So, List of the query is created to match the bindVariables list. + */ + for (int i = 0; i < batchedArgs.size(); ++i) { + batchedQueries.add(this.sql); + } + + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursorWithErrorList = vtGateConn + .executeBatch(context, batchedQueries, batchedArgs, vitessConnection.getVtSession()) + .checkedGet(); + + if (null == cursorWithErrorList) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + return this.generateBatchUpdateResult(cursorWithErrorList, batchedQueries); + } finally { + this.clearBatch(); + } + + + } + + //Methods which are currently not supported + + public ParameterMetaData getParameterMetaData() throws SQLException { + checkOpen(); + if (this.parameterMetadata == null) { + this.parameterMetadata = new VitessParameterMetaData(calculateParameterCount()); + } + + return this.parameterMetadata; + } + + /** + * This function was ported from mysql-connector-java ParseInfo object and greatly simplified to + * just the parts for counting parameters + */ + private int calculateParameterCount() throws SQLException { + if (sql == null) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + ": sql null"); + } + + char quotedIdentifierChar = '`'; + char currentQuoteChar = 0; + boolean inQuotes = false; + boolean inQuotedId = false; + int statementCount = 0; + int statementLength = sql.length(); + int statementStartPos = StringUtils.findStartOfStatement(sql); + + for (int i = statementStartPos; i < statementLength; ++i) { + char c = sql.charAt(i); + + if (c == '\\' && i < (statementLength - 1)) { + i++; + continue; // next character is escaped + } + + // are we in a quoted identifier? (only valid when the id is not inside a 'string') + if (!inQuotes && c == quotedIdentifierChar) { + inQuotedId = !inQuotedId; + } else if (!inQuotedId) { + // only respect quotes when not in a quoted identifier + if (inQuotes) { + if (((c == '\'') || (c == '"')) && c == currentQuoteChar) { + if (i < (statementLength - 1) && sql.charAt(i + 1) == currentQuoteChar) { + i++; + continue; // inline quote escape } - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } + inQuotes = !inQuotes; + currentQuoteChar = 0; + } + } else { + if (c == '#' || (c == '-' && (i + 1) < statementLength && sql.charAt(i + 1) == '-')) { + // comment, run out to end of statement, or newline, whichever comes first + int endOfStmt = statementLength - 1; - this.vitessResultSet = new VitessResultSet(cursor, this); - } finally { - this.bindVariables.clear(); - } - return this.vitessResultSet; - } + for (; i < endOfStmt; i++) { + c = sql.charAt(i); - public int executeUpdate() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; + if (c == '\r' || c == '\n') { + break; + } + } - checkOpen(); - checkNotReadOnly(); - closeOpenResultSetAndResetCount(); + continue; + } else if (c == '/' && (i + 1) < statementLength) { + // Comment? + char cNext = sql.charAt(i + 1); + if (cNext == '*') { + i += 2; - vtGateConn = this.vitessConnection.getVtGateConn(); + for (int j = i; j < statementLength; j++) { + i++; + cNext = sql.charAt(j); - try { - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()).checkedGet(); + if (cNext == '*' && (j + 1) < statementLength) { + if (sql.charAt(j + 1) == '/') { + i++; - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } + if (i < statementLength) { + c = sql.charAt(i); + } - if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { - throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); + break; // comment done + } + } + } } - - if (this.retrieveGeneratedKeys) { - this.generatedId = cursor.getInsertId(); + } else if ((c == '\'') || (c == '"')) { + inQuotes = true; + currentQuoteChar = c; + } + } + } + + if ((c == '?') && !inQuotes && !inQuotedId) { + statementCount++; + } + } + + return statementCount; + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setObject(int parameterIndex, Object parameterObject, int targetSqlType, + int scaleOrLength) throws SQLException { + if (null == parameterObject) { + setNull(parameterIndex, Types.OTHER); + } else { + try { + switch (targetSqlType) { + case Types.BOOLEAN: + if (parameterObject instanceof Boolean) { + setBoolean(parameterIndex, (Boolean) parameterObject); + break; + } else if (parameterObject instanceof String) { + setBoolean(parameterIndex, "true".equalsIgnoreCase((String) parameterObject) || !"0" + .equalsIgnoreCase((String) parameterObject)); + break; + } else if (parameterObject instanceof Number) { + int intValue = ((Number) parameterObject).intValue(); + setBoolean(parameterIndex, intValue != 0); + break; + } else { + throw new SQLException("Conversion from" + parameterObject.getClass().getName() + + "to Types.Boolean is not Possible"); } - - this.resultCount = cursor.getRowsAffected(); - - if (this.resultCount > Integer.MAX_VALUE) { - truncatedUpdateCount = Integer.MAX_VALUE; + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.REAL: + case Types.FLOAT: + case Types.DOUBLE: + case Types.DECIMAL: + case Types.NUMERIC: + setNumericObject(parameterIndex, parameterObject, targetSqlType, scaleOrLength); + break; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (parameterObject instanceof BigDecimal) { + setString(parameterIndex, + (StringUtils.fixDecimalExponent((parameterObject).toString()))); } else { - truncatedUpdateCount = (int) this.resultCount; + setString(parameterIndex, parameterObject.toString()); } - } finally { - this.bindVariables.clear(); - } - return truncatedUpdateCount; - } - - public boolean execute() throws SQLException { - checkOpen(); - closeOpenResultSetAndResetCount(); - - if (!maybeSelect(this.sql)) { - this.executeUpdate(); - return false; - } else { - this.executeQuery(); - return true; - } - } - - public void clearParameters() throws SQLException { - checkOpen(); - this.bindVariables.clear(); - } - - public void setNull(int parameterIndex, int sqlType) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, null); - } - - public void setBoolean(int parameterIndex, boolean x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setByte(int parameterIndex, byte x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setShort(int parameterIndex, short x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setInt(int parameterIndex, int x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setLong(int parameterIndex, long x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setFloat(int parameterIndex, float x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setDouble(int parameterIndex, double x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setString(int parameterIndex, String x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setBytes(int parameterIndex, byte[] x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setDate(int parameterIndex, Date x) throws SQLException { - checkOpen(); - String date = DateTime.formatDate(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); - } - - public void setTime(int parameterIndex, Time x) throws SQLException { - checkOpen(); - String time = DateTime.formatTime(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); - } - - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - checkOpen(); - String timeStamp = DateTime.formatTimestamp(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); - } - - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { - checkOpen(); - String date = DateTime.formatDate(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); - } - - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { - checkOpen(); - String time = DateTime.formatTime(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); - } - - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { - checkOpen(); - String timeStamp = DateTime.formatTimestamp(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); - } - - public void setObject(int parameterIndex, Object x) throws SQLException { - if (x == null) { - setNull(parameterIndex, Types.NULL); - } else if (x instanceof String) { - setString(parameterIndex, (String) x); - } else if (x instanceof Short) { - setShort(parameterIndex, (Short) x); - } else if (x instanceof Integer) { - setInt(parameterIndex, (Integer) x); - } else if (x instanceof Long) { - setLong(parameterIndex, (Long) x); - } else if (x instanceof Float) { - setFloat(parameterIndex, (Float) x); - } else if (x instanceof Double) { - setDouble(parameterIndex, (Double) x); - } else if (x instanceof Boolean) { - setBoolean(parameterIndex, (Boolean) x); - } else if (x instanceof Byte) { - setByte(parameterIndex, (Byte) x); - } else if (x instanceof Character) { - setString(parameterIndex, String.valueOf(x)); - } else if (x instanceof Date) { - setDate(parameterIndex, (Date) x); - } else if (x instanceof Time) { - setTime(parameterIndex, (Time) x); - } else if (x instanceof Timestamp) { - setTimestamp(parameterIndex, (Timestamp) x); - } else if (x instanceof BigDecimal) { - setBigDecimal(parameterIndex, (BigDecimal) x); - } else if (x instanceof BigInteger) { - setBigInteger(parameterIndex, (BigInteger) x); - } else if (x instanceof byte[]) { - setBytes(parameterIndex, (byte[]) x); - } else if (getConnection().getTreatUtilDateAsTimestamp() && x instanceof java.util.Date) { - setTimestamp(parameterIndex, new Timestamp(((java.util.Date) x).getTime())); - } else { - throw new SQLException( - Constants.SQLExceptionMessages.SQL_TYPE_INFER + x.getClass().getCanonicalName()); - } - } - - /** - * Add bindVariables to the batch and clear it to have new set of bindVariables. - * - * @throws SQLException - */ - public void addBatch() throws SQLException { - checkOpen(); - this.batchedArgs.add(new HashMap<>(this.bindVariables)); - this.bindVariables.clear(); - } - - /** - * Clear all the batched bindVariables. - * - * @throws SQLException - */ - @Override public void clearBatch() throws SQLException { - checkOpen(); - this.batchedArgs.clear(); - } - - /** - * Submits a batch of commands to the database for execution and - * if all commands execute successfully, returns an array of update counts. - * The array returned is according to the order in which they were added to the batch. - *

- * If one of the commands in a batch update fails to execute properly, - * this method throws a BatchUpdateException, and a JDBC - * driver may or may not continue to process the remaining commands in - * the batch. If the driver continues processing after a failure, - * the array returned by the method BatchUpdateException.getUpdateCounts - * will contain as many elements as there are commands in the batch. - * - * @return int[] of results corresponding to each command - * @throws SQLException - */ - @Override public int[] executeBatch() throws SQLException { - checkOpen(); - // An executeBatch can't contain SELECT statements as defined by the documentation: - // https://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html - // "This list may contain statements for updating, inserting, or deleting a row; and it may - // also contain DDL statements such as CREATE TABLE and DROP TABLE. It cannot, however, - // contain a statement that would produce a ResultSet object, such as a SELECT statement. - // In other words, the list can contain only statements that produce an update count." - checkNotReadOnly(); - - VTGateConnection vtGateConn; - List cursorWithErrorList; - List batchedQueries = new ArrayList<>(); - - if(0 == batchedArgs.size()) { - return new int[0]; - } - - try { - vtGateConn = this.vitessConnection.getVtGateConn(); - - this.retrieveGeneratedKeys = true; // mimicking mysql-connector-j - /* - * Current api does not support single query and multiple bindVariables list. - * So, List of the query is created to match the bindVariables list. - */ - for (int i = 0; i < batchedArgs.size(); ++i) { - batchedQueries.add(this.sql); + break; + case Types.CLOB: + if (parameterObject instanceof Clob) { + setClob(parameterIndex, (Clob) parameterObject); + } else { + setString(parameterIndex, parameterObject.toString()); } - - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursorWithErrorList = vtGateConn.executeBatch(context, batchedQueries, batchedArgs, vitessConnection.getVtSession()).checkedGet(); - - if (null == cursorWithErrorList) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + break; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + case Types.BLOB: + if (parameterObject instanceof Blob) { + setBlob(parameterIndex, (Blob) parameterObject); + } else { + setBytes(parameterIndex, (byte[]) parameterObject); } - - return this.generateBatchUpdateResult(cursorWithErrorList, batchedQueries); - } finally { - this.clearBatch(); - } - - - } - - //Methods which are currently not supported - - public ParameterMetaData getParameterMetaData() throws SQLException { - checkOpen(); - if (this.parameterMetadata == null) { - this.parameterMetadata = new VitessParameterMetaData(calculateParameterCount()); - } - - return this.parameterMetadata; - } - - /** - * This function was ported from mysql-connector-java ParseInfo object and greatly simplified to just the parts - * for counting parameters - */ - private int calculateParameterCount() throws SQLException { - if (sql == null) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + ": sql null"); - } - - char quotedIdentifierChar = '`'; - char currentQuoteChar = 0; - boolean inQuotes = false; - boolean inQuotedId = false; - int statementCount = 0; - int statementLength = sql.length(); - int statementStartPos = StringUtils.findStartOfStatement(sql); - - for (int i = statementStartPos; i < statementLength; ++i) { - char c = sql.charAt(i); - - if (c == '\\' && i < (statementLength - 1)) { - i++; - continue; // next character is escaped + break; + case Types.DATE: + case Types.TIMESTAMP: + java.util.Date parameterAsDate; + if (parameterObject instanceof String) { + ParsePosition pp = new ParsePosition(0); + DateFormat sdf = new SimpleDateFormat( + StringUtils.getDateTimePattern((String) parameterObject, false), Locale.US); + parameterAsDate = sdf.parse((String) parameterObject, pp); + } else { + parameterAsDate = (java.util.Date) parameterObject; } - - // are we in a quoted identifier? (only valid when the id is not inside a 'string') - if (!inQuotes && c == quotedIdentifierChar) { - inQuotedId = !inQuotedId; - } else if (!inQuotedId) { - // only respect quotes when not in a quoted identifier - if (inQuotes) { - if (((c == '\'') || (c == '"')) && c == currentQuoteChar) { - if (i < (statementLength - 1) && sql.charAt(i + 1) == currentQuoteChar) { - i++; - continue; // inline quote escape - } - - inQuotes = !inQuotes; - currentQuoteChar = 0; - } + switch (targetSqlType) { + case Types.DATE: + if (parameterAsDate instanceof Date) { + setDate(parameterIndex, (Date) parameterAsDate); } else { - if (c == '#' || (c == '-' && (i + 1) < statementLength && sql.charAt(i + 1) == '-')) { - // comment, run out to end of statement, or newline, whichever comes first - int endOfStmt = statementLength - 1; - - for (; i < endOfStmt; i++) { - c = sql.charAt(i); - - if (c == '\r' || c == '\n') { - break; - } - } - - continue; - } else if (c == '/' && (i + 1) < statementLength) { - // Comment? - char cNext = sql.charAt(i + 1); - if (cNext == '*') { - i += 2; - - for (int j = i; j < statementLength; j++) { - i++; - cNext = sql.charAt(j); - - if (cNext == '*' && (j + 1) < statementLength) { - if (sql.charAt(j + 1) == '/') { - i++; - - if (i < statementLength) { - c = sql.charAt(i); - } - - break; // comment done - } - } - } - } - } else if ((c == '\'') || (c == '"')) { - inQuotes = true; - currentQuoteChar = c; - } + setDate(parameterIndex, new Date(parameterAsDate.getTime())); } - } - - if ((c == '?') && !inQuotes && !inQuotedId) { - statementCount++; - } - } - - return statementCount; - } - - public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setCharacterStream(int parameterIndex, Reader reader, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setObject(int parameterIndex, Object parameterObject, int targetSqlType, - int scaleOrLength) throws SQLException { - if (null == parameterObject) { - setNull(parameterIndex, Types.OTHER); - } else { - try { - switch (targetSqlType) { - case Types.BOOLEAN: - if (parameterObject instanceof Boolean) { - setBoolean(parameterIndex, (Boolean) parameterObject); - break; - } else if (parameterObject instanceof String) { - setBoolean(parameterIndex, - "true".equalsIgnoreCase((String) parameterObject) || !"0" - .equalsIgnoreCase((String) parameterObject)); - break; - } else if (parameterObject instanceof Number) { - int intValue = ((Number) parameterObject).intValue(); - setBoolean(parameterIndex, intValue != 0); - break; - } else { - throw new SQLException( - "Conversion from" + parameterObject.getClass().getName() - + "to Types.Boolean is not Possible"); - } - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: - case Types.DECIMAL: - case Types.NUMERIC: - setNumericObject(parameterIndex, parameterObject, targetSqlType, - scaleOrLength); - break; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (parameterObject instanceof BigDecimal) { - setString(parameterIndex, - (StringUtils.fixDecimalExponent((parameterObject).toString()))); - } else { - setString(parameterIndex, parameterObject.toString()); - } - break; - case Types.CLOB: - if (parameterObject instanceof Clob) { - setClob(parameterIndex, (Clob) parameterObject); - } else { - setString(parameterIndex, parameterObject.toString()); - } - break; - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - case Types.BLOB: - if (parameterObject instanceof Blob) { - setBlob(parameterIndex, (Blob) parameterObject); - } else { - setBytes(parameterIndex, (byte[]) parameterObject); - } - break; - case Types.DATE: - case Types.TIMESTAMP: - java.util.Date parameterAsDate; - if (parameterObject instanceof String) { - ParsePosition pp = new ParsePosition(0); - DateFormat sdf = new SimpleDateFormat( - StringUtils.getDateTimePattern((String) parameterObject, false), - Locale.US); - parameterAsDate = sdf.parse((String) parameterObject, pp); - } else { - parameterAsDate = (java.util.Date) parameterObject; - } - switch (targetSqlType) { - case Types.DATE: - if (parameterAsDate instanceof Date) { - setDate(parameterIndex, (Date) parameterAsDate); - } else { - setDate(parameterIndex, new Date(parameterAsDate.getTime())); - } - break; - case Types.TIMESTAMP: - if (parameterAsDate instanceof Timestamp) { - setTimestamp(parameterIndex, (Timestamp) parameterAsDate); - } else { - setTimestamp(parameterIndex, - new Timestamp(parameterAsDate.getTime())); - } - break; - } - break; - case Types.TIME: - if (parameterObject instanceof String) { - DateFormat sdf = new SimpleDateFormat( - StringUtils.getDateTimePattern((String) parameterObject, true), - Locale.US); - setTime(parameterIndex, - new Time(sdf.parse((String) parameterObject).getTime())); - } else if (parameterObject instanceof Timestamp) { - Timestamp timestamp = (Timestamp) parameterObject; - setTime(parameterIndex, new Time(timestamp.getTime())); - } else { - setTime(parameterIndex, (Time) parameterObject); - } - break; - default: - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + break; + case Types.TIMESTAMP: + if (parameterAsDate instanceof Timestamp) { + setTimestamp(parameterIndex, (Timestamp) parameterAsDate); + } else { + setTimestamp(parameterIndex, new Timestamp(parameterAsDate.getTime())); } - } catch (Exception ex) { - throw new SQLException(ex); + break; } - } - } - - public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBinaryStream(int parameterIndex, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setCharacterStream(int parameterIndex, Reader reader, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setUnicodeStream(int parameterIndex, InputStream x, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setRef(int parameterIndex, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBlob(int parameterIndex, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setClob(int parameterIndex, Clob x) throws SQLException { - checkOpen(); - if (x.length() > Integer.MAX_VALUE) { + break; + case Types.TIME: + if (parameterObject instanceof String) { + DateFormat sdf = new SimpleDateFormat( + StringUtils.getDateTimePattern((String) parameterObject, true), Locale.US); + setTime(parameterIndex, new Time(sdf.parse((String) parameterObject).getTime())); + } else if (parameterObject instanceof Timestamp) { + Timestamp timestamp = (Timestamp) parameterObject; + setTime(parameterIndex, new Time(timestamp.getTime())); + } else { + setTime(parameterIndex, (Time) parameterObject); + } + break; + default: throw new SQLFeatureNotSupportedException( - String.format("Clob size over %d not support", Integer.MAX_VALUE), Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - // Clob uses 1-based indexing! - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, - x.getSubString(1, (int) x.length())); - } - - public void setArray(int parameterIndex, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSetMetaData getMetaData() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setURL(int parameterIndex, URL x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setRowId(int parameterIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNString(int parameterIndex, String value) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNCharacterStream(int parameterIndex, Reader value, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNClob(int parameterIndex, NClob value) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBlob(int parameterIndex, InputStream inputStream, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setClob(int parameterIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNClob(int parameterIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setObject(int parameterIndex, Object parameterObject, int targetSqlType) - throws SQLException { - if (!(parameterObject instanceof BigDecimal)) { - setObject(parameterIndex, parameterObject, targetSqlType, 0); - } else { - setObject(parameterIndex, parameterObject, targetSqlType, - ((BigDecimal) parameterObject).scale()); - } - } - - private void setNumericObject(int parameterIndex, Object parameterObj, int targetSqlType, - int scale) throws SQLException { - Number numberParam; - if (parameterObj instanceof Boolean) { - numberParam = (Boolean) parameterObj ? Integer.valueOf(1) : Integer.valueOf(0); - } else if (parameterObj instanceof String) { - switch (targetSqlType) { - case Types.BIT: - if ("1".equals(parameterObj) || "0".equals(parameterObj)) { - numberParam = Integer.valueOf((String) parameterObj); - } else { - boolean parameterAsBoolean = "true".equalsIgnoreCase((String) parameterObj); - numberParam = parameterAsBoolean ? Integer.valueOf(1) : Integer.valueOf(0); - } - break; - - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - numberParam = Integer.valueOf((String) parameterObj); - break; - - case Types.BIGINT: - numberParam = Long.valueOf((String) parameterObj); - break; - - case Types.REAL: - numberParam = Float.valueOf((String) parameterObj); - break; - - case Types.FLOAT: - case Types.DOUBLE: - numberParam = Double.valueOf((String) parameterObj); - break; - - case Types.DECIMAL: - case Types.NUMERIC: - default: - numberParam = new java.math.BigDecimal((String) parameterObj); + } catch (Exception ex) { + throw new SQLException(ex); + } + } + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + checkOpen(); + if (x.length() > Integer.MAX_VALUE) { + throw new SQLFeatureNotSupportedException( + String.format("Clob size over %d not support", Integer.MAX_VALUE), + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + // Clob uses 1-based indexing! + this.bindVariables + .put(Constants.LITERAL_V + parameterIndex, x.getSubString(1, (int) x.length())); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSetMetaData getMetaData() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setObject(int parameterIndex, Object parameterObject, int targetSqlType) + throws SQLException { + if (!(parameterObject instanceof BigDecimal)) { + setObject(parameterIndex, parameterObject, targetSqlType, 0); + } else { + setObject(parameterIndex, parameterObject, targetSqlType, + ((BigDecimal) parameterObject).scale()); + } + } + + private void setNumericObject(int parameterIndex, Object parameterObj, int targetSqlType, + int scale) throws SQLException { + Number numberParam; + if (parameterObj instanceof Boolean) { + numberParam = (Boolean) parameterObj ? Integer.valueOf(1) : Integer.valueOf(0); + } else if (parameterObj instanceof String) { + switch (targetSqlType) { + case Types.BIT: + if ("1".equals(parameterObj) || "0".equals(parameterObj)) { + numberParam = Integer.valueOf((String) parameterObj); + } else { + boolean parameterAsBoolean = "true".equalsIgnoreCase((String) parameterObj); + numberParam = parameterAsBoolean ? Integer.valueOf(1) : Integer.valueOf(0); + } + break; + + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + numberParam = Integer.valueOf((String) parameterObj); + break; + + case Types.BIGINT: + numberParam = Long.valueOf((String) parameterObj); + break; + + case Types.REAL: + numberParam = Float.valueOf((String) parameterObj); + break; + + case Types.FLOAT: + case Types.DOUBLE: + numberParam = Double.valueOf((String) parameterObj); + break; + + case Types.DECIMAL: + case Types.NUMERIC: + default: + numberParam = new java.math.BigDecimal((String) parameterObj); + } + } else { + numberParam = (Number) parameterObj; + } + switch (targetSqlType) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + setInt(parameterIndex, numberParam.intValue()); + break; + + case Types.BIGINT: + setLong(parameterIndex, numberParam.longValue()); + break; + + case Types.REAL: + setFloat(parameterIndex, numberParam.floatValue()); + break; + + case Types.FLOAT: + case Types.DOUBLE: + setDouble(parameterIndex, numberParam.doubleValue()); + break; + + case Types.DECIMAL: + case Types.NUMERIC: + + if (numberParam instanceof java.math.BigDecimal) { + BigDecimal scaledBigDecimal; + try { + scaledBigDecimal = ((java.math.BigDecimal) numberParam).setScale(scale); + } catch (ArithmeticException ex) { + try { + scaledBigDecimal = ((java.math.BigDecimal) numberParam) + .setScale(scale, BigDecimal.ROUND_HALF_UP); + } catch (ArithmeticException arEx) { + throw new SQLException( + "Can't set the scale of '" + scale + "' for Decimal Argument" + numberParam); } + } + setBigDecimal(parameterIndex, scaledBigDecimal); + } else if (numberParam instanceof java.math.BigInteger) { + setBigInteger(parameterIndex, (BigInteger) numberParam); } else { - numberParam = (Number) parameterObj; - } - switch (targetSqlType) { - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - setInt(parameterIndex, numberParam.intValue()); - break; - - case Types.BIGINT: - setLong(parameterIndex, numberParam.longValue()); - break; - - case Types.REAL: - setFloat(parameterIndex, numberParam.floatValue()); - break; - - case Types.FLOAT: - case Types.DOUBLE: - setDouble(parameterIndex, numberParam.doubleValue()); - break; - - case Types.DECIMAL: - case Types.NUMERIC: - - if (numberParam instanceof java.math.BigDecimal) { - BigDecimal scaledBigDecimal; - try { - scaledBigDecimal = ((java.math.BigDecimal) numberParam).setScale(scale); - } catch (ArithmeticException ex) { - try { - scaledBigDecimal = ((java.math.BigDecimal) numberParam) - .setScale(scale, BigDecimal.ROUND_HALF_UP); - } catch (ArithmeticException arEx) { - throw new SQLException( - "Can't set the scale of '" + scale + "' for Decimal Argument" - + numberParam); - } - } - setBigDecimal(parameterIndex, scaledBigDecimal); - } else if (numberParam instanceof java.math.BigInteger) { - setBigInteger(parameterIndex, (BigInteger) numberParam); - } else { - setBigDecimal(parameterIndex, - new java.math.BigDecimal(numberParam.doubleValue())); - } - break; + setBigDecimal(parameterIndex, new java.math.BigDecimal(numberParam.doubleValue())); } + break; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java index f13a31d24fb..7c025010612 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java @@ -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. @@ -26,7 +26,6 @@ import io.vitess.util.Constants; import io.vitess.util.StringUtils; -import javax.sql.rowset.serial.SerialClob; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Reader; @@ -56,1555 +55,1554 @@ import java.util.List; import java.util.Map; +import javax.sql.rowset.serial.SerialClob; + /** * Created by harshit.gangal on 23/01/16. */ public class VitessResultSet implements ResultSet { - private Cursor cursor; - private List fields; - private VitessStatement vitessStatement; - private boolean closed = false; - private Row row; - private int currentRow; - private int maxRows; - private int fetchSize; - /** - * Last column name index read - */ - private int lastIndexRead = -1; - - public VitessResultSet(Cursor cursor) throws SQLException { - this(cursor, null); - } - - public VitessResultSet(Cursor cursor, VitessStatement vitessStatement) throws SQLException { - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); - } - - this.cursor = cursor; - this.vitessStatement = vitessStatement; - try { - this.fields = enhancedFieldsFromCursor(vitessStatement == null ? null : vitessStatement.getConnection()); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); - } - this.currentRow = 0; - if (null != vitessStatement) { - this.maxRows = vitessStatement.getMaxRows(); - this.fetchSize = vitessStatement.getFetchSize(); - } - } - - public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][] data, ConnectionProperties connection) - throws SQLException { - - if (columnNames.length != columnTypes.length) { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); - } - Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); - for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { - Query.Field.Builder queryField = - Query.Field.newBuilder().setName(columnNames[columnCounter]) - .setType(columnTypes[columnCounter]); - queryResultBuilder.addFields(queryField.build()); - } - if (null != data) { - for (String[] rowData : data) { - - Query.Row.Builder queryRow = Query.Row.newBuilder(); - StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); - } - queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); - queryResultBuilder.addRows(queryRow); - sb.delete(0, sb.length()); - } - } - this.cursor = new SimpleCursor(queryResultBuilder.build()); - this.vitessStatement = null; - try { - this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); - } - this.currentRow = 0; - } - - public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, - ArrayList> data, VitessConnection connection) throws SQLException { - - if (columnNames.length != columnTypes.length) { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); - } - Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); - for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { - Query.Field.Builder queryField = - Query.Field.newBuilder().setName(columnNames[columnCounter]) - .setType(columnTypes[columnCounter]); - queryResultBuilder.addFields(queryField.build()); - } - for (ArrayList rowData : data) { - - Query.Row.Builder queryRow = Query.Row.newBuilder(); - StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - if (null != aRowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); - } else { - queryRow.addLengths(-1); - } - } - queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); - queryResultBuilder.addRows(queryRow); - sb.delete(0, sb.length()); - } - this.cursor = new SimpleCursor(queryResultBuilder.build()); - this.vitessStatement = null; - try { - this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); - } - this.currentRow = 0; - } - - private List enhancedFieldsFromCursor(ConnectionProperties connection) throws SQLException { - if (cursor == null|| cursor.getFields() == null) { - throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); - } - List rawFields = cursor.getFields(); - List fields = new ArrayList<>(rawFields.size()); - for (Query.Field field : rawFields) { - fields.add(new FieldWithMetadata(connection, field)); - } - return fields; - } - - public boolean next() throws SQLException { - checkOpen(); - - if (this.maxRows > 0 && this.currentRow >= this.maxRows) { - return false; - } - - this.row = this.cursor.next(); - ++this.currentRow; - - return row != null; - } - - public void close() throws SQLException { - if (!this.closed) { - try { - this.cursor.close(); - } catch (Exception e) { - throw new SQLException(Constants.SQLExceptionMessages.VITESS_CURSOR_CLOSE_ERROR); - } finally { - //Dereferencing all the objects - this.closed = true; - this.cursor = null; - this.vitessStatement = null; - this.fields = null; - this.row = null; - } - } - } - - public boolean wasNull() throws SQLException { - checkOpen(); - if (this.lastIndexRead == -1) { - throw new SQLException(Constants.SQLExceptionMessages.NO_COLUMN_ACCESSED); - } - return this.row.wasNull(); - } - - public String getString(int columnIndex) throws SQLException { - Object object; - String columnValue; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - object = this.row.getObject(columnIndex); - if (object instanceof byte[]) { - FieldWithMetadata field = this.fields.get(columnIndex - 1); - if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields()) { - columnValue = convertBytesToString((byte[]) object, field.getEncoding()); - } else { - columnValue = new String((byte[]) object); - } + private Cursor cursor; + private List fields; + private VitessStatement vitessStatement; + private boolean closed = false; + private Row row; + private int currentRow; + private int maxRows; + private int fetchSize; + /** + * Last column name index read + */ + private int lastIndexRead = -1; + + public VitessResultSet(Cursor cursor) throws SQLException { + this(cursor, null); + } + + public VitessResultSet(Cursor cursor, VitessStatement vitessStatement) throws SQLException { + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); + } + + this.cursor = cursor; + this.vitessStatement = vitessStatement; + try { + this.fields = enhancedFieldsFromCursor( + vitessStatement == null ? null : vitessStatement.getConnection()); + } catch (SQLException e) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } + this.currentRow = 0; + if (null != vitessStatement) { + this.maxRows = vitessStatement.getMaxRows(); + this.fetchSize = vitessStatement.getFetchSize(); + } + } + + public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][] data, + ConnectionProperties connection) throws SQLException { + + if (columnNames.length != columnTypes.length) { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); + } + Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); + for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { + Query.Field.Builder queryField = Query.Field.newBuilder().setName(columnNames[columnCounter]) + .setType(columnTypes[columnCounter]); + queryResultBuilder.addFields(queryField.build()); + } + if (null != data) { + for (String[] rowData : data) { + + Query.Row.Builder queryRow = Query.Row.newBuilder(); + StringBuilder sb = new StringBuilder(); + for (String aRowData : rowData) { + sb.append(aRowData); + queryRow.addLengths(aRowData.length()); + } + queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); + queryResultBuilder.addRows(queryRow); + sb.delete(0, sb.length()); + } + } + this.cursor = new SimpleCursor(queryResultBuilder.build()); + this.vitessStatement = null; + try { + this.fields = enhancedFieldsFromCursor(connection); + } catch (SQLException e) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } + this.currentRow = 0; + } + + public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, + ArrayList> data, VitessConnection connection) throws SQLException { + + if (columnNames.length != columnTypes.length) { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); + } + Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); + for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { + Query.Field.Builder queryField = Query.Field.newBuilder().setName(columnNames[columnCounter]) + .setType(columnTypes[columnCounter]); + queryResultBuilder.addFields(queryField.build()); + } + for (ArrayList rowData : data) { + + Query.Row.Builder queryRow = Query.Row.newBuilder(); + StringBuilder sb = new StringBuilder(); + for (String aRowData : rowData) { + if (null != aRowData) { + sb.append(aRowData); + queryRow.addLengths(aRowData.length()); } else { - columnValue = String.valueOf(object); - } - return columnValue; - } - - public boolean getBoolean(int columnIndex) throws SQLException { - String boolString; - int bool; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return false; - } - - // Mysql 5.0 and higher have a BIT Data Type, need to check for this as well. - FieldWithMetadata field = this.fields.get(columnIndex - 1); - - if (field.getVitessTypeValue() == Query.Type.BIT_VALUE) { - return byteArrayToBoolean(columnIndex); - } - - boolString = this.getString(columnIndex); - try { - bool = Integer.valueOf(boolString); - } catch (NumberFormatException nfe) { - return null != boolString && "true".equalsIgnoreCase(boolString.trim()); - } - return bool > 0; + queryRow.addLengths(-1); + } + } + queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); + queryResultBuilder.addRows(queryRow); + sb.delete(0, sb.length()); + } + this.cursor = new SimpleCursor(queryResultBuilder.build()); + this.vitessStatement = null; + try { + this.fields = enhancedFieldsFromCursor(connection); + } catch (SQLException e) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } + this.currentRow = 0; + } + + private List enhancedFieldsFromCursor(ConnectionProperties connection) + throws SQLException { + if (cursor == null || cursor.getFields() == null) { + throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); + } + List rawFields = cursor.getFields(); + List fields = new ArrayList<>(rawFields.size()); + for (Query.Field field : rawFields) { + fields.add(new FieldWithMetadata(connection, field)); + } + return fields; + } + + public boolean next() throws SQLException { + checkOpen(); + + if (this.maxRows > 0 && this.currentRow >= this.maxRows) { + return false; + } + + this.row = this.cursor.next(); + ++this.currentRow; + + return row != null; + } + + public void close() throws SQLException { + if (!this.closed) { + try { + this.cursor.close(); + } catch (Exception e) { + throw new SQLException(Constants.SQLExceptionMessages.VITESS_CURSOR_CLOSE_ERROR); + } finally { + //Dereferencing all the objects + this.closed = true; + this.cursor = null; + this.vitessStatement = null; + this.fields = null; + this.row = null; + } } + } - public byte getByte(int columnIndex) throws SQLException { - String byteString; - byte value; - - preAccessor(columnIndex); - if (isNull(columnIndex)) { - return 0; - } - - //If the return column type is of byte, - // return byte otherwise typecast - Object object = this.row.getObject(columnIndex); - if (object instanceof Byte) { - return (byte) object; - } - - byteString = this.getString(columnIndex); - try { - value = Byte.parseByte(byteString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + public boolean wasNull() throws SQLException { + checkOpen(); + if (this.lastIndexRead == -1) { + throw new SQLException(Constants.SQLExceptionMessages.NO_COLUMN_ACCESSED); } + return this.row.wasNull(); + } - public short getShort(int columnIndex) throws SQLException { - String shortString; - short value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - shortString = this.getString(columnIndex); + public String getString(int columnIndex) throws SQLException { + Object object; + String columnValue; - try { - value = Short.parseShort(shortString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } + preAccessor(columnIndex); - return value; + if (isNull(columnIndex)) { + return null; } - public int getInt(int columnIndex) throws SQLException { - String intString; - int value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - intString = this.getString(columnIndex); - - try { - value = Integer.parseInt(intString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + object = this.row.getObject(columnIndex); + if (object instanceof byte[]) { + FieldWithMetadata field = this.fields.get(columnIndex - 1); + if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields()) { + columnValue = convertBytesToString((byte[]) object, field.getEncoding()); + } else { + columnValue = new String((byte[]) object); + } + } else { + columnValue = String.valueOf(object); } + return columnValue; + } - public long getLong(int columnIndex) throws SQLException { - String longString; - long value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - longString = this.getString(columnIndex); + public boolean getBoolean(int columnIndex) throws SQLException { + String boolString; + int bool; - try { - value = Long.parseLong(longString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } + preAccessor(columnIndex); - return value; + if (isNull(columnIndex)) { + return false; } - public float getFloat(int columnIndex) throws SQLException { - String floatString; - float value; + // Mysql 5.0 and higher have a BIT Data Type, need to check for this as well. + FieldWithMetadata field = this.fields.get(columnIndex - 1); - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - floatString = this.getString(columnIndex); - - try { - value = Float.parseFloat(floatString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + if (field.getVitessTypeValue() == Query.Type.BIT_VALUE) { + return byteArrayToBoolean(columnIndex); } - public double getDouble(int columnIndex) throws SQLException { - String doubleString; - double value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - doubleString = this.getString(columnIndex); - - try { - value = Double.parseDouble(doubleString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + boolString = this.getString(columnIndex); + try { + bool = Integer.valueOf(boolString); + } catch (NumberFormatException nfe) { + return null != boolString && "true".equalsIgnoreCase(boolString.trim()); } + return bool > 0; + } - public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { - String bigDecimalString; - BigDecimal value; + public byte getByte(int columnIndex) throws SQLException { + String byteString; + byte value; - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - bigDecimalString = this.getString(columnIndex); - - try { - value = new BigDecimal(bigDecimalString); - value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + preAccessor(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public BigInteger getBigInteger(int columnIndex) throws SQLException { - String bigIntegerString; - BigInteger value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - bigIntegerString = this.getString(columnIndex); - - try { - value = new BigInteger(bigIntegerString); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + //If the return column type is of byte, + // return byte otherwise typecast + Object object = this.row.getObject(columnIndex); + if (object instanceof Byte) { + return (byte) object; } - public byte[] getBytes(int columnIndex) throws SQLException { - String bytesString; - byte[] value; - - preAccessor(columnIndex); - if (isNull(columnIndex)) { - return null; - } - //If the return column type is of byte[], - // return byte[] otherwise typecast - Object object = this.row.getObject(columnIndex); - if (object instanceof byte[]) { - return (byte[]) object; - } - - bytesString = this.getString(columnIndex); - try { - value = bytesString.getBytes(); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + byteString = this.getString(columnIndex); + try { + value = Byte.parseByte(byteString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public Date getDate(int columnIndex) throws SQLException { - preAccessor(columnIndex); + return value; + } - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDate(columnIndex, nullDateTime, null); - } - - public Time getTime(int columnIndex) throws SQLException { - preAccessor(columnIndex); + public short getShort(int columnIndex) throws SQLException { + String shortString; + short value; - if (isNull(columnIndex)) { - return null; - } + preAccessor(columnIndex); - return this.row.getTime(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public Timestamp getTimestamp(int columnIndex) throws SQLException { - preAccessor(columnIndex); + shortString = this.getString(columnIndex); - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDateTime(columnIndex, nullDateTime, null); + try { + value = Short.parseShort(shortString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public String getString(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getString(columnIndex); - } + return value; + } - public boolean getBoolean(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBoolean(columnIndex); - } + public int getInt(int columnIndex) throws SQLException { + String intString; + int value; - public byte getByte(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getByte(columnIndex); - } + preAccessor(columnIndex); - public short getShort(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getShort(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public int getInt(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getInt(columnIndex); - } + intString = this.getString(columnIndex); - public long getLong(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getLong(columnIndex); + try { + value = Integer.parseInt(intString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public float getFloat(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getFloat(columnIndex); - } + return value; + } - public double getDouble(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getDouble(columnIndex); - } + public long getLong(int columnIndex) throws SQLException { + String longString; + long value; - public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBigDecimal(columnIndex, scale); - } + preAccessor(columnIndex); - public BigInteger getBigInteger(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBigInteger(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public byte[] getBytes(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBytes(columnIndex); - } + longString = this.getString(columnIndex); - public Date getDate(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getDate(columnIndex); + try { + value = Long.parseLong(longString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public Time getTime(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTime(columnIndex); - } + return value; + } - public Timestamp getTimestamp(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTimestamp(columnIndex); - } + public float getFloat(int columnIndex) throws SQLException { + String floatString; + float value; - public SQLWarning getWarnings() throws SQLException { - checkOpen(); - //no-op, All exceptions thrown, none kept as warning - return null; - } + preAccessor(columnIndex); - public void clearWarnings() throws SQLException { - checkOpen(); - //no-op, All exceptions thrown, none kept as warning + if (isNull(columnIndex)) { + return 0; } + floatString = this.getString(columnIndex); - public ResultSetMetaData getMetaData() throws SQLException { - return new VitessResultSetMetaData(fields); + try { + value = Float.parseFloat(floatString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public Object getObject(int columnIndex) throws SQLException { - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - Object retVal = this.row.getObject(columnIndex); + return value; + } - FieldWithMetadata field = this.fields.get(columnIndex - 1); - if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields() && retVal instanceof byte[]) { - retVal = convertBytesIfPossible((byte[]) retVal, field); - } + public double getDouble(int columnIndex) throws SQLException { + String doubleString; + double value; - return retVal; - } - - private Object convertBytesIfPossible(byte[] bytes, FieldWithMetadata field) throws SQLException { - String encoding = field.getEncoding(); - switch (field.getJavaType()) { - case Types.BIT: - if (!field.isSingleBit()) { - return bytes; - } - return byteArrayToBoolean(bytes); - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (!field.isOpaqueBinary()) { - return convertBytesToString(bytes, encoding); - } - return bytes; - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - return bytes; - default: - return convertBytesToString(bytes, encoding); - } - } + preAccessor(columnIndex); - private String convertBytesToString(byte[] bytes, String encoding) throws SQLException { - if (encoding == null) { - return StringUtils.toString(bytes); - } else { - try { - return StringUtils.toString(bytes, 0, bytes.length, encoding); - } catch (UnsupportedEncodingException e) { - throw new SQLException("Unsupported character encoding: " + encoding, e); - } - } + if (isNull(columnIndex)) { + return 0; } - public Object getObject(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getObject(columnIndex); - } + doubleString = this.getString(columnIndex); - public int findColumn(String columnLabel) throws SQLException { - return this.cursor.findColumn(columnLabel); + try { + value = Double.parseDouble(doubleString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - String bigDecimalString; - BigDecimal value; - - preAccessor(columnIndex); + return value; + } - if (isNull(columnIndex)) { - return null; - } + public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { + String bigDecimalString; + BigDecimal value; - bigDecimalString = this.getString(columnIndex); + preAccessor(columnIndex); - try { - value = new BigDecimal(bigDecimalString); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + if (isNull(columnIndex)) { + return null; } - public BigDecimal getBigDecimal(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBigDecimal(columnIndex); - } + bigDecimalString = this.getString(columnIndex); - public boolean isBeforeFirst() throws SQLException { - checkOpen(); - return this.currentRow == 0; + try { + value = new BigDecimal(bigDecimalString); + value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); + } catch (Exception ex) { + throw new SQLException(ex); } - public boolean isFirst() throws SQLException { - checkOpen(); - return currentRow == 1; - } + return value; + } - public int getRow() throws SQLException { - checkOpen(); - return this.currentRow; - } + public BigInteger getBigInteger(int columnIndex) throws SQLException { + String bigIntegerString; + BigInteger value; - public int getFetchDirection() throws SQLException { - checkOpen(); - return ResultSet.FETCH_FORWARD; - } + preAccessor(columnIndex); - public void setFetchDirection(int direction) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (isNull(columnIndex)) { + return null; } - public int getFetchSize() throws SQLException { - checkOpen(); - return this.fetchSize; - } + bigIntegerString = this.getString(columnIndex); - public void setFetchSize(int rows) throws SQLException { - checkOpen(); - if (rows < 0) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); - } - this.fetchSize = rows; + try { + value = new BigInteger(bigIntegerString); + } catch (Exception ex) { + throw new SQLException(ex); } - public int getType() throws SQLException { - checkOpen(); - return ResultSet.TYPE_FORWARD_ONLY; - } + return value; + } - public int getConcurrency() throws SQLException { - checkOpen(); - return ResultSet.CONCUR_READ_ONLY; - } + public byte[] getBytes(int columnIndex) throws SQLException { + String bytesString; + byte[] value; - public Statement getStatement() throws SQLException { - checkOpen(); - return this.vitessStatement; + preAccessor(columnIndex); + if (isNull(columnIndex)) { + return null; } - - public Date getDate(int columnIndex, Calendar cal) throws SQLException { - preAccessor(columnIndex); - - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDate(columnIndex, nullDateTime, cal); + //If the return column type is of byte[], + // return byte[] otherwise typecast + Object object = this.row.getObject(columnIndex); + if (object instanceof byte[]) { + return (byte[]) object; } - public Date getDate(String columnLabel, Calendar cal) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getDate(columnIndex, cal); + bytesString = this.getString(columnIndex); + try { + value = bytesString.getBytes(); + } catch (Exception ex) { + throw new SQLException(ex); } - public Time getTime(int columnIndex, Calendar cal) throws SQLException { - preAccessor(columnIndex); + return value; + } - if (isNull(columnIndex)) { - return null; - } + public Date getDate(int columnIndex) throws SQLException { + preAccessor(columnIndex); - return this.row.getTime(columnIndex, cal); - } - - public Time getTime(String columnLabel, Calendar cal) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTime(columnIndex, cal); - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDate(columnIndex, nullDateTime, null); + } - public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { - preAccessor(columnIndex); + public Time getTime(int columnIndex) throws SQLException { + preAccessor(columnIndex); - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDateTime(columnIndex, nullDateTime, cal); + if (isNull(columnIndex)) { + return null; } - public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTimestamp(columnIndex, cal); - } + return this.row.getTime(columnIndex); + } - public boolean isClosed() { - return this.closed; - } + public Timestamp getTimestamp(int columnIndex) throws SQLException { + preAccessor(columnIndex); - public T unwrap(Class iface) throws SQLException { - try { - return iface.cast(this); - } catch (ClassCastException cce) { - throw new SQLException( - Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), cce); - } - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDateTime(columnIndex, nullDateTime, null); + } - public boolean isWrapperFor(Class iface) throws SQLException { - checkOpen(); - return iface.isInstance(this); - } + public String getString(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getString(columnIndex); + } - private void checkOpen() throws SQLException { - if (closed) - throw new SQLException(Constants.SQLExceptionMessages.CLOSED_RESULT_SET); - } + public boolean getBoolean(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBoolean(columnIndex); + } - private void preAccessor(int columnIndex) throws SQLException { - checkOpen(); + public byte getByte(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getByte(columnIndex); + } - if (columnIndex < 1 || columnIndex > this.fields.size()) { - throw new SQLException( - Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); - } + public short getShort(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getShort(columnIndex); + } - // set last read column index for wasNull() - lastIndexRead = columnIndex; - } + public int getInt(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getInt(columnIndex); + } - protected enum NullDateTime { - NO_CHANGE, - NULL, - ROUND, - } + public long getLong(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getLong(columnIndex); + } - private NullDateTime getNullDateTime(int columnIndex) throws SQLException { - if (isNull(columnIndex)) { - return NullDateTime.NULL; - } + public float getFloat(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getFloat(columnIndex); + } - if (!hasZeroDateTimePrefix(columnIndex)) { - return NullDateTime.NO_CHANGE; - } + public double getDouble(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getDouble(columnIndex); + } - switch (this.vitessStatement.getConnection().getZeroDateTimeBehavior()) { - case CONVERTTONULL: - return NullDateTime.NULL; - case EXCEPTION: - throw new SQLException( - Constants.SQLExceptionMessages.ZERO_TIMESTAMP + ": " + columnIndex); - case ROUND: - return NullDateTime.ROUND; - case GARBLE: - default: - return NullDateTime.NO_CHANGE; - } - } + public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBigDecimal(columnIndex, scale); + } - private Date getNullableDate(int columnIndex, NullDateTime nullDateTime, Calendar cal) - throws SQLException { - switch (nullDateTime) { - case NULL: - return null; - case ROUND: - return new Date(-1900, 0, 1); - case NO_CHANGE: - default: - if (cal == null) { - return this.row.getDate(columnIndex); - } else { - return this.row.getDate(columnIndex, cal); - } - } - } + public BigInteger getBigInteger(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBigInteger(columnIndex); + } + + public byte[] getBytes(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBytes(columnIndex); + } - private Timestamp getNullableDateTime(int columnIndex, NullDateTime nullDateTime, Calendar cal) - throws SQLException { - switch (nullDateTime) { - case NULL: - return null; - case ROUND: - return new Timestamp(-1900, 0, 1, 0, 0, 0, 0); - case NO_CHANGE: - default: - if (cal == null) { - return this.row.getTimestamp(columnIndex); - } else { - return this.row.getTimestamp(columnIndex, cal); - } - } - } + public Date getDate(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getDate(columnIndex); + } - private boolean hasZeroDateTimePrefix(int columnIndex) throws SQLException { - return this.row.getRawValue(columnIndex).startsWith(Constants.ZERO_DATE_TIME_PREFIX); - } + public Time getTime(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTime(columnIndex); + } - private boolean isNull(int columnIndex) throws SQLException { - return null == this.row.getObject(columnIndex); - } + public Timestamp getTimestamp(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTimestamp(columnIndex); + } - //Unsupported Methods + public SQLWarning getWarnings() throws SQLException { + checkOpen(); + //no-op, All exceptions thrown, none kept as warning + return null; + } - public InputStream getAsciiStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public void clearWarnings() throws SQLException { + checkOpen(); + //no-op, All exceptions thrown, none kept as warning + } - public InputStream getUnicodeStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - public InputStream getBinaryStream(int columnIndex) throws SQLException { - preAccessor(columnIndex); - if (isNull(columnIndex)) { - return null; - } - FieldWithMetadata field = this.fields.get(columnIndex - 1); - switch (field.getJavaType()) { - case Types.BIT: - case Types.BINARY: - case Types.VARBINARY: - case Types.BLOB: - case Types.LONGVARBINARY: - return this.row.getBinaryInputStream(columnIndex); - } + public ResultSetMetaData getMetaData() throws SQLException { + return new VitessResultSetMetaData(fields); + } - byte[] bytes = getBytes(columnIndex); + public Object getObject(int columnIndex) throws SQLException { + preAccessor(columnIndex); + + if (isNull(columnIndex)) { + return null; + } + + Object retVal = this.row.getObject(columnIndex); + + FieldWithMetadata field = this.fields.get(columnIndex - 1); + if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields() + && retVal instanceof byte[]) { + retVal = convertBytesIfPossible((byte[]) retVal, field); + } + + return retVal; + } + + private Object convertBytesIfPossible(byte[] bytes, FieldWithMetadata field) throws SQLException { + String encoding = field.getEncoding(); + switch (field.getJavaType()) { + case Types.BIT: + if (!field.isSingleBit()) { + return bytes; + } + return byteArrayToBoolean(bytes); + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (!field.isOpaqueBinary()) { + return convertBytesToString(bytes, encoding); + } + return bytes; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + return bytes; + default: + return convertBytesToString(bytes, encoding); + } + } + + private String convertBytesToString(byte[] bytes, String encoding) throws SQLException { + if (encoding == null) { + return StringUtils.toString(bytes); + } else { + try { + return StringUtils.toString(bytes, 0, bytes.length, encoding); + } catch (UnsupportedEncodingException e) { + throw new SQLException("Unsupported character encoding: " + encoding, e); + } + } + } + + public Object getObject(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getObject(columnIndex); + } + + public int findColumn(String columnLabel) throws SQLException { + return this.cursor.findColumn(columnLabel); + } - if (bytes != null) { - return new ByteArrayInputStream(bytes); - } - return null; - } + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + String bigDecimalString; + BigDecimal value; - public InputStream getAsciiStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + preAccessor(columnIndex); - public InputStream getUnicodeStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (isNull(columnIndex)) { + return null; } - public InputStream getBinaryStream(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBinaryStream(columnIndex); - } + bigDecimalString = this.getString(columnIndex); - public String getCursorName() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + try { + value = new BigDecimal(bigDecimalString); + } catch (Exception ex) { + throw new SQLException(ex); } - public Reader getCharacterStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + return value; + } - public Reader getCharacterStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public BigDecimal getBigDecimal(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBigDecimal(columnIndex); + } - public boolean isAfterLast() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isBeforeFirst() throws SQLException { + checkOpen(); + return this.currentRow == 0; + } - public boolean isLast() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isFirst() throws SQLException { + checkOpen(); + return currentRow == 1; + } - public void beforeFirst() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getRow() throws SQLException { + checkOpen(); + return this.currentRow; + } - public void afterLast() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getFetchDirection() throws SQLException { + checkOpen(); + return ResultSet.FETCH_FORWARD; + } - public boolean first() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public void setFetchDirection(int direction) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - public boolean last() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + public int getFetchSize() throws SQLException { + checkOpen(); + return this.fetchSize; + } + + public void setFetchSize(int rows) throws SQLException { + checkOpen(); + if (rows < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); } + this.fetchSize = rows; + } - public boolean absolute(int row) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getType() throws SQLException { + checkOpen(); + return ResultSet.TYPE_FORWARD_ONLY; + } - public boolean relative(int rows) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getConcurrency() throws SQLException { + checkOpen(); + return ResultSet.CONCUR_READ_ONLY; + } - public boolean previous() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Statement getStatement() throws SQLException { + checkOpen(); + return this.vitessStatement; + } - public boolean rowUpdated() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + preAccessor(columnIndex); - public boolean rowInserted() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDate(columnIndex, nullDateTime, cal); + } - public boolean rowDeleted() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Date getDate(String columnLabel, Calendar cal) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getDate(columnIndex, cal); + } - public void updateNull(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + preAccessor(columnIndex); - public void updateBoolean(int columnIndex, boolean x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (isNull(columnIndex)) { + return null; } - public void updateByte(int columnIndex, byte x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateShort(int columnIndex, short x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + return this.row.getTime(columnIndex, cal); + } - public void updateInt(int columnIndex, int x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Time getTime(String columnLabel, Calendar cal) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTime(columnIndex, cal); + } - public void updateLong(int columnIndex, long x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + preAccessor(columnIndex); - public void updateFloat(int columnIndex, float x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDateTime(columnIndex, nullDateTime, cal); + } - public void updateDouble(int columnIndex, double x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTimestamp(columnIndex, cal); + } - public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isClosed() { + return this.closed; + } - public void updateString(int columnIndex, String x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException cce) { + throw new SQLException(Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), + cce); } + } - public void updateBytes(int columnIndex, byte[] x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isWrapperFor(Class iface) throws SQLException { + checkOpen(); + return iface.isInstance(this); + } - public void updateDate(int columnIndex, Date x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + private void checkOpen() throws SQLException { + if (closed) { + throw new SQLException(Constants.SQLExceptionMessages.CLOSED_RESULT_SET); } + } - public void updateTime(int columnIndex, Time x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + private void preAccessor(int columnIndex) throws SQLException { + checkOpen(); - public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (columnIndex < 1 || columnIndex > this.fields.size()) { + throw new SQLException( + Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); } - public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + // set last read column index for wasNull() + lastIndexRead = columnIndex; + } - public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + protected enum NullDateTime { + NO_CHANGE, NULL, ROUND, + } - public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + private NullDateTime getNullDateTime(int columnIndex) throws SQLException { + if (isNull(columnIndex)) { + return NullDateTime.NULL; } - public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (!hasZeroDateTimePrefix(columnIndex)) { + return NullDateTime.NO_CHANGE; } - public void updateObject(int columnIndex, Object x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + switch (this.vitessStatement.getConnection().getZeroDateTimeBehavior()) { + case CONVERTTONULL: + return NullDateTime.NULL; + case EXCEPTION: + throw new SQLException(Constants.SQLExceptionMessages.ZERO_TIMESTAMP + ": " + columnIndex); + case ROUND: + return NullDateTime.ROUND; + case GARBLE: + default: + return NullDateTime.NO_CHANGE; } + } - public void updateNull(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBoolean(String columnLabel, boolean x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateByte(String columnLabel, byte x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateShort(String columnLabel, short x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateInt(String columnLabel, int x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateLong(String columnLabel, long x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateFloat(String columnLabel, float x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateDouble(String columnLabel, double x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateString(String columnLabel, String x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBytes(String columnLabel, byte[] x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateDate(String columnLabel, Date x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateTime(String columnLabel, Time x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(String columnLabel, InputStream x, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(String columnLabel, InputStream x, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(String columnLabel, Reader reader, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateObject(String columnLabel, Object x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void insertRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void deleteRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void refreshRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void cancelRowUpdates() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void moveToInsertRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void moveToCurrentRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Object getObject(int columnIndex, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Ref getRef(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Blob getBlob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Clob getClob(int columnIndex) throws SQLException { - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; + private Date getNullableDate(int columnIndex, NullDateTime nullDateTime, Calendar cal) + throws SQLException { + switch (nullDateTime) { + case NULL: + return null; + case ROUND: + return new Date(-1900, 0, 1); + case NO_CHANGE: + default: + if (cal == null) { + return this.row.getDate(columnIndex); + } else { + return this.row.getDate(columnIndex, cal); } - - return new SerialClob(getString(columnIndex).toCharArray()); - } - - public Array getArray(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Object getObject(String columnLabel, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Ref getRef(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Blob getBlob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Clob getClob(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getClob(columnIndex); - } - - public Array getArray(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public URL getURL(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public URL getURL(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } + } - public void updateRef(int columnIndex, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRef(String columnLabel, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(int columnIndex, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(String columnLabel, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(int columnIndex, Clob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(String columnLabel, Clob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateArray(int columnIndex, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateArray(String columnLabel, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public RowId getRowId(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public RowId getRowId(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRowId(int columnIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRowId(String columnLabel, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getHoldability() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNString(int columnIndex, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNString(String columnLabel, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(int columnIndex, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(String columnLabel, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public NClob getNClob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public NClob getNClob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public SQLXML getSQLXML(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public SQLXML getSQLXML(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public String getNString(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public String getNString(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Reader getNCharacterStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Reader getNCharacterStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(String columnLabel, Reader reader, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(int columnIndex, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(String columnLabel, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(String columnLabel, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(String columnLabel, Reader reader, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(int columnIndex, InputStream inputStream, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(String columnLabel, InputStream inputStream, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public T getObject(int columnIndex, Class type) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public T getObject(String columnLabel, Class type) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - @VisibleForTesting - List getFields() { - return fields; - } - - private boolean byteArrayToBoolean(int columnIndex) throws SQLException { - return byteArrayToBoolean(this.row.getObject(columnIndex)); - } - - private boolean byteArrayToBoolean(Object value) { - if (value == null) { - return false; - } - - if (((byte[]) value).length == 0) { - return false; - } - - byte boolVal = ((byte[]) value)[0]; - - if (boolVal == (byte) '1') { - return true; - } else if (boolVal == (byte) '0') { - return false; - } - - return (boolVal == -1 || boolVal > 0); + private Timestamp getNullableDateTime(int columnIndex, NullDateTime nullDateTime, Calendar cal) + throws SQLException { + switch (nullDateTime) { + case NULL: + return null; + case ROUND: + return new Timestamp(-1900, 0, 1, 0, 0, 0, 0); + case NO_CHANGE: + default: + if (cal == null) { + return this.row.getTimestamp(columnIndex); + } else { + return this.row.getTimestamp(columnIndex, cal); + } } + } + + private boolean hasZeroDateTimePrefix(int columnIndex) throws SQLException { + return this.row.getRawValue(columnIndex).startsWith(Constants.ZERO_DATE_TIME_PREFIX); + } + + private boolean isNull(int columnIndex) throws SQLException { + return null == this.row.getObject(columnIndex); + } + + //Unsupported Methods + + public InputStream getAsciiStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getBinaryStream(int columnIndex) throws SQLException { + preAccessor(columnIndex); + if (isNull(columnIndex)) { + return null; + } + FieldWithMetadata field = this.fields.get(columnIndex - 1); + switch (field.getJavaType()) { + case Types.BIT: + case Types.BINARY: + case Types.VARBINARY: + case Types.BLOB: + case Types.LONGVARBINARY: + return this.row.getBinaryInputStream(columnIndex); + } + + byte[] bytes = getBytes(columnIndex); + + if (bytes != null) { + return new ByteArrayInputStream(bytes); + } + return null; + } + + public InputStream getAsciiStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getUnicodeStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getBinaryStream(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBinaryStream(columnIndex); + } + + public String getCursorName() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getCharacterStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getCharacterStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isAfterLast() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isLast() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void beforeFirst() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void afterLast() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean first() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean last() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean absolute(int row) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean relative(int rows) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean previous() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean rowUpdated() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean rowInserted() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean rowDeleted() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNull(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateByte(int columnIndex, byte x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateShort(int columnIndex, short x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateInt(int columnIndex, int x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateLong(int columnIndex, long x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateFloat(int columnIndex, float x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDouble(int columnIndex, double x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateString(int columnIndex, String x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBytes(int columnIndex, byte[] x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDate(int columnIndex, Date x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTime(int columnIndex, Time x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(int columnIndex, Object x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNull(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBoolean(String columnLabel, boolean x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateByte(String columnLabel, byte x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateShort(String columnLabel, short x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateInt(String columnLabel, int x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateLong(String columnLabel, long x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateFloat(String columnLabel, float x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDouble(String columnLabel, double x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateString(String columnLabel, String x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBytes(String columnLabel, byte[] x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDate(String columnLabel, Date x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTime(String columnLabel, Time x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(String columnLabel, InputStream x, int length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(String columnLabel, Reader reader, int length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(String columnLabel, Object x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void insertRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void deleteRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void refreshRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void cancelRowUpdates() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void moveToInsertRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void moveToCurrentRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Object getObject(int columnIndex, Map> map) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Ref getRef(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Blob getBlob(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Clob getClob(int columnIndex) throws SQLException { + preAccessor(columnIndex); + + if (isNull(columnIndex)) { + return null; + } + + return new SerialClob(getString(columnIndex).toCharArray()); + } + + public Array getArray(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Object getObject(String columnLabel, Map> map) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Ref getRef(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Blob getBlob(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Clob getClob(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getClob(columnIndex); + } + + public Array getArray(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public URL getURL(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public URL getURL(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRef(int columnIndex, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRef(String columnLabel, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(int columnIndex, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(String columnLabel, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(int columnIndex, Clob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(String columnLabel, Clob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateArray(int columnIndex, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateArray(String columnLabel, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public RowId getRowId(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public RowId getRowId(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRowId(int columnIndex, RowId x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRowId(String columnLabel, RowId x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getHoldability() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNString(int columnIndex, String nString) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNString(String columnLabel, String nString) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(String columnLabel, NClob nClob) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public NClob getNClob(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public NClob getNClob(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public SQLXML getSQLXML(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public SQLXML getSQLXML(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public String getNString(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public String getNString(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getNCharacterStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getNCharacterStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(String columnLabel, Reader reader, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(String columnLabel, InputStream x, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(String columnLabel, InputStream x, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(String columnLabel, Reader reader, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(int columnIndex, InputStream inputStream, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(String columnLabel, InputStream inputStream, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(int columnIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(int columnIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public T getObject(int columnIndex, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public T getObject(String columnLabel, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + @VisibleForTesting + List getFields() { + return fields; + } + + private boolean byteArrayToBoolean(int columnIndex) throws SQLException { + return byteArrayToBoolean(this.row.getObject(columnIndex)); + } + + private boolean byteArrayToBoolean(Object value) { + if (value == null) { + return false; + } + + if (((byte[]) value).length == 0) { + return false; + } + + byte boolVal = ((byte[]) value)[0]; + + if (boolVal == (byte) '1') { + return true; + } else if (boolVal == (byte) '0') { + return false; + } + + return (boolVal == -1 || boolVal > 0); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java index 8eddb40752f..93a260ebab5 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java @@ -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. @@ -33,363 +33,364 @@ */ public class VitessResultSetMetaData implements ResultSetMetaData { - /* Get actual class name to be printed on */ - private static Logger logger = Logger.getLogger(VitessResultSetMetaData.class.getName()); - private List fields; - - public VitessResultSetMetaData(List fields) throws SQLException { - this.fields = ImmutableList.copyOf(fields); - } - - public int getColumnCount() throws SQLException { - return fields.size(); - } - - public boolean isAutoIncrement(int column) throws SQLException { - return getField(column).isAutoIncrement(); - } - - public boolean isCaseSensitive(int column) throws SQLException { - FieldWithMetadata field = getField(column); - switch (field.getJavaType()) { - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.DATE: - case Types.DECIMAL: - case Types.NUMERIC: - case Types.TIME: - case Types.TIMESTAMP: - return false; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (field.isBinary() || !field.getConnectionProperties().isIncludeAllFields()) { - return true; - } - try { - String collationName = field.getCollation(); - return collationName != null && !collationName.endsWith("_ci"); - } catch (SQLException e) { - if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { - return false; - } else { - throw e; - } - } - default: - return true; - } - } - - public boolean isSearchable(int column) throws SQLException { - return true; - } - - public boolean isCurrency(int column) throws SQLException { + /* Get actual class name to be printed on */ + private static Logger logger = Logger.getLogger(VitessResultSetMetaData.class.getName()); + private List fields; + + public VitessResultSetMetaData(List fields) throws SQLException { + this.fields = ImmutableList.copyOf(fields); + } + + public int getColumnCount() throws SQLException { + return fields.size(); + } + + public boolean isAutoIncrement(int column) throws SQLException { + return getField(column).isAutoIncrement(); + } + + public boolean isCaseSensitive(int column) throws SQLException { + FieldWithMetadata field = getField(column); + switch (field.getJavaType()) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.DATE: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.TIME: + case Types.TIMESTAMP: return false; - } - - /** - * Indicates the nullability of values in the designated column. - * - * @param column the first column is 1, the second is 2, ... - * @return the nullability status of the given column; one of columnNoNulls, - * columnNullable or columnNullableUnknown - * @exception SQLException if a database access error occurs - */ - public int isNullable(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return ResultSetMetaData.columnNullableUnknown; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (field.isBinary() || !field.getConnectionProperties().isIncludeAllFields()) { + return true; } - return field.isNotNull() ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable; - } - - public boolean isSigned(int column) throws SQLException { - return getField(column).isSigned(); - } - - public int getColumnDisplaySize(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return 0; + try { + String collationName = field.getCollation(); + return collationName != null && !collationName.endsWith("_ci"); + } catch (SQLException e) { + if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { + return false; + } else { + throw e; + } } - // If we can't find a charset, we'll return 0. In that case assume 1 byte per char - return field.getColumnLength() / Math.max(field.getMaxBytesPerCharacter(), 1); + default: + return true; } - - public String getColumnLabel(int column) throws SQLException { - return getField(column).getName(); + } + + public boolean isSearchable(int column) throws SQLException { + return true; + } + + public boolean isCurrency(int column) throws SQLException { + return false; + } + + /** + * Indicates the nullability of values in the designated column. + * + * @param column the first column is 1, the second is 2, ... + * @return the nullability status of the given column; one of columnNoNulls, + * columnNullable or columnNullableUnknown + * @throws SQLException if a database access error occurs + */ + public int isNullable(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return ResultSetMetaData.columnNullableUnknown; } + return field.isNotNull() ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable; + } - public String getColumnName(int column) throws SQLException { - return getField(column).getName(); - } + public boolean isSigned(int column) throws SQLException { + return getField(column).isSigned(); + } - public String getSchemaName(int column) throws SQLException { - return getField(column).getDatabase(); + public int getColumnDisplaySize(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return 0; } - - public int getPrecision(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return 0; - } - if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { - return field.getColumnLength() + field.getPrecisionAdjustFactor(); - } - switch (field.getJavaType()) { - case Types.VARBINARY: - case Types.LONGVARBINARY: - return field.getColumnLength(); - default: - return field.getColumnLength() / field.getMaxBytesPerCharacter(); - } + // If we can't find a charset, we'll return 0. In that case assume 1 byte per char + return field.getColumnLength() / Math.max(field.getMaxBytesPerCharacter(), 1); + } + + public String getColumnLabel(int column) throws SQLException { + return getField(column).getName(); + } + + public String getColumnName(int column) throws SQLException { + return getField(column).getName(); + } + + public String getSchemaName(int column) throws SQLException { + return getField(column).getDatabase(); + } + + public int getPrecision(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return 0; } - - private static boolean isDecimalType(int javaType, int vitessType) { - switch (javaType) { - case Types.BIT: - case Types.TINYINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.NUMERIC: - case Types.DECIMAL: - return true; - case Types.SMALLINT: - return vitessType != Query.Type.YEAR_VALUE; - default: - return false; - } + if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { + return field.getColumnLength() + field.getPrecisionAdjustFactor(); } - - public int getScale(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { - return getField(column).getDecimals(); - } - return 0; + switch (field.getJavaType()) { + case Types.VARBINARY: + case Types.LONGVARBINARY: + return field.getColumnLength(); + default: + return field.getColumnLength() / field.getMaxBytesPerCharacter(); } - - public String getTableName(int column) throws SQLException { - return getField(column).getTable(); + } + + private static boolean isDecimalType(int javaType, int vitessType) { + switch (javaType) { + case Types.BIT: + case Types.TINYINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.NUMERIC: + case Types.DECIMAL: + return true; + case Types.SMALLINT: + return vitessType != Query.Type.YEAR_VALUE; + default: + return false; } + } - public String getCatalogName(int column) throws SQLException { - return getField(column).getDatabase(); + public int getScale(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { + return getField(column).getDecimals(); } + return 0; + } - public int getColumnType(int column) throws SQLException { - return getField(column).getJavaType(); - } + public String getTableName(int column) throws SQLException { + return getField(column).getTable(); + } - public String getColumnTypeName(int column) throws SQLException { - FieldWithMetadata field = getField(column); + public String getCatalogName(int column) throws SQLException { + return getField(column).getDatabase(); + } - int vitessTypeValue = field.getVitessTypeValue(); - int javaType = field.getJavaType(); + public int getColumnType(int column) throws SQLException { + return getField(column).getJavaType(); + } - switch (vitessTypeValue) { - case Query.Type.BIT_VALUE: - return "BIT"; + public String getColumnTypeName(int column) throws SQLException { + FieldWithMetadata field = getField(column); - case Query.Type.DECIMAL_VALUE: - return "DECIMAL"; + int vitessTypeValue = field.getVitessTypeValue(); + int javaType = field.getJavaType(); - case Query.Type.INT8_VALUE: - return "TINYINT"; - case Query.Type.UINT8_VALUE: - return "TINYINT UNSIGNED"; + switch (vitessTypeValue) { + case Query.Type.BIT_VALUE: + return "BIT"; - case Query.Type.INT16_VALUE: - return "SMALLINT"; - case Query.Type.UINT16_VALUE: - return "SMALLINT UNSIGNED"; + case Query.Type.DECIMAL_VALUE: + return "DECIMAL"; - case Query.Type.INT24_VALUE: - return "MEDIUMINT"; - case Query.Type.UINT24_VALUE: - return "MEDIUMINT UNSIGNED"; + case Query.Type.INT8_VALUE: + return "TINYINT"; + case Query.Type.UINT8_VALUE: + return "TINYINT UNSIGNED"; - case Query.Type.INT32_VALUE: - return "INT"; - case Query.Type.UINT32_VALUE: - return "INT UNSIGNED"; + case Query.Type.INT16_VALUE: + return "SMALLINT"; + case Query.Type.UINT16_VALUE: + return "SMALLINT UNSIGNED"; - case Query.Type.INT64_VALUE: - return "BIGINT"; - case Query.Type.UINT64_VALUE: - return "BIGINT UNSIGNED"; + case Query.Type.INT24_VALUE: + return "MEDIUMINT"; + case Query.Type.UINT24_VALUE: + return "MEDIUMINT UNSIGNED"; - case Query.Type.FLOAT32_VALUE: - return "FLOAT"; + case Query.Type.INT32_VALUE: + return "INT"; + case Query.Type.UINT32_VALUE: + return "INT UNSIGNED"; - case Query.Type.FLOAT64_VALUE: - return "DOUBLE"; + case Query.Type.INT64_VALUE: + return "BIGINT"; + case Query.Type.UINT64_VALUE: + return "BIGINT UNSIGNED"; - case Query.Type.NULL_TYPE_VALUE: - return "NULL"; + case Query.Type.FLOAT32_VALUE: + return "FLOAT"; - case Query.Type.TIMESTAMP_VALUE: - return "TIMESTAMP"; + case Query.Type.FLOAT64_VALUE: + return "DOUBLE"; - case Query.Type.DATE_VALUE: - return "DATE"; + case Query.Type.NULL_TYPE_VALUE: + return "NULL"; - case Query.Type.TIME_VALUE: - return "TIME"; + case Query.Type.TIMESTAMP_VALUE: + return "TIMESTAMP"; - case Query.Type.DATETIME_VALUE: - return "DATETIME"; + case Query.Type.DATE_VALUE: + return "DATE"; - case Query.Type.BLOB_VALUE: - return "BLOB"; + case Query.Type.TIME_VALUE: + return "TIME"; - case Query.Type.TEXT_VALUE: - return "TEXT"; + case Query.Type.DATETIME_VALUE: + return "DATETIME"; - case Query.Type.VARCHAR_VALUE: - return "VARCHAR"; + case Query.Type.BLOB_VALUE: + return "BLOB"; - case Query.Type.VARBINARY_VALUE: - if (javaType == Types.VARBINARY) { - return "VARBINARY"; - } - return "VARCHAR"; + case Query.Type.TEXT_VALUE: + return "TEXT"; - case Query.Type.BINARY_VALUE: - if (javaType == Types.BINARY) { - return "BINARY"; - } - return "CHAR"; + case Query.Type.VARCHAR_VALUE: + return "VARCHAR"; - case Query.Type.CHAR_VALUE: - return "CHAR"; + case Query.Type.VARBINARY_VALUE: + if (javaType == Types.VARBINARY) { + return "VARBINARY"; + } + return "VARCHAR"; - case Query.Type.ENUM_VALUE: - return "ENUM"; + case Query.Type.BINARY_VALUE: + if (javaType == Types.BINARY) { + return "BINARY"; + } + return "CHAR"; - case Query.Type.YEAR_VALUE: - return "YEAR"; + case Query.Type.CHAR_VALUE: + return "CHAR"; - case Query.Type.SET_VALUE: - return "SET"; + case Query.Type.ENUM_VALUE: + return "ENUM"; - case Query.Type.TUPLE_VALUE: - return "TUPLE"; + case Query.Type.YEAR_VALUE: + return "YEAR"; - default: - return "UNKNOWN"; - } - } + case Query.Type.SET_VALUE: + return "SET"; - public boolean isReadOnly(int column) throws SQLException { - return getField(column).isReadOnly(); - } + case Query.Type.TUPLE_VALUE: + return "TUPLE"; - public boolean isWritable(int column) throws SQLException { - return !isReadOnly(column); + default: + return "UNKNOWN"; } + } - public boolean isDefinitelyWritable(int column) throws SQLException { - return isWritable(column); - } + public boolean isReadOnly(int column) throws SQLException { + return getField(column).isReadOnly(); + } - public String getColumnClassName(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return null; - } - return getClassNameForJavaType(field.getJavaType(), field.getVitessTypeValue(), field.isUnsigned(), - field.isBinary() || field.isBlob(), field.isOpaqueBinary(), field.getConnectionProperties().getYearIsDateType()); - } + public boolean isWritable(int column) throws SQLException { + return !isReadOnly(column); + } - public T unwrap(Class iface) throws SQLException { - return null; - } + public boolean isDefinitelyWritable(int column) throws SQLException { + return isWritable(column); + } - public boolean isWrapperFor(Class iface) throws SQLException { - return false; + public String getColumnClassName(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return null; } - - private FieldWithMetadata getField(int columnIndex) throws SQLException { - if (columnIndex >= 1 && columnIndex <= this.fields.size()) { - return fields.get(columnIndex - 1); - } else { - throw new SQLException( - Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); - } + return getClassNameForJavaType(field.getJavaType(), field.getVitessTypeValue(), + field.isUnsigned(), field.isBinary() || field.isBlob(), field.isOpaqueBinary(), + field.getConnectionProperties().getYearIsDateType()); + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + private FieldWithMetadata getField(int columnIndex) throws SQLException { + if (columnIndex >= 1 && columnIndex <= this.fields.size()) { + return fields.get(columnIndex - 1); + } else { + throw new SQLException( + Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); } - - private String getClassNameForJavaType(int javaType, int vitessType, boolean isUnsigned, boolean isBinaryOrBlob, boolean isOpaqueBinary, - boolean treatYearAsDate) { - switch (javaType) { - case Types.BIT: - case Types.BOOLEAN: - return "java.lang.Boolean"; - case Types.TINYINT: - if (isUnsigned) { - return "java.lang.Integer"; - } - return "java.lang.Integer"; - case Types.SMALLINT: - if (vitessType == Query.Type.YEAR_VALUE) { - return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; - } - if (isUnsigned) { - return "java.lang.Integer"; - } - return "java.lang.Integer"; - case Types.INTEGER: - if (!isUnsigned || vitessType == Query.Type.UINT24_VALUE) { - return "java.lang.Integer"; - } - return "java.lang.Long"; - case Types.BIGINT: - if (!isUnsigned) { - return "java.lang.Long"; - } - return "java.math.BigInteger"; - case Types.DECIMAL: - case Types.NUMERIC: - return "java.math.BigDecimal"; - case Types.REAL: - return "java.lang.Float"; - case Types.FLOAT: - case Types.DOUBLE: - return "java.lang.Double"; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (!isOpaqueBinary) { - return "java.lang.String"; - } - return "[B"; - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - if (isBinaryOrBlob) { - return "[B"; - } else { - return "java.lang.String"; - } - case Types.DATE: - return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; - case Types.TIME: - return "java.sql.Time"; - case Types.TIMESTAMP: - return "java.sql.Timestamp"; - default: - return "java.lang.Object"; + } + + private String getClassNameForJavaType(int javaType, int vitessType, boolean isUnsigned, + boolean isBinaryOrBlob, boolean isOpaqueBinary, boolean treatYearAsDate) { + switch (javaType) { + case Types.BIT: + case Types.BOOLEAN: + return "java.lang.Boolean"; + case Types.TINYINT: + if (isUnsigned) { + return "java.lang.Integer"; + } + return "java.lang.Integer"; + case Types.SMALLINT: + if (vitessType == Query.Type.YEAR_VALUE) { + return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; + } + if (isUnsigned) { + return "java.lang.Integer"; + } + return "java.lang.Integer"; + case Types.INTEGER: + if (!isUnsigned || vitessType == Query.Type.UINT24_VALUE) { + return "java.lang.Integer"; + } + return "java.lang.Long"; + case Types.BIGINT: + if (!isUnsigned) { + return "java.lang.Long"; + } + return "java.math.BigInteger"; + case Types.DECIMAL: + case Types.NUMERIC: + return "java.math.BigDecimal"; + case Types.REAL: + return "java.lang.Float"; + case Types.FLOAT: + case Types.DOUBLE: + return "java.lang.Double"; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (!isOpaqueBinary) { + return "java.lang.String"; + } + return "[B"; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + if (isBinaryOrBlob) { + return "[B"; + } else { + return "java.lang.String"; } + case Types.DATE: + return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; + case Types.TIME: + return "java.sql.Time"; + case Types.TIMESTAMP: + return "java.sql.Timestamp"; + default: + return "java.lang.Object"; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java index bde82e6f01e..de76f81038d 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java @@ -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. @@ -39,176 +39,169 @@ * Created by harshit.gangal on 19/01/16. *

* This class expects an sql query to be provided when a call to DB is made by the method: - * execute(sql), executeQuery(sql), executeUpdate(sql). - * When executeBatch() is called, the sql is not required; - * instead all the queries to be executed must be added via the addBatch(sql) method. - * In all the cases, once a method is called, - * no reference of the query/queries provided is/are kept. + * execute(sql), executeQuery(sql), executeUpdate(sql). When executeBatch() is called, the sql is + * not required; instead all the queries to be executed must be added via the addBatch(sql) method. + * In all the cases, once a method is called, no reference of the query/queries provided is/are + * kept. */ public class VitessStatement implements Statement { - protected static final String[] ON_DUPLICATE_KEY_UPDATE_CLAUSE = new String[] { "ON", "DUPLICATE", "KEY", "UPDATE" }; - protected VitessResultSet vitessResultSet; - protected VitessConnection vitessConnection; - protected boolean closed; - protected long resultCount; - protected long queryTimeoutInMillis; - protected int maxFieldSize = Constants.MAX_BUFFER_SIZE; - protected int maxRows = 0; - protected int fetchSize = 0; - protected int resultSetConcurrency; - protected int resultSetType; - protected boolean retrieveGeneratedKeys = false; - protected long generatedId = -1; - protected long[][] batchGeneratedKeys; - /** - * Holds batched commands - */ - private List batchedArgs; - - - public VitessStatement(VitessConnection vitessConnection) { - this(vitessConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - } - - public VitessStatement(VitessConnection vitessConnection, int resultSetType, - int resultSetConcurrency) { - this.vitessConnection = vitessConnection; - this.queryTimeoutInMillis = vitessConnection.getTimeout(); - this.vitessResultSet = null; - this.resultSetType = resultSetType; - this.resultSetConcurrency = resultSetConcurrency; - this.closed = false; - this.resultCount = -1; - this.vitessConnection.registerStatement(this); - this.batchedArgs = new ArrayList<>(); - this.batchGeneratedKeys = null; - } - - /** - * To execute an Select/Show Statement - * - * @param sql - SQL Query - * @return ResultSet - * @throws SQLException - */ - public ResultSet executeQuery(String sql) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - - checkOpen(); - checkSQLNullOrEmpty(sql); - closeOpenResultSetAndResetCount(); - - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - - //Setting to default value - this.retrieveGeneratedKeys = false; - this.generatedId = -1; - - vtGateConn = this.vitessConnection.getVtGateConn(); - - if ((vitessConnection.isSimpleExecute() && this.fetchSize == 0) || vitessConnection.isInTransaction()) { - checkAndBeginTransaction(); - Context context = - this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); - } else { - /* Stream query is not suppose to run in a txn. */ - Context context = - this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.streamExecute(context, sql, null, vitessConnection.getVtSession()); - } - - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } - this.vitessResultSet = new VitessResultSet(cursor, this); - return this.vitessResultSet; - } - - /** - * To execute a DML statement - * - * @param sql - SQL Query - * @return Rows Affected Count - * @throws SQLException - */ - public int executeUpdate(String sql) throws SQLException { - return executeUpdate(sql, Statement.NO_GENERATED_KEYS); - } - - /** - * To Execute Unknown Statement - * - * @param sql - * @return - * @throws SQLException - */ - public boolean execute(String sql) throws SQLException { - return execute(sql, Statement.NO_GENERATED_KEYS); - } - - /** - * To get the resultSet generated - * - * @return ResultSet - * @throws SQLException - */ - public ResultSet getResultSet() throws SQLException { - checkOpen(); - return this.vitessResultSet; - } - - public int getUpdateCount() throws SQLException { - int truncatedUpdateCount; - - checkOpen(); + protected static final String[] ON_DUPLICATE_KEY_UPDATE_CLAUSE = new String[]{"ON", "DUPLICATE", + "KEY", "UPDATE"}; + protected VitessResultSet vitessResultSet; + protected VitessConnection vitessConnection; + protected boolean closed; + protected long resultCount; + protected long queryTimeoutInMillis; + protected int maxFieldSize = Constants.MAX_BUFFER_SIZE; + protected int maxRows = 0; + protected int fetchSize = 0; + protected int resultSetConcurrency; + protected int resultSetType; + protected boolean retrieveGeneratedKeys = false; + protected long generatedId = -1; + protected long[][] batchGeneratedKeys; + /** + * Holds batched commands + */ + private List batchedArgs; + + + public VitessStatement(VitessConnection vitessConnection) { + this(vitessConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } + + public VitessStatement(VitessConnection vitessConnection, int resultSetType, + int resultSetConcurrency) { + this.vitessConnection = vitessConnection; + this.queryTimeoutInMillis = vitessConnection.getTimeout(); + this.vitessResultSet = null; + this.resultSetType = resultSetType; + this.resultSetConcurrency = resultSetConcurrency; + this.closed = false; + this.resultCount = -1; + this.vitessConnection.registerStatement(this); + this.batchedArgs = new ArrayList<>(); + this.batchGeneratedKeys = null; + } + + /** + * To execute an Select/Show Statement + * + * @param sql - SQL Query + * @return ResultSet + */ + public ResultSet executeQuery(String sql) throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + + checkOpen(); + checkSQLNullOrEmpty(sql); + closeOpenResultSetAndResetCount(); + + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + + //Setting to default value + this.retrieveGeneratedKeys = false; + this.generatedId = -1; + + vtGateConn = this.vitessConnection.getVtGateConn(); + + if ((vitessConnection.isSimpleExecute() && this.fetchSize == 0) || vitessConnection + .isInTransaction()) { + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); + } else { + /* Stream query is not suppose to run in a txn. */ + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn.streamExecute(context, sql, null, vitessConnection.getVtSession()); + } + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + this.vitessResultSet = new VitessResultSet(cursor, this); + return this.vitessResultSet; + } + + /** + * To execute a DML statement + * + * @param sql - SQL Query + * @return Rows Affected Count + */ + public int executeUpdate(String sql) throws SQLException { + return executeUpdate(sql, Statement.NO_GENERATED_KEYS); + } + + /** + * To Execute Unknown Statement + */ + public boolean execute(String sql) throws SQLException { + return execute(sql, Statement.NO_GENERATED_KEYS); + } + + /** + * To get the resultSet generated + * + * @return ResultSet + */ + public ResultSet getResultSet() throws SQLException { + checkOpen(); + return this.vitessResultSet; + } + + public int getUpdateCount() throws SQLException { + int truncatedUpdateCount; + + checkOpen(); + + if (null != this.vitessResultSet) { + return -1; + } + + if (this.resultCount > Integer.MAX_VALUE) { + truncatedUpdateCount = Integer.MAX_VALUE; + } else { + truncatedUpdateCount = (int) this.resultCount; + } + return truncatedUpdateCount; + } + + public void close() throws SQLException { + SQLException postponedSQLException = null; + + if (!this.closed) { + if (null != this.vitessConnection) { + this.vitessConnection.unregisterStatement(this); + } + try { if (null != this.vitessResultSet) { - return -1; + this.vitessResultSet.close(); } + } catch (SQLException ex) { + postponedSQLException = ex; + } - if (this.resultCount > Integer.MAX_VALUE) { - truncatedUpdateCount = Integer.MAX_VALUE; - } else { - truncatedUpdateCount = (int) this.resultCount; - } - return truncatedUpdateCount; - } - - public void close() throws SQLException { - SQLException postponedSQLException = null; - - if (!this.closed) { - if (null != this.vitessConnection) { - this.vitessConnection.unregisterStatement(this); - } - try { - if (null != this.vitessResultSet) { - this.vitessResultSet.close(); - } - } catch (SQLException ex) { - postponedSQLException = ex; - } - - this.vitessConnection = null; - this.vitessResultSet = null; - this.closed = true; + this.vitessConnection = null; + this.vitessResultSet = null; + this.closed = true; - if (null != postponedSQLException) { - throw postponedSQLException; - } - } + if (null != postponedSQLException) { + throw postponedSQLException; + } } + } - public int getMaxFieldSize() throws SQLException { - checkOpen(); - return this.maxFieldSize; - } + public int getMaxFieldSize() throws SQLException { + checkOpen(); + return this.maxFieldSize; + } - public void setMaxFieldSize(int max) throws SQLException { + public void setMaxFieldSize(int max) throws SQLException { /* Currently not used checkOpen(); if (max < 0 || max > Constants.MAX_BUFFER_SIZE) { @@ -217,527 +210,510 @@ public void setMaxFieldSize(int max) throws SQLException { } this.maxFieldSize = max; */ - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getMaxRows() throws SQLException { - checkOpen(); - return this.maxRows; - } - - public void setMaxRows(int max) throws SQLException { - checkOpen(); - if (max < 0) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max row"); - } - this.maxRows = max; - } - - public int getQueryTimeout() throws SQLException { - checkOpen(); - return (int) (this.queryTimeoutInMillis / 1000); - } - - public void setQueryTimeout(int seconds) throws SQLException { - checkOpen(); - if (seconds < 0) { - throw new SQLException( - Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "query timeout"); + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getMaxRows() throws SQLException { + checkOpen(); + return this.maxRows; + } + + public void setMaxRows(int max) throws SQLException { + checkOpen(); + if (max < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max row"); + } + this.maxRows = max; + } + + public int getQueryTimeout() throws SQLException { + checkOpen(); + return (int) (this.queryTimeoutInMillis / 1000); + } + + public void setQueryTimeout(int seconds) throws SQLException { + checkOpen(); + if (seconds < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "query timeout"); + } + this.queryTimeoutInMillis = + (0 == seconds) ? vitessConnection.getTimeout() : (long) seconds * 1000; + } + + /** + * Return Warnings + *

+ * Not implementing as Error is Thrown when occurred + * + * @return SQLWarning or null + */ + public SQLWarning getWarnings() throws SQLException { + checkOpen(); + return null; + } + + /** + * Clear the warnings - Not saving Warnings + */ + public void clearWarnings() { + //no-op + } + + public void setCursorName(String name) throws SQLException { + checkOpen(); + } + + public int getFetchDirection() throws SQLException { + checkOpen(); + return ResultSet.FETCH_FORWARD; + } + + public void setFetchDirection(int direction) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getFetchSize() throws SQLException { + checkOpen(); + return this.fetchSize; + } + + public void setFetchSize(int rows) throws SQLException { + checkOpen(); + if (rows < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); + } + this.fetchSize = rows; + } + + public int getResultSetConcurrency() throws SQLException { + checkOpen(); + return this.resultSetConcurrency; + } + + public int getResultSetType() throws SQLException { + checkOpen(); + return this.resultSetType; + } + + public VitessConnection getConnection() throws SQLException { + checkOpen(); + return vitessConnection; + } + + public boolean isClosed() { + return this.closed; + } + + /** + * Unwrap a class + * + * @param iface - A Class defining an interface that the result must implement. + * @param - the type of the class modeled by this Class object + * @return an object that implements the interface. May be a proxy for the actual implementing + * object. + */ + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException cce) { + throw new SQLException(Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), + cce); + } + } + + /** + * Checking Wrapper + * + * @param iface - A Class defining an interface that the result must implement. + * @return true if this implements the interface or directly or indirectly wraps an object that + * does. + */ + public boolean isWrapperFor(Class iface) throws SQLException { + checkOpen(); + return iface.isInstance(this); + } + + /** + * + */ + public ResultSet getGeneratedKeys() throws SQLException { + checkOpen(); + if (!this.retrieveGeneratedKeys) { + throw new SQLException(Constants.SQLExceptionMessages.GENERATED_KEYS_NOT_REQUESTED); + } + + String[] columnNames = new String[1]; + columnNames[0] = "GENERATED_KEY"; + Query.Type[] columnTypes = new Query.Type[1]; + columnTypes[0] = Query.Type.UINT64; + String[][] data = null; + + if (this.generatedId > 0) { + // This is as per Mysql JDBC Driver. + // As the actual count of generated value is not known, + // only the rows affected is known, so using firstInsertId all the auto_inc values + // are generated. As per Vitess Config, the increment value is 1 and not changeable. + data = new String[(int) this.resultCount][1]; + for (int i = 0; i < this.resultCount; ++i) { + data[i][0] = String.valueOf(this.generatedId + i); + } + } else if (this.batchGeneratedKeys != null) { + long totalAffected = 0; + for (long[] batchGeneratedKey : this.batchGeneratedKeys) { + long rowsAffected = batchGeneratedKey[1]; + totalAffected += rowsAffected; + } + data = new String[(int) totalAffected][1]; + int idx = 0; + for (long[] batchGeneratedKey : this.batchGeneratedKeys) { + long insertId = batchGeneratedKey[0]; + long rowsAffected = batchGeneratedKey[1]; + for (int j = 0; j < rowsAffected; j++) { + data[idx++][0] = String.valueOf(insertId + j); } - this.queryTimeoutInMillis = - (0 == seconds) ? vitessConnection.getTimeout() : (long) seconds * 1000; - } - - /** - * Return Warnings - *

- * Not implementing as Error is Thrown when occurred - * - * @return SQLWarning or null - * @throws SQLException - */ - public SQLWarning getWarnings() throws SQLException { - checkOpen(); - return null; - } - - /** - * Clear the warnings - Not saving Warnings - * - */ - public void clearWarnings() { - //no-op - } - - public void setCursorName(String name) throws SQLException { - checkOpen(); - } - - public int getFetchDirection() throws SQLException { - checkOpen(); - return ResultSet.FETCH_FORWARD; - } - - public void setFetchDirection(int direction) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getFetchSize() throws SQLException { - checkOpen(); - return this.fetchSize; - } - - public void setFetchSize(int rows) throws SQLException { - checkOpen(); - if (rows < 0) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); - } - this.fetchSize = rows; - } - - public int getResultSetConcurrency() throws SQLException { - checkOpen(); - return this.resultSetConcurrency; - } - - public int getResultSetType() throws SQLException { - checkOpen(); - return this.resultSetType; - } - - public VitessConnection getConnection() throws SQLException { - checkOpen(); - return vitessConnection; - } - - public boolean isClosed() { - return this.closed; - } - - /** - * Unwrap a class - * - * @param iface - A Class defining an interface that the result must implement. - * @param - the type of the class modeled by this Class object - * @return an object that implements the interface. May be a proxy for the actual implementing object. - * @throws SQLException - */ - public T unwrap(Class iface) throws SQLException { + } + } + return new VitessResultSet(columnNames, columnTypes, data, this.vitessConnection); + } + + /** + * To execute DML statement + * + * @param sql - SQL Query + * @param autoGeneratedKeys - Flag for generated Keys + * @return Row Affected Count + */ + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + int truncatedUpdateCount; + + checkOpen(); + checkNotReadOnly(); + checkSQLNullOrEmpty(sql); + closeOpenResultSetAndResetCount(); + + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + + vtGateConn = this.vitessConnection.getVtGateConn(); + + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { + throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); + } + + if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { + this.retrieveGeneratedKeys = true; + this.generatedId = cursor.getInsertId(); + } else { + this.retrieveGeneratedKeys = false; + this.generatedId = -1; + } + + this.resultCount = cursor.getRowsAffected(); + + if (this.resultCount > Integer.MAX_VALUE) { + truncatedUpdateCount = Integer.MAX_VALUE; + } else { + truncatedUpdateCount = (int) this.resultCount; + } + + return truncatedUpdateCount; + } + + /** + * To execute Unknown Statement + * + * @param sql - SQL Query + * @param autoGeneratedKeys - Flag for generated Keys + * @return - true if the first result is a ResultSet object; + * false if it is an update count or there are no results + */ + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + checkOpen(); + checkSQLNullOrEmpty(sql); + closeOpenResultSetAndResetCount(); + + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + if (!maybeSelect(sql)) { + this.executeUpdate(sql, autoGeneratedKeys); + return false; + } else { + this.executeQuery(sql); + return true; + } + } + + /** + * Add the query in the batch. + */ + public void addBatch(String sql) throws SQLException { + checkOpen(); + checkSQLNullOrEmpty(sql); + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + this.batchedArgs.add(sql); + } + + /** + * Clear all the queries batched. + */ + public void clearBatch() throws SQLException { + checkOpen(); + this.batchedArgs.clear(); + } + + /** + * Submits a batch of commands to the database for execution and if all commands execute + * successfully, returns an array of update counts. The array returned is according to the order + * in which they were added to the batch. + *

+ * If one of the commands in a batch update fails to execute properly, this method throws a + * BatchUpdateException, and a JDBC driver may or may not continue to process the + * remaining commands in the batch. If the driver continues processing after a failure, the array + * returned by the method BatchUpdateException.getUpdateCounts will contain as many + * elements as there are commands in the batch. + * + * @return int[] of results corresponding to each command + */ + public int[] executeBatch() throws SQLException { + checkOpen(); + checkNotReadOnly(); + VTGateConnection vtGateConn; + List cursorWithErrorList; + + if (0 == batchedArgs.size()) { + return new int[0]; + } + + try { + vtGateConn = this.vitessConnection.getVtGateConn(); + + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursorWithErrorList = vtGateConn + .executeBatch(context, batchedArgs, null, vitessConnection.getVtSession()).checkedGet(); + + if (null == cursorWithErrorList) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + this.retrieveGeneratedKeys = true;// mimicking mysql-connector-j + return this.generateBatchUpdateResult(cursorWithErrorList, batchedArgs); + } finally { + this.clearBatch(); + } + } + + // Internal Methods Created + + + protected void closeOpenResultSetAndResetCount() throws SQLException { + try { + if (null != this.vitessResultSet) { + this.vitessResultSet.close(); + } + } catch (SQLException ex) { + throw new SQLException(ex); + } finally { + this.vitessResultSet = null; + this.resultCount = -1; + } + } + + protected void checkOpen() throws SQLException { + if (closed) { + throw new SQLException(Constants.SQLExceptionMessages.STMT_CLOSED); + } + } + + protected void checkNotReadOnly() throws SQLException { + if (vitessConnection.isReadOnly()) { + throw new SQLException(Constants.SQLExceptionMessages.READ_ONLY); + } + } + + protected void checkSQLNullOrEmpty(String sql) throws SQLException { + if (StringUtils.isNullOrEmptyWithoutWS(sql)) { + throw new SQLException(Constants.SQLExceptionMessages.SQL_EMPTY); + } + } + + /** + * This method returns the updateCounts array containing the status for each query sent in the + * batch. If any of the query does return success. It throws a BatchUpdateException. + * + * @param cursorWithErrorList Consists list of Cursor and Error object. + * @param batchedArgs holds batched commands + * @return int[] of results corresponding to each query + */ + protected int[] generateBatchUpdateResult(List cursorWithErrorList, + List batchedArgs) throws BatchUpdateException { + int[] updateCounts = new int[cursorWithErrorList.size()]; + ArrayList generatedKeys = new ArrayList<>(); + + Vtrpc.RPCError rpcError = null; + String batchCommand = null; + CursorWithError cursorWithError = null; + for (int i = 0; i < cursorWithErrorList.size(); i++) { + cursorWithError = cursorWithErrorList.get(i); + batchCommand = batchedArgs.get(i); + if (null == cursorWithError.getError()) { try { - return iface.cast(this); - } catch (ClassCastException cce) { - throw new SQLException( - Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), cce); - } - } - - /** - * Checking Wrapper - * - * @param iface - A Class defining an interface that the result must implement. - * @return true if this implements the interface or directly or indirectly wraps an object that does. - * @throws SQLException - */ - public boolean isWrapperFor(Class iface) throws SQLException { - checkOpen(); - return iface.isInstance(this); - } - - /** - * @return - * @throws SQLException - */ - public ResultSet getGeneratedKeys() throws SQLException { - checkOpen(); - if (!this.retrieveGeneratedKeys) { - throw new SQLException(Constants.SQLExceptionMessages.GENERATED_KEYS_NOT_REQUESTED); - } - - String[] columnNames = new String[1]; - columnNames[0] = "GENERATED_KEY"; - Query.Type[] columnTypes = new Query.Type[1]; - columnTypes[0] = Query.Type.UINT64; - String[][] data = null; - - if (this.generatedId > 0) { - // This is as per Mysql JDBC Driver. - // As the actual count of generated value is not known, - // only the rows affected is known, so using firstInsertId all the auto_inc values - // are generated. As per Vitess Config, the increment value is 1 and not changeable. - data = new String[(int) this.resultCount][1]; - for (int i = 0; i < this.resultCount; ++i) { - data[i][0] = String.valueOf(this.generatedId + i); - } - } else if (this.batchGeneratedKeys != null) { - long totalAffected = 0; - for (long[] batchGeneratedKey : this.batchGeneratedKeys) { - long rowsAffected = batchGeneratedKey[1]; - totalAffected += rowsAffected; - } - data = new String[(int) totalAffected][1]; - int idx = 0; - for (long[] batchGeneratedKey : this.batchGeneratedKeys) { - long insertId = batchGeneratedKey[0]; - long rowsAffected = batchGeneratedKey[1]; - for (int j = 0; j < rowsAffected; j++) { - data[idx++][0] = String.valueOf(insertId + j); - } - } - } - return new VitessResultSet(columnNames, columnTypes, data, this.vitessConnection); - } - - /** - * To execute DML statement - * - * @param sql - SQL Query - * @param autoGeneratedKeys - Flag for generated Keys - * @return Row Affected Count - * @throws SQLException - */ - public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; - - checkOpen(); - checkNotReadOnly(); - checkSQLNullOrEmpty(sql); - closeOpenResultSetAndResetCount(); - - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - - vtGateConn = this.vitessConnection.getVtGateConn(); - - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); - - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } - - if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { - throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); - } - - if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { - this.retrieveGeneratedKeys = true; - this.generatedId = cursor.getInsertId(); - } else { - this.retrieveGeneratedKeys = false; - this.generatedId = -1; - } - - this.resultCount = cursor.getRowsAffected(); - - if (this.resultCount > Integer.MAX_VALUE) { + long rowsAffected = cursorWithError.getCursor().getRowsAffected(); + int truncatedUpdateCount; + boolean queryBatchUpsert = false; + if (rowsAffected > Integer.MAX_VALUE) { truncatedUpdateCount = Integer.MAX_VALUE; - } else { - truncatedUpdateCount = (int) this.resultCount; - } - - return truncatedUpdateCount; - } - - /** - * To execute Unknown Statement - * - * @param sql - SQL Query - * @param autoGeneratedKeys - Flag for generated Keys - * @return - true if the first result is a ResultSet - * object; false if it is an update count or there are - * no results - * @throws SQLException - */ - public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - checkOpen(); - checkSQLNullOrEmpty(sql); - closeOpenResultSetAndResetCount(); - - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - if (!maybeSelect(sql)) { - this.executeUpdate(sql, autoGeneratedKeys); - return false; - } else { - this.executeQuery(sql); - return true; - } - } - - /** - * Add the query in the batch. - * - * @param sql - * @throws SQLException - */ - public void addBatch(String sql) throws SQLException { - checkOpen(); - checkSQLNullOrEmpty(sql); - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - this.batchedArgs.add(sql); - } - - /** - * Clear all the queries batched. - * - * @throws SQLException - */ - public void clearBatch() throws SQLException { - checkOpen(); - this.batchedArgs.clear(); - } - - /** - * Submits a batch of commands to the database for execution and - * if all commands execute successfully, returns an array of update counts. - * The array returned is according to the order in which they were added to the batch. - *

- * If one of the commands in a batch update fails to execute properly, - * this method throws a BatchUpdateException, and a JDBC - * driver may or may not continue to process the remaining commands in - * the batch. If the driver continues processing after a failure, - * the array returned by the method BatchUpdateException.getUpdateCounts - * will contain as many elements as there are commands in the batch. - * - * @return int[] of results corresponding to each command - * @throws SQLException - */ - public int[] executeBatch() throws SQLException { - checkOpen(); - checkNotReadOnly(); - VTGateConnection vtGateConn; - List cursorWithErrorList; - - if(0 == batchedArgs.size()) { - return new int[0]; - } - - try { - vtGateConn = this.vitessConnection.getVtGateConn(); - - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursorWithErrorList = - vtGateConn.executeBatch(context, batchedArgs, null, vitessConnection.getVtSession()).checkedGet(); - - if (null == cursorWithErrorList) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } - - this.retrieveGeneratedKeys = true;// mimicking mysql-connector-j - return this.generateBatchUpdateResult(cursorWithErrorList, batchedArgs); - } finally { - this.clearBatch(); - } - } - - // Internal Methods Created - - - protected void closeOpenResultSetAndResetCount() throws SQLException { - try { - if (null != this.vitessResultSet) { - this.vitessResultSet.close(); - } - } catch (SQLException ex) { - throw new SQLException(ex); - } finally { - this.vitessResultSet = null; - this.resultCount = -1; - } - } - - protected void checkOpen() throws SQLException { - if (closed) { - throw new SQLException(Constants.SQLExceptionMessages.STMT_CLOSED); - } - } - - protected void checkNotReadOnly() throws SQLException { - if (vitessConnection.isReadOnly()) { - throw new SQLException(Constants.SQLExceptionMessages.READ_ONLY); - } - } - - protected void checkSQLNullOrEmpty(String sql) throws SQLException { - if (StringUtils.isNullOrEmptyWithoutWS(sql)) { - throw new SQLException(Constants.SQLExceptionMessages.SQL_EMPTY); - } - } - - /** - * This method returns the updateCounts array containing the status for each query - * sent in the batch. If any of the query does return success. - * It throws a BatchUpdateException. - * - * @param cursorWithErrorList Consists list of Cursor and Error object. - * @param batchedArgs holds batched commands - * @return int[] of results corresponding to each query - * @throws BatchUpdateException - */ - protected int[] generateBatchUpdateResult(List cursorWithErrorList, List batchedArgs) - throws BatchUpdateException { - int[] updateCounts = new int[cursorWithErrorList.size()]; - ArrayList generatedKeys = new ArrayList<>(); - - Vtrpc.RPCError rpcError = null; - String batchCommand = null; - CursorWithError cursorWithError = null; - for (int i = 0; i < cursorWithErrorList.size(); i++) { - cursorWithError = cursorWithErrorList.get(i); - batchCommand = batchedArgs.get(i); - if (null == cursorWithError.getError()) { - try { - long rowsAffected = cursorWithError.getCursor().getRowsAffected(); - int truncatedUpdateCount; - boolean queryBatchUpsert = false; - if (rowsAffected > Integer.MAX_VALUE) { - truncatedUpdateCount = Integer.MAX_VALUE; - } else { - if (sqlIsUpsert(batchCommand)) { - // mimicking mysql-connector-j here. - // but it would fail for: insert into t1 values ('a'), ('b') on duplicate key update ts = now(); - truncatedUpdateCount = 1; - queryBatchUpsert = true; - } else { - truncatedUpdateCount = (int) rowsAffected; - } - } - updateCounts[i] = truncatedUpdateCount; - long insertId = cursorWithError.getCursor().getInsertId(); - if (this.retrieveGeneratedKeys && (!queryBatchUpsert || insertId > 0)) { - generatedKeys.add(new long[]{insertId, truncatedUpdateCount}); - } - } catch (SQLException ex) { - /* This case should not happen as API has returned cursor and not error. - * Handling by Statement.SUCCESS_NO_INFO - */ - updateCounts[i] = Statement.SUCCESS_NO_INFO; - if (this.retrieveGeneratedKeys) { - generatedKeys.add(new long[]{Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}); - } - } + } else { + if (sqlIsUpsert(batchCommand)) { + // mimicking mysql-connector-j here. + // but it would fail for: insert into t1 values ('a'), ('b') on duplicate key + // update ts = now(); + truncatedUpdateCount = 1; + queryBatchUpsert = true; } else { - rpcError = cursorWithError.getError(); - updateCounts[i] = Statement.EXECUTE_FAILED; - if (this.retrieveGeneratedKeys) { - generatedKeys.add(new long[]{Statement.EXECUTE_FAILED, Statement.EXECUTE_FAILED}); - } + truncatedUpdateCount = (int) rowsAffected; } + } + updateCounts[i] = truncatedUpdateCount; + long insertId = cursorWithError.getCursor().getInsertId(); + if (this.retrieveGeneratedKeys && (!queryBatchUpsert || insertId > 0)) { + generatedKeys.add(new long[]{insertId, truncatedUpdateCount}); + } + } catch (SQLException ex) { + /* This case should not happen as API has returned cursor and not error. + * Handling by Statement.SUCCESS_NO_INFO + */ + updateCounts[i] = Statement.SUCCESS_NO_INFO; + if (this.retrieveGeneratedKeys) { + generatedKeys.add(new long[]{Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}); + } } - - if (null != rpcError) { - int errno = Proto.getErrno(rpcError.getMessage()); - String sqlState = Proto.getSQLState(rpcError.getMessage()); - throw new BatchUpdateException(rpcError.toString(), sqlState, errno, updateCounts); - } + } else { + rpcError = cursorWithError.getError(); + updateCounts[i] = Statement.EXECUTE_FAILED; if (this.retrieveGeneratedKeys) { - this.batchGeneratedKeys = generatedKeys.toArray(new long[generatedKeys.size()][2]); - } - return updateCounts; - } - - private boolean sqlIsUpsert(String sql) { - return StringUtils.indexOfIgnoreCase(0, sql, ON_DUPLICATE_KEY_UPDATE_CLAUSE, "\"'`", "\"'`", StringUtils.SEARCH_MODE__ALL) != -1; - } - - protected boolean maybeSelect(String sql) { - char firstNonWsCharOfQuery = StringUtils.firstAlphaCharUc(sql, StringUtils.findStartOfStatement(sql)); - return firstNonWsCharOfQuery == 'S'; - } - - protected void checkAndBeginTransaction() throws SQLException { - if (!(this.vitessConnection.getAutoCommit() || this.vitessConnection.isInTransaction())) { - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); - vtGateConn.execute(context,"begin",null,this.vitessConnection.getVtSession()).checkedGet(); + generatedKeys.add(new long[]{Statement.EXECUTE_FAILED, Statement.EXECUTE_FAILED}); } - } - - //Unsupported Methods - - /** - * Not Required to be implemented as More Results are handled in next() call - * - * @throws SQLException - */ - public boolean getMoreResults() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * Not Required to be implemented as More Results are handled in next() call - * - * @throws SQLException - */ - public boolean getMoreResults(int current) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setEscapeProcessing(boolean enable) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void cancel() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int executeUpdate(String sql, String[] columnNames) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean execute(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean execute(String sql, String[] columnNames) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getResultSetHoldability() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean isPoolable() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setPoolable(boolean poolable) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void closeOnCompletion() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean isCloseOnCompletion() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + } + } + + if (null != rpcError) { + int errno = Proto.getErrno(rpcError.getMessage()); + String sqlState = Proto.getSQLState(rpcError.getMessage()); + throw new BatchUpdateException(rpcError.toString(), sqlState, errno, updateCounts); + } + if (this.retrieveGeneratedKeys) { + this.batchGeneratedKeys = generatedKeys.toArray(new long[generatedKeys.size()][2]); + } + return updateCounts; + } + + private boolean sqlIsUpsert(String sql) { + return StringUtils.indexOfIgnoreCase(0, sql, ON_DUPLICATE_KEY_UPDATE_CLAUSE, "\"'`", "\"'`", + StringUtils.SEARCH_MODE__ALL) != -1; + } + + protected boolean maybeSelect(String sql) { + char firstNonWsCharOfQuery = StringUtils + .firstAlphaCharUc(sql, StringUtils.findStartOfStatement(sql)); + return firstNonWsCharOfQuery == 'S'; + } + + protected void checkAndBeginTransaction() throws SQLException { + if (!(this.vitessConnection.getAutoCommit() || this.vitessConnection.isInTransaction())) { + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + vtGateConn.execute(context, "begin", null, this.vitessConnection.getVtSession()).checkedGet(); + } + } + + //Unsupported Methods + + /** + * Not Required to be implemented as More Results are handled in next() call + */ + public boolean getMoreResults() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * Not Required to be implemented as More Results are handled in next() call + */ + public boolean getMoreResults(int current) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void cancel() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int executeUpdate(String sql, String[] columnNames) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean execute(String sql, int[] columnIndexes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean execute(String sql, String[] columnNames) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getResultSetHoldability() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isPoolable() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setPoolable(boolean poolable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void closeOnCompletion() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isCloseOnCompletion() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java index b9047d2a8c9..6a5b496ee16 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java @@ -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. @@ -41,204 +41,200 @@ * Created by naveen.nahata on 24/02/16. */ public class VitessVTGateManager { - private static Logger logger = Logger.getLogger(VitessVTGateManager.class.getName()); - /* - Current implementation have one VTGateConn for ip-port-username combination - */ - private static ConcurrentHashMap vtGateConnHashMap = - new ConcurrentHashMap<>(); - private static Timer vtgateConnRefreshTimer = null; - private static Timer vtgateClosureTimer = null; - private static long vtgateClosureDelaySeconds = 0L; + + private static Logger logger = Logger.getLogger(VitessVTGateManager.class.getName()); + /* + Current implementation have one VTGateConn for ip-port-username combination + */ + private static ConcurrentHashMap vtGateConnHashMap = + new ConcurrentHashMap<>(); + private static Timer vtgateConnRefreshTimer = null; + private static Timer vtgateClosureTimer = null; + private static long vtgateClosureDelaySeconds = 0L; + + /** + * VTGateConnections object consist of vtGateIdentifire list and return vtGate object in round + * robin. + */ + public static class VTGateConnections { + + private List vtGateIdentifiers = new ArrayList<>(); + int counter; /** - * VTGateConnections object consist of vtGateIdentifire list and return vtGate object in round robin. + * Constructor */ - public static class VTGateConnections { - private List vtGateIdentifiers = new ArrayList<>(); - int counter; - - /** - * Constructor - * - * @param connection - */ - public VTGateConnections(final VitessConnection connection) { - maybeStartClosureTimer(connection); - for (final VitessJDBCUrl.HostInfo hostInfo : connection.getUrl().getHostInfos()) { - String identifier = getIdentifer(hostInfo.getHostname(), hostInfo.getPort(), connection.getUsername(), connection.getTarget()); - synchronized (VitessVTGateManager.class) { - if (!vtGateConnHashMap.containsKey(identifier)) { - updateVtGateConnHashMap(identifier, hostInfo, connection); - } - if (connection.getUseSSL() && connection.getRefreshConnection() && vtgateConnRefreshTimer == null) { - logger.info("ssl vtgate connection detected -- installing connection refresh based on ssl keystore modification"); - vtgateConnRefreshTimer = new Timer("ssl-refresh-vtgate-conn", true); - vtgateConnRefreshTimer.scheduleAtFixedRate( - new TimerTask() { - @Override - public void run() { - refreshUpdatedSSLConnections(hostInfo, connection); - } - }, - TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds()), - TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds())); - } - } - vtGateIdentifiers.add(identifier); - } - Random random = new Random(); - counter = random.nextInt(vtGateIdentifiers.size()); - } - - /** - * Return VTGate Instance object. - * - * @return - */ - public VTGateConnection getVtGateConnInstance() { - counter++; - counter = counter % vtGateIdentifiers.size(); - return vtGateConnHashMap.get(vtGateIdentifiers.get(counter)); - } - - } - - private static void maybeStartClosureTimer(VitessConnection connection) { - if (connection.getRefreshClosureDelayed() && vtgateClosureTimer == null) { - synchronized (VitessVTGateManager.class) { - if (vtgateClosureTimer == null) { - vtgateClosureTimer = new Timer("vtgate-conn-closure", true); - vtgateClosureDelaySeconds = connection.getRefreshClosureDelaySeconds(); - } - } + public VTGateConnections(final VitessConnection connection) { + maybeStartClosureTimer(connection); + for (final VitessJDBCUrl.HostInfo hostInfo : connection.getUrl().getHostInfos()) { + String identifier = getIdentifer(hostInfo.getHostname(), hostInfo.getPort(), + connection.getUsername(), connection.getTarget()); + synchronized (VitessVTGateManager.class) { + if (!vtGateConnHashMap.containsKey(identifier)) { + updateVtGateConnHashMap(identifier, hostInfo, connection); + } + if (connection.getUseSSL() && connection.getRefreshConnection() + && vtgateConnRefreshTimer == null) { + logger.info( + "ssl vtgate connection detected -- installing connection refresh based on ssl " + + "keystore modification"); + vtgateConnRefreshTimer = new Timer("ssl-refresh-vtgate-conn", true); + vtgateConnRefreshTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + refreshUpdatedSSLConnections(hostInfo, connection); + } + }, TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds()), + TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds())); + } } - } - - private static String getIdentifer(String hostname, int port, String userIdentifer, String keyspace) { - return (hostname + port + userIdentifer + keyspace); + vtGateIdentifiers.add(identifier); + } + Random random = new Random(); + counter = random.nextInt(vtGateIdentifiers.size()); } /** - * Create VTGateConn and update vtGateConnHashMap. - * - * @param identifier - * @param hostInfo - * @param connection + * Return VTGate Instance object. */ - private static void updateVtGateConnHashMap(String identifier, VitessJDBCUrl.HostInfo hostInfo, - VitessConnection connection) { - vtGateConnHashMap.put(identifier, getVtGateConn(hostInfo, connection)); + public VTGateConnection getVtGateConnInstance() { + counter++; + counter = counter % vtGateIdentifiers.size(); + return vtGateConnHashMap.get(vtGateIdentifiers.get(counter)); } - private static void refreshUpdatedSSLConnections(VitessJDBCUrl.HostInfo hostInfo, VitessConnection connection) { - synchronized (VitessVTGateManager.class) { - int updatedCount = 0; - for (Map.Entry entry : vtGateConnHashMap.entrySet()) { - if (entry.getValue() instanceof RefreshableVTGateConnection) { - RefreshableVTGateConnection existing = (RefreshableVTGateConnection) entry.getValue(); - if (existing.checkKeystoreUpdates()) { - updatedCount++; - VTGateConnection old = vtGateConnHashMap.replace(entry.getKey(), getVtGateConn(hostInfo, connection)); - closeRefreshedConnection(old); - } - } - } - if (updatedCount > 0) { - logger.info("refreshed " + updatedCount + " vtgate connections due to keystore update"); - } - } - } + } - private static void closeRefreshedConnection(final VTGateConnection old) { - if (vtgateClosureTimer != null) { - logger.info(String.format("%s Closing connection with a %s second delay", old, vtgateClosureDelaySeconds)); - vtgateClosureTimer.schedule(new TimerTask() { - @Override - public void run() { - actuallyCloseRefreshedConnection(old); - } - }, - TimeUnit.SECONDS.toMillis(vtgateClosureDelaySeconds)); - } else { - actuallyCloseRefreshedConnection(old); + private static void maybeStartClosureTimer(VitessConnection connection) { + if (connection.getRefreshClosureDelayed() && vtgateClosureTimer == null) { + synchronized (VitessVTGateManager.class) { + if (vtgateClosureTimer == null) { + vtgateClosureTimer = new Timer("vtgate-conn-closure", true); + vtgateClosureDelaySeconds = connection.getRefreshClosureDelaySeconds(); } + } } - - private static void actuallyCloseRefreshedConnection(final VTGateConnection old) { - try { - logger.info(old + " Closing connection because it had been refreshed"); - old.close(); - } catch (IOException ioe) { - logger.log(Level.WARNING, String.format("Error closing VTGateConnection %s", old), ioe); + } + + private static String getIdentifer(String hostname, int port, String userIdentifer, + String keyspace) { + return (hostname + port + userIdentifer + keyspace); + } + + /** + * Create VTGateConn and update vtGateConnHashMap. + */ + private static void updateVtGateConnHashMap(String identifier, VitessJDBCUrl.HostInfo hostInfo, + VitessConnection connection) { + vtGateConnHashMap.put(identifier, getVtGateConn(hostInfo, connection)); + } + + private static void refreshUpdatedSSLConnections(VitessJDBCUrl.HostInfo hostInfo, + VitessConnection connection) { + synchronized (VitessVTGateManager.class) { + int updatedCount = 0; + for (Map.Entry entry : vtGateConnHashMap.entrySet()) { + if (entry.getValue() instanceof RefreshableVTGateConnection) { + RefreshableVTGateConnection existing = (RefreshableVTGateConnection) entry.getValue(); + if (existing.checkKeystoreUpdates()) { + updatedCount++; + VTGateConnection old = vtGateConnHashMap + .replace(entry.getKey(), getVtGateConn(hostInfo, connection)); + closeRefreshedConnection(old); + } } + } + if (updatedCount > 0) { + logger.info("refreshed " + updatedCount + " vtgate connections due to keystore update"); + } } - - /** - * Create vtGateConn object with given identifier. - * - * @param hostInfo - * @param connection - * @return - */ - private static VTGateConnection getVtGateConn(VitessJDBCUrl.HostInfo hostInfo, VitessConnection connection) { - final Context context = connection.createContext(connection.getTimeout()); - RetryingInterceptorConfig retryingConfig = getRetryingInterceptorConfig(connection); - if (connection.getUseSSL()) { - final String keyStorePath = connection.getKeyStore() != null - ? connection.getKeyStore() : System.getProperty(Constants.Property.KEYSTORE_FULL); - final String keyStorePassword = connection.getKeyStorePassword() != null - ? connection.getKeyStorePassword() : System.getProperty(Constants.Property.KEYSTORE_PASSWORD_FULL); - final String keyAlias = connection.getKeyAlias() != null - ? connection.getKeyAlias() : System.getProperty(Constants.Property.KEY_ALIAS_FULL); - final String keyPassword = connection.getKeyPassword() != null - ? connection.getKeyPassword() : System.getProperty(Constants.Property.KEY_PASSWORD_FULL); - final String trustStorePath = connection.getTrustStore() != null - ? connection.getTrustStore() : System.getProperty(Constants.Property.TRUSTSTORE_FULL); - final String trustStorePassword = connection.getTrustStorePassword() != null - ? connection.getTrustStorePassword() : System.getProperty(Constants.Property.TRUSTSTORE_PASSWORD_FULL); - final String trustAlias = connection.getTrustAlias() != null - ? connection.getTrustAlias() : System.getProperty(Constants.Property.TRUST_ALIAS_FULL); - - final TlsOptions tlsOptions = new TlsOptions() - .keyStorePath(keyStorePath) - .keyStorePassword(keyStorePassword) - .keyAlias(keyAlias) - .keyPassword(keyPassword) - .trustStorePath(trustStorePath) - .trustStorePassword(trustStorePassword) - .trustAlias(trustAlias); - - return new RefreshableVTGateConnection( - new GrpcClientFactory(retryingConfig).createTls(context, hostInfo.toString(), tlsOptions), - keyStorePath, - trustStorePath); - } else { - return new VTGateConnection(new GrpcClientFactory(retryingConfig).create(context, hostInfo.toString())); + } + + private static void closeRefreshedConnection(final VTGateConnection old) { + if (vtgateClosureTimer != null) { + logger.info(String + .format("%s Closing connection with a %s second delay", old, vtgateClosureDelaySeconds)); + vtgateClosureTimer.schedule(new TimerTask() { + @Override + public void run() { + actuallyCloseRefreshedConnection(old); } + }, TimeUnit.SECONDS.toMillis(vtgateClosureDelaySeconds)); + } else { + actuallyCloseRefreshedConnection(old); } + } + + private static void actuallyCloseRefreshedConnection(final VTGateConnection old) { + try { + logger.info(old + " Closing connection because it had been refreshed"); + old.close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, String.format("Error closing VTGateConnection %s", old), ioe); + } + } + + /** + * Create vtGateConn object with given identifier. + */ + private static VTGateConnection getVtGateConn(VitessJDBCUrl.HostInfo hostInfo, + VitessConnection connection) { + final Context context = connection.createContext(connection.getTimeout()); + RetryingInterceptorConfig retryingConfig = getRetryingInterceptorConfig(connection); + if (connection.getUseSSL()) { + final String keyStorePath = connection.getKeyStore() != null ? connection.getKeyStore() + : System.getProperty(Constants.Property.KEYSTORE_FULL); + final String keyStorePassword = + connection.getKeyStorePassword() != null ? connection.getKeyStorePassword() + : System.getProperty(Constants.Property.KEYSTORE_PASSWORD_FULL); + final String keyAlias = connection.getKeyAlias() != null ? connection.getKeyAlias() + : System.getProperty(Constants.Property.KEY_ALIAS_FULL); + final String keyPassword = connection.getKeyPassword() != null ? connection.getKeyPassword() + : System.getProperty(Constants.Property.KEY_PASSWORD_FULL); + final String trustStorePath = connection.getTrustStore() != null ? connection.getTrustStore() + : System.getProperty(Constants.Property.TRUSTSTORE_FULL); + final String trustStorePassword = + connection.getTrustStorePassword() != null ? connection.getTrustStorePassword() + : System.getProperty(Constants.Property.TRUSTSTORE_PASSWORD_FULL); + final String trustAlias = connection.getTrustAlias() != null ? connection.getTrustAlias() + : System.getProperty(Constants.Property.TRUST_ALIAS_FULL); + + final TlsOptions tlsOptions = new TlsOptions().keyStorePath(keyStorePath) + .keyStorePassword(keyStorePassword).keyAlias(keyAlias).keyPassword(keyPassword) + .trustStorePath(trustStorePath).trustStorePassword(trustStorePassword) + .trustAlias(trustAlias); + + return new RefreshableVTGateConnection( + new GrpcClientFactory(retryingConfig).createTls(context, hostInfo.toString(), tlsOptions), + keyStorePath, trustStorePath); + } else { + return new VTGateConnection( + new GrpcClientFactory(retryingConfig).create(context, hostInfo.toString())); + } + } - private static RetryingInterceptorConfig getRetryingInterceptorConfig(VitessConnection conn) { - if (!conn.getGrpcRetriesEnabled()) { - return RetryingInterceptorConfig.noOpConfig(); - } - - return RetryingInterceptorConfig.exponentialConfig(conn.getGrpcRetryInitialBackoffMillis(), conn.getGrpcRetryMaxBackoffMillis(), conn.getGrpcRetryBackoffMultiplier()); + private static RetryingInterceptorConfig getRetryingInterceptorConfig(VitessConnection conn) { + if (!conn.getGrpcRetriesEnabled()) { + return RetryingInterceptorConfig.noOpConfig(); } - public static void close() throws SQLException { - SQLException exception = null; + return RetryingInterceptorConfig.exponentialConfig(conn.getGrpcRetryInitialBackoffMillis(), + conn.getGrpcRetryMaxBackoffMillis(), conn.getGrpcRetryBackoffMultiplier()); + } - for (VTGateConnection vtGateConn : vtGateConnHashMap.values()) { - try { - vtGateConn.close(); - } catch (IOException e) { - exception = new SQLException(e.getMessage(), e); - } - } - vtGateConnHashMap.clear(); - if (null != exception) { - throw exception; - } + public static void close() throws SQLException { + SQLException exception = null; + + for (VTGateConnection vtGateConn : vtGateConnHashMap.values()) { + try { + vtGateConn.close(); + } catch (IOException e) { + exception = new SQLException(e.getMessage(), e); + } + } + vtGateConnHashMap.clear(); + if (null != exception) { + throw exception; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java b/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java index 75ce676eef4..4612542d3bc 100644 --- a/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java +++ b/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java @@ -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,38 +16,34 @@ package io.vitess.util; -import org.joda.time.Duration; - import io.vitess.client.Context; import io.vitess.proto.Vtrpc; +import org.joda.time.Duration; + /** * Created by naveen.nahata on 24/02/16. */ public class CommonUtils { - /** - * Create context used to create grpc client and executing query. - * - * @param username - * @param timeout - * @return - */ - public static Context createContext(String username, long timeout) { - Context context = Context.getDefault(); - Vtrpc.CallerID callerID = null; - if (null != username) { - callerID = Vtrpc.CallerID.newBuilder().setPrincipal(username).build(); - } - - if (null != callerID) { - context = context.withCallerId(callerID); - } - if (timeout > 0) { - context = context.withDeadlineAfter(Duration.millis(timeout)); - } - - return context; + /** + * Create context used to create grpc client and executing query. + */ + public static Context createContext(String username, long timeout) { + Context context = Context.getDefault(); + Vtrpc.CallerID callerID = null; + if (null != username) { + callerID = Vtrpc.CallerID.newBuilder().setPrincipal(username).build(); } + + if (null != callerID) { + context = context.withCallerId(callerID); + } + if (timeout > 0) { + context = context.withDeadlineAfter(Duration.millis(timeout)); + } + + return context; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/Constants.java b/java/jdbc/src/main/java/io/vitess/util/Constants.java index aebc7778b95..78666e7ed88 100644 --- a/java/jdbc/src/main/java/io/vitess/util/Constants.java +++ b/java/jdbc/src/main/java/io/vitess/util/Constants.java @@ -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.util; import com.google.protobuf.ByteString; + import io.vitess.proto.Query; import io.vitess.proto.Topodata; @@ -25,153 +26,157 @@ */ public class Constants { - public static final boolean JDBC_COMPLIANT = false; - public static final String URL_PREFIX = "jdbc:vitess://"; - public static final String URL_PATTERN = - "^jdbc:(vitess)://((\\w+)(:(\\w*))?@)?([^/?]*)(/([^/?]*))?(/(\\w+))?(\\?(\\S+))?"; - public static final String VITESS_HOST = "Hostname of Vitess Server"; - public static final String VITESS_PORT = "Port number of Vitess Server"; - public static final String VITESS_DB_NAME = "Database name"; - public static final String VITESS_TABLET_TYPE = - "Tablet Type to which Vitess will connect(master, replica, rdonly)"; - public static final String DEFAULT_PORT = "15991"; - public static final Topodata.TabletType DEFAULT_TABLET_TYPE = Topodata.TabletType.MASTER; - public static final String LITERAL_V = "v"; - public static final String LITERAL_SINGLE_QUOTE = "'"; - public static final int DRIVER_MAJOR_VERSION = 2; - public static final int DRIVER_MINOR_VERSION = 2; - public static final int MAX_BUFFER_SIZE = 65535; - //Default Timeout in miliseconds - public static final int DEFAULT_TIMEOUT = 30000; - public static final String VITESS_KEYSPACE = "Keyspace name in Vitess Server"; - public static final Constants.QueryExecuteType DEFAULT_EXECUTE_TYPE = QueryExecuteType.SIMPLE; - public static final String EXECUTE_TYPE_DESC = "Query execution type: simple or stream \n"; - public static final String USERNAME_DESC = "Username used for ACL validation \n"; - public static final Query.ExecuteOptions.IncludedFields DEFAULT_INCLUDED_FIELDS = Query.ExecuteOptions.IncludedFields.ALL; - public static final String DEFAULT_KEYSPACE = ""; - public static final String DEFAULT_SHARD = ""; - public static final String DEFAULT_USERNAME = null; - public static final String DEFAULT_TARGET = ""; - public static final String DEFAULT_CATALOG = DEFAULT_KEYSPACE; - public static final ByteString ZERO_DATE_TIME_PREFIX = ByteString.copyFromUtf8("0000-00-00"); + public static final boolean JDBC_COMPLIANT = false; + public static final String URL_PREFIX = "jdbc:vitess://"; + public static final String URL_PATTERN = "^jdbc:(vitess)://((\\w+)(:(\\w*))?@)?([^/?]*)(/" + + "([^/?]*))?(/(\\w+))?(\\?(\\S+))?"; + public static final String VITESS_HOST = "Hostname of Vitess Server"; + public static final String VITESS_PORT = "Port number of Vitess Server"; + public static final String VITESS_DB_NAME = "Database name"; + public static final String VITESS_TABLET_TYPE = "Tablet Type to which Vitess will connect" + + "(master, replica, rdonly)"; + public static final String DEFAULT_PORT = "15991"; + public static final Topodata.TabletType DEFAULT_TABLET_TYPE = Topodata.TabletType.MASTER; + public static final String LITERAL_V = "v"; + public static final String LITERAL_SINGLE_QUOTE = "'"; + public static final int DRIVER_MAJOR_VERSION = 2; + public static final int DRIVER_MINOR_VERSION = 2; + public static final int MAX_BUFFER_SIZE = 65535; + //Default Timeout in miliseconds + public static final int DEFAULT_TIMEOUT = 30000; + public static final String VITESS_KEYSPACE = "Keyspace name in Vitess Server"; + public static final Constants.QueryExecuteType DEFAULT_EXECUTE_TYPE = QueryExecuteType.SIMPLE; + public static final String EXECUTE_TYPE_DESC = "Query execution type: simple or stream \n"; + public static final String USERNAME_DESC = "Username used for ACL validation \n"; + public static final Query.ExecuteOptions.IncludedFields DEFAULT_INCLUDED_FIELDS = + Query.ExecuteOptions.IncludedFields.ALL; + public static final String DEFAULT_KEYSPACE = ""; + public static final String DEFAULT_SHARD = ""; + public static final String DEFAULT_USERNAME = null; + public static final String DEFAULT_TARGET = ""; + public static final String DEFAULT_CATALOG = DEFAULT_KEYSPACE; + public static final ByteString ZERO_DATE_TIME_PREFIX = ByteString.copyFromUtf8("0000-00-00"); private Constants() { - } - - - public static final class SQLExceptionMessages { - public static final String CONN_UNAVAILABLE = "Connection not available"; - public static final String CONN_CLOSED = "Connection is Closed"; - public static final String INIT_FAILED = "Failed to Initialize Vitess JDBC Driver"; - public static final String INVALID_CONN_URL = "Connection URL is invalid"; - public static final String STMT_CLOSED = "Statement is closed"; - public static final String SQL_FEATURE_NOT_SUPPORTED = "SQL Feature Not Supported"; - public static final String TIMEOUT_NEGATIVE = "Timeout value cannot be negative"; - public static final String COMMIT_WHEN_AUTO_COMMIT_TRUE = - "Cannot call commit when auto commit is true"; - public static final String ROLLBACK_WHEN_AUTO_COMMIT_TRUE = - "Cannot call rollback when auto commit is true"; - public static final String CLOSED_RESULT_SET = "Result Set closed"; - public static final String INVALID_COLUMN_INDEX = "Invalid Column Index"; - public static final String VITESS_CURSOR_CLOSE_ERROR = - "Getting Error while closing ResultSet"; - public static final String CONN_INIT_ERROR = "Connection initialization error"; - public static final String MALFORMED_URL = "Malformed URL Exception"; - public static final String SQL_TYPE_INFER = - "Cannot infer the SQL type to use for an instance of "; - public static final String DML_NOT_ON_MASTER = - "DML Statement cannot be executed on non master instance type"; - public static final String SQL_EMPTY = "SQL statement is not valid"; - public static final String RESULT_SET_TYPE_NOT_SUPPORTED = - "This Result Set type is not supported"; - public static final String RESULT_SET_CONCUR_NOT_SUPPORTED = - "This Result Set Concurrency is not supported"; - public static final String METHOD_CALLED_ON_OPEN_TRANSACTION = - "This method should not be called when a transaction is open"; - public static final String ISOLATION_LEVEL_NOT_SUPPORTED = - "This isolation level is not supported"; - public static final String EXECUTOR_NULL = "Executor cannot be null"; - public static final String CLASS_CAST_EXCEPTION = "Unable to unwrap to "; - public static final String INVALID_COLUMN_TYPE = "Invalid Column Type"; - public static final String UNKNOWN_COLUMN_TYPE = "Unknown Column Type"; - public static final String INVALID_RESULT_SET = "Unable to build ResultSet"; - public static final String METHOD_NOT_ALLOWED = - "This method cannot be called using this class object"; - public static final String SQL_RETURNED_RESULT_SET = - "ResultSet generation is not allowed through this method"; - public static final String ILLEGAL_VALUE_FOR = "Illegal value for "; - public static final String METHOD_CALL_FAILED = "Failed to execute this method"; - public static final String CURSOR_NULL = "Cursor cannot be null"; - public static final String NO_COLUMN_ACCESSED = - "No column was accessed before calling this method"; - public static final String RESULT_SET_INIT_ERROR = "ResultSet initialization error"; - public static final String GENERATED_KEYS_NOT_REQUESTED = - "Generated keys not requested. You need to specify " - + "Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection.prepareStatement()"; - public static final String NO_KEYSPACE = - "Querying Database Information without providing keyspace"; - public static final String QUERY_FAILED = "One or more queries failed in batch execution"; - public static final String READ_ONLY = - "Connection has been set to read only and an update was attempted"; - public static final String ZERO_TIMESTAMP = "Zero timestamp cannot be represented as java.sql.Date"; - } - - - public static final class Property { - @Deprecated - public static final String OLD_TABLET_TYPE = "TABLET_TYPE"; - public static final String TABLET_TYPE = "tabletType"; - public static final String HOST = "host"; - public static final String PORT = "port"; - public static final String DBNAME = "dbName"; - public static final String KEYSPACE = "keyspace"; - public static final String USERNAME = "userName"; - public static final String EXECUTE_TYPE = "executeType"; - public static final String TWOPC_ENABLED = "twopcEnabled"; - public static final String SHARD = "shard"; - - public static final String USE_SSL = "useSSL"; - public static final String KEYSTORE = "keyStore"; - public static final String KEYSTORE_PASSWORD = "keyStorePassword"; - public static final String KEY_ALIAS = "keyAlias"; - public static final String KEY_PASSWORD = "keyPassword"; - public static final String TRUSTSTORE = "trustStore"; - public static final String TRUSTSTORE_PASSWORD = "trustStorePassword"; - public static final String TRUST_ALIAS = "trustAlias"; - - public static final String KEYSTORE_FULL = "javax.net.ssl.keyStore"; - public static final String KEYSTORE_PASSWORD_FULL = "javax.net.ssl.keyStorePassword"; - public static final String KEY_ALIAS_FULL = "javax.net.ssl.keyAlias"; - public static final String KEY_PASSWORD_FULL = "javax.net.ssl.keyPassword"; - public static final String TRUSTSTORE_FULL = "javax.net.ssl.trustStore"; - public static final String TRUSTSTORE_PASSWORD_FULL = "javax.net.ssl.trustStorePassword"; - public static final String TRUST_ALIAS_FULL = "javax.net.ssl.trustAlias"; - public static final String INCLUDED_FIELDS = "includedFields"; - public static final String TARGET = "target"; - } - - - public enum QueryExecuteType { - SIMPLE, STREAM - } - - public enum ZeroDateTimeBehavior { - /** - * This is the current behavior. It completely garbles null timestamps. It is mostly likely - * entirely incorrect but we will keep it for backwards compatibility. - */ - GARBLE, - /** - * This matches the MySQL JDBC driver convertToNull behavior. - */ - CONVERTTONULL, - /** - * This matches the MySQL JDBC driver exception behavior. - */ - EXCEPTION, - /** - * This matches the MySQL JDBC driver round behavior. - */ - ROUND - } + } + + + public static final class SQLExceptionMessages { + + public static final String CONN_UNAVAILABLE = "Connection not available"; + public static final String CONN_CLOSED = "Connection is Closed"; + public static final String INIT_FAILED = "Failed to Initialize Vitess JDBC Driver"; + public static final String INVALID_CONN_URL = "Connection URL is invalid"; + public static final String STMT_CLOSED = "Statement is closed"; + public static final String SQL_FEATURE_NOT_SUPPORTED = "SQL Feature Not Supported"; + public static final String TIMEOUT_NEGATIVE = "Timeout value cannot be negative"; + public static final String COMMIT_WHEN_AUTO_COMMIT_TRUE = "Cannot call commit when auto " + + "commit is true"; + public static final String ROLLBACK_WHEN_AUTO_COMMIT_TRUE = "Cannot call rollback when auto " + + "commit is true"; + public static final String CLOSED_RESULT_SET = "Result Set closed"; + public static final String INVALID_COLUMN_INDEX = "Invalid Column Index"; + public static final String VITESS_CURSOR_CLOSE_ERROR = "Getting Error while closing ResultSet"; + public static final String CONN_INIT_ERROR = "Connection initialization error"; + public static final String MALFORMED_URL = "Malformed URL Exception"; + public static final String SQL_TYPE_INFER = "Cannot infer the SQL type to use for an instance" + + " of "; + public static final String DML_NOT_ON_MASTER = "DML Statement cannot be executed on non " + + "master instance type"; + public static final String SQL_EMPTY = "SQL statement is not valid"; + public static final String RESULT_SET_TYPE_NOT_SUPPORTED = "This Result Set type is not " + + "supported"; + public static final String RESULT_SET_CONCUR_NOT_SUPPORTED = "This Result Set Concurrency is " + + "not supported"; + public static final String METHOD_CALLED_ON_OPEN_TRANSACTION = "This method should not be " + + "called when a transaction is open"; + public static final String ISOLATION_LEVEL_NOT_SUPPORTED = "This isolation level is not " + + "supported"; + public static final String EXECUTOR_NULL = "Executor cannot be null"; + public static final String CLASS_CAST_EXCEPTION = "Unable to unwrap to "; + public static final String INVALID_COLUMN_TYPE = "Invalid Column Type"; + public static final String UNKNOWN_COLUMN_TYPE = "Unknown Column Type"; + public static final String INVALID_RESULT_SET = "Unable to build ResultSet"; + public static final String METHOD_NOT_ALLOWED = "This method cannot be called using this " + + "class object"; + public static final String SQL_RETURNED_RESULT_SET = "ResultSet generation is not allowed " + + "through this method"; + public static final String ILLEGAL_VALUE_FOR = "Illegal value for "; + public static final String METHOD_CALL_FAILED = "Failed to execute this method"; + public static final String CURSOR_NULL = "Cursor cannot be null"; + public static final String NO_COLUMN_ACCESSED = "No column was accessed before calling this " + + "method"; + public static final String RESULT_SET_INIT_ERROR = "ResultSet initialization error"; + public static final String GENERATED_KEYS_NOT_REQUESTED = + "Generated keys not requested. You need to specify " + + "Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection" + + ".prepareStatement()"; + public static final String NO_KEYSPACE = "Querying Database Information without providing " + + "keyspace"; + public static final String QUERY_FAILED = "One or more queries failed in batch execution"; + public static final String READ_ONLY = "Connection has been set to read only and an update " + + "was attempted"; + public static final String ZERO_TIMESTAMP = "Zero timestamp cannot be represented as java.sql" + + ".Date"; + } + + + public static final class Property { + + @Deprecated + public static final String OLD_TABLET_TYPE = "TABLET_TYPE"; + public static final String TABLET_TYPE = "tabletType"; + public static final String HOST = "host"; + public static final String PORT = "port"; + public static final String DBNAME = "dbName"; + public static final String KEYSPACE = "keyspace"; + public static final String USERNAME = "userName"; + public static final String EXECUTE_TYPE = "executeType"; + public static final String TWOPC_ENABLED = "twopcEnabled"; + public static final String SHARD = "shard"; + + public static final String USE_SSL = "useSSL"; + public static final String KEYSTORE = "keyStore"; + public static final String KEYSTORE_PASSWORD = "keyStorePassword"; + public static final String KEY_ALIAS = "keyAlias"; + public static final String KEY_PASSWORD = "keyPassword"; + public static final String TRUSTSTORE = "trustStore"; + public static final String TRUSTSTORE_PASSWORD = "trustStorePassword"; + public static final String TRUST_ALIAS = "trustAlias"; + + public static final String KEYSTORE_FULL = "javax.net.ssl.keyStore"; + public static final String KEYSTORE_PASSWORD_FULL = "javax.net.ssl.keyStorePassword"; + public static final String KEY_ALIAS_FULL = "javax.net.ssl.keyAlias"; + public static final String KEY_PASSWORD_FULL = "javax.net.ssl.keyPassword"; + public static final String TRUSTSTORE_FULL = "javax.net.ssl.trustStore"; + public static final String TRUSTSTORE_PASSWORD_FULL = "javax.net.ssl.trustStorePassword"; + public static final String TRUST_ALIAS_FULL = "javax.net.ssl.trustAlias"; + public static final String INCLUDED_FIELDS = "includedFields"; + public static final String TARGET = "target"; + } + + + public enum QueryExecuteType { + SIMPLE, STREAM + } + + public enum ZeroDateTimeBehavior { + /** + * This is the current behavior. It completely garbles null timestamps. It is mostly likely + * entirely incorrect but we will keep it for backwards compatibility. + */ + GARBLE, + /** + * This matches the MySQL JDBC driver convertToNull behavior. + */ + CONVERTTONULL, + /** + * This matches the MySQL JDBC driver exception behavior. + */ + EXCEPTION, + /** + * This matches the MySQL JDBC driver round behavior. + */ + ROUND + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java b/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java index 075b5f4f5da..c52ee81f41a 100644 --- a/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java +++ b/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java @@ -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,13 +16,13 @@ package io.vitess.util; +import io.vitess.proto.Query; + import java.sql.Connection; import java.sql.Types; import java.util.HashMap; import java.util.Map; -import io.vitess.proto.Query; - /** * Created by ashudeep.sharma on 07/03/16. */ @@ -32,519 +32,521 @@ * MysqlDefs contains many values that are needed for communication with the MySQL server. */ public final class MysqlDefs { - public static final int FIELD_TYPE_BLOB = 252; - /** - * Used to indicate that the server sent no field-level character set information, so the driver should use the - * connection-level character encoding instead. - */ - public static final int NO_CHARSET_INFO = -1; - static final int COM_BINLOG_DUMP = 18; - static final int COM_CHANGE_USER = 17; - static final int COM_CLOSE_STATEMENT = 25; - static final int COM_CONNECT_OUT = 20; - static final int COM_END = 29; - static final int COM_EXECUTE = 23; - static final int COM_FETCH = 28; - static final int COM_LONG_DATA = 24; - static final int COM_PREPARE = 22; - static final int COM_REGISTER_SLAVE = 21; - static final int COM_RESET_STMT = 26; - static final int COM_SET_OPTION = 27; - static final int COM_TABLE_DUMP = 19; - static final int CONNECT = 11; - static final int CREATE_DB = 5; - static final int DEBUG = 13; - static final int DELAYED_INSERT = 16; - static final int DROP_DB = 6; - static final int FIELD_LIST = 4; - static final int FIELD_TYPE_BIT = 16; - static final int FIELD_TYPE_DATE = 10; - static final int FIELD_TYPE_DATETIME = 12; - // Data Types - static final int FIELD_TYPE_DECIMAL = 0; - static final int FIELD_TYPE_DOUBLE = 5; - static final int FIELD_TYPE_ENUM = 247; - static final int FIELD_TYPE_FLOAT = 4; - static final int FIELD_TYPE_GEOMETRY = 255; - static final int FIELD_TYPE_INT24 = 9; - static final int FIELD_TYPE_LONG = 3; - static final int FIELD_TYPE_LONG_BLOB = 251; - static final int FIELD_TYPE_LONGLONG = 8; - static final int FIELD_TYPE_MEDIUM_BLOB = 250; - static final int FIELD_TYPE_NEW_DECIMAL = 246; - static final int FIELD_TYPE_NEWDATE = 14; - static final int FIELD_TYPE_NULL = 6; - static final int FIELD_TYPE_SET = 248; - static final int FIELD_TYPE_SHORT = 2; - static final int FIELD_TYPE_STRING = 254; - static final int FIELD_TYPE_TIME = 11; - static final int FIELD_TYPE_TIMESTAMP = 7; - static final int FIELD_TYPE_TINY = 1; - // Older data types - static final int FIELD_TYPE_TINY_BLOB = 249; - static final int FIELD_TYPE_VAR_STRING = 253; - static final int FIELD_TYPE_VARCHAR = 15; - // Newer data types - static final int FIELD_TYPE_YEAR = 13; - static final int FIELD_TYPE_JSON = 245; - static final int INIT_DB = 2; - - // Unlike mysql-vanilla, vtgate returns ints for Field.getLength(). To ensure no type conversion issues, - // we diverge from mysql-connector-j here, who instead have these fields as longs, and have a function clampedGetLength - // to convert field lengths to ints after comparison. - public static final int LENGTH_BLOB = 65535; - public static final int LENGTH_LONGBLOB = Integer.MAX_VALUE; - public static final int LENGTH_MEDIUMBLOB = 16777215; - public static final int LENGTH_TINYBLOB = 255; - - // Limitations - static final int MAX_ROWS = 50000000; // From the MySQL FAQ - static final byte OPEN_CURSOR_FLAG = 1; - - static final int PING = 14; - - static final int PROCESS_INFO = 10; - - static final int PROCESS_KILL = 12; - - static final int QUERY = 3; - - static final int QUIT = 1; - - static final int RELOAD = 7; - - static final int SHUTDOWN = 8; - - // - // Constants defined from mysql - // - // DB Operations - static final int SLEEP = 0; - - static final int STATISTICS = 9; - - static final int TIME = 15; - public static Map vitesstoMySqlType = new HashMap(); - public static Map mysqlConnectionTransactionMapping = - new HashMap(); - private static Map mysqlToJdbcTypesMap = new HashMap(); - - static { - mysqlToJdbcTypesMap.put("BIT", mysqlToJavaType(FIELD_TYPE_BIT)); - - mysqlToJdbcTypesMap.put("TINYINT", mysqlToJavaType(FIELD_TYPE_TINY)); - mysqlToJdbcTypesMap.put("SMALLINT", mysqlToJavaType(FIELD_TYPE_SHORT)); - mysqlToJdbcTypesMap.put("MEDIUMINT", mysqlToJavaType(FIELD_TYPE_INT24)); - mysqlToJdbcTypesMap.put("INT", mysqlToJavaType(FIELD_TYPE_LONG)); - mysqlToJdbcTypesMap.put("INTEGER", mysqlToJavaType(FIELD_TYPE_LONG)); - mysqlToJdbcTypesMap.put("BIGINT", mysqlToJavaType(FIELD_TYPE_LONGLONG)); - mysqlToJdbcTypesMap.put("INT24", mysqlToJavaType(FIELD_TYPE_INT24)); - mysqlToJdbcTypesMap.put("REAL", mysqlToJavaType(FIELD_TYPE_DOUBLE)); - mysqlToJdbcTypesMap.put("FLOAT", mysqlToJavaType(FIELD_TYPE_FLOAT)); - mysqlToJdbcTypesMap.put("DECIMAL", mysqlToJavaType(FIELD_TYPE_DECIMAL)); - mysqlToJdbcTypesMap.put("NUMERIC", mysqlToJavaType(FIELD_TYPE_DECIMAL)); - mysqlToJdbcTypesMap.put("DOUBLE", mysqlToJavaType(FIELD_TYPE_DOUBLE)); - mysqlToJdbcTypesMap.put("CHAR", mysqlToJavaType(FIELD_TYPE_STRING)); - mysqlToJdbcTypesMap.put("VARCHAR", mysqlToJavaType(FIELD_TYPE_VAR_STRING)); - mysqlToJdbcTypesMap.put("DATE", mysqlToJavaType(FIELD_TYPE_DATE)); - mysqlToJdbcTypesMap.put("TIME", mysqlToJavaType(FIELD_TYPE_TIME)); - mysqlToJdbcTypesMap.put("YEAR", mysqlToJavaType(FIELD_TYPE_YEAR)); - mysqlToJdbcTypesMap.put("TIMESTAMP", mysqlToJavaType(FIELD_TYPE_TIMESTAMP)); - mysqlToJdbcTypesMap.put("DATETIME", mysqlToJavaType(FIELD_TYPE_DATETIME)); - mysqlToJdbcTypesMap.put("TINYBLOB", Types.BINARY); - mysqlToJdbcTypesMap.put("BLOB", Types.LONGVARBINARY); - mysqlToJdbcTypesMap.put("MEDIUMBLOB", Types.LONGVARBINARY); - mysqlToJdbcTypesMap.put("LONGBLOB", Types.LONGVARBINARY); - mysqlToJdbcTypesMap.put("TINYTEXT", Types.VARCHAR); - mysqlToJdbcTypesMap.put("TEXT", Types.LONGVARCHAR); - mysqlToJdbcTypesMap.put("MEDIUMTEXT", Types.LONGVARCHAR); - mysqlToJdbcTypesMap.put("LONGTEXT", Types.LONGVARCHAR); - mysqlToJdbcTypesMap.put("ENUM", mysqlToJavaType(FIELD_TYPE_ENUM)); - mysqlToJdbcTypesMap.put("SET", mysqlToJavaType(FIELD_TYPE_SET)); - mysqlToJdbcTypesMap.put("GEOMETRY", mysqlToJavaType(FIELD_TYPE_GEOMETRY)); - mysqlToJdbcTypesMap.put("JSON", mysqlToJavaType(FIELD_TYPE_JSON)); - } - - static { - vitesstoMySqlType.put(Query.Type.NULL_TYPE, Types.NULL); - vitesstoMySqlType.put(Query.Type.INT8, Types.TINYINT); - vitesstoMySqlType.put(Query.Type.UINT8, Types.TINYINT); - vitesstoMySqlType.put(Query.Type.INT16, Types.SMALLINT); - vitesstoMySqlType.put(Query.Type.UINT16, Types.SMALLINT); - vitesstoMySqlType.put(Query.Type.INT24, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.UINT24, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.INT32, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.UINT32, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.INT64, Types.BIGINT); - vitesstoMySqlType.put(Query.Type.UINT64, Types.BIGINT); - vitesstoMySqlType.put(Query.Type.FLOAT32, Types.FLOAT); - vitesstoMySqlType.put(Query.Type.FLOAT64, Types.DOUBLE); - vitesstoMySqlType.put(Query.Type.TIMESTAMP, Types.TIMESTAMP); - vitesstoMySqlType.put(Query.Type.DATE, Types.DATE); - vitesstoMySqlType.put(Query.Type.TIME, Types.TIME); - vitesstoMySqlType.put(Query.Type.DATETIME, Types.TIMESTAMP); - vitesstoMySqlType.put(Query.Type.YEAR, Types.SMALLINT); - vitesstoMySqlType.put(Query.Type.DECIMAL, Types.DECIMAL); - vitesstoMySqlType.put(Query.Type.TEXT, Types.VARCHAR); - vitesstoMySqlType.put(Query.Type.BLOB, Types.BLOB); - vitesstoMySqlType.put(Query.Type.VARCHAR, Types.VARCHAR); - vitesstoMySqlType.put(Query.Type.VARBINARY, Types.VARBINARY); - vitesstoMySqlType.put(Query.Type.CHAR, Types.CHAR); - vitesstoMySqlType.put(Query.Type.BINARY, Types.BINARY); - vitesstoMySqlType.put(Query.Type.BIT, Types.BIT); - vitesstoMySqlType.put(Query.Type.ENUM, Types.CHAR); - vitesstoMySqlType.put(Query.Type.SET, Types.CHAR); - vitesstoMySqlType.put(Query.Type.TUPLE, Types.OTHER); - vitesstoMySqlType.put(Query.Type.GEOMETRY, Types.BINARY); - vitesstoMySqlType.put(Query.Type.JSON, Types.CHAR); - } - - static { - mysqlConnectionTransactionMapping.put("TRANSACTION-NONE", Connection.TRANSACTION_NONE); - mysqlConnectionTransactionMapping - .put("REPEATABLE-READ", Connection.TRANSACTION_REPEATABLE_READ); - mysqlConnectionTransactionMapping - .put("READ-COMMITTED", Connection.TRANSACTION_READ_COMMITTED); - mysqlConnectionTransactionMapping - .put("READ-UNCOMMITTED", Connection.TRANSACTION_READ_UNCOMMITTED); - mysqlConnectionTransactionMapping.put("SERIALIZABLE", Connection.TRANSACTION_SERIALIZABLE); - } - - /** - * Maps the given MySQL type to the correct JDBC type. - */ - public static int mysqlToJavaType(int mysqlType) { - int jdbcType; - switch (mysqlType) { - case MysqlDefs.FIELD_TYPE_NEW_DECIMAL: - case MysqlDefs.FIELD_TYPE_DECIMAL: - jdbcType = Types.DECIMAL; + public static final int FIELD_TYPE_BLOB = 252; + /** + * Used to indicate that the server sent no field-level character set information, so the driver + * should use the connection-level character encoding instead. + */ + public static final int NO_CHARSET_INFO = -1; + static final int COM_BINLOG_DUMP = 18; + static final int COM_CHANGE_USER = 17; + static final int COM_CLOSE_STATEMENT = 25; + static final int COM_CONNECT_OUT = 20; + static final int COM_END = 29; + static final int COM_EXECUTE = 23; + static final int COM_FETCH = 28; + static final int COM_LONG_DATA = 24; + static final int COM_PREPARE = 22; + static final int COM_REGISTER_SLAVE = 21; + static final int COM_RESET_STMT = 26; + static final int COM_SET_OPTION = 27; + static final int COM_TABLE_DUMP = 19; + static final int CONNECT = 11; + static final int CREATE_DB = 5; + static final int DEBUG = 13; + static final int DELAYED_INSERT = 16; + static final int DROP_DB = 6; + static final int FIELD_LIST = 4; + static final int FIELD_TYPE_BIT = 16; + static final int FIELD_TYPE_DATE = 10; + static final int FIELD_TYPE_DATETIME = 12; + // Data Types + static final int FIELD_TYPE_DECIMAL = 0; + static final int FIELD_TYPE_DOUBLE = 5; + static final int FIELD_TYPE_ENUM = 247; + static final int FIELD_TYPE_FLOAT = 4; + static final int FIELD_TYPE_GEOMETRY = 255; + static final int FIELD_TYPE_INT24 = 9; + static final int FIELD_TYPE_LONG = 3; + static final int FIELD_TYPE_LONG_BLOB = 251; + static final int FIELD_TYPE_LONGLONG = 8; + static final int FIELD_TYPE_MEDIUM_BLOB = 250; + static final int FIELD_TYPE_NEW_DECIMAL = 246; + static final int FIELD_TYPE_NEWDATE = 14; + static final int FIELD_TYPE_NULL = 6; + static final int FIELD_TYPE_SET = 248; + static final int FIELD_TYPE_SHORT = 2; + static final int FIELD_TYPE_STRING = 254; + static final int FIELD_TYPE_TIME = 11; + static final int FIELD_TYPE_TIMESTAMP = 7; + static final int FIELD_TYPE_TINY = 1; + // Older data types + static final int FIELD_TYPE_TINY_BLOB = 249; + static final int FIELD_TYPE_VAR_STRING = 253; + static final int FIELD_TYPE_VARCHAR = 15; + // Newer data types + static final int FIELD_TYPE_YEAR = 13; + static final int FIELD_TYPE_JSON = 245; + static final int INIT_DB = 2; + + // Unlike mysql-vanilla, vtgate returns ints for Field.getLength(). To ensure no type + // conversion issues, + // we diverge from mysql-connector-j here, who instead have these fields as longs, and have a + // function clampedGetLength + // to convert field lengths to ints after comparison. + public static final int LENGTH_BLOB = 65535; + public static final int LENGTH_LONGBLOB = Integer.MAX_VALUE; + public static final int LENGTH_MEDIUMBLOB = 16777215; + public static final int LENGTH_TINYBLOB = 255; + + // Limitations + static final int MAX_ROWS = 50000000; // From the MySQL FAQ + static final byte OPEN_CURSOR_FLAG = 1; + + static final int PING = 14; + + static final int PROCESS_INFO = 10; + + static final int PROCESS_KILL = 12; + + static final int QUERY = 3; + + static final int QUIT = 1; + + static final int RELOAD = 7; + + static final int SHUTDOWN = 8; + + // + // Constants defined from mysql + // + // DB Operations + static final int SLEEP = 0; + + static final int STATISTICS = 9; + + static final int TIME = 15; + public static Map vitesstoMySqlType = new HashMap(); + public static Map mysqlConnectionTransactionMapping = new HashMap(); + private static Map mysqlToJdbcTypesMap = new HashMap(); + + static { + mysqlToJdbcTypesMap.put("BIT", mysqlToJavaType(FIELD_TYPE_BIT)); + + mysqlToJdbcTypesMap.put("TINYINT", mysqlToJavaType(FIELD_TYPE_TINY)); + mysqlToJdbcTypesMap.put("SMALLINT", mysqlToJavaType(FIELD_TYPE_SHORT)); + mysqlToJdbcTypesMap.put("MEDIUMINT", mysqlToJavaType(FIELD_TYPE_INT24)); + mysqlToJdbcTypesMap.put("INT", mysqlToJavaType(FIELD_TYPE_LONG)); + mysqlToJdbcTypesMap.put("INTEGER", mysqlToJavaType(FIELD_TYPE_LONG)); + mysqlToJdbcTypesMap.put("BIGINT", mysqlToJavaType(FIELD_TYPE_LONGLONG)); + mysqlToJdbcTypesMap.put("INT24", mysqlToJavaType(FIELD_TYPE_INT24)); + mysqlToJdbcTypesMap.put("REAL", mysqlToJavaType(FIELD_TYPE_DOUBLE)); + mysqlToJdbcTypesMap.put("FLOAT", mysqlToJavaType(FIELD_TYPE_FLOAT)); + mysqlToJdbcTypesMap.put("DECIMAL", mysqlToJavaType(FIELD_TYPE_DECIMAL)); + mysqlToJdbcTypesMap.put("NUMERIC", mysqlToJavaType(FIELD_TYPE_DECIMAL)); + mysqlToJdbcTypesMap.put("DOUBLE", mysqlToJavaType(FIELD_TYPE_DOUBLE)); + mysqlToJdbcTypesMap.put("CHAR", mysqlToJavaType(FIELD_TYPE_STRING)); + mysqlToJdbcTypesMap.put("VARCHAR", mysqlToJavaType(FIELD_TYPE_VAR_STRING)); + mysqlToJdbcTypesMap.put("DATE", mysqlToJavaType(FIELD_TYPE_DATE)); + mysqlToJdbcTypesMap.put("TIME", mysqlToJavaType(FIELD_TYPE_TIME)); + mysqlToJdbcTypesMap.put("YEAR", mysqlToJavaType(FIELD_TYPE_YEAR)); + mysqlToJdbcTypesMap.put("TIMESTAMP", mysqlToJavaType(FIELD_TYPE_TIMESTAMP)); + mysqlToJdbcTypesMap.put("DATETIME", mysqlToJavaType(FIELD_TYPE_DATETIME)); + mysqlToJdbcTypesMap.put("TINYBLOB", Types.BINARY); + mysqlToJdbcTypesMap.put("BLOB", Types.LONGVARBINARY); + mysqlToJdbcTypesMap.put("MEDIUMBLOB", Types.LONGVARBINARY); + mysqlToJdbcTypesMap.put("LONGBLOB", Types.LONGVARBINARY); + mysqlToJdbcTypesMap.put("TINYTEXT", Types.VARCHAR); + mysqlToJdbcTypesMap.put("TEXT", Types.LONGVARCHAR); + mysqlToJdbcTypesMap.put("MEDIUMTEXT", Types.LONGVARCHAR); + mysqlToJdbcTypesMap.put("LONGTEXT", Types.LONGVARCHAR); + mysqlToJdbcTypesMap.put("ENUM", mysqlToJavaType(FIELD_TYPE_ENUM)); + mysqlToJdbcTypesMap.put("SET", mysqlToJavaType(FIELD_TYPE_SET)); + mysqlToJdbcTypesMap.put("GEOMETRY", mysqlToJavaType(FIELD_TYPE_GEOMETRY)); + mysqlToJdbcTypesMap.put("JSON", mysqlToJavaType(FIELD_TYPE_JSON)); + } + + static { + vitesstoMySqlType.put(Query.Type.NULL_TYPE, Types.NULL); + vitesstoMySqlType.put(Query.Type.INT8, Types.TINYINT); + vitesstoMySqlType.put(Query.Type.UINT8, Types.TINYINT); + vitesstoMySqlType.put(Query.Type.INT16, Types.SMALLINT); + vitesstoMySqlType.put(Query.Type.UINT16, Types.SMALLINT); + vitesstoMySqlType.put(Query.Type.INT24, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.UINT24, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.INT32, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.UINT32, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.INT64, Types.BIGINT); + vitesstoMySqlType.put(Query.Type.UINT64, Types.BIGINT); + vitesstoMySqlType.put(Query.Type.FLOAT32, Types.FLOAT); + vitesstoMySqlType.put(Query.Type.FLOAT64, Types.DOUBLE); + vitesstoMySqlType.put(Query.Type.TIMESTAMP, Types.TIMESTAMP); + vitesstoMySqlType.put(Query.Type.DATE, Types.DATE); + vitesstoMySqlType.put(Query.Type.TIME, Types.TIME); + vitesstoMySqlType.put(Query.Type.DATETIME, Types.TIMESTAMP); + vitesstoMySqlType.put(Query.Type.YEAR, Types.SMALLINT); + vitesstoMySqlType.put(Query.Type.DECIMAL, Types.DECIMAL); + vitesstoMySqlType.put(Query.Type.TEXT, Types.VARCHAR); + vitesstoMySqlType.put(Query.Type.BLOB, Types.BLOB); + vitesstoMySqlType.put(Query.Type.VARCHAR, Types.VARCHAR); + vitesstoMySqlType.put(Query.Type.VARBINARY, Types.VARBINARY); + vitesstoMySqlType.put(Query.Type.CHAR, Types.CHAR); + vitesstoMySqlType.put(Query.Type.BINARY, Types.BINARY); + vitesstoMySqlType.put(Query.Type.BIT, Types.BIT); + vitesstoMySqlType.put(Query.Type.ENUM, Types.CHAR); + vitesstoMySqlType.put(Query.Type.SET, Types.CHAR); + vitesstoMySqlType.put(Query.Type.TUPLE, Types.OTHER); + vitesstoMySqlType.put(Query.Type.GEOMETRY, Types.BINARY); + vitesstoMySqlType.put(Query.Type.JSON, Types.CHAR); + } + + static { + mysqlConnectionTransactionMapping.put("TRANSACTION-NONE", Connection.TRANSACTION_NONE); + mysqlConnectionTransactionMapping + .put("REPEATABLE-READ", Connection.TRANSACTION_REPEATABLE_READ); + mysqlConnectionTransactionMapping.put("READ-COMMITTED", Connection.TRANSACTION_READ_COMMITTED); + mysqlConnectionTransactionMapping + .put("READ-UNCOMMITTED", Connection.TRANSACTION_READ_UNCOMMITTED); + mysqlConnectionTransactionMapping.put("SERIALIZABLE", Connection.TRANSACTION_SERIALIZABLE); + } + + /** + * Maps the given MySQL type to the correct JDBC type. + */ + public static int mysqlToJavaType(int mysqlType) { + int jdbcType; + + switch (mysqlType) { + case MysqlDefs.FIELD_TYPE_NEW_DECIMAL: + case MysqlDefs.FIELD_TYPE_DECIMAL: + jdbcType = Types.DECIMAL; + + break; + + case MysqlDefs.FIELD_TYPE_TINY: + jdbcType = Types.TINYINT; + + break; + + case MysqlDefs.FIELD_TYPE_SHORT: + jdbcType = Types.SMALLINT; + + break; - break; + case MysqlDefs.FIELD_TYPE_LONG: + jdbcType = Types.INTEGER; + + break; - case MysqlDefs.FIELD_TYPE_TINY: - jdbcType = Types.TINYINT; + case MysqlDefs.FIELD_TYPE_FLOAT: + jdbcType = Types.REAL; - break; + break; - case MysqlDefs.FIELD_TYPE_SHORT: - jdbcType = Types.SMALLINT; + case MysqlDefs.FIELD_TYPE_DOUBLE: + jdbcType = Types.DOUBLE; - break; + break; - case MysqlDefs.FIELD_TYPE_LONG: - jdbcType = Types.INTEGER; + case MysqlDefs.FIELD_TYPE_NULL: + jdbcType = Types.NULL; - break; + break; - case MysqlDefs.FIELD_TYPE_FLOAT: - jdbcType = Types.REAL; + case MysqlDefs.FIELD_TYPE_TIMESTAMP: + jdbcType = Types.TIMESTAMP; - break; + break; - case MysqlDefs.FIELD_TYPE_DOUBLE: - jdbcType = Types.DOUBLE; + case MysqlDefs.FIELD_TYPE_LONGLONG: + jdbcType = Types.BIGINT; - break; + break; - case MysqlDefs.FIELD_TYPE_NULL: - jdbcType = Types.NULL; + case MysqlDefs.FIELD_TYPE_INT24: + jdbcType = Types.INTEGER; - break; + break; - case MysqlDefs.FIELD_TYPE_TIMESTAMP: - jdbcType = Types.TIMESTAMP; + case MysqlDefs.FIELD_TYPE_DATE: + jdbcType = Types.DATE; - break; + break; - case MysqlDefs.FIELD_TYPE_LONGLONG: - jdbcType = Types.BIGINT; + case MysqlDefs.FIELD_TYPE_TIME: + jdbcType = Types.TIME; - break; + break; - case MysqlDefs.FIELD_TYPE_INT24: - jdbcType = Types.INTEGER; + case MysqlDefs.FIELD_TYPE_DATETIME: + jdbcType = Types.TIMESTAMP; - break; + break; - case MysqlDefs.FIELD_TYPE_DATE: - jdbcType = Types.DATE; + case MysqlDefs.FIELD_TYPE_YEAR: + jdbcType = Types.DATE; - break; + break; - case MysqlDefs.FIELD_TYPE_TIME: - jdbcType = Types.TIME; + case MysqlDefs.FIELD_TYPE_NEWDATE: + jdbcType = Types.DATE; - break; + break; - case MysqlDefs.FIELD_TYPE_DATETIME: - jdbcType = Types.TIMESTAMP; + case MysqlDefs.FIELD_TYPE_ENUM: + jdbcType = Types.CHAR; - break; + break; - case MysqlDefs.FIELD_TYPE_YEAR: - jdbcType = Types.DATE; + case MysqlDefs.FIELD_TYPE_SET: + jdbcType = Types.CHAR; - break; + break; - case MysqlDefs.FIELD_TYPE_NEWDATE: - jdbcType = Types.DATE; + case MysqlDefs.FIELD_TYPE_TINY_BLOB: + jdbcType = Types.VARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_ENUM: - jdbcType = Types.CHAR; + case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: + jdbcType = Types.LONGVARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_SET: - jdbcType = Types.CHAR; + case MysqlDefs.FIELD_TYPE_LONG_BLOB: + jdbcType = Types.LONGVARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_TINY_BLOB: - jdbcType = Types.VARBINARY; + case MysqlDefs.FIELD_TYPE_BLOB: + jdbcType = Types.LONGVARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: - jdbcType = Types.LONGVARBINARY; + case MysqlDefs.FIELD_TYPE_VAR_STRING: + case MysqlDefs.FIELD_TYPE_VARCHAR: + jdbcType = Types.VARCHAR; - break; + break; - case MysqlDefs.FIELD_TYPE_LONG_BLOB: - jdbcType = Types.LONGVARBINARY; + case MysqlDefs.FIELD_TYPE_JSON: + case MysqlDefs.FIELD_TYPE_STRING: + jdbcType = Types.CHAR; - break; + break; + case MysqlDefs.FIELD_TYPE_GEOMETRY: + jdbcType = Types.BINARY; - case MysqlDefs.FIELD_TYPE_BLOB: - jdbcType = Types.LONGVARBINARY; + break; + case MysqlDefs.FIELD_TYPE_BIT: + jdbcType = Types.BIT; - break; - - case MysqlDefs.FIELD_TYPE_VAR_STRING: - case MysqlDefs.FIELD_TYPE_VARCHAR: - jdbcType = Types.VARCHAR; - - break; - - case MysqlDefs.FIELD_TYPE_JSON: - case MysqlDefs.FIELD_TYPE_STRING: - jdbcType = Types.CHAR; - - break; - case MysqlDefs.FIELD_TYPE_GEOMETRY: - jdbcType = Types.BINARY; - - break; - case MysqlDefs.FIELD_TYPE_BIT: - jdbcType = Types.BIT; - - break; - default: - jdbcType = Types.VARCHAR; - } - - return jdbcType; + break; + default: + jdbcType = Types.VARCHAR; } - /** - * Maps the given MySQL type to the correct JDBC type. - */ - public static int mysqlToJavaType(String mysqlType) { - if (mysqlType.equalsIgnoreCase("BIT")) { - return mysqlToJavaType(FIELD_TYPE_BIT); - } else if (mysqlType.equalsIgnoreCase("TINYINT")) { - return mysqlToJavaType(FIELD_TYPE_TINY); - } else if (mysqlType.equalsIgnoreCase("SMALLINT")) { - return mysqlToJavaType(FIELD_TYPE_SHORT); - } else if (mysqlType.equalsIgnoreCase("MEDIUMINT")) { - return mysqlToJavaType(FIELD_TYPE_INT24); - } else if (mysqlType.equalsIgnoreCase("INT") || mysqlType.equalsIgnoreCase("INTEGER")) { - return mysqlToJavaType(FIELD_TYPE_LONG); - } else if (mysqlType.equalsIgnoreCase("BIGINT")) { - return mysqlToJavaType(FIELD_TYPE_LONGLONG); - } else if (mysqlType.equalsIgnoreCase("INT24")) { - return mysqlToJavaType(FIELD_TYPE_INT24); - } else if (mysqlType.equalsIgnoreCase("REAL")) { - return mysqlToJavaType(FIELD_TYPE_DOUBLE); - } else if (mysqlType.equalsIgnoreCase("FLOAT")) { - return mysqlToJavaType(FIELD_TYPE_FLOAT); - } else if (mysqlType.equalsIgnoreCase("DECIMAL")) { - return mysqlToJavaType(FIELD_TYPE_DECIMAL); - } else if (mysqlType.equalsIgnoreCase("NUMERIC")) { - return mysqlToJavaType(FIELD_TYPE_DECIMAL); - } else if (mysqlType.equalsIgnoreCase("DOUBLE")) { - return mysqlToJavaType(FIELD_TYPE_DOUBLE); - } else if (mysqlType.equalsIgnoreCase("CHAR")) { - return mysqlToJavaType(FIELD_TYPE_STRING); - } else if (mysqlType.equalsIgnoreCase("VARCHAR")) { - return mysqlToJavaType(FIELD_TYPE_VAR_STRING); - } else if (mysqlType.equalsIgnoreCase("DATE")) { - return mysqlToJavaType(FIELD_TYPE_DATE); - } else if (mysqlType.equalsIgnoreCase("TIME")) { - return mysqlToJavaType(FIELD_TYPE_TIME); - } else if (mysqlType.equalsIgnoreCase("YEAR")) { - return mysqlToJavaType(FIELD_TYPE_YEAR); - } else if (mysqlType.equalsIgnoreCase("TIMESTAMP")) { - return mysqlToJavaType(FIELD_TYPE_TIMESTAMP); - } else if (mysqlType.equalsIgnoreCase("DATETIME")) { - return mysqlToJavaType(FIELD_TYPE_DATETIME); - } else if (mysqlType.equalsIgnoreCase("TINYBLOB")) { - return Types.BINARY; - } else if (mysqlType.equalsIgnoreCase("BLOB")) { - return Types.LONGVARBINARY; - } else if (mysqlType.equalsIgnoreCase("MEDIUMBLOB")) { - return Types.LONGVARBINARY; - } else if (mysqlType.equalsIgnoreCase("LONGBLOB")) { - return Types.LONGVARBINARY; - } else if (mysqlType.equalsIgnoreCase("TINYTEXT")) { - return Types.VARCHAR; - } else if (mysqlType.equalsIgnoreCase("TEXT")) { - return Types.LONGVARCHAR; - } else if (mysqlType.equalsIgnoreCase("MEDIUMTEXT")) { - return Types.LONGVARCHAR; - } else if (mysqlType.equalsIgnoreCase("LONGTEXT")) { - return Types.LONGVARCHAR; - } else if (mysqlType.equalsIgnoreCase("ENUM")) { - return mysqlToJavaType(FIELD_TYPE_ENUM); - } else if (mysqlType.equalsIgnoreCase("SET")) { - return mysqlToJavaType(FIELD_TYPE_SET); - } else if (mysqlType.equalsIgnoreCase("GEOMETRY")) { - return mysqlToJavaType(FIELD_TYPE_GEOMETRY); - } else if (mysqlType.equalsIgnoreCase("BINARY")) { - return Types.BINARY; // no concrete type on the wire - } else if (mysqlType.equalsIgnoreCase("VARBINARY")) { - return Types.VARBINARY; // no concrete type on the wire - } else if (mysqlType.equalsIgnoreCase("BIT")) { - return mysqlToJavaType(FIELD_TYPE_BIT); - } else if (mysqlType.equalsIgnoreCase("JSON")) { - return mysqlToJavaType(FIELD_TYPE_JSON); - } - - // Punt - return Types.OTHER; + return jdbcType; + } + + /** + * Maps the given MySQL type to the correct JDBC type. + */ + public static int mysqlToJavaType(String mysqlType) { + if (mysqlType.equalsIgnoreCase("BIT")) { + return mysqlToJavaType(FIELD_TYPE_BIT); + } else if (mysqlType.equalsIgnoreCase("TINYINT")) { + return mysqlToJavaType(FIELD_TYPE_TINY); + } else if (mysqlType.equalsIgnoreCase("SMALLINT")) { + return mysqlToJavaType(FIELD_TYPE_SHORT); + } else if (mysqlType.equalsIgnoreCase("MEDIUMINT")) { + return mysqlToJavaType(FIELD_TYPE_INT24); + } else if (mysqlType.equalsIgnoreCase("INT") || mysqlType.equalsIgnoreCase("INTEGER")) { + return mysqlToJavaType(FIELD_TYPE_LONG); + } else if (mysqlType.equalsIgnoreCase("BIGINT")) { + return mysqlToJavaType(FIELD_TYPE_LONGLONG); + } else if (mysqlType.equalsIgnoreCase("INT24")) { + return mysqlToJavaType(FIELD_TYPE_INT24); + } else if (mysqlType.equalsIgnoreCase("REAL")) { + return mysqlToJavaType(FIELD_TYPE_DOUBLE); + } else if (mysqlType.equalsIgnoreCase("FLOAT")) { + return mysqlToJavaType(FIELD_TYPE_FLOAT); + } else if (mysqlType.equalsIgnoreCase("DECIMAL")) { + return mysqlToJavaType(FIELD_TYPE_DECIMAL); + } else if (mysqlType.equalsIgnoreCase("NUMERIC")) { + return mysqlToJavaType(FIELD_TYPE_DECIMAL); + } else if (mysqlType.equalsIgnoreCase("DOUBLE")) { + return mysqlToJavaType(FIELD_TYPE_DOUBLE); + } else if (mysqlType.equalsIgnoreCase("CHAR")) { + return mysqlToJavaType(FIELD_TYPE_STRING); + } else if (mysqlType.equalsIgnoreCase("VARCHAR")) { + return mysqlToJavaType(FIELD_TYPE_VAR_STRING); + } else if (mysqlType.equalsIgnoreCase("DATE")) { + return mysqlToJavaType(FIELD_TYPE_DATE); + } else if (mysqlType.equalsIgnoreCase("TIME")) { + return mysqlToJavaType(FIELD_TYPE_TIME); + } else if (mysqlType.equalsIgnoreCase("YEAR")) { + return mysqlToJavaType(FIELD_TYPE_YEAR); + } else if (mysqlType.equalsIgnoreCase("TIMESTAMP")) { + return mysqlToJavaType(FIELD_TYPE_TIMESTAMP); + } else if (mysqlType.equalsIgnoreCase("DATETIME")) { + return mysqlToJavaType(FIELD_TYPE_DATETIME); + } else if (mysqlType.equalsIgnoreCase("TINYBLOB")) { + return Types.BINARY; + } else if (mysqlType.equalsIgnoreCase("BLOB")) { + return Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("MEDIUMBLOB")) { + return Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("LONGBLOB")) { + return Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("TINYTEXT")) { + return Types.VARCHAR; + } else if (mysqlType.equalsIgnoreCase("TEXT")) { + return Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("MEDIUMTEXT")) { + return Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("LONGTEXT")) { + return Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("ENUM")) { + return mysqlToJavaType(FIELD_TYPE_ENUM); + } else if (mysqlType.equalsIgnoreCase("SET")) { + return mysqlToJavaType(FIELD_TYPE_SET); + } else if (mysqlType.equalsIgnoreCase("GEOMETRY")) { + return mysqlToJavaType(FIELD_TYPE_GEOMETRY); + } else if (mysqlType.equalsIgnoreCase("BINARY")) { + return Types.BINARY; // no concrete type on the wire + } else if (mysqlType.equalsIgnoreCase("VARBINARY")) { + return Types.VARBINARY; // no concrete type on the wire + } else if (mysqlType.equalsIgnoreCase("BIT")) { + return mysqlToJavaType(FIELD_TYPE_BIT); + } else if (mysqlType.equalsIgnoreCase("JSON")) { + return mysqlToJavaType(FIELD_TYPE_JSON); } - /** - * @param mysqlType - */ - public static String typeToName(int mysqlType) { - switch (mysqlType) { - case MysqlDefs.FIELD_TYPE_DECIMAL: - return "FIELD_TYPE_DECIMAL"; + // Punt + return Types.OTHER; + } - case MysqlDefs.FIELD_TYPE_TINY: - return "FIELD_TYPE_TINY"; + /** + * + */ + public static String typeToName(int mysqlType) { + switch (mysqlType) { + case MysqlDefs.FIELD_TYPE_DECIMAL: + return "FIELD_TYPE_DECIMAL"; - case MysqlDefs.FIELD_TYPE_SHORT: - return "FIELD_TYPE_SHORT"; + case MysqlDefs.FIELD_TYPE_TINY: + return "FIELD_TYPE_TINY"; - case MysqlDefs.FIELD_TYPE_LONG: - return "FIELD_TYPE_LONG"; + case MysqlDefs.FIELD_TYPE_SHORT: + return "FIELD_TYPE_SHORT"; - case MysqlDefs.FIELD_TYPE_FLOAT: - return "FIELD_TYPE_FLOAT"; + case MysqlDefs.FIELD_TYPE_LONG: + return "FIELD_TYPE_LONG"; - case MysqlDefs.FIELD_TYPE_DOUBLE: - return "FIELD_TYPE_DOUBLE"; + case MysqlDefs.FIELD_TYPE_FLOAT: + return "FIELD_TYPE_FLOAT"; - case MysqlDefs.FIELD_TYPE_NULL: - return "FIELD_TYPE_NULL"; + case MysqlDefs.FIELD_TYPE_DOUBLE: + return "FIELD_TYPE_DOUBLE"; - case MysqlDefs.FIELD_TYPE_TIMESTAMP: - return "FIELD_TYPE_TIMESTAMP"; + case MysqlDefs.FIELD_TYPE_NULL: + return "FIELD_TYPE_NULL"; - case MysqlDefs.FIELD_TYPE_LONGLONG: - return "FIELD_TYPE_LONGLONG"; + case MysqlDefs.FIELD_TYPE_TIMESTAMP: + return "FIELD_TYPE_TIMESTAMP"; - case MysqlDefs.FIELD_TYPE_INT24: - return "FIELD_TYPE_INT24"; + case MysqlDefs.FIELD_TYPE_LONGLONG: + return "FIELD_TYPE_LONGLONG"; - case MysqlDefs.FIELD_TYPE_DATE: - return "FIELD_TYPE_DATE"; + case MysqlDefs.FIELD_TYPE_INT24: + return "FIELD_TYPE_INT24"; - case MysqlDefs.FIELD_TYPE_TIME: - return "FIELD_TYPE_TIME"; + case MysqlDefs.FIELD_TYPE_DATE: + return "FIELD_TYPE_DATE"; - case MysqlDefs.FIELD_TYPE_DATETIME: - return "FIELD_TYPE_DATETIME"; + case MysqlDefs.FIELD_TYPE_TIME: + return "FIELD_TYPE_TIME"; - case MysqlDefs.FIELD_TYPE_YEAR: - return "FIELD_TYPE_YEAR"; + case MysqlDefs.FIELD_TYPE_DATETIME: + return "FIELD_TYPE_DATETIME"; - case MysqlDefs.FIELD_TYPE_NEWDATE: - return "FIELD_TYPE_NEWDATE"; + case MysqlDefs.FIELD_TYPE_YEAR: + return "FIELD_TYPE_YEAR"; - case MysqlDefs.FIELD_TYPE_ENUM: - return "FIELD_TYPE_ENUM"; + case MysqlDefs.FIELD_TYPE_NEWDATE: + return "FIELD_TYPE_NEWDATE"; - case MysqlDefs.FIELD_TYPE_SET: - return "FIELD_TYPE_SET"; + case MysqlDefs.FIELD_TYPE_ENUM: + return "FIELD_TYPE_ENUM"; - case MysqlDefs.FIELD_TYPE_TINY_BLOB: - return "FIELD_TYPE_TINY_BLOB"; + case MysqlDefs.FIELD_TYPE_SET: + return "FIELD_TYPE_SET"; - case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: - return "FIELD_TYPE_MEDIUM_BLOB"; + case MysqlDefs.FIELD_TYPE_TINY_BLOB: + return "FIELD_TYPE_TINY_BLOB"; - case MysqlDefs.FIELD_TYPE_LONG_BLOB: - return "FIELD_TYPE_LONG_BLOB"; + case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: + return "FIELD_TYPE_MEDIUM_BLOB"; - case MysqlDefs.FIELD_TYPE_BLOB: - return "FIELD_TYPE_BLOB"; + case MysqlDefs.FIELD_TYPE_LONG_BLOB: + return "FIELD_TYPE_LONG_BLOB"; - case MysqlDefs.FIELD_TYPE_VAR_STRING: - return "FIELD_TYPE_VAR_STRING"; + case MysqlDefs.FIELD_TYPE_BLOB: + return "FIELD_TYPE_BLOB"; - case MysqlDefs.FIELD_TYPE_STRING: - return "FIELD_TYPE_STRING"; + case MysqlDefs.FIELD_TYPE_VAR_STRING: + return "FIELD_TYPE_VAR_STRING"; - case MysqlDefs.FIELD_TYPE_VARCHAR: - return "FIELD_TYPE_VARCHAR"; + case MysqlDefs.FIELD_TYPE_STRING: + return "FIELD_TYPE_STRING"; - case MysqlDefs.FIELD_TYPE_GEOMETRY: - return "FIELD_TYPE_GEOMETRY"; + case MysqlDefs.FIELD_TYPE_VARCHAR: + return "FIELD_TYPE_VARCHAR"; - case MysqlDefs.FIELD_TYPE_JSON: - return "FIELD_TYPE_JSON"; + case MysqlDefs.FIELD_TYPE_GEOMETRY: + return "FIELD_TYPE_GEOMETRY"; - default: - return " Unknown MySQL Type # " + mysqlType; - } - } + case MysqlDefs.FIELD_TYPE_JSON: + return "FIELD_TYPE_JSON"; - static void appendJdbcTypeMappingQuery(StringBuilder buf, String mysqlTypeColumnName) { - - buf.append("CASE "); - Map typesMap = new HashMap(); - typesMap.putAll(mysqlToJdbcTypesMap); - typesMap.put("BINARY", Types.BINARY); - typesMap.put("VARBINARY", Types.VARBINARY); - - for (String mysqlTypeName : typesMap.keySet()) { - buf.append(" WHEN "); - buf.append(mysqlTypeColumnName); - buf.append("='"); - buf.append(mysqlTypeName); - buf.append("' THEN "); - buf.append(typesMap.get(mysqlTypeName)); - - if (mysqlTypeName.equalsIgnoreCase("DOUBLE") || mysqlTypeName.equalsIgnoreCase("FLOAT") - || mysqlTypeName.equalsIgnoreCase("DECIMAL") || mysqlTypeName - .equalsIgnoreCase("NUMERIC")) { - buf.append(" WHEN "); - buf.append(mysqlTypeColumnName); - buf.append("='"); - buf.append(mysqlTypeName); - buf.append(" unsigned' THEN "); - buf.append(typesMap.get(mysqlTypeName)); - } - } - - buf.append(" ELSE "); - buf.append(Types.OTHER); - buf.append(" END "); + default: + return " Unknown MySQL Type # " + mysqlType; } + } + + static void appendJdbcTypeMappingQuery(StringBuilder buf, String mysqlTypeColumnName) { + + buf.append("CASE "); + Map typesMap = new HashMap(); + typesMap.putAll(mysqlToJdbcTypesMap); + typesMap.put("BINARY", Types.BINARY); + typesMap.put("VARBINARY", Types.VARBINARY); + + for (String mysqlTypeName : typesMap.keySet()) { + buf.append(" WHEN "); + buf.append(mysqlTypeColumnName); + buf.append("='"); + buf.append(mysqlTypeName); + buf.append("' THEN "); + buf.append(typesMap.get(mysqlTypeName)); + + if (mysqlTypeName.equalsIgnoreCase("DOUBLE") || mysqlTypeName.equalsIgnoreCase("FLOAT") + || mysqlTypeName.equalsIgnoreCase("DECIMAL") || mysqlTypeName + .equalsIgnoreCase("NUMERIC")) { + buf.append(" WHEN "); + buf.append(mysqlTypeColumnName); + buf.append("='"); + buf.append(mysqlTypeName); + buf.append(" unsigned' THEN "); + buf.append(typesMap.get(mysqlTypeName)); + } + } + + buf.append(" ELSE "); + buf.append(Types.OTHER); + buf.append(" END "); + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/StringUtils.java b/java/jdbc/src/main/java/io/vitess/util/StringUtils.java index 96b4203d70d..4173f025e7f 100644 --- a/java/jdbc/src/main/java/io/vitess/util/StringUtils.java +++ b/java/jdbc/src/main/java/io/vitess/util/StringUtils.java @@ -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. @@ -34,927 +34,908 @@ */ public class StringUtils { - private static final String platformEncoding = System.getProperty("file.encoding"); - private static final ConcurrentHashMap charsetsByAlias = new ConcurrentHashMap(); - - // length of MySQL version reference in comments of type '/*![00000] */' - private static final int NON_COMMENTS_MYSQL_VERSION_REF_LENGTH = 5; + /** + * Full search mode: allow backslash escape, skip between markers, skip block comments, skip line + * comments and skip white space. + */ + public static final Set SEARCH_MODE__ALL = Collections + .unmodifiableSet(EnumSet.allOf(SearchMode.class)); + /** + * Search mode: skip between markers, skip block comments, skip line comments and skip white + * space. + */ + public static final Set SEARCH_MODE__MRK_COM_WS = Collections.unmodifiableSet(EnumSet + .of(SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS, + SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_WHITE_SPACE)); + private static final String platformEncoding = System.getProperty("file.encoding"); + private static final ConcurrentHashMap charsetsByAlias = + new ConcurrentHashMap(); + // length of MySQL version reference in comments of type '/*![00000] */' + private static final int NON_COMMENTS_MYSQL_VERSION_REF_LENGTH = 5; + + /* + * Convenience EnumSets for several SearchMode combinations + */ + + private StringUtils() { + } + + /** + * Determines whether or not the string 'searchIn' contains the string 'searchFor', disregarding + * case and leading whitespace + * + * @param searchIn the string to search in + * @param searchFor the string to search for + * @return true if the string starts with 'searchFor' ignoring whitespace + */ + public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor) { + return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0); + } + + /** + * Determines whether or not the string 'searchIn' contains the string 'searchFor', disregarding + * case and leading whitespace + * + * @param searchIn the string to search in + * @param searchFor the string to search for + * @param beginPos where to start searching + * @return true if the string starts with 'searchFor' ignoring whitespace + */ + + public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor, int beginPos) { + if (null == searchIn) { + return true; + } + int inLength = searchIn.length(); - private StringUtils() { + for (; beginPos < inLength; beginPos++) { + if (!Character.isWhitespace(searchIn.charAt(beginPos))) { + break; + } } - public enum SearchMode { - ALLOW_BACKSLASH_ESCAPE, SKIP_BETWEEN_MARKERS, SKIP_BLOCK_COMMENTS, SKIP_LINE_COMMENTS, SKIP_WHITE_SPACE; + return startsWithIgnoreCase(searchIn, beginPos, searchFor); + } + + /** + * Determines whether or not the string 'searchIn' contains the string 'searchFor', dis-regarding + * case starting at 'startAt' Shorthand for a String.regionMatch(...) + * + * @param searchIn the string to search in + * @param startAt the position to start at + * @param searchFor the string to search for + * @return whether searchIn starts with searchFor, ignoring case + */ + public static boolean startsWithIgnoreCase(String searchIn, int startAt, String searchFor) { + return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor.length()); + } + + private static boolean isCharEqualIgnoreCase(char charToCompare, char compareToCharUC, + char compareToCharLC) { + return Character.toLowerCase(charToCompare) == compareToCharLC + || Character.toUpperCase(charToCompare) == compareToCharUC; + } + + public static boolean isNullOrEmptyWithoutWS(String string) { + return null == string || 0 == string.trim().length(); + } + + /** + * Create the SQL string with parameters set by setXXX methods of PreparedStatement + * + * @return updated SQL string + */ + public static String getSqlWithoutParameter(String sql, Map parameterMap) { + if (!sql.contains("?")) { + return sql; } - /* - * Convenience EnumSets for several SearchMode combinations - */ - - /** - * Full search mode: allow backslash escape, skip between markers, skip block comments, skip line comments and skip white space. - */ - public static final Set SEARCH_MODE__ALL = Collections.unmodifiableSet(EnumSet.allOf(SearchMode.class)); - - /** - * Search mode: skip between markers, skip block comments, skip line comments and skip white space. - */ - public static final Set SEARCH_MODE__MRK_COM_WS = Collections.unmodifiableSet( - EnumSet.of(SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS, SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_WHITE_SPACE)); - - /** - * Determines whether or not the string 'searchIn' contains the string - * 'searchFor', disregarding case and leading whitespace - * - * @param searchIn the string to search in - * @param searchFor the string to search for - * @return true if the string starts with 'searchFor' ignoring whitespace - */ - public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor) { - return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0); + StringBuilder newSql = new StringBuilder(sql); + + int paramLoc = 1; + while (getCharIndexFromSqlByParamLocation(sql, '?', paramLoc) > 0) { + // check the user has set the needs parameters + if (parameterMap.containsKey(paramLoc)) { + int tt = getCharIndexFromSqlByParamLocation(newSql.toString(), '?', 1); + newSql.deleteCharAt(tt); + newSql.insert(tt, parameterMap.get(paramLoc)); + } + paramLoc++; } - /** - * Determines whether or not the string 'searchIn' contains the string - * 'searchFor', disregarding case and leading whitespace - * - * @param searchIn the string to search in - * @param searchFor the string to search for - * @param beginPos where to start searching - * @return true if the string starts with 'searchFor' ignoring whitespace - */ - - public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor, - int beginPos) { - if (null == searchIn) { - return true; - } - - int inLength = searchIn.length(); - - for (; beginPos < inLength; beginPos++) { - if (!Character.isWhitespace(searchIn.charAt(beginPos))) { - break; - } - } - - return startsWithIgnoreCase(searchIn, beginPos, searchFor); + return newSql.toString(); + + } + + /** + * Get the index of given char from the SQL string by parameter location + *
The -1 will be return, if nothing found + */ + private static int getCharIndexFromSqlByParamLocation(final String sql, final char cchar, + final int paramLoc) { + int signalCount = 0; + int charIndex = -1; + int num = 0; + for (int i = 0; i < sql.length(); i++) { + char c = sql.charAt(i); + if (c == '\'' || c == '\\') { // record the count of char "'" and char "\" + signalCount++; + } else if (c == cchar && signalCount % 2 == 0) { // check if the ? is really the parameter + num++; + if (num == paramLoc) { + charIndex = i; + break; + } + } } - - /** - * Determines whether or not the string 'searchIn' contains the string - * 'searchFor', dis-regarding case starting at 'startAt' Shorthand for a - * String.regionMatch(...) - * - * @param searchIn the string to search in - * @param startAt the position to start at - * @param searchFor the string to search for - * @return whether searchIn starts with searchFor, ignoring case - */ - public static boolean startsWithIgnoreCase(String searchIn, int startAt, String searchFor) { - return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor.length()); + return charIndex; + } + + /** + * Adds '+' to decimal numbers that are positive (MySQL doesn't understand them otherwise + * + * @param decimalString The value as a string + * @return String the string with a '+' added (if needed) + */ + public static String fixDecimalExponent(String decimalString) { + int ePos = decimalString.indexOf('E'); + + if (ePos == -1) { + ePos = decimalString.indexOf('e'); } - private static boolean isCharEqualIgnoreCase(char charToCompare, char compareToCharUC, char compareToCharLC) { - return Character.toLowerCase(charToCompare) == compareToCharLC || Character.toUpperCase(charToCompare) == compareToCharUC; - } + if (ePos != -1) { + if (decimalString.length() > (ePos + 1)) { + char maybeMinusChar = decimalString.charAt(ePos + 1); - public static boolean isNullOrEmptyWithoutWS(String string) { - return null == string || 0 == string.trim().length(); + if (maybeMinusChar != '-' && maybeMinusChar != '+') { + StringBuilder strBuilder = new StringBuilder(decimalString.length() + 1); + strBuilder.append(decimalString.substring(0, ePos + 1)); + strBuilder.append('+'); + strBuilder.append(decimalString.substring(ePos + 1, decimalString.length())); + decimalString = strBuilder.toString(); + } + } } - /** - * Create the SQL string with parameters set by setXXX methods of PreparedStatement - * - * @param sql - * @param parameterMap - * @return updated SQL string - */ - public static String getSqlWithoutParameter(String sql, Map parameterMap) { - if (!sql.contains("?")) { - return sql; - } + return decimalString; + } - StringBuilder newSql = new StringBuilder(sql); + /* + * DateTime Format Parsing Logic from Mysql JDBC + */ + public static String getDateTimePattern(String dt, boolean toTime) throws Exception { + int dtLength = (dt != null) ? dt.length() : 0; - int paramLoc = 1; - while (getCharIndexFromSqlByParamLocation(sql, '?', paramLoc) > 0) { - // check the user has set the needs parameters - if (parameterMap.containsKey(paramLoc)) { - int tt = getCharIndexFromSqlByParamLocation(newSql.toString(), '?', 1); - newSql.deleteCharAt(tt); - newSql.insert(tt, parameterMap.get(paramLoc)); - } - paramLoc++; - } + if ((dtLength >= 8) && (dtLength <= 10)) { + int dashCount = 0; + boolean isDateOnly = true; - return newSql.toString(); - - } - - /** - * Get the index of given char from the SQL string by parameter location - *
The -1 will be return, if nothing found - * - * @param sql - * @param cchar - * @param paramLoc - * @return - */ - private static int getCharIndexFromSqlByParamLocation(final String sql, final char cchar, - final int paramLoc) { - int signalCount = 0; - int charIndex = -1; - int num = 0; - for (int i = 0; i < sql.length(); i++) { - char c = sql.charAt(i); - if (c == '\'' || c == '\\')// record the count of char "'" and char "\" - { - signalCount++; - } else if (c == cchar - && signalCount % 2 == 0) {// check if the ? is really the parameter - num++; - if (num == paramLoc) { - charIndex = i; - break; - } - } - } - return charIndex; - } + for (int i = 0; i < dtLength; i++) { + char c = dt.charAt(i); - /** - * Adds '+' to decimal numbers that are positive (MySQL doesn't understand - * them otherwise - * - * @param decimalString The value as a string - * @return String the string with a '+' added (if needed) - */ - public static String fixDecimalExponent(String decimalString) { - int ePos = decimalString.indexOf('E'); + if (!Character.isDigit(c) && (c != '-')) { + isDateOnly = false; - if (ePos == -1) { - ePos = decimalString.indexOf('e'); + break; } - if (ePos != -1) { - if (decimalString.length() > (ePos + 1)) { - char maybeMinusChar = decimalString.charAt(ePos + 1); - - if (maybeMinusChar != '-' && maybeMinusChar != '+') { - StringBuilder strBuilder = new StringBuilder(decimalString.length() + 1); - strBuilder.append(decimalString.substring(0, ePos + 1)); - strBuilder.append('+'); - strBuilder.append(decimalString.substring(ePos + 1, decimalString.length())); - decimalString = strBuilder.toString(); - } - } + if (c == '-') { + dashCount++; } + } - return decimalString; + if (isDateOnly && (dashCount == 2)) { + return "yyyy-MM-dd"; + } } - /* - * DateTime Format Parsing Logic from Mysql JDBC - */ - public static String getDateTimePattern(String dt, boolean toTime) throws Exception { - int dtLength = (dt != null) ? dt.length() : 0; + // Special case - time-only + boolean colonsOnly = true; + for (int i = 0; i < dtLength; i++) { + char c = dt.charAt(i); - if ((dtLength >= 8) && (dtLength <= 10)) { - int dashCount = 0; - boolean isDateOnly = true; + if (!Character.isDigit(c) && (c != ':')) { + colonsOnly = false; - for (int i = 0; i < dtLength; i++) { - char c = dt.charAt(i); - - if (!Character.isDigit(c) && (c != '-')) { - isDateOnly = false; + break; + } + } - break; - } + if (colonsOnly) { + return "HH:mm:ss"; + } - if (c == '-') { - dashCount++; - } - } + int n; + int z; + int count; + int maxvecs; + char c; + char separator; + StringReader reader = new StringReader(dt + " "); + ArrayList vec = new ArrayList<>(); + ArrayList vecRemovelist = new ArrayList<>(); + Object[] nv = new Object[3]; + Object[] v; + nv[0] = 'y'; + nv[1] = new StringBuilder(); + nv[2] = 0; + vec.add(nv); + + if (toTime) { + nv = new Object[3]; + nv[0] = 'h'; + nv[1] = new StringBuilder(); + nv[2] = 0; + vec.add(nv); + } - if (isDateOnly && (dashCount == 2)) { - return "yyyy-MM-dd"; - } - } + while ((z = reader.read()) != -1) { + separator = (char) z; + maxvecs = vec.size(); - // Special case - time-only - boolean colonsOnly = true; - for (int i = 0; i < dtLength; i++) { - char c = dt.charAt(i); + for (count = 0; count < maxvecs; count++) { + v = vec.get(count); + n = (Integer) v[2]; + c = getSuccessor((Character) v[0], n); - if (!Character.isDigit(c) && (c != ':')) { - colonsOnly = false; + if (!Character.isLetterOrDigit(separator)) { + if ((c == (Character) v[0]) && (c != 'S')) { + vecRemovelist.add(v); + } else { + ((StringBuilder) v[1]).append(separator); - break; + if ((c == 'X') || (c == 'Y')) { + v[2] = 4; } - } - - if (colonsOnly) { - return "HH:mm:ss"; - } - - int n; - int z; - int count; - int maxvecs; - char c; - char separator; - StringReader reader = new StringReader(dt + " "); - ArrayList vec = new ArrayList<>(); - ArrayList vecRemovelist = new ArrayList<>(); - Object[] nv = new Object[3]; - Object[] v; - nv[0] = 'y'; - nv[1] = new StringBuilder(); - nv[2] = 0; - vec.add(nv); - - if (toTime) { + } + } else { + if (c == 'X') { + c = 'y'; nv = new Object[3]; - nv[0] = 'h'; - nv[1] = new StringBuilder(); - nv[2] = 0; + nv[1] = (new StringBuilder((v[1]).toString())).append('M'); + nv[0] = 'M'; + nv[2] = 1; vec.add(nv); - } - - while ((z = reader.read()) != -1) { - separator = (char) z; - maxvecs = vec.size(); - - for (count = 0; count < maxvecs; count++) { - v = vec.get(count); - n = (Integer) v[2]; - c = getSuccessor((Character) v[0], n); - - if (!Character.isLetterOrDigit(separator)) { - if ((c == (Character) v[0]) && (c != 'S')) { - vecRemovelist.add(v); - } else { - ((StringBuilder) v[1]).append(separator); - - if ((c == 'X') || (c == 'Y')) { - v[2] = 4; - } - } - } else { - if (c == 'X') { - c = 'y'; - nv = new Object[3]; - nv[1] = (new StringBuilder((v[1]).toString())).append('M'); - nv[0] = 'M'; - nv[2] = 1; - vec.add(nv); - } else if (c == 'Y') { - c = 'M'; - nv = new Object[3]; - nv[1] = (new StringBuilder((v[1]).toString())).append('d'); - nv[0] = 'd'; - nv[2] = 1; - vec.add(nv); - } - - ((StringBuilder) v[1]).append(c); - if (c == (Character) v[0]) { - v[2] = n + 1; - } else { - v[0] = c; - v[2] = 1; - } - } - } - - for (Object[] aVecRemovelist : vecRemovelist) { - v = aVecRemovelist; - vec.remove(v); - } - vecRemovelist.clear(); - } - - int size = vec.size(); - for (int i = 0; i < size; i++) { - v = vec.get(i); - c = (Character) v[0]; - n = (Integer) v[2]; - - boolean bk = getSuccessor(c, n) != c; - boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk); - boolean finishesAtDate = (bk && (c == 'd') && !toTime); - boolean containsEnd = ((v[1]).toString().indexOf('W') != -1); - - if ((!atEnd && !finishesAtDate) || (containsEnd)) { - vecRemovelist.add(v); - } - } + } else if (c == 'Y') { + c = 'M'; + nv = new Object[3]; + nv[1] = (new StringBuilder((v[1]).toString())).append('d'); + nv[0] = 'd'; + nv[2] = 1; + vec.add(nv); + } + + ((StringBuilder) v[1]).append(c); + if (c == (Character) v[0]) { + v[2] = n + 1; + } else { + v[0] = c; + v[2] = 1; + } + } + } + + for (Object[] aVecRemovelist : vecRemovelist) { + v = aVecRemovelist; + vec.remove(v); + } + vecRemovelist.clear(); + } - size = vecRemovelist.size(); + int size = vec.size(); + for (int i = 0; i < size; i++) { + v = vec.get(i); + c = (Character) v[0]; + n = (Integer) v[2]; - for (int i = 0; i < size; i++) { - vec.remove(vecRemovelist.get(i)); - } + boolean bk = getSuccessor(c, n) != c; + boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk); + boolean finishesAtDate = (bk && (c == 'd') && !toTime); + boolean containsEnd = ((v[1]).toString().indexOf('W') != -1); - vecRemovelist.clear(); - v = vec.get(0); // might throw exception - - StringBuilder format = (StringBuilder) v[1]; - format.setLength(format.length() - 1); - - return format.toString(); - } - - private static char getSuccessor(char c, int n) { - return ((c == 'y') && (n == 2)) ? - 'X' : - (((c == 'y') && (n < 4)) ? - 'y' : - ((c == 'y') ? - 'M' : - (((c == 'M') && (n == 2)) ? - 'Y' : - (((c == 'M') && (n < 3)) ? - 'M' : - ((c == 'M') ? - 'd' : - (((c == 'd') && (n < 2)) ? - 'd' : - ((c == 'd') ? - 'H' : - (((c == 'H') && (n < 2)) ? - 'H' : - ((c == 'H') ? - 'm' : - (((c == 'm') && (n < 2)) ? - 'm' : - ((c == 'm') ? - 's' : - (((c == 's') && (n < 2)) ? - 's' : - 'W')))))))))))); - } - - /** - * Finds the true start of a SQL statement, by skipping leading comments. - * If the query is multiple lines - * @param sql to parse - * @return position index in string - */ - public static int findStartOfStatement(String sql) { - int statementStartPos = 0; - if (StringUtils.startsWithIgnoreCaseAndWs(sql, "/*")) { - statementStartPos = sql.indexOf("*/"); - - if (statementStartPos == -1) { - statementStartPos = 0; - } else { - statementStartPos += 2; - } - } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "--") || StringUtils.startsWithIgnoreCaseAndWs(sql, "#")) { - statementStartPos = sql.indexOf('\n'); + if ((!atEnd && !finishesAtDate) || (containsEnd)) { + vecRemovelist.add(v); + } + } - if (statementStartPos == -1) { - statementStartPos = sql.indexOf('\r'); + size = vecRemovelist.size(); - if (statementStartPos == -1) { - statementStartPos = 0; - } - } - } - return statementStartPos; + for (int i = 0; i < size; i++) { + vec.remove(vecRemovelist.get(i)); } - public static char firstAlphaCharUc(String searchIn, int startAt) { - if (searchIn == null) { - return 0; - } + vecRemovelist.clear(); + v = vec.get(0); // might throw exception + + StringBuilder format = (StringBuilder) v[1]; + format.setLength(format.length() - 1); + + return format.toString(); + } + + private static char getSuccessor(char c, int n) { + return ((c == 'y') && (n == 2)) ? 'X' : (((c == 'y') && (n < 4)) ? 'y' : ((c == 'y') ? 'M' + : (((c == 'M') && (n == 2)) ? 'Y' : (((c == 'M') && (n < 3)) ? 'M' : ((c == 'M') ? 'd' + : (((c == 'd') && (n < 2)) ? 'd' : ((c == 'd') ? 'H' : (((c == 'H') && (n < 2)) ? 'H' + : ((c == 'H') ? 'm' : (((c == 'm') && (n < 2)) ? 'm' + : ((c == 'm') ? 's' : (((c == 's') && (n < 2)) ? 's' : 'W')))))))))))); + } + + /** + * Finds the true start of a SQL statement, by skipping leading comments. If the query is multiple + * lines + * + * @param sql to parse + * @return position index in string + */ + public static int findStartOfStatement(String sql) { + int statementStartPos = 0; + if (StringUtils.startsWithIgnoreCaseAndWs(sql, "/*")) { + statementStartPos = sql.indexOf("*/"); + + if (statementStartPos == -1) { + statementStartPos = 0; + } else { + statementStartPos += 2; + } + } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "--") || StringUtils + .startsWithIgnoreCaseAndWs(sql, "#")) { + statementStartPos = sql.indexOf('\n'); + + if (statementStartPos == -1) { + statementStartPos = sql.indexOf('\r'); + + if (statementStartPos == -1) { + statementStartPos = 0; + } + } + } + return statementStartPos; + } - int length = searchIn.length(); + public static char firstAlphaCharUc(String searchIn, int startAt) { + if (searchIn == null) { + return 0; + } - for (int i = startAt; i < length; i++) { - char c = searchIn.charAt(i); + int length = searchIn.length(); - if (Character.isLetter(c)) { - return Character.toUpperCase(c); - } - } + for (int i = startAt; i < length; i++) { + char c = searchIn.charAt(i); - return 0; + if (Character.isLetter(c)) { + return Character.toUpperCase(c); + } } - public static String toString(byte[] value, int offset, int length, String encoding) throws UnsupportedEncodingException { - Charset cs = findCharset(encoding); - return cs.decode(ByteBuffer.wrap(value, offset, length)).toString(); + return 0; + } + + public static String toString(byte[] value, int offset, int length, String encoding) + throws UnsupportedEncodingException { + Charset cs = findCharset(encoding); + return cs.decode(ByteBuffer.wrap(value, offset, length)).toString(); + } + + public static String toString(byte[] value, String encoding) throws UnsupportedEncodingException { + return findCharset(encoding).decode(ByteBuffer.wrap(value)).toString(); + } + + public static String toString(byte[] value, int offset, int length) { + try { + return findCharset(platformEncoding).decode(ByteBuffer.wrap(value, offset, length)) + .toString(); + } catch (UnsupportedEncodingException e) { + // can't happen, emulating new String(byte[]) } - - public static String toString(byte[] value, String encoding) throws UnsupportedEncodingException { - return findCharset(encoding) - .decode(ByteBuffer.wrap(value)) - .toString(); + return null; + } + + public static String toString(byte[] value) { + try { + return findCharset(platformEncoding).decode(ByteBuffer.wrap(value)).toString(); + } catch (UnsupportedEncodingException e) { + // can't happen, emulating new String(byte[]) } - - public static String toString(byte[] value, int offset, int length) { - try { - return findCharset(platformEncoding) - .decode(ByteBuffer.wrap(value, offset, length)) - .toString(); - } catch (UnsupportedEncodingException e) { - // can't happen, emulating new String(byte[]) - } - return null; + return null; + } + + public static byte[] getBytes(String value, String encoding) throws UnsupportedEncodingException { + return getBytes(value, 0, value.length(), encoding); + } + + public static byte[] getBytes(String value, int offset, int length, String encoding) + throws UnsupportedEncodingException { + Charset cs = findCharset(encoding); + ByteBuffer buf = cs.encode(CharBuffer.wrap(value.toCharArray(), offset, length)); + // can't simply .array() this to get the bytes especially with variable-length charsets the + // buffer is sometimes larger than the actual encoded data + int encodedLen = buf.limit(); + byte[] asBytes = new byte[encodedLen]; + buf.get(asBytes, 0, encodedLen); + return asBytes; + } + + private static Charset findCharset(String alias) throws UnsupportedEncodingException { + try { + Charset cs = charsetsByAlias.get(alias); + if (cs == null) { + cs = Charset.forName(alias); + Charset oldCs = charsetsByAlias.putIfAbsent(alias, cs); + if (oldCs != null) { + // if the previous value was recently set by another thread we return it instead of + // value we found here + cs = oldCs; + } + } + return cs; + // We re-throw these runtimes for compatibility with java.io + } catch (IllegalArgumentException iae) { + throw new UnsupportedEncodingException(alias); } - - public static String toString(byte[] value) { - try { - return findCharset(platformEncoding) - .decode(ByteBuffer.wrap(value)) - .toString(); - } catch (UnsupportedEncodingException e) { - // can't happen, emulating new String(byte[]) - } - return null; + } + + /** + * Searches for a quoteChar in the searchIn string + */ + public static int indexOfQuoteDoubleAware(String searchIn, String quoteChar, int startFrom) { + if (searchIn == null || quoteChar == null || quoteChar.length() == 0 || startFrom > searchIn + .length()) { + return -1; } - - public static byte[] getBytes(String value, String encoding) throws UnsupportedEncodingException { - return getBytes(value, 0, value.length(), encoding); + int lastIndex = searchIn.length() - 1; + int beginPos = startFrom; + int pos = -1; + boolean next = true; + while (next) { + pos = searchIn.indexOf(quoteChar, beginPos); + if (pos == -1 || pos == lastIndex || !searchIn.startsWith(quoteChar, pos + 1)) { + next = false; + } else { + beginPos = pos + 2; + } } - - public static byte[] getBytes(String value, int offset, int length, String encoding) throws UnsupportedEncodingException { - Charset cs = findCharset(encoding); - ByteBuffer buf = cs.encode(CharBuffer.wrap(value.toCharArray(), offset, length)); - // can't simply .array() this to get the bytes especially with variable-length charsets the buffer is sometimes larger than the actual encoded data - int encodedLen = buf.limit(); - byte[] asBytes = new byte[encodedLen]; - buf.get(asBytes, 0, encodedLen); - return asBytes; + return pos; + } + + /** + * Quotes an identifier, escaping any dangling quotes within + */ + public static String quoteIdentifier(String identifier, String quoteChar) { + if (identifier == null) { + return null; } - - private static Charset findCharset(String alias) throws UnsupportedEncodingException { - try { - Charset cs = charsetsByAlias.get(alias); - if (cs == null) { - cs = Charset.forName(alias); - Charset oldCs = charsetsByAlias.putIfAbsent(alias, cs); - if (oldCs != null) { - // if the previous value was recently set by another thread we return it instead of value we found here - cs = oldCs; - } - } - return cs; - // We re-throw these runtimes for compatibility with java.io - } catch (IllegalArgumentException iae) { - throw new UnsupportedEncodingException(alias); - } + identifier = identifier.trim(); + int quoteCharLength = quoteChar.length(); + if (quoteCharLength == 0 || " ".equals(quoteChar)) { + return identifier; } - /** - * Searches for a quoteChar in the searchIn string - * @param searchIn - * @param quoteChar - * @param startFrom - * @return - */ - public static int indexOfQuoteDoubleAware(String searchIn, String quoteChar, int startFrom) { - if (searchIn == null || quoteChar == null || quoteChar.length() == 0 || startFrom > searchIn.length()) { - return -1; - } - int lastIndex = searchIn.length() - 1; - int beginPos = startFrom; - int pos = -1; - boolean next = true; - while (next) { - pos = searchIn.indexOf(quoteChar, beginPos); - if (pos == -1 || pos == lastIndex || !searchIn.startsWith(quoteChar, pos + 1)) { - next = false; - } else { - beginPos = pos + 2; - } - } - return pos; - } - - /** - * Quotes an identifier, escaping any dangling quotes within - * @param identifier - * @param quoteChar - * @return - */ - public static String quoteIdentifier(String identifier, String quoteChar) { - if (identifier == null) { - return null; - } - identifier = identifier.trim(); - int quoteCharLength = quoteChar.length(); - if (quoteCharLength == 0 || " ".equals(quoteChar)) { - return identifier; - } - - if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { - String identifierQuoteTrimmed = identifier.substring(quoteCharLength, identifier.length() - quoteCharLength); - int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); - while (quoteCharPos >= 0) { - int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; - int quoteCharNextPosition = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextExpectedPos); - - if (quoteCharNextPosition == quoteCharNextExpectedPos) { - quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); - } else { - // Not a pair of quotes! - break; - } - } - - if (quoteCharPos < 0) { - return identifier; - } - } - - return quoteChar + identifier.replaceAll(quoteChar, quoteChar + quoteChar) + quoteChar; - } - - /** - * Finds the position of the first of a consecutive sequence of strings within a string, ignoring case, with the option to skip text delimited by given - * markers or within comments. - *

- * Independently of the searchMode provided, when searching for the second and following strings SearchMode.SKIP_WHITE_SPACE will - * be added and SearchMode.SKIP_BETWEEN_MARKERS removed. - *

- * - * @param startingPosition - * the position to start the search from - * @param searchIn - * the string to search in - * @param searchFor - * the array of strings to search for - * @param openingMarkers - * characters which delimit the beginning of a text block to skip - * @param closingMarkers - * characters which delimit the end of a text block to skip - * @param searchMode - * a Set, ideally an EnumSet, containing the flags from the enum StringUtils.SearchMode that determine the - * behavior of the search - * @return the position where searchFor is found within searchIn starting from startingPosition. - */ - public static int indexOfIgnoreCase(int startingPosition, String searchIn, String[] searchForSequence, String openingMarkers, String closingMarkers, - Set searchMode) { - if ((searchIn == null) || (searchForSequence == null)) { - return -1; - } - - int searchInLength = searchIn.length(); - int searchForLength = 0; - for (String searchForPart : searchForSequence) { - searchForLength += searchForPart.length(); - } // minimum length for searchFor (without gaps between words) - - if (searchForLength == 0) { - return -1; - } + if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { + String identifierQuoteTrimmed = identifier + .substring(quoteCharLength, identifier.length() - quoteCharLength); + int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); + while (quoteCharPos >= 0) { + int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; + int quoteCharNextPosition = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextExpectedPos); + + if (quoteCharNextPosition == quoteCharNextExpectedPos) { + quoteCharPos = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); + } else { + // Not a pair of quotes! + break; + } + } + + if (quoteCharPos < 0) { + return identifier; + } + } - int searchForWordsCount = searchForSequence.length; - searchForLength += searchForWordsCount > 0 ? searchForWordsCount - 1 : 0; // add gaps between words - int stopSearchingAt = searchInLength - searchForLength; + return quoteChar + identifier.replaceAll(quoteChar, quoteChar + quoteChar) + quoteChar; + } + + /** + * Finds the position of the first of a consecutive sequence of strings within a string, ignoring + * case, with the option to skip text delimited by given markers or within comments. + *

+ * Independently of the searchMode provided, when searching for the second and + * following strings SearchMode.SKIP_WHITE_SPACE will be added and + * SearchMode.SKIP_BETWEEN_MARKERS removed. + *

+ * + * @param startingPosition the position to start the search from + * @param searchIn the string to search in + * @param searchFor the array of strings to search for + * @param openingMarkers characters which delimit the beginning of a text block to skip + * @param closingMarkers characters which delimit the end of a text block to skip + * @param searchMode a Set, ideally an EnumSet, containing the flags + * from the enum StringUtils.SearchMode that determine the behavior of the + * search + * @return the position where searchFor is found within searchIn + * starting from startingPosition. + */ + public static int indexOfIgnoreCase(int startingPosition, String searchIn, + String[] searchForSequence, String openingMarkers, String closingMarkers, + Set searchMode) { + if ((searchIn == null) || (searchForSequence == null)) { + return -1; + } - if (startingPosition > stopSearchingAt) { - return -1; - } + int searchInLength = searchIn.length(); + int searchForLength = 0; + for (String searchForPart : searchForSequence) { + searchForLength += searchForPart.length(); + } // minimum length for searchFor (without gaps between words) - if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) - && (openingMarkers == null || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { - throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); - } + if (searchForLength == 0) { + return -1; + } - if (Character.isWhitespace(searchForSequence[0].charAt(0)) && searchMode.contains(SearchMode.SKIP_WHITE_SPACE)) { - // Can't skip white spaces if first searchFor char is one - searchMode = EnumSet.copyOf(searchMode); - searchMode.remove(SearchMode.SKIP_WHITE_SPACE); - } + int searchForWordsCount = searchForSequence.length; + searchForLength += + searchForWordsCount > 0 ? searchForWordsCount - 1 : 0; // add gaps between words + int stopSearchingAt = searchInLength - searchForLength; - // searchMode set used to search 2nd and following words can't contain SearchMode.SKIP_BETWEEN_MARKERS and must - // contain SearchMode.SKIP_WHITE_SPACE - Set searchMode2 = EnumSet.of(SearchMode.SKIP_WHITE_SPACE); - searchMode2.addAll(searchMode); - searchMode2.remove(SearchMode.SKIP_BETWEEN_MARKERS); + if (startingPosition > stopSearchingAt) { + return -1; + } - for (int positionOfFirstWord = startingPosition; positionOfFirstWord <= stopSearchingAt; positionOfFirstWord++) { - positionOfFirstWord = indexOfIgnoreCase(positionOfFirstWord, searchIn, searchForSequence[0], openingMarkers, closingMarkers, searchMode); + if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (openingMarkers == null + || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { + throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); + } - if (positionOfFirstWord == -1 || positionOfFirstWord > stopSearchingAt) { - return -1; - } + if (Character.isWhitespace(searchForSequence[0].charAt(0)) && searchMode + .contains(SearchMode.SKIP_WHITE_SPACE)) { + // Can't skip white spaces if first searchFor char is one + searchMode = EnumSet.copyOf(searchMode); + searchMode.remove(SearchMode.SKIP_WHITE_SPACE); + } - int startingPositionForNextWord = positionOfFirstWord + searchForSequence[0].length(); - int wc = 0; - boolean match = true; - while (++wc < searchForWordsCount && match) { - int positionOfNextWord = indexOfNextChar(startingPositionForNextWord, searchInLength - 1, searchIn, null, null, searchMode2); - if (startingPositionForNextWord == positionOfNextWord || !startsWithIgnoreCase(searchIn, positionOfNextWord, searchForSequence[wc])) { - // either no gap between words or match failed - match = false; - } else { - startingPositionForNextWord = positionOfNextWord + searchForSequence[wc].length(); - } - } + // searchMode set used to search 2nd and following words can't contain SearchMode + // .SKIP_BETWEEN_MARKERS and must + // contain SearchMode.SKIP_WHITE_SPACE + Set searchMode2 = EnumSet.of(SearchMode.SKIP_WHITE_SPACE); + searchMode2.addAll(searchMode); + searchMode2.remove(SearchMode.SKIP_BETWEEN_MARKERS); - if (match) { - return positionOfFirstWord; - } - } + for (int positionOfFirstWord = startingPosition; positionOfFirstWord <= stopSearchingAt; + positionOfFirstWord++) { + positionOfFirstWord = indexOfIgnoreCase(positionOfFirstWord, searchIn, searchForSequence[0], + openingMarkers, closingMarkers, searchMode); + if (positionOfFirstWord == -1 || positionOfFirstWord > stopSearchingAt) { return -1; + } + + int startingPositionForNextWord = positionOfFirstWord + searchForSequence[0].length(); + int wc = 0; + boolean match = true; + while (++wc < searchForWordsCount && match) { + int positionOfNextWord = indexOfNextChar(startingPositionForNextWord, searchInLength - 1, + searchIn, null, null, searchMode2); + if (startingPositionForNextWord == positionOfNextWord || !startsWithIgnoreCase(searchIn, + positionOfNextWord, searchForSequence[wc])) { + // either no gap between words or match failed + match = false; + } else { + startingPositionForNextWord = positionOfNextWord + searchForSequence[wc].length(); + } + } + + if (match) { + return positionOfFirstWord; + } } - /** - * Convenience function for {@link #indexOfIgnoreCase(int, String, String, String, String, Set)}, passing {@link #SEARCH_MODE__ALL} - */ - public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, String openingMarkers, String closingMarkers) { - return indexOfIgnoreCase(startingPosition, searchIn, searchFor, openingMarkers, closingMarkers, SEARCH_MODE__ALL); - } - - /** - * Finds the position of a substring within a string, ignoring case, with the option to skip text delimited by given markers or within comments. - * - * @param startingPosition - * the position to start the search from - * @param searchIn - * the string to search in - * @param searchFor - * the string to search for - * @param openingMarkers - * characters which delimit the beginning of a text block to skip - * @param closingMarkers - * characters which delimit the end of a text block to skip - * @param searchMode - * a Set, ideally an EnumSet, containing the flags from the enum StringUtils.SearchMode that determine the - * behavior of the search - * @return the position where searchFor is found within searchIn starting from startingPosition. - */ - public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, String openingMarkers, String closingMarkers, - Set searchMode) { - if (searchIn == null || searchFor == null) { - return -1; - } - - int searchInLength = searchIn.length(); - int searchForLength = searchFor.length(); - int stopSearchingAt = searchInLength - searchForLength; - - if (startingPosition > stopSearchingAt || searchForLength == 0) { - return -1; - } - - if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) - && (openingMarkers == null || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { - throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); - } + return -1; + } + + /** + * Convenience function for {@link #indexOfIgnoreCase(int, String, String, String, String, Set)}, + * passing {@link #SEARCH_MODE__ALL} + */ + public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, + String openingMarkers, String closingMarkers) { + return indexOfIgnoreCase(startingPosition, searchIn, searchFor, openingMarkers, closingMarkers, + SEARCH_MODE__ALL); + } + + /** + * Finds the position of a substring within a string, ignoring case, with the option to skip text + * delimited by given markers or within comments. + * + * @param startingPosition the position to start the search from + * @param searchIn the string to search in + * @param searchFor the string to search for + * @param openingMarkers characters which delimit the beginning of a text block to skip + * @param closingMarkers characters which delimit the end of a text block to skip + * @param searchMode a Set, ideally an EnumSet, containing the flags + * from the enum StringUtils.SearchMode that determine the behavior of the + * search + * @return the position where searchFor is found within searchIn + * starting from startingPosition. + */ + public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, + String openingMarkers, String closingMarkers, Set searchMode) { + if (searchIn == null || searchFor == null) { + return -1; + } - // Some locales don't follow upper-case rule, so need to check both - char firstCharOfSearchForUc = Character.toUpperCase(searchFor.charAt(0)); - char firstCharOfSearchForLc = Character.toLowerCase(searchFor.charAt(0)); + int searchInLength = searchIn.length(); + int searchForLength = searchFor.length(); + int stopSearchingAt = searchInLength - searchForLength; - if (Character.isWhitespace(firstCharOfSearchForLc) && searchMode.contains(SearchMode.SKIP_WHITE_SPACE)) { - // Can't skip white spaces if first searchFor char is one - searchMode = EnumSet.copyOf(searchMode); - searchMode.remove(SearchMode.SKIP_WHITE_SPACE); - } + if (startingPosition > stopSearchingAt || searchForLength == 0) { + return -1; + } - for (int i = startingPosition; i <= stopSearchingAt; i++) { - i = indexOfNextChar(i, stopSearchingAt, searchIn, openingMarkers, closingMarkers, searchMode); + if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (openingMarkers == null + || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { + throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); + } - if (i == -1) { - return -1; - } + // Some locales don't follow upper-case rule, so need to check both + char firstCharOfSearchForUc = Character.toUpperCase(searchFor.charAt(0)); + char firstCharOfSearchForLc = Character.toLowerCase(searchFor.charAt(0)); - char c = searchIn.charAt(i); + if (Character.isWhitespace(firstCharOfSearchForLc) && searchMode + .contains(SearchMode.SKIP_WHITE_SPACE)) { + // Can't skip white spaces if first searchFor char is one + searchMode = EnumSet.copyOf(searchMode); + searchMode.remove(SearchMode.SKIP_WHITE_SPACE); + } - if (isCharEqualIgnoreCase(c, firstCharOfSearchForUc, firstCharOfSearchForLc) && startsWithIgnoreCase(searchIn, i, searchFor)) { - return i; - } - } + for (int i = startingPosition; i <= stopSearchingAt; i++) { + i = indexOfNextChar(i, stopSearchingAt, searchIn, openingMarkers, closingMarkers, searchMode); + if (i == -1) { return -1; - } + } - /** - * Finds the position the next character from a string, possibly skipping white space, comments and text between markers. - * - * @param startingPosition - * the position to start the search from - * @param stopPosition - * the position where to stop the search (inclusive) - * @param searchIn - * the string to search in - * @param openingMarkers - * characters which delimit the beginning of a text block to skip - * @param closingMarkers - * characters which delimit the end of a text block to skip - * @param searchMode - * a Set, ideally an EnumSet, containing the flags from the enum StringUtils.SearchMode that determine the - * behavior of the search - * @return the position where searchFor is found within searchIn starting from startingPosition. - */ - private static int indexOfNextChar(int startingPosition, int stopPosition, String searchIn, String openingMarkers, String closingMarkers, - Set searchMode) { - if (searchIn == null) { - return -1; - } + char c = searchIn.charAt(i); - int searchInLength = searchIn.length(); - if (startingPosition >= searchInLength) { - return -1; - } + if (isCharEqualIgnoreCase(c, firstCharOfSearchForUc, firstCharOfSearchForLc) + && startsWithIgnoreCase(searchIn, i, searchFor)) { + return i; + } + } - char c0 = Character.MIN_VALUE; // current char - char c1 = searchIn.charAt(startingPosition); // lookahead(1) - char c2 = startingPosition + 1 < searchInLength ? searchIn.charAt(startingPosition + 1) : Character.MIN_VALUE; // lookahead(2) - - for (int i = startingPosition; i <= stopPosition; i++) { - c0 = c1; - c1 = c2; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - - boolean dashDashCommentImmediateEnd = false; - int markerIndex = -1; - if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { - i++; // next char is escaped, skip it - // reset lookahead - c1 = c2; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (markerIndex = openingMarkers.indexOf(c0)) != -1) { - // marker found, skip until closing, while being aware of nested markers if opening and closing markers are distinct - int nestedMarkersCount = 0; - char openingMarker = c0; - char closingMarker = closingMarkers.charAt(markerIndex); - while (++i <= stopPosition && ((c0 = searchIn.charAt(i)) != closingMarker || nestedMarkersCount != 0)) { - if (c0 == openingMarker) { - nestedMarkersCount++; - } else if (c0 == closingMarker) { - nestedMarkersCount--; - } else if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { - i++; // next char is escaped, skip it - } - } - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - - } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '/' && c1 == '*') { - if (c2 != '!') { - // comments block found, skip until end of block ("*/") (backslash escape doesn't work on comments) - i++; // move to next char ('*') - while (++i <= stopPosition - && (searchIn.charAt(i) != '*' || (i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE) != '/')) { - // continue - } - i++; // move to next char ('/') - } else { - // special non-comments block found, move to end of opening marker ("/*![12345]") - i++; // move to next char ('*') - i++; // move to next char ('!') - // check if a 5 digits MySQL version reference follows, if so skip them - int j = 1; - for (; j <= NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; j++) { - if (i + j >= searchInLength || !Character.isDigit(searchIn.charAt(i + j))) { - break; - } - } - if (j == NON_COMMENTS_MYSQL_VERSION_REF_LENGTH) { - i += NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; - } - } - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '*' && c1 == '/') { - // special non-comments block closing marker ("*/") found - assume that if we get it here it's because it - // belongs to a non-comments block ("/*!"), otherwise the query should be misspelled as nesting comments isn't allowed. - i++; // move to next char ('/') - // reset lookahead - c1 = c2; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else if (searchMode.contains(SearchMode.SKIP_LINE_COMMENTS) - && ((c0 == '-' && c1 == '-' && (Character.isWhitespace(c2) || (dashDashCommentImmediateEnd = c2 == ';') || c2 == Character.MIN_VALUE)) - || c0 == '#')) { - if (dashDashCommentImmediateEnd) { - // comments line found but closed immediately by query delimiter marker - i++; // move to next char ('-') - i++; // move to next char (';') - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else { - // comments line found, skip until eol (backslash escape doesn't work on comments) - while (++i <= stopPosition && (c0 = searchIn.charAt(i)) != '\n' && c0 != '\r') { - // continue - } - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - if (c0 == '\r' && c1 == '\n') { - // \r\n sequence found - i++; // skip next char ('\n') - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - } - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } - } else if (!searchMode.contains(SearchMode.SKIP_WHITE_SPACE) || !Character.isWhitespace(c0)) { - return i; - } - } - return -1; + return -1; + } + + /** + * Finds the position the next character from a string, possibly skipping white space, comments + * and text between markers. + * + * @param startingPosition the position to start the search from + * @param stopPosition the position where to stop the search (inclusive) + * @param searchIn the string to search in + * @param openingMarkers characters which delimit the beginning of a text block to skip + * @param closingMarkers characters which delimit the end of a text block to skip + * @param searchMode a Set, ideally an EnumSet, containing the flags + * from the enum StringUtils.SearchMode that determine the behavior of the + * search + * @return the position where searchFor is found within searchIn + * starting from startingPosition. + */ + private static int indexOfNextChar(int startingPosition, int stopPosition, String searchIn, + String openingMarkers, String closingMarkers, Set searchMode) { + if (searchIn == null) { + return -1; } - /** - * Trims identifier, removes quote chars from first and last positions - * and replaces double occurrences of quote char from entire identifier, - * i.e converts quoted identifier into form as it is stored in database. - * - * @param identifier - * @param quoteChar - * ` or " - * @return - *
    - *
  • null -> null
  • - *
  • abc -> abc
  • - *
  • `abc` -> abc
  • - *
  • `ab``c` -> ab`c
  • - *
  • `"ab`c"` -> "ab`c"
  • - *
  • `ab"c` -> ab"c
  • - *
  • "abc" -> abc
  • - *
  • "`ab""c`" -> `ab"c`
  • - *
  • "ab`c" -> ab`c
  • - *
- */ - public static String unQuoteIdentifier(String identifier, String quoteChar) { - if (identifier == null) { - return null; - } - identifier = identifier.trim(); - int quoteCharLength = quoteChar.length(); - if (quoteCharLength == 0 || " ".equals(quoteChar)) { - return identifier; - } + int searchInLength = searchIn.length(); + if (startingPosition >= searchInLength) { + return -1; + } - // Check if the identifier is really quoted or if it simply contains quote chars in it (assuming that the value is a valid identifier). - if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { - String identifierQuoteTrimmed = identifier.substring(quoteCharLength, identifier.length() - quoteCharLength); - // Check for pairs of quotes. - int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); - while (quoteCharPos >= 0) { - int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; - int quoteCharNextPosition = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextExpectedPos); - - if (quoteCharNextPosition == quoteCharNextExpectedPos) { - quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); - } else { - // Not a pair of quotes! Return as it is... - return identifier; - } + char c0 = Character.MIN_VALUE; // current char + char c1 = searchIn.charAt(startingPosition); // lookahead(1) + char c2 = startingPosition + 1 < searchInLength ? searchIn.charAt(startingPosition + 1) + : Character.MIN_VALUE; // lookahead(2) + + for (int i = startingPosition; i <= stopPosition; i++) { + c0 = c1; + c1 = c2; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + + boolean dashDashCommentImmediateEnd = false; + int markerIndex = -1; + if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { + i++; // next char is escaped, skip it + // reset lookahead + c1 = c2; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) + && (markerIndex = openingMarkers.indexOf(c0)) != -1) { + // marker found, skip until closing, while being aware of nested markers if opening and + // closing markers are distinct + int nestedMarkersCount = 0; + char openingMarker = c0; + char closingMarker = closingMarkers.charAt(markerIndex); + while (++i <= stopPosition && ((c0 = searchIn.charAt(i)) != closingMarker + || nestedMarkersCount != 0)) { + if (c0 == openingMarker) { + nestedMarkersCount++; + } else if (c0 == closingMarker) { + nestedMarkersCount--; + } else if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { + i++; // next char is escaped, skip it + } + } + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + + } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '/' && c1 == '*') { + if (c2 != '!') { + // comments block found, skip until end of block ("*/") (backslash escape doesn't work + // on comments) + i++; // move to next char ('*') + while (++i <= stopPosition && (searchIn.charAt(i) != '*' + || (i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE) != '/')) { + // continue + } + i++; // move to next char ('/') + } else { + // special non-comments block found, move to end of opening marker ("/*![12345]") + i++; // move to next char ('*') + i++; // move to next char ('!') + // check if a 5 digits MySQL version reference follows, if so skip them + int j = 1; + for (; j <= NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; j++) { + if (i + j >= searchInLength || !Character.isDigit(searchIn.charAt(i + j))) { + break; } - return identifier.substring(quoteCharLength, (identifier.length() - quoteCharLength)).replaceAll(quoteChar + quoteChar, quoteChar); - } - return identifier; + } + if (j == NON_COMMENTS_MYSQL_VERSION_REF_LENGTH) { + i += NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; + } + } + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '*' && c1 == '/') { + // special non-comments block closing marker ("*/") found - assume that if we get it here + // it's because it + // belongs to a non-comments block ("/*!"), otherwise the query should be misspelled as + // nesting comments isn't allowed. + i++; // move to next char ('/') + // reset lookahead + c1 = c2; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else if (searchMode.contains(SearchMode.SKIP_LINE_COMMENTS) && ( + (c0 == '-' && c1 == '-' && (Character.isWhitespace(c2) || (dashDashCommentImmediateEnd = + c2 == ';') || c2 == Character.MIN_VALUE)) || c0 == '#')) { + if (dashDashCommentImmediateEnd) { + // comments line found but closed immediately by query delimiter marker + i++; // move to next char ('-') + i++; // move to next char (';') + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else { + // comments line found, skip until eol (backslash escape doesn't work on comments) + while (++i <= stopPosition && (c0 = searchIn.charAt(i)) != '\n' && c0 != '\r') { + // continue + } + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + if (c0 == '\r' && c1 == '\n') { + // \r\n sequence found + i++; // skip next char ('\n') + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + } + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } + } else if (!searchMode.contains(SearchMode.SKIP_WHITE_SPACE) || !Character.isWhitespace(c0)) { + return i; + } + } + return -1; + } + + /** + * Trims identifier, removes quote chars from first and last positions and replaces double + * occurrences of quote char from entire identifier, i.e converts quoted identifier into form as + * it is stored in database. + * + * @param quoteChar ` or " + * @return
    + *
  • null -> null
  • + *
  • abc -> abc
  • + *
  • `abc` -> abc
  • + *
  • `ab``c` -> ab`c
  • + *
  • `"ab`c"` -> "ab`c"
  • + *
  • `ab"c` -> ab"c
  • + *
  • "abc" -> abc
  • + *
  • "`ab""c`" -> `ab"c`
  • + *
  • "ab`c" -> ab`c
  • + *
+ */ + public static String unQuoteIdentifier(String identifier, String quoteChar) { + if (identifier == null) { + return null; + } + identifier = identifier.trim(); + int quoteCharLength = quoteChar.length(); + if (quoteCharLength == 0 || " ".equals(quoteChar)) { + return identifier; } - /** - * Splits stringToSplit into a list, using the given delimiter (skipping delimiters within quotes) - * - * @param stringToSplit - * the string to split - * @param delimiter - * the string to split on - * @param markers - * the marker for the beginning of a text block to skip, when looking for a delimiter - * @param markerCloses - * the marker for the end of a text block to skip, when looking for a delimiter - * @return the list of strings, split by delimiter - * - * @throws IllegalArgumentException - */ - public static List split(String stringToSplit, String delimiter, String markers, String markerCloses) { - if (stringToSplit == null) { - return new ArrayList<>(); - } - if (delimiter == null) { - throw new IllegalArgumentException(); - } + // Check if the identifier is really quoted or if it simply contains quote chars in it + // (assuming that the value is a valid identifier). + if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { + String identifierQuoteTrimmed = identifier + .substring(quoteCharLength, identifier.length() - quoteCharLength); + // Check for pairs of quotes. + int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); + while (quoteCharPos >= 0) { + int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; + int quoteCharNextPosition = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextExpectedPos); + + if (quoteCharNextPosition == quoteCharNextExpectedPos) { + quoteCharPos = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); + } else { + // Not a pair of quotes! Return as it is... + return identifier; + } + } + return identifier.substring(quoteCharLength, (identifier.length() - quoteCharLength)) + .replaceAll(quoteChar + quoteChar, quoteChar); + } + return identifier; + } + + /** + * Splits stringToSplit into a list, using the given delimiter (skipping delimiters within + * quotes) + * + * @param stringToSplit the string to split + * @param delimiter the string to split on + * @param markers the marker for the beginning of a text block to skip, when looking for a + * delimiter + * @param markerCloses the marker for the end of a text block to skip, when looking for a + * delimiter + * @return the list of strings, split by delimiter + */ + public static List split(String stringToSplit, String delimiter, String markers, + String markerCloses) { + if (stringToSplit == null) { + return new ArrayList<>(); + } + if (delimiter == null) { + throw new IllegalArgumentException(); + } - int delimPos = 0; - int currentPos = 0; - List splitTokens = new ArrayList<>(); - while ((delimPos = indexOfIgnoreCase(currentPos, stringToSplit, delimiter, markers, markerCloses, SEARCH_MODE__MRK_COM_WS)) != -1) { - String token = stringToSplit.substring(currentPos, delimPos); - splitTokens.add(token); - currentPos = delimPos + 1; - } + int delimPos = 0; + int currentPos = 0; + List splitTokens = new ArrayList<>(); + while ( + (delimPos = indexOfIgnoreCase(currentPos, stringToSplit, delimiter, markers, markerCloses, + SEARCH_MODE__MRK_COM_WS)) != -1) { + String token = stringToSplit.substring(currentPos, delimPos); + splitTokens.add(token); + currentPos = delimPos + 1; + } - if (currentPos < stringToSplit.length()) { - String token = stringToSplit.substring(currentPos); - splitTokens.add(token); - } - return splitTokens; + if (currentPos < stringToSplit.length()) { + String token = stringToSplit.substring(currentPos); + splitTokens.add(token); } + return splitTokens; + } + + public enum SearchMode { + ALLOW_BACKSLASH_ESCAPE, SKIP_BETWEEN_MARKERS, SKIP_BLOCK_COMMENTS, SKIP_LINE_COMMENTS, + SKIP_WHITE_SPACE; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java b/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java index a5b559495dc..1d502a180e9 100644 --- a/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java +++ b/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java @@ -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,529 +24,573 @@ import java.util.Map; /** - * These classes were pulled from mysql-connector-java and simplified to just the parts supporting the statically available - * charsets + * These classes were pulled from mysql-connector-java and simplified to just the parts supporting + * the statically available charsets */ public class CharsetMapping { - private static final int MAP_SIZE = 255; // Size of static maps - public static final String[] COLLATION_INDEX_TO_COLLATION_NAME; - private static final MysqlCharset[] COLLATION_INDEX_TO_CHARSET; - - static final Map CHARSET_NAME_TO_CHARSET; - private static final Map> JAVA_ENCODING_UC_TO_MYSQL_CHARSET; - - private static final String MYSQL_CHARSET_NAME_armscii8 = "armscii8"; - private static final String MYSQL_CHARSET_NAME_ascii = "ascii"; - private static final String MYSQL_CHARSET_NAME_big5 = "big5"; - private static final String MYSQL_CHARSET_NAME_binary = "binary"; - private static final String MYSQL_CHARSET_NAME_cp1250 = "cp1250"; - private static final String MYSQL_CHARSET_NAME_cp1251 = "cp1251"; - private static final String MYSQL_CHARSET_NAME_cp1256 = "cp1256"; - private static final String MYSQL_CHARSET_NAME_cp1257 = "cp1257"; - private static final String MYSQL_CHARSET_NAME_cp850 = "cp850"; - private static final String MYSQL_CHARSET_NAME_cp852 = "cp852"; - private static final String MYSQL_CHARSET_NAME_cp866 = "cp866"; - private static final String MYSQL_CHARSET_NAME_cp932 = "cp932"; - private static final String MYSQL_CHARSET_NAME_dec8 = "dec8"; - private static final String MYSQL_CHARSET_NAME_eucjpms = "eucjpms"; - private static final String MYSQL_CHARSET_NAME_euckr = "euckr"; - private static final String MYSQL_CHARSET_NAME_gb18030 = "gb18030"; - private static final String MYSQL_CHARSET_NAME_gb2312 = "gb2312"; - private static final String MYSQL_CHARSET_NAME_gbk = "gbk"; - private static final String MYSQL_CHARSET_NAME_geostd8 = "geostd8"; - private static final String MYSQL_CHARSET_NAME_greek = "greek"; - private static final String MYSQL_CHARSET_NAME_hebrew = "hebrew"; - private static final String MYSQL_CHARSET_NAME_hp8 = "hp8"; - private static final String MYSQL_CHARSET_NAME_keybcs2 = "keybcs2"; - private static final String MYSQL_CHARSET_NAME_koi8r = "koi8r"; - private static final String MYSQL_CHARSET_NAME_koi8u = "koi8u"; - private static final String MYSQL_CHARSET_NAME_latin1 = "latin1"; - private static final String MYSQL_CHARSET_NAME_latin2 = "latin2"; - private static final String MYSQL_CHARSET_NAME_latin5 = "latin5"; - private static final String MYSQL_CHARSET_NAME_latin7 = "latin7"; - private static final String MYSQL_CHARSET_NAME_macce = "macce"; - private static final String MYSQL_CHARSET_NAME_macroman = "macroman"; - private static final String MYSQL_CHARSET_NAME_sjis = "sjis"; - private static final String MYSQL_CHARSET_NAME_swe7 = "swe7"; - private static final String MYSQL_CHARSET_NAME_tis620 = "tis620"; - private static final String MYSQL_CHARSET_NAME_ucs2 = "ucs2"; - private static final String MYSQL_CHARSET_NAME_ujis = "ujis"; - private static final String MYSQL_CHARSET_NAME_utf16 = "utf16"; - private static final String MYSQL_CHARSET_NAME_utf16le = "utf16le"; - private static final String MYSQL_CHARSET_NAME_utf32 = "utf32"; - private static final String MYSQL_CHARSET_NAME_utf8 = "utf8"; - private static final String MYSQL_CHARSET_NAME_utf8mb4 = "utf8mb4"; - - private static final String MYSQL_4_0_CHARSET_NAME_cp1251cias = "cp1251cias"; - private static final String MYSQL_4_0_CHARSET_NAME_cp1251csas = "cp1251csas"; - private static final String MYSQL_4_0_CHARSET_NAME_croat = "croat"; // 4.1 => 27 latin2 latin2_croatian_ci - private static final String MYSQL_4_0_CHARSET_NAME_czech = "czech"; // 4.1 => 2 latin2 latin2_czech_ci - private static final String MYSQL_4_0_CHARSET_NAME_danish = "danish"; // 4.1 => 15 latin1 latin1_danish_ci - private static final String MYSQL_4_0_CHARSET_NAME_dos = "dos"; // 4.1 => 4 cp850 cp850_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_estonia = "estonia"; // 4.1 => 20 latin7 latin7_estonian_ci - private static final String MYSQL_4_0_CHARSET_NAME_euc_kr = "euc_kr"; // 4.1 => 19 euckr euckr_korean_ci - private static final String MYSQL_4_0_CHARSET_NAME_german1 = "german1"; // 4.1 => 5 latin1 latin1_german1_ci - private static final String MYSQL_4_0_CHARSET_NAME_hungarian = "hungarian"; // 4.1 => 21 latin2 latin2_hungarian_ci - private static final String MYSQL_4_0_CHARSET_NAME_koi8_ru = "koi8_ru"; // 4.1 => 7 koi8r koi8r_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_koi8_ukr = "koi8_ukr"; // 4.1 => 22 koi8u koi8u_ukrainian_ci - private static final String MYSQL_4_0_CHARSET_NAME_latin1_de = "latin1_de"; // 4.1 => 31 latin1 latin1_german2_ci - private static final String MYSQL_4_0_CHARSET_NAME_latvian = "latvian"; - private static final String MYSQL_4_0_CHARSET_NAME_latvian1 = "latvian1"; - private static final String MYSQL_4_0_CHARSET_NAME_usa7 = "usa7"; // 4.1 => 11 ascii ascii_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_win1250 = "win1250"; // 4.1 => 26 cp1250 cp1250_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_win1251 = "win1251"; // 4.1 => 17 (removed) - private static final String MYSQL_4_0_CHARSET_NAME_win1251ukr = "win1251ukr"; // 4.1 => 23 cp1251 cp1251_ukrainian_ci - - private static final String NOT_USED = MYSQL_CHARSET_NAME_latin1; // punting for not-used character sets - - public static final int MYSQL_COLLATION_INDEX_utf8 = 33; - public static final int MYSQL_COLLATION_INDEX_binary = 63; - - static { - // complete list of mysql character sets and their corresponding java encoding names - MysqlCharset[] charset = new MysqlCharset[]{new MysqlCharset(MYSQL_4_0_CHARSET_NAME_usa7, 1, 0, new String[]{"US-ASCII"}, 4, 0), - new MysqlCharset(MYSQL_CHARSET_NAME_ascii, 1, 0, new String[]{"US-ASCII", "ASCII"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_big5, 2, 0, new String[]{"Big5"}), - new MysqlCharset(MYSQL_CHARSET_NAME_gbk, 2, 0, new String[]{"GBK"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_sjis, 2, 0, new String[]{"SHIFT_JIS", "Cp943", "WINDOWS-31J"}), // SJIS is alias for SHIFT_JIS, Cp943 is rather a cp932 but we map it to sjis for years - new MysqlCharset(MYSQL_CHARSET_NAME_cp932, 2, 1, new String[]{"WINDOWS-31J"}), // MS932 is alias for WINDOWS-31J - - new MysqlCharset(MYSQL_CHARSET_NAME_gb2312, 2, 0, new String[]{"GB2312"}), - new MysqlCharset(MYSQL_CHARSET_NAME_ujis, 3, 0, new String[]{"EUC_JP"}), - new MysqlCharset(MYSQL_CHARSET_NAME_eucjpms, 3, 0, new String[]{"EUC_JP_Solaris"}, 5, 0, 3), // "EUC_JP_Solaris = >5.0.3 eucjpms," - - new MysqlCharset(MYSQL_CHARSET_NAME_gb18030, 4, 0, new String[]{"GB18030"}, 5, 7, 4), - - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_euc_kr, 2, 0, new String[]{"EUC_KR"}, 4, 0), - new MysqlCharset(MYSQL_CHARSET_NAME_euckr, 2, 0, new String[]{"EUC-KR"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_latin1, 1, 1, new String[]{"Cp1252", "ISO8859_1"}), - new MysqlCharset(MYSQL_CHARSET_NAME_swe7, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_hp8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_dec8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_armscii8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_geostd8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - - new MysqlCharset(MYSQL_CHARSET_NAME_latin2, 1, 0, new String[]{"ISO8859_2"}), // latin2 is an alias - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_czech, 1, 0, new String[]{"ISO8859_2"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_hungarian, 1, 0, new String[]{"ISO8859_2"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_croat, 1, 0, new String[]{"ISO8859_2"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_greek, 1, 0, new String[]{"ISO8859_7", "greek"}), - new MysqlCharset(MYSQL_CHARSET_NAME_latin7, 1, 0, new String[]{"ISO-8859-13"}), // was ISO8859_7, that's incorrect; also + "LATIN7 = latin7," is wrong java encoding name - - new MysqlCharset(MYSQL_CHARSET_NAME_hebrew, 1, 0, new String[]{"ISO8859_8"}), // hebrew is an alias - new MysqlCharset(MYSQL_CHARSET_NAME_latin5, 1, 0, new String[]{"ISO8859_9"}), // LATIN5 is an alias - - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian, 1, 0, new String[]{"ISO8859_13"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian1, 1, 0, new String[]{"ISO8859_13"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_estonia, 1, 1, new String[]{"ISO8859_13"}, 4, 0), //, "ISO8859_13"); // punting for "estonia"; - - new MysqlCharset(MYSQL_CHARSET_NAME_cp850, 1, 0, new String[]{"Cp850", "Cp437"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_dos, 1, 0, new String[]{"Cp850", "Cp437"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp852, 1, 0, new String[]{"Cp852"}), - new MysqlCharset(MYSQL_CHARSET_NAME_keybcs2, 1, 0, new String[]{"Cp852"}), // new, Kamenicky encoding usually known as Cp895 but there is no official cp895 specification; close to Cp852, see http://ftp.muni.cz/pub/localization/charsets/cs-encodings-faq - - new MysqlCharset(MYSQL_CHARSET_NAME_cp866, 1, 0, new String[]{"Cp866"}), - - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ru, 1, 0, new String[]{"KOI8_R"}, 4, 0), - new MysqlCharset(MYSQL_CHARSET_NAME_koi8r, 1, 1, new String[]{"KOI8_R"}), - new MysqlCharset(MYSQL_CHARSET_NAME_koi8u, 1, 0, new String[]{"KOI8_R"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ukr, 1, 0, new String[]{"KOI8_R"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_tis620, 1, 0, new String[]{"TIS620"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp1250, 1, 0, new String[]{"Cp1250"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1250, 1, 0, new String[]{"Cp1250"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp1251, 1, 1, new String[]{"Cp1251"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251, 1, 0, new String[]{"Cp1251"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251cias, 1, 0, new String[]{"Cp1251"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251csas, 1, 0, new String[]{"Cp1251"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251ukr, 1, 0, new String[]{"Cp1251"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp1256, 1, 0, new String[]{"Cp1256"}), - new MysqlCharset(MYSQL_CHARSET_NAME_cp1257, 1, 0, new String[]{"Cp1257"}), - new MysqlCharset(MYSQL_CHARSET_NAME_macroman, 1, 0, new String[]{"MacRoman"}), - new MysqlCharset(MYSQL_CHARSET_NAME_macce, 1, 0, new String[]{"MacCentralEurope"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_utf8, 3, 1, new String[]{"UTF-8"}), - new MysqlCharset(MYSQL_CHARSET_NAME_utf8mb4, 4, 0, new String[]{"UTF-8"}), // "UTF-8 = *> 5.5.2 utf8mb4," - - new MysqlCharset(MYSQL_CHARSET_NAME_ucs2, 2, 0, new String[]{"UnicodeBig"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_binary, 1, 1, new String[]{"ISO8859_1"}), // US-ASCII ? - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latin1_de, 1, 0, new String[]{"ISO8859_1"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_german1, 1, 0, new String[]{"ISO8859_1"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_danish, 1, 0, new String[]{"ISO8859_1"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_utf16, 4, 0, new String[]{"UTF-16"}), - new MysqlCharset(MYSQL_CHARSET_NAME_utf16le, 4, 0, new String[]{"UTF-16LE"}), - new MysqlCharset(MYSQL_CHARSET_NAME_utf32, 4, 0, new String[]{"UTF-32"}) - }; - HashMap charsetNameToMysqlCharsetMap = new HashMap(); - HashMap> javaUcToMysqlCharsetMap = new HashMap>(); - - for (int i = 0; i < charset.length; i++) { - String charsetName = charset[i].charsetName; - - charsetNameToMysqlCharsetMap.put(charsetName, charset[i]); - - for (String encUC : charset[i].javaEncodingsUc) { - - // fill javaUcToMysqlCharsetMap - List charsets = javaUcToMysqlCharsetMap.get(encUC); - if (charsets == null) { - charsets = new ArrayList(); - javaUcToMysqlCharsetMap.put(encUC, charsets); - } - charsets.add(charset[i]); - } - } - - CHARSET_NAME_TO_CHARSET = Collections.unmodifiableMap(charsetNameToMysqlCharsetMap); - JAVA_ENCODING_UC_TO_MYSQL_CHARSET = Collections.unmodifiableMap(javaUcToMysqlCharsetMap); - - // complete list of mysql collations and their corresponding character sets each element of collation[1]..collation[MAP_SIZE-1] must not be null - Collation[] collation = new Collation[MAP_SIZE]; - collation[1] = new Collation(1, "big5_chinese_ci", 1, MYSQL_CHARSET_NAME_big5); - collation[84] = new Collation(84, "big5_bin", 0, MYSQL_CHARSET_NAME_big5); - - collation[2] = new Collation(2, "latin2_czech_cs", 0, MYSQL_CHARSET_NAME_latin2); - collation[9] = new Collation(9, "latin2_general_ci", 1, MYSQL_CHARSET_NAME_latin2); - collation[21] = new Collation(21, "latin2_hungarian_ci", 0, MYSQL_CHARSET_NAME_latin2); - collation[27] = new Collation(27, "latin2_croatian_ci", 0, MYSQL_CHARSET_NAME_latin2); - collation[77] = new Collation(77, "latin2_bin", 0, MYSQL_CHARSET_NAME_latin2); - - collation[4] = new Collation(4, "cp850_general_ci", 1, MYSQL_CHARSET_NAME_cp850); - collation[80] = new Collation(80, "cp850_bin", 0, MYSQL_CHARSET_NAME_cp850); - - collation[5] = new Collation(5, "latin1_german1_ci", 1, MYSQL_CHARSET_NAME_latin1); - collation[8] = new Collation(8, "latin1_swedish_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[15] = new Collation(15, "latin1_danish_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[31] = new Collation(31, "latin1_german2_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[47] = new Collation(47, "latin1_bin", 0, MYSQL_CHARSET_NAME_latin1); - collation[48] = new Collation(48, "latin1_general_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[49] = new Collation(49, "latin1_general_cs", 0, MYSQL_CHARSET_NAME_latin1); - collation[76] = new Collation(76, "not_implemented", 0, NOT_USED); - collation[94] = new Collation(94, "latin1_spanish_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[100] = new Collation(100, "not_implemented", 0, NOT_USED); - collation[125] = new Collation(125, "not_implemented", 0, NOT_USED); - collation[126] = new Collation(126, "not_implemented", 0, NOT_USED); - collation[127] = new Collation(127, "not_implemented", 0, NOT_USED); - collation[152] = new Collation(152, "not_implemented", 0, NOT_USED); - collation[153] = new Collation(153, "not_implemented", 0, NOT_USED); - collation[154] = new Collation(154, "not_implemented", 0, NOT_USED); - collation[155] = new Collation(155, "not_implemented", 0, NOT_USED); - collation[156] = new Collation(156, "not_implemented", 0, NOT_USED); - collation[157] = new Collation(157, "not_implemented", 0, NOT_USED); - collation[158] = new Collation(158, "not_implemented", 0, NOT_USED); - collation[184] = new Collation(184, "not_implemented", 0, NOT_USED); - collation[185] = new Collation(185, "not_implemented", 0, NOT_USED); - collation[186] = new Collation(186, "not_implemented", 0, NOT_USED); - collation[187] = new Collation(187, "not_implemented", 0, NOT_USED); - collation[188] = new Collation(188, "not_implemented", 0, NOT_USED); - collation[189] = new Collation(189, "not_implemented", 0, NOT_USED); - collation[190] = new Collation(190, "not_implemented", 0, NOT_USED); - collation[191] = new Collation(191, "not_implemented", 0, NOT_USED); - collation[216] = new Collation(216, "not_implemented", 0, NOT_USED); - collation[217] = new Collation(217, "not_implemented", 0, NOT_USED); - collation[218] = new Collation(218, "not_implemented", 0, NOT_USED); - collation[219] = new Collation(219, "not_implemented", 0, NOT_USED); - collation[220] = new Collation(220, "not_implemented", 0, NOT_USED); - collation[221] = new Collation(221, "not_implemented", 0, NOT_USED); - collation[222] = new Collation(222, "not_implemented", 0, NOT_USED); - collation[248] = new Collation(248, "gb18030_chinese_ci", 1, MYSQL_CHARSET_NAME_gb18030); - collation[249] = new Collation(249, "gb18030_bin", 0, MYSQL_CHARSET_NAME_gb18030); - collation[250] = new Collation(250, "gb18030_unicode_520_ci", 0, MYSQL_CHARSET_NAME_gb18030); - collation[251] = new Collation(251, "not_implemented", 0, NOT_USED); - collation[252] = new Collation(252, "not_implemented", 0, NOT_USED); - collation[253] = new Collation(253, "not_implemented", 0, NOT_USED); - collation[254] = new Collation(254, "not_implemented", 0, NOT_USED); - collation[10] = new Collation(10, "swe7_swedish_ci", 0, MYSQL_CHARSET_NAME_swe7); - collation[82] = new Collation(82, "swe7_bin", 0, MYSQL_CHARSET_NAME_swe7); - collation[6] = new Collation(6, "hp8_english_ci", 0, MYSQL_CHARSET_NAME_hp8); - collation[72] = new Collation(72, "hp8_bin", 0, MYSQL_CHARSET_NAME_hp8); - collation[3] = new Collation(3, "dec8_swedish_ci", 0, MYSQL_CHARSET_NAME_dec8); - collation[69] = new Collation(69, "dec8_bin", 0, MYSQL_CHARSET_NAME_dec8); - collation[32] = new Collation(32, "armscii8_general_ci", 0, MYSQL_CHARSET_NAME_armscii8); - collation[64] = new Collation(64, "armscii8_bin", 0, MYSQL_CHARSET_NAME_armscii8); - collation[92] = new Collation(92, "geostd8_general_ci", 0, MYSQL_CHARSET_NAME_geostd8); - collation[93] = new Collation(93, "geostd8_bin", 0, MYSQL_CHARSET_NAME_geostd8); - - collation[7] = new Collation(7, "koi8r_general_ci", 0, MYSQL_CHARSET_NAME_koi8r); - collation[74] = new Collation(74, "koi8r_bin", 0, MYSQL_CHARSET_NAME_koi8r); - - collation[11] = new Collation(11, "ascii_general_ci", 0, MYSQL_CHARSET_NAME_ascii); - collation[65] = new Collation(65, "ascii_bin", 0, MYSQL_CHARSET_NAME_ascii); - - collation[12] = new Collation(12, "ujis_japanese_ci", 0, MYSQL_CHARSET_NAME_ujis); - collation[91] = new Collation(91, "ujis_bin", 0, MYSQL_CHARSET_NAME_ujis); - - collation[13] = new Collation(13, "sjis_japanese_ci", 0, MYSQL_CHARSET_NAME_sjis); - collation[14] = new Collation(14, "cp1251_bulgarian_ci", 0, MYSQL_CHARSET_NAME_cp1251); - collation[16] = new Collation(16, "hebrew_general_ci", 0, MYSQL_CHARSET_NAME_hebrew); - collation[17] = new Collation(17, "latin1_german1_ci", 0, MYSQL_4_0_CHARSET_NAME_win1251); // removed since 4.1 - collation[18] = new Collation(18, "tis620_thai_ci", 0, MYSQL_CHARSET_NAME_tis620); - collation[19] = new Collation(19, "euckr_korean_ci", 0, MYSQL_CHARSET_NAME_euckr); - collation[20] = new Collation(20, "latin7_estonian_cs", 0, MYSQL_CHARSET_NAME_latin7); - collation[22] = new Collation(22, "koi8u_general_ci", 0, MYSQL_CHARSET_NAME_koi8u); - collation[23] = new Collation(23, "cp1251_ukrainian_ci", 0, MYSQL_CHARSET_NAME_cp1251); - collation[24] = new Collation(24, "gb2312_chinese_ci", 0, MYSQL_CHARSET_NAME_gb2312); - collation[25] = new Collation(25, "greek_general_ci", 0, MYSQL_CHARSET_NAME_greek); - collation[26] = new Collation(26, "cp1250_general_ci", 1, MYSQL_CHARSET_NAME_cp1250); - collation[28] = new Collation(28, "gbk_chinese_ci", 1, MYSQL_CHARSET_NAME_gbk); - collation[29] = new Collation(29, "cp1257_lithuanian_ci", 0, MYSQL_CHARSET_NAME_cp1257); - collation[30] = new Collation(30, "latin5_turkish_ci", 1, MYSQL_CHARSET_NAME_latin5); - collation[33] = new Collation(33, "utf8_general_ci", 1, MYSQL_CHARSET_NAME_utf8); - collation[34] = new Collation(34, "cp1250_czech_cs", 0, MYSQL_CHARSET_NAME_cp1250); - collation[35] = new Collation(35, "ucs2_general_ci", 1, MYSQL_CHARSET_NAME_ucs2); - collation[36] = new Collation(36, "cp866_general_ci", 1, MYSQL_CHARSET_NAME_cp866); - collation[37] = new Collation(37, "keybcs2_general_ci", 1, MYSQL_CHARSET_NAME_keybcs2); - collation[38] = new Collation(38, "macce_general_ci", 1, MYSQL_CHARSET_NAME_macce); - collation[39] = new Collation(39, "macroman_general_ci", 1, MYSQL_CHARSET_NAME_macroman); - collation[40] = new Collation(40, "cp852_general_ci", 1, MYSQL_CHARSET_NAME_cp852); - collation[41] = new Collation(41, "latin7_general_ci", 1, MYSQL_CHARSET_NAME_latin7); - collation[42] = new Collation(42, "latin7_general_cs", 0, MYSQL_CHARSET_NAME_latin7); - collation[43] = new Collation(43, "macce_bin", 0, MYSQL_CHARSET_NAME_macce); - collation[44] = new Collation(44, "cp1250_croatian_ci", 0, MYSQL_CHARSET_NAME_cp1250); - collation[45] = new Collation(45, "utf8mb4_general_ci", 1, MYSQL_CHARSET_NAME_utf8mb4); - collation[46] = new Collation(46, "utf8mb4_bin", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[50] = new Collation(50, "cp1251_bin", 0, MYSQL_CHARSET_NAME_cp1251); - collation[51] = new Collation(51, "cp1251_general_ci", 1, MYSQL_CHARSET_NAME_cp1251); - collation[52] = new Collation(52, "cp1251_general_cs", 0, MYSQL_CHARSET_NAME_cp1251); - collation[53] = new Collation(53, "macroman_bin", 0, MYSQL_CHARSET_NAME_macroman); - collation[54] = new Collation(54, "utf16_general_ci", 1, MYSQL_CHARSET_NAME_utf16); - collation[55] = new Collation(55, "utf16_bin", 0, MYSQL_CHARSET_NAME_utf16); - collation[56] = new Collation(56, "utf16le_general_ci", 1, MYSQL_CHARSET_NAME_utf16le); - collation[57] = new Collation(57, "cp1256_general_ci", 1, MYSQL_CHARSET_NAME_cp1256); - collation[58] = new Collation(58, "cp1257_bin", 0, MYSQL_CHARSET_NAME_cp1257); - collation[59] = new Collation(59, "cp1257_general_ci", 1, MYSQL_CHARSET_NAME_cp1257); - collation[60] = new Collation(60, "utf32_general_ci", 1, MYSQL_CHARSET_NAME_utf32); - collation[61] = new Collation(61, "utf32_bin", 0, MYSQL_CHARSET_NAME_utf32); - collation[62] = new Collation(62, "utf16le_bin", 0, MYSQL_CHARSET_NAME_utf16le); - collation[63] = new Collation(63, "binary", 1, MYSQL_CHARSET_NAME_binary); - collation[66] = new Collation(66, "cp1250_bin", 0, MYSQL_CHARSET_NAME_cp1250); - collation[67] = new Collation(67, "cp1256_bin", 0, MYSQL_CHARSET_NAME_cp1256); - collation[68] = new Collation(68, "cp866_bin", 0, MYSQL_CHARSET_NAME_cp866); - collation[70] = new Collation(70, "greek_bin", 0, MYSQL_CHARSET_NAME_greek); - collation[71] = new Collation(71, "hebrew_bin", 0, MYSQL_CHARSET_NAME_hebrew); - collation[73] = new Collation(73, "keybcs2_bin", 0, MYSQL_CHARSET_NAME_keybcs2); - collation[75] = new Collation(75, "koi8u_bin", 0, MYSQL_CHARSET_NAME_koi8u); - collation[78] = new Collation(78, "latin5_bin", 0, MYSQL_CHARSET_NAME_latin5); - collation[79] = new Collation(79, "latin7_bin", 0, MYSQL_CHARSET_NAME_latin7); - collation[81] = new Collation(81, "cp852_bin", 0, MYSQL_CHARSET_NAME_cp852); - collation[83] = new Collation(83, "utf8_bin", 0, MYSQL_CHARSET_NAME_utf8); - collation[85] = new Collation(85, "euckr_bin", 0, MYSQL_CHARSET_NAME_euckr); - collation[86] = new Collation(86, "gb2312_bin", 0, MYSQL_CHARSET_NAME_gb2312); - collation[87] = new Collation(87, "gbk_bin", 0, MYSQL_CHARSET_NAME_gbk); - collation[88] = new Collation(88, "sjis_bin", 0, MYSQL_CHARSET_NAME_sjis); - collation[89] = new Collation(89, "tis620_bin", 0, MYSQL_CHARSET_NAME_tis620); - collation[90] = new Collation(90, "ucs2_bin", 0, MYSQL_CHARSET_NAME_ucs2); - collation[95] = new Collation(95, "cp932_japanese_ci", 1, MYSQL_CHARSET_NAME_cp932); - collation[96] = new Collation(96, "cp932_bin", 0, MYSQL_CHARSET_NAME_cp932); - collation[97] = new Collation(97, "eucjpms_japanese_ci", 1, MYSQL_CHARSET_NAME_eucjpms); - collation[98] = new Collation(98, "eucjpms_bin", 0, MYSQL_CHARSET_NAME_eucjpms); - collation[99] = new Collation(99, "cp1250_polish_ci", 0, MYSQL_CHARSET_NAME_cp1250); - collation[101] = new Collation(101, "utf16_unicode_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[102] = new Collation(102, "utf16_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[103] = new Collation(103, "utf16_latvian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[104] = new Collation(104, "utf16_romanian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[105] = new Collation(105, "utf16_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[106] = new Collation(106, "utf16_polish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[107] = new Collation(107, "utf16_estonian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[108] = new Collation(108, "utf16_spanish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[109] = new Collation(109, "utf16_swedish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[110] = new Collation(110, "utf16_turkish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[111] = new Collation(111, "utf16_czech_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[112] = new Collation(112, "utf16_danish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[113] = new Collation(113, "utf16_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[114] = new Collation(114, "utf16_slovak_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[115] = new Collation(115, "utf16_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[116] = new Collation(116, "utf16_roman_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[117] = new Collation(117, "utf16_persian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[118] = new Collation(118, "utf16_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[119] = new Collation(119, "utf16_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[120] = new Collation(120, "utf16_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[121] = new Collation(121, "utf16_german2_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[122] = new Collation(122, "utf16_croatian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[123] = new Collation(123, "utf16_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[124] = new Collation(124, "utf16_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[128] = new Collation(128, "ucs2_unicode_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[129] = new Collation(129, "ucs2_icelandic_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[130] = new Collation(130, "ucs2_latvian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[131] = new Collation(131, "ucs2_romanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[132] = new Collation(132, "ucs2_slovenian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[133] = new Collation(133, "ucs2_polish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[134] = new Collation(134, "ucs2_estonian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[135] = new Collation(135, "ucs2_spanish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[136] = new Collation(136, "ucs2_swedish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[137] = new Collation(137, "ucs2_turkish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[138] = new Collation(138, "ucs2_czech_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[139] = new Collation(139, "ucs2_danish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[140] = new Collation(140, "ucs2_lithuanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[141] = new Collation(141, "ucs2_slovak_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[142] = new Collation(142, "ucs2_spanish2_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[143] = new Collation(143, "ucs2_roman_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[144] = new Collation(144, "ucs2_persian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[145] = new Collation(145, "ucs2_esperanto_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[146] = new Collation(146, "ucs2_hungarian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[147] = new Collation(147, "ucs2_sinhala_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[148] = new Collation(148, "ucs2_german2_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[149] = new Collation(149, "ucs2_croatian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[150] = new Collation(150, "ucs2_unicode_520_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[151] = new Collation(151, "ucs2_vietnamese_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[159] = new Collation(159, "ucs2_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[160] = new Collation(160, "utf32_unicode_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[161] = new Collation(161, "utf32_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[162] = new Collation(162, "utf32_latvian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[163] = new Collation(163, "utf32_romanian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[164] = new Collation(164, "utf32_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[165] = new Collation(165, "utf32_polish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[166] = new Collation(166, "utf32_estonian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[167] = new Collation(167, "utf32_spanish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[168] = new Collation(168, "utf32_swedish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[169] = new Collation(169, "utf32_turkish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[170] = new Collation(170, "utf32_czech_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[171] = new Collation(171, "utf32_danish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[172] = new Collation(172, "utf32_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[173] = new Collation(173, "utf32_slovak_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[174] = new Collation(174, "utf32_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[175] = new Collation(175, "utf32_roman_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[176] = new Collation(176, "utf32_persian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[177] = new Collation(177, "utf32_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[178] = new Collation(178, "utf32_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[179] = new Collation(179, "utf32_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[180] = new Collation(180, "utf32_german2_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[181] = new Collation(181, "utf32_croatian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[182] = new Collation(182, "utf32_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[183] = new Collation(183, "utf32_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[192] = new Collation(192, "utf8_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[193] = new Collation(193, "utf8_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[194] = new Collation(194, "utf8_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[195] = new Collation(195, "utf8_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[196] = new Collation(196, "utf8_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[197] = new Collation(197, "utf8_polish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[198] = new Collation(198, "utf8_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[199] = new Collation(199, "utf8_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[200] = new Collation(200, "utf8_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[201] = new Collation(201, "utf8_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[202] = new Collation(202, "utf8_czech_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[203] = new Collation(203, "utf8_danish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[204] = new Collation(204, "utf8_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[205] = new Collation(205, "utf8_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[206] = new Collation(206, "utf8_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[207] = new Collation(207, "utf8_roman_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[208] = new Collation(208, "utf8_persian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[209] = new Collation(209, "utf8_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[210] = new Collation(210, "utf8_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[211] = new Collation(211, "utf8_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[212] = new Collation(212, "utf8_german2_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[213] = new Collation(213, "utf8_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[214] = new Collation(214, "utf8_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[215] = new Collation(215, "utf8_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[223] = new Collation(223, "utf8_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[224] = new Collation(224, "utf8mb4_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[225] = new Collation(225, "utf8mb4_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[226] = new Collation(226, "utf8mb4_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[227] = new Collation(227, "utf8mb4_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[228] = new Collation(228, "utf8mb4_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[229] = new Collation(229, "utf8mb4_polish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[230] = new Collation(230, "utf8mb4_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[231] = new Collation(231, "utf8mb4_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[232] = new Collation(232, "utf8mb4_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[233] = new Collation(233, "utf8mb4_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[234] = new Collation(234, "utf8mb4_czech_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[235] = new Collation(235, "utf8mb4_danish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[236] = new Collation(236, "utf8mb4_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[237] = new Collation(237, "utf8mb4_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[238] = new Collation(238, "utf8mb4_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[239] = new Collation(239, "utf8mb4_roman_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[240] = new Collation(240, "utf8mb4_persian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[241] = new Collation(241, "utf8mb4_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[242] = new Collation(242, "utf8mb4_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[243] = new Collation(243, "utf8mb4_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[244] = new Collation(244, "utf8mb4_german2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[245] = new Collation(245, "utf8mb4_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[246] = new Collation(246, "utf8mb4_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[247] = new Collation(247, "utf8mb4_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - - COLLATION_INDEX_TO_COLLATION_NAME = new String[MAP_SIZE]; - COLLATION_INDEX_TO_CHARSET = new MysqlCharset[MAP_SIZE]; - - // Add all collations to lookup maps for easy indexing - for (int i = 1; i < MAP_SIZE; i++) { - COLLATION_INDEX_TO_COLLATION_NAME[i] = collation[i].collationName; - COLLATION_INDEX_TO_CHARSET[i] = collation[i].mysqlCharset; - } - - // Sanity check - for (int i = 1; i < MAP_SIZE; i++) { - if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { - throw new RuntimeException("Assertion failure: No mapping from charset index " + i + " to a mysql collation"); - } - if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { - throw new RuntimeException("Assertion failure: No mapping from charset index " + i + " to a Java character set"); - } + private static final int MAP_SIZE = 255; // Size of static maps + public static final String[] COLLATION_INDEX_TO_COLLATION_NAME; + private static final MysqlCharset[] COLLATION_INDEX_TO_CHARSET; + + static final Map CHARSET_NAME_TO_CHARSET; + private static final Map> JAVA_ENCODING_UC_TO_MYSQL_CHARSET; + + private static final String MYSQL_CHARSET_NAME_armscii8 = "armscii8"; + private static final String MYSQL_CHARSET_NAME_ascii = "ascii"; + private static final String MYSQL_CHARSET_NAME_big5 = "big5"; + private static final String MYSQL_CHARSET_NAME_binary = "binary"; + private static final String MYSQL_CHARSET_NAME_cp1250 = "cp1250"; + private static final String MYSQL_CHARSET_NAME_cp1251 = "cp1251"; + private static final String MYSQL_CHARSET_NAME_cp1256 = "cp1256"; + private static final String MYSQL_CHARSET_NAME_cp1257 = "cp1257"; + private static final String MYSQL_CHARSET_NAME_cp850 = "cp850"; + private static final String MYSQL_CHARSET_NAME_cp852 = "cp852"; + private static final String MYSQL_CHARSET_NAME_cp866 = "cp866"; + private static final String MYSQL_CHARSET_NAME_cp932 = "cp932"; + private static final String MYSQL_CHARSET_NAME_dec8 = "dec8"; + private static final String MYSQL_CHARSET_NAME_eucjpms = "eucjpms"; + private static final String MYSQL_CHARSET_NAME_euckr = "euckr"; + private static final String MYSQL_CHARSET_NAME_gb18030 = "gb18030"; + private static final String MYSQL_CHARSET_NAME_gb2312 = "gb2312"; + private static final String MYSQL_CHARSET_NAME_gbk = "gbk"; + private static final String MYSQL_CHARSET_NAME_geostd8 = "geostd8"; + private static final String MYSQL_CHARSET_NAME_greek = "greek"; + private static final String MYSQL_CHARSET_NAME_hebrew = "hebrew"; + private static final String MYSQL_CHARSET_NAME_hp8 = "hp8"; + private static final String MYSQL_CHARSET_NAME_keybcs2 = "keybcs2"; + private static final String MYSQL_CHARSET_NAME_koi8r = "koi8r"; + private static final String MYSQL_CHARSET_NAME_koi8u = "koi8u"; + private static final String MYSQL_CHARSET_NAME_latin1 = "latin1"; + private static final String MYSQL_CHARSET_NAME_latin2 = "latin2"; + private static final String MYSQL_CHARSET_NAME_latin5 = "latin5"; + private static final String MYSQL_CHARSET_NAME_latin7 = "latin7"; + private static final String MYSQL_CHARSET_NAME_macce = "macce"; + private static final String MYSQL_CHARSET_NAME_macroman = "macroman"; + private static final String MYSQL_CHARSET_NAME_sjis = "sjis"; + private static final String MYSQL_CHARSET_NAME_swe7 = "swe7"; + private static final String MYSQL_CHARSET_NAME_tis620 = "tis620"; + private static final String MYSQL_CHARSET_NAME_ucs2 = "ucs2"; + private static final String MYSQL_CHARSET_NAME_ujis = "ujis"; + private static final String MYSQL_CHARSET_NAME_utf16 = "utf16"; + private static final String MYSQL_CHARSET_NAME_utf16le = "utf16le"; + private static final String MYSQL_CHARSET_NAME_utf32 = "utf32"; + private static final String MYSQL_CHARSET_NAME_utf8 = "utf8"; + private static final String MYSQL_CHARSET_NAME_utf8mb4 = "utf8mb4"; + + private static final String MYSQL_4_0_CHARSET_NAME_cp1251cias = "cp1251cias"; + private static final String MYSQL_4_0_CHARSET_NAME_cp1251csas = "cp1251csas"; + private static final String MYSQL_4_0_CHARSET_NAME_croat = "croat"; // 4.1 => 27 + // latin2 latin2_croatian_ci + private static final String MYSQL_4_0_CHARSET_NAME_czech = "czech"; // 4.1 => 2 latin2 + // latin2_czech_ci + private static final String MYSQL_4_0_CHARSET_NAME_danish = "danish"; // 4.1 => 15 + // latin1 latin1_danish_ci + private static final String MYSQL_4_0_CHARSET_NAME_dos = "dos"; // 4.1 => 4 cp850 + // cp850_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_estonia = "estonia"; // 4.1 => 20 + // latin7 latin7_estonian_ci + private static final String MYSQL_4_0_CHARSET_NAME_euc_kr = "euc_kr"; // 4.1 => 19 + // euckr euckr_korean_ci + private static final String MYSQL_4_0_CHARSET_NAME_german1 = "german1"; // 4.1 => 5 + // latin1 latin1_german1_ci + private static final String MYSQL_4_0_CHARSET_NAME_hungarian = "hungarian"; // 4.1 => 21 + // latin2 latin2_hungarian_ci + private static final String MYSQL_4_0_CHARSET_NAME_koi8_ru = "koi8_ru"; // 4.1 => 7 + // koi8r koi8r_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_koi8_ukr = "koi8_ukr"; // 4.1 => 22 + // koi8u koi8u_ukrainian_ci + private static final String MYSQL_4_0_CHARSET_NAME_latin1_de = "latin1_de"; // 4.1 => 31 + // latin1 latin1_german2_ci + private static final String MYSQL_4_0_CHARSET_NAME_latvian = "latvian"; + private static final String MYSQL_4_0_CHARSET_NAME_latvian1 = "latvian1"; + private static final String MYSQL_4_0_CHARSET_NAME_usa7 = "usa7"; // 4.1 => 11 + // ascii ascii_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_win1250 = "win1250"; // 4.1 => 26 + // cp1250 cp1250_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_win1251 = "win1251"; // 4.1 => 17 + // (removed) + private static final String MYSQL_4_0_CHARSET_NAME_win1251ukr = "win1251ukr"; // 4.1 => 23 + // cp1251 cp1251_ukrainian_ci + + private static final String NOT_USED = MYSQL_CHARSET_NAME_latin1; // punting for not-used + // character sets + + public static final int MYSQL_COLLATION_INDEX_utf8 = 33; + public static final int MYSQL_COLLATION_INDEX_binary = 63; + + static { + // complete list of mysql character sets and their corresponding java encoding names + MysqlCharset[] charset = new MysqlCharset[]{ + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_usa7, 1, 0, new String[]{"US-ASCII"}, 4, 0), + new MysqlCharset(MYSQL_CHARSET_NAME_ascii, 1, 0, new String[]{"US-ASCII", "ASCII"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_big5, 2, 0, new String[]{"Big5"}), + new MysqlCharset(MYSQL_CHARSET_NAME_gbk, 2, 0, new String[]{"GBK"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_sjis, 2, 0, + new String[]{"SHIFT_JIS", "Cp943", "WINDOWS-31J"}), + // SJIS is alias for SHIFT_JIS, Cp943 is rather a cp932 but we map it to sjis for years + new MysqlCharset(MYSQL_CHARSET_NAME_cp932, 2, 1, new String[]{"WINDOWS-31J"}), + // MS932 is alias for WINDOWS-31J + + new MysqlCharset(MYSQL_CHARSET_NAME_gb2312, 2, 0, new String[]{"GB2312"}), + new MysqlCharset(MYSQL_CHARSET_NAME_ujis, 3, 0, new String[]{"EUC_JP"}), + new MysqlCharset(MYSQL_CHARSET_NAME_eucjpms, 3, 0, new String[]{"EUC_JP_Solaris"}, 5, 0, 3), + // "EUC_JP_Solaris = >5.0.3 eucjpms," + + new MysqlCharset(MYSQL_CHARSET_NAME_gb18030, 4, 0, new String[]{"GB18030"}, 5, 7, 4), + + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_euc_kr, 2, 0, new String[]{"EUC_KR"}, 4, 0), + new MysqlCharset(MYSQL_CHARSET_NAME_euckr, 2, 0, new String[]{"EUC-KR"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_latin1, 1, 1, new String[]{"Cp1252", "ISO8859_1"}), + new MysqlCharset(MYSQL_CHARSET_NAME_swe7, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_hp8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_dec8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_armscii8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_geostd8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + + new MysqlCharset(MYSQL_CHARSET_NAME_latin2, 1, 0, new String[]{"ISO8859_2"}), + // latin2 is an alias + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_czech, 1, 0, new String[]{"ISO8859_2"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_hungarian, 1, 0, new String[]{"ISO8859_2"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_croat, 1, 0, new String[]{"ISO8859_2"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_greek, 1, 0, new String[]{"ISO8859_7", "greek"}), + new MysqlCharset(MYSQL_CHARSET_NAME_latin7, 1, 0, new String[]{"ISO-8859-13"}), + // was ISO8859_7, that's incorrect; also + "LATIN7 = latin7," is wrong java encoding + // name + + new MysqlCharset(MYSQL_CHARSET_NAME_hebrew, 1, 0, new String[]{"ISO8859_8"}), + // hebrew is an alias + new MysqlCharset(MYSQL_CHARSET_NAME_latin5, 1, 0, new String[]{"ISO8859_9"}), + // LATIN5 is an alias + + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian, 1, 0, new String[]{"ISO8859_13"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian1, 1, 0, new String[]{"ISO8859_13"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_estonia, 1, 1, new String[]{"ISO8859_13"}, 4, 0), + //, "ISO8859_13"); // punting for "estonia"; + + new MysqlCharset(MYSQL_CHARSET_NAME_cp850, 1, 0, new String[]{"Cp850", "Cp437"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_dos, 1, 0, new String[]{"Cp850", "Cp437"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp852, 1, 0, new String[]{"Cp852"}), + new MysqlCharset(MYSQL_CHARSET_NAME_keybcs2, 1, 0, new String[]{"Cp852"}), + // new, Kamenicky encoding usually known as Cp895 but there is no official cp895 + // specification; close to Cp852, see http://ftp.muni + // .cz/pub/localization/charsets/cs-encodings-faq + + new MysqlCharset(MYSQL_CHARSET_NAME_cp866, 1, 0, new String[]{"Cp866"}), + + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ru, 1, 0, new String[]{"KOI8_R"}, 4, 0), + new MysqlCharset(MYSQL_CHARSET_NAME_koi8r, 1, 1, new String[]{"KOI8_R"}), + new MysqlCharset(MYSQL_CHARSET_NAME_koi8u, 1, 0, new String[]{"KOI8_R"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ukr, 1, 0, new String[]{"KOI8_R"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_tis620, 1, 0, new String[]{"TIS620"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp1250, 1, 0, new String[]{"Cp1250"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1250, 1, 0, new String[]{"Cp1250"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp1251, 1, 1, new String[]{"Cp1251"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251, 1, 0, new String[]{"Cp1251"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251cias, 1, 0, new String[]{"Cp1251"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251csas, 1, 0, new String[]{"Cp1251"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251ukr, 1, 0, new String[]{"Cp1251"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp1256, 1, 0, new String[]{"Cp1256"}), + new MysqlCharset(MYSQL_CHARSET_NAME_cp1257, 1, 0, new String[]{"Cp1257"}), + new MysqlCharset(MYSQL_CHARSET_NAME_macroman, 1, 0, new String[]{"MacRoman"}), + new MysqlCharset(MYSQL_CHARSET_NAME_macce, 1, 0, new String[]{"MacCentralEurope"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_utf8, 3, 1, new String[]{"UTF-8"}), + new MysqlCharset(MYSQL_CHARSET_NAME_utf8mb4, 4, 0, new String[]{"UTF-8"}), + // "UTF-8 = *> 5.5.2 utf8mb4," + + new MysqlCharset(MYSQL_CHARSET_NAME_ucs2, 2, 0, new String[]{"UnicodeBig"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_binary, 1, 1, new String[]{"ISO8859_1"}), + // US-ASCII ? + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latin1_de, 1, 0, new String[]{"ISO8859_1"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_german1, 1, 0, new String[]{"ISO8859_1"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_danish, 1, 0, new String[]{"ISO8859_1"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_utf16, 4, 0, new String[]{"UTF-16"}), + new MysqlCharset(MYSQL_CHARSET_NAME_utf16le, 4, 0, new String[]{"UTF-16LE"}), + new MysqlCharset(MYSQL_CHARSET_NAME_utf32, 4, 0, new String[]{"UTF-32"})}; + + HashMap charsetNameToMysqlCharsetMap = new HashMap(); + HashMap> javaUcToMysqlCharsetMap = new HashMap>(); + + for (int i = 0; i < charset.length; i++) { + String charsetName = charset[i].charsetName; + + charsetNameToMysqlCharsetMap.put(charsetName, charset[i]); + + for (String encUC : charset[i].javaEncodingsUc) { + + // fill javaUcToMysqlCharsetMap + List charsets = javaUcToMysqlCharsetMap.get(encUC); + if (charsets == null) { + charsets = new ArrayList(); + javaUcToMysqlCharsetMap.put(encUC, charsets); } + charsets.add(charset[i]); + } } - /** - * MySQL charset could map to several Java encodings. - * So here we choose the one according to next rules: - *
  • if there is no static mapping for this charset then return javaEncoding value as is because this - * could be a custom charset for example - *
  • if static mapping exists and javaEncoding equals to one of Java encoding canonical names or aliases available - * for this mapping then javaEncoding value as is; this is required when result should match to connection encoding, for example if connection encoding is - * Cp943 we must avoid getting SHIFT_JIS for sjis mysql charset - *
  • if static mapping exists and javaEncoding doesn't match any Java encoding canonical - * names or aliases available for this mapping then return default Java encoding (the first in mapping list) - * - * @param collationIndex - * @param javaEncoding - */ - public static String getJavaEncodingForCollationIndex(Integer collationIndex, String javaEncoding) { - String res = javaEncoding; - if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { - MysqlCharset cs = COLLATION_INDEX_TO_CHARSET[collationIndex]; - if (cs != null) { - res = cs.getMatchingJavaEncoding(javaEncoding); - } - } - return res; + CHARSET_NAME_TO_CHARSET = Collections.unmodifiableMap(charsetNameToMysqlCharsetMap); + JAVA_ENCODING_UC_TO_MYSQL_CHARSET = Collections.unmodifiableMap(javaUcToMysqlCharsetMap); + + // complete list of mysql collations and their corresponding character sets each element of + // collation[1]..collation[MAP_SIZE-1] must not be null + Collation[] collation = new Collation[MAP_SIZE]; + collation[1] = new Collation(1, "big5_chinese_ci", 1, MYSQL_CHARSET_NAME_big5); + collation[84] = new Collation(84, "big5_bin", 0, MYSQL_CHARSET_NAME_big5); + + collation[2] = new Collation(2, "latin2_czech_cs", 0, MYSQL_CHARSET_NAME_latin2); + collation[9] = new Collation(9, "latin2_general_ci", 1, MYSQL_CHARSET_NAME_latin2); + collation[21] = new Collation(21, "latin2_hungarian_ci", 0, MYSQL_CHARSET_NAME_latin2); + collation[27] = new Collation(27, "latin2_croatian_ci", 0, MYSQL_CHARSET_NAME_latin2); + collation[77] = new Collation(77, "latin2_bin", 0, MYSQL_CHARSET_NAME_latin2); + + collation[4] = new Collation(4, "cp850_general_ci", 1, MYSQL_CHARSET_NAME_cp850); + collation[80] = new Collation(80, "cp850_bin", 0, MYSQL_CHARSET_NAME_cp850); + + collation[5] = new Collation(5, "latin1_german1_ci", 1, MYSQL_CHARSET_NAME_latin1); + collation[8] = new Collation(8, "latin1_swedish_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[15] = new Collation(15, "latin1_danish_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[31] = new Collation(31, "latin1_german2_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[47] = new Collation(47, "latin1_bin", 0, MYSQL_CHARSET_NAME_latin1); + collation[48] = new Collation(48, "latin1_general_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[49] = new Collation(49, "latin1_general_cs", 0, MYSQL_CHARSET_NAME_latin1); + collation[76] = new Collation(76, "not_implemented", 0, NOT_USED); + collation[94] = new Collation(94, "latin1_spanish_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[100] = new Collation(100, "not_implemented", 0, NOT_USED); + collation[125] = new Collation(125, "not_implemented", 0, NOT_USED); + collation[126] = new Collation(126, "not_implemented", 0, NOT_USED); + collation[127] = new Collation(127, "not_implemented", 0, NOT_USED); + collation[152] = new Collation(152, "not_implemented", 0, NOT_USED); + collation[153] = new Collation(153, "not_implemented", 0, NOT_USED); + collation[154] = new Collation(154, "not_implemented", 0, NOT_USED); + collation[155] = new Collation(155, "not_implemented", 0, NOT_USED); + collation[156] = new Collation(156, "not_implemented", 0, NOT_USED); + collation[157] = new Collation(157, "not_implemented", 0, NOT_USED); + collation[158] = new Collation(158, "not_implemented", 0, NOT_USED); + collation[184] = new Collation(184, "not_implemented", 0, NOT_USED); + collation[185] = new Collation(185, "not_implemented", 0, NOT_USED); + collation[186] = new Collation(186, "not_implemented", 0, NOT_USED); + collation[187] = new Collation(187, "not_implemented", 0, NOT_USED); + collation[188] = new Collation(188, "not_implemented", 0, NOT_USED); + collation[189] = new Collation(189, "not_implemented", 0, NOT_USED); + collation[190] = new Collation(190, "not_implemented", 0, NOT_USED); + collation[191] = new Collation(191, "not_implemented", 0, NOT_USED); + collation[216] = new Collation(216, "not_implemented", 0, NOT_USED); + collation[217] = new Collation(217, "not_implemented", 0, NOT_USED); + collation[218] = new Collation(218, "not_implemented", 0, NOT_USED); + collation[219] = new Collation(219, "not_implemented", 0, NOT_USED); + collation[220] = new Collation(220, "not_implemented", 0, NOT_USED); + collation[221] = new Collation(221, "not_implemented", 0, NOT_USED); + collation[222] = new Collation(222, "not_implemented", 0, NOT_USED); + collation[248] = new Collation(248, "gb18030_chinese_ci", 1, MYSQL_CHARSET_NAME_gb18030); + collation[249] = new Collation(249, "gb18030_bin", 0, MYSQL_CHARSET_NAME_gb18030); + collation[250] = new Collation(250, "gb18030_unicode_520_ci", 0, MYSQL_CHARSET_NAME_gb18030); + collation[251] = new Collation(251, "not_implemented", 0, NOT_USED); + collation[252] = new Collation(252, "not_implemented", 0, NOT_USED); + collation[253] = new Collation(253, "not_implemented", 0, NOT_USED); + collation[254] = new Collation(254, "not_implemented", 0, NOT_USED); + collation[10] = new Collation(10, "swe7_swedish_ci", 0, MYSQL_CHARSET_NAME_swe7); + collation[82] = new Collation(82, "swe7_bin", 0, MYSQL_CHARSET_NAME_swe7); + collation[6] = new Collation(6, "hp8_english_ci", 0, MYSQL_CHARSET_NAME_hp8); + collation[72] = new Collation(72, "hp8_bin", 0, MYSQL_CHARSET_NAME_hp8); + collation[3] = new Collation(3, "dec8_swedish_ci", 0, MYSQL_CHARSET_NAME_dec8); + collation[69] = new Collation(69, "dec8_bin", 0, MYSQL_CHARSET_NAME_dec8); + collation[32] = new Collation(32, "armscii8_general_ci", 0, MYSQL_CHARSET_NAME_armscii8); + collation[64] = new Collation(64, "armscii8_bin", 0, MYSQL_CHARSET_NAME_armscii8); + collation[92] = new Collation(92, "geostd8_general_ci", 0, MYSQL_CHARSET_NAME_geostd8); + collation[93] = new Collation(93, "geostd8_bin", 0, MYSQL_CHARSET_NAME_geostd8); + + collation[7] = new Collation(7, "koi8r_general_ci", 0, MYSQL_CHARSET_NAME_koi8r); + collation[74] = new Collation(74, "koi8r_bin", 0, MYSQL_CHARSET_NAME_koi8r); + + collation[11] = new Collation(11, "ascii_general_ci", 0, MYSQL_CHARSET_NAME_ascii); + collation[65] = new Collation(65, "ascii_bin", 0, MYSQL_CHARSET_NAME_ascii); + + collation[12] = new Collation(12, "ujis_japanese_ci", 0, MYSQL_CHARSET_NAME_ujis); + collation[91] = new Collation(91, "ujis_bin", 0, MYSQL_CHARSET_NAME_ujis); + + collation[13] = new Collation(13, "sjis_japanese_ci", 0, MYSQL_CHARSET_NAME_sjis); + collation[14] = new Collation(14, "cp1251_bulgarian_ci", 0, MYSQL_CHARSET_NAME_cp1251); + collation[16] = new Collation(16, "hebrew_general_ci", 0, MYSQL_CHARSET_NAME_hebrew); + collation[17] = new Collation(17, "latin1_german1_ci", 0, + MYSQL_4_0_CHARSET_NAME_win1251); // removed since 4.1 + collation[18] = new Collation(18, "tis620_thai_ci", 0, MYSQL_CHARSET_NAME_tis620); + collation[19] = new Collation(19, "euckr_korean_ci", 0, MYSQL_CHARSET_NAME_euckr); + collation[20] = new Collation(20, "latin7_estonian_cs", 0, MYSQL_CHARSET_NAME_latin7); + collation[22] = new Collation(22, "koi8u_general_ci", 0, MYSQL_CHARSET_NAME_koi8u); + collation[23] = new Collation(23, "cp1251_ukrainian_ci", 0, MYSQL_CHARSET_NAME_cp1251); + collation[24] = new Collation(24, "gb2312_chinese_ci", 0, MYSQL_CHARSET_NAME_gb2312); + collation[25] = new Collation(25, "greek_general_ci", 0, MYSQL_CHARSET_NAME_greek); + collation[26] = new Collation(26, "cp1250_general_ci", 1, MYSQL_CHARSET_NAME_cp1250); + collation[28] = new Collation(28, "gbk_chinese_ci", 1, MYSQL_CHARSET_NAME_gbk); + collation[29] = new Collation(29, "cp1257_lithuanian_ci", 0, MYSQL_CHARSET_NAME_cp1257); + collation[30] = new Collation(30, "latin5_turkish_ci", 1, MYSQL_CHARSET_NAME_latin5); + collation[33] = new Collation(33, "utf8_general_ci", 1, MYSQL_CHARSET_NAME_utf8); + collation[34] = new Collation(34, "cp1250_czech_cs", 0, MYSQL_CHARSET_NAME_cp1250); + collation[35] = new Collation(35, "ucs2_general_ci", 1, MYSQL_CHARSET_NAME_ucs2); + collation[36] = new Collation(36, "cp866_general_ci", 1, MYSQL_CHARSET_NAME_cp866); + collation[37] = new Collation(37, "keybcs2_general_ci", 1, MYSQL_CHARSET_NAME_keybcs2); + collation[38] = new Collation(38, "macce_general_ci", 1, MYSQL_CHARSET_NAME_macce); + collation[39] = new Collation(39, "macroman_general_ci", 1, MYSQL_CHARSET_NAME_macroman); + collation[40] = new Collation(40, "cp852_general_ci", 1, MYSQL_CHARSET_NAME_cp852); + collation[41] = new Collation(41, "latin7_general_ci", 1, MYSQL_CHARSET_NAME_latin7); + collation[42] = new Collation(42, "latin7_general_cs", 0, MYSQL_CHARSET_NAME_latin7); + collation[43] = new Collation(43, "macce_bin", 0, MYSQL_CHARSET_NAME_macce); + collation[44] = new Collation(44, "cp1250_croatian_ci", 0, MYSQL_CHARSET_NAME_cp1250); + collation[45] = new Collation(45, "utf8mb4_general_ci", 1, MYSQL_CHARSET_NAME_utf8mb4); + collation[46] = new Collation(46, "utf8mb4_bin", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[50] = new Collation(50, "cp1251_bin", 0, MYSQL_CHARSET_NAME_cp1251); + collation[51] = new Collation(51, "cp1251_general_ci", 1, MYSQL_CHARSET_NAME_cp1251); + collation[52] = new Collation(52, "cp1251_general_cs", 0, MYSQL_CHARSET_NAME_cp1251); + collation[53] = new Collation(53, "macroman_bin", 0, MYSQL_CHARSET_NAME_macroman); + collation[54] = new Collation(54, "utf16_general_ci", 1, MYSQL_CHARSET_NAME_utf16); + collation[55] = new Collation(55, "utf16_bin", 0, MYSQL_CHARSET_NAME_utf16); + collation[56] = new Collation(56, "utf16le_general_ci", 1, MYSQL_CHARSET_NAME_utf16le); + collation[57] = new Collation(57, "cp1256_general_ci", 1, MYSQL_CHARSET_NAME_cp1256); + collation[58] = new Collation(58, "cp1257_bin", 0, MYSQL_CHARSET_NAME_cp1257); + collation[59] = new Collation(59, "cp1257_general_ci", 1, MYSQL_CHARSET_NAME_cp1257); + collation[60] = new Collation(60, "utf32_general_ci", 1, MYSQL_CHARSET_NAME_utf32); + collation[61] = new Collation(61, "utf32_bin", 0, MYSQL_CHARSET_NAME_utf32); + collation[62] = new Collation(62, "utf16le_bin", 0, MYSQL_CHARSET_NAME_utf16le); + collation[63] = new Collation(63, "binary", 1, MYSQL_CHARSET_NAME_binary); + collation[66] = new Collation(66, "cp1250_bin", 0, MYSQL_CHARSET_NAME_cp1250); + collation[67] = new Collation(67, "cp1256_bin", 0, MYSQL_CHARSET_NAME_cp1256); + collation[68] = new Collation(68, "cp866_bin", 0, MYSQL_CHARSET_NAME_cp866); + collation[70] = new Collation(70, "greek_bin", 0, MYSQL_CHARSET_NAME_greek); + collation[71] = new Collation(71, "hebrew_bin", 0, MYSQL_CHARSET_NAME_hebrew); + collation[73] = new Collation(73, "keybcs2_bin", 0, MYSQL_CHARSET_NAME_keybcs2); + collation[75] = new Collation(75, "koi8u_bin", 0, MYSQL_CHARSET_NAME_koi8u); + collation[78] = new Collation(78, "latin5_bin", 0, MYSQL_CHARSET_NAME_latin5); + collation[79] = new Collation(79, "latin7_bin", 0, MYSQL_CHARSET_NAME_latin7); + collation[81] = new Collation(81, "cp852_bin", 0, MYSQL_CHARSET_NAME_cp852); + collation[83] = new Collation(83, "utf8_bin", 0, MYSQL_CHARSET_NAME_utf8); + collation[85] = new Collation(85, "euckr_bin", 0, MYSQL_CHARSET_NAME_euckr); + collation[86] = new Collation(86, "gb2312_bin", 0, MYSQL_CHARSET_NAME_gb2312); + collation[87] = new Collation(87, "gbk_bin", 0, MYSQL_CHARSET_NAME_gbk); + collation[88] = new Collation(88, "sjis_bin", 0, MYSQL_CHARSET_NAME_sjis); + collation[89] = new Collation(89, "tis620_bin", 0, MYSQL_CHARSET_NAME_tis620); + collation[90] = new Collation(90, "ucs2_bin", 0, MYSQL_CHARSET_NAME_ucs2); + collation[95] = new Collation(95, "cp932_japanese_ci", 1, MYSQL_CHARSET_NAME_cp932); + collation[96] = new Collation(96, "cp932_bin", 0, MYSQL_CHARSET_NAME_cp932); + collation[97] = new Collation(97, "eucjpms_japanese_ci", 1, MYSQL_CHARSET_NAME_eucjpms); + collation[98] = new Collation(98, "eucjpms_bin", 0, MYSQL_CHARSET_NAME_eucjpms); + collation[99] = new Collation(99, "cp1250_polish_ci", 0, MYSQL_CHARSET_NAME_cp1250); + collation[101] = new Collation(101, "utf16_unicode_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[102] = new Collation(102, "utf16_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[103] = new Collation(103, "utf16_latvian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[104] = new Collation(104, "utf16_romanian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[105] = new Collation(105, "utf16_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[106] = new Collation(106, "utf16_polish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[107] = new Collation(107, "utf16_estonian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[108] = new Collation(108, "utf16_spanish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[109] = new Collation(109, "utf16_swedish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[110] = new Collation(110, "utf16_turkish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[111] = new Collation(111, "utf16_czech_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[112] = new Collation(112, "utf16_danish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[113] = new Collation(113, "utf16_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[114] = new Collation(114, "utf16_slovak_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[115] = new Collation(115, "utf16_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[116] = new Collation(116, "utf16_roman_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[117] = new Collation(117, "utf16_persian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[118] = new Collation(118, "utf16_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[119] = new Collation(119, "utf16_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[120] = new Collation(120, "utf16_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[121] = new Collation(121, "utf16_german2_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[122] = new Collation(122, "utf16_croatian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[123] = new Collation(123, "utf16_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[124] = new Collation(124, "utf16_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[128] = new Collation(128, "ucs2_unicode_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[129] = new Collation(129, "ucs2_icelandic_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[130] = new Collation(130, "ucs2_latvian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[131] = new Collation(131, "ucs2_romanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[132] = new Collation(132, "ucs2_slovenian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[133] = new Collation(133, "ucs2_polish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[134] = new Collation(134, "ucs2_estonian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[135] = new Collation(135, "ucs2_spanish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[136] = new Collation(136, "ucs2_swedish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[137] = new Collation(137, "ucs2_turkish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[138] = new Collation(138, "ucs2_czech_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[139] = new Collation(139, "ucs2_danish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[140] = new Collation(140, "ucs2_lithuanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[141] = new Collation(141, "ucs2_slovak_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[142] = new Collation(142, "ucs2_spanish2_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[143] = new Collation(143, "ucs2_roman_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[144] = new Collation(144, "ucs2_persian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[145] = new Collation(145, "ucs2_esperanto_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[146] = new Collation(146, "ucs2_hungarian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[147] = new Collation(147, "ucs2_sinhala_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[148] = new Collation(148, "ucs2_german2_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[149] = new Collation(149, "ucs2_croatian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[150] = new Collation(150, "ucs2_unicode_520_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[151] = new Collation(151, "ucs2_vietnamese_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[159] = new Collation(159, "ucs2_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[160] = new Collation(160, "utf32_unicode_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[161] = new Collation(161, "utf32_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[162] = new Collation(162, "utf32_latvian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[163] = new Collation(163, "utf32_romanian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[164] = new Collation(164, "utf32_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[165] = new Collation(165, "utf32_polish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[166] = new Collation(166, "utf32_estonian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[167] = new Collation(167, "utf32_spanish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[168] = new Collation(168, "utf32_swedish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[169] = new Collation(169, "utf32_turkish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[170] = new Collation(170, "utf32_czech_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[171] = new Collation(171, "utf32_danish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[172] = new Collation(172, "utf32_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[173] = new Collation(173, "utf32_slovak_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[174] = new Collation(174, "utf32_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[175] = new Collation(175, "utf32_roman_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[176] = new Collation(176, "utf32_persian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[177] = new Collation(177, "utf32_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[178] = new Collation(178, "utf32_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[179] = new Collation(179, "utf32_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[180] = new Collation(180, "utf32_german2_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[181] = new Collation(181, "utf32_croatian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[182] = new Collation(182, "utf32_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[183] = new Collation(183, "utf32_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[192] = new Collation(192, "utf8_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[193] = new Collation(193, "utf8_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[194] = new Collation(194, "utf8_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[195] = new Collation(195, "utf8_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[196] = new Collation(196, "utf8_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[197] = new Collation(197, "utf8_polish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[198] = new Collation(198, "utf8_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[199] = new Collation(199, "utf8_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[200] = new Collation(200, "utf8_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[201] = new Collation(201, "utf8_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[202] = new Collation(202, "utf8_czech_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[203] = new Collation(203, "utf8_danish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[204] = new Collation(204, "utf8_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[205] = new Collation(205, "utf8_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[206] = new Collation(206, "utf8_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[207] = new Collation(207, "utf8_roman_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[208] = new Collation(208, "utf8_persian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[209] = new Collation(209, "utf8_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[210] = new Collation(210, "utf8_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[211] = new Collation(211, "utf8_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[212] = new Collation(212, "utf8_german2_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[213] = new Collation(213, "utf8_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[214] = new Collation(214, "utf8_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[215] = new Collation(215, "utf8_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[223] = new Collation(223, "utf8_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[224] = new Collation(224, "utf8mb4_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[225] = new Collation(225, "utf8mb4_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[226] = new Collation(226, "utf8mb4_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[227] = new Collation(227, "utf8mb4_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[228] = new Collation(228, "utf8mb4_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[229] = new Collation(229, "utf8mb4_polish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[230] = new Collation(230, "utf8mb4_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[231] = new Collation(231, "utf8mb4_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[232] = new Collation(232, "utf8mb4_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[233] = new Collation(233, "utf8mb4_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[234] = new Collation(234, "utf8mb4_czech_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[235] = new Collation(235, "utf8mb4_danish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[236] = new Collation(236, "utf8mb4_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[237] = new Collation(237, "utf8mb4_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[238] = new Collation(238, "utf8mb4_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[239] = new Collation(239, "utf8mb4_roman_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[240] = new Collation(240, "utf8mb4_persian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[241] = new Collation(241, "utf8mb4_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[242] = new Collation(242, "utf8mb4_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[243] = new Collation(243, "utf8mb4_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[244] = new Collation(244, "utf8mb4_german2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[245] = new Collation(245, "utf8mb4_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[246] = new Collation(246, "utf8mb4_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[247] = new Collation(247, "utf8mb4_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + + COLLATION_INDEX_TO_COLLATION_NAME = new String[MAP_SIZE]; + COLLATION_INDEX_TO_CHARSET = new MysqlCharset[MAP_SIZE]; + + // Add all collations to lookup maps for easy indexing + for (int i = 1; i < MAP_SIZE; i++) { + COLLATION_INDEX_TO_COLLATION_NAME[i] = collation[i].collationName; + COLLATION_INDEX_TO_CHARSET[i] = collation[i].mysqlCharset; } - public static String getMysqlCharsetNameForCollationIndex(Integer collationIndex) { - if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { - return COLLATION_INDEX_TO_CHARSET[collationIndex].charsetName; - } - return null; + // Sanity check + for (int i = 1; i < MAP_SIZE; i++) { + if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { + throw new RuntimeException( + "Assertion failure: No mapping from charset index " + i + " to a mysql collation"); + } + if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { + throw new RuntimeException( + "Assertion failure: No mapping from charset index " + i + " to a Java character set"); + } } + } + + /** + * MySQL charset could map to several Java encodings. So here we choose the one according to next + * rules: + *
  • if there is no static mapping for this charset then return javaEncoding value as is + * because this could be a custom charset for example + *
  • if static mapping exists and javaEncoding equals to one of Java encoding canonical names + * or aliases available for this mapping then javaEncoding value as is; this is required when + * result should match to connection encoding, for example if connection encoding is Cp943 we must + * avoid getting SHIFT_JIS for sjis mysql charset + *
  • if static mapping exists and javaEncoding doesn't match any Java encoding canonical + * names or aliases available for this mapping then return default Java encoding (the first in + * mapping list) + */ + public static String getJavaEncodingForCollationIndex(Integer collationIndex, + String javaEncoding) { + String res = javaEncoding; + if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { + MysqlCharset cs = COLLATION_INDEX_TO_CHARSET[collationIndex]; + if (cs != null) { + res = cs.getMatchingJavaEncoding(javaEncoding); + } + } + return res; + } - public static String getMysqlCharsetForJavaEncoding(String javaEncoding) { - if (javaEncoding != null) { - List mysqlCharsets = CharsetMapping.JAVA_ENCODING_UC_TO_MYSQL_CHARSET.get(javaEncoding.toUpperCase(Locale.ENGLISH)); + public static String getMysqlCharsetNameForCollationIndex(Integer collationIndex) { + if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { + return COLLATION_INDEX_TO_CHARSET[collationIndex].charsetName; + } + return null; + } - if (mysqlCharsets != null && !mysqlCharsets.isEmpty()) { - return mysqlCharsets.get(0).charsetName; - } - } + public static String getMysqlCharsetForJavaEncoding(String javaEncoding) { + if (javaEncoding != null) { + List mysqlCharsets = CharsetMapping.JAVA_ENCODING_UC_TO_MYSQL_CHARSET + .get(javaEncoding.toUpperCase(Locale.ENGLISH)); - return null; + if (mysqlCharsets != null && !mysqlCharsets.isEmpty()) { + return mysqlCharsets.get(0).charsetName; + } } - public static int getMblen(String charsetName) { - if (charsetName != null) { - MysqlCharset cs = CHARSET_NAME_TO_CHARSET.get(charsetName); - if (cs != null) { - return cs.mblen; - } - } - return 0; + return null; + } + + public static int getMblen(String charsetName) { + if (charsetName != null) { + MysqlCharset cs = CHARSET_NAME_TO_CHARSET.get(charsetName); + if (cs != null) { + return cs.mblen; + } } + return 0; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java b/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java index 638958564a5..53c095f623e 100644 --- a/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java +++ b/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java @@ -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,33 +17,27 @@ package io.vitess.util.charset; /** - * These classes were pulled from mysql-connector-java and simplified to just the parts supporting the statically available - * charsets + * These classes were pulled from mysql-connector-java and simplified to just the parts supporting + * the statically available charsets */ class Collation { - public final int index; - public final String collationName; - public final int priority; - public final MysqlCharset mysqlCharset; - public Collation(int index, String collationName, int priority, String charsetName) { - this.index = index; - this.collationName = collationName; - this.priority = priority; - this.mysqlCharset = CharsetMapping.CHARSET_NAME_TO_CHARSET.get(charsetName); - } + public final int index; + public final String collationName; + public final int priority; + public final MysqlCharset mysqlCharset; - @Override - public String toString() { - return "[" + - "index=" + - this.index + - ",collationName=" + - this.collationName + - ",charsetName=" + - this.mysqlCharset.charsetName + - ",javaCharsetName=" + - this.mysqlCharset.getMatchingJavaEncoding(null) + - "]"; - } + public Collation(int index, String collationName, int priority, String charsetName) { + this.index = index; + this.collationName = collationName; + this.priority = priority; + this.mysqlCharset = CharsetMapping.CHARSET_NAME_TO_CHARSET.get(charsetName); + } + + @Override + public String toString() { + return "[" + "index=" + this.index + ",collationName=" + this.collationName + ",charsetName=" + + this.mysqlCharset.charsetName + ",javaCharsetName=" + this.mysqlCharset + .getMatchingJavaEncoding(null) + "]"; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java b/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java index 7357673ee4e..78447d31e73 100644 --- a/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java +++ b/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java @@ -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,118 +17,121 @@ package io.vitess.util.charset; import java.nio.charset.Charset; -import java.sql.SQLException; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Set; /** - * These classes were pulled from mysql-connector-java and simplified to just the parts supporting the statically available - * charsets + * These classes were pulled from mysql-connector-java and simplified to just the parts supporting + * the statically available charsets */ class MysqlCharset { - public final String charsetName; - public final int mblen; - public final int priority; - public final Set javaEncodingsUc = new HashSet<>(); - private String defaultEncoding = null; - - public int major = 4; - public int minor = 1; - public int subminor = 0; - - /** - * Constructs MysqlCharset object - * - * @param charsetName MySQL charset name - * @param mblen Max number of bytes per character - * @param priority MysqlCharset with highest lever of this param will be used for Java encoding --> Mysql charsets conversion. - * @param javaEncodings List of Java encodings corresponding to this MySQL charset; the first name in list is the default for mysql --> java data conversion - */ - public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings) { - this.charsetName = charsetName; - this.mblen = mblen; - this.priority = priority; - - for (int i = 0; i < javaEncodings.length; i++) { - String encoding = javaEncodings[i]; - try { - Charset cs = Charset.forName(encoding); - addEncodingMapping(cs.name()); - - Set als = cs.aliases(); - Iterator ali = als.iterator(); - while (ali.hasNext()) { - addEncodingMapping(ali.next()); - } - } catch (Exception e) { - // if there is no support of this charset in JVM it's still possible to use our converter for 1-byte charsets - if (mblen == 1) { - addEncodingMapping(encoding); - } - } - } - if (this.javaEncodingsUc.size() == 0) { - if (mblen > 1) { - addEncodingMapping("UTF-8"); - } else { - addEncodingMapping("Cp1252"); - } - } - } + public final String charsetName; + public final int mblen; + public final int priority; + public final Set javaEncodingsUc = new HashSet<>(); + private String defaultEncoding = null; - private void addEncodingMapping(String encoding) { - String encodingUc = encoding.toUpperCase(Locale.ENGLISH); + public int major = 4; + public int minor = 1; + public int subminor = 0; - if (this.defaultEncoding == null) { - this.defaultEncoding = encodingUc; - } + /** + * Constructs MysqlCharset object + * + * @param charsetName MySQL charset name + * @param mblen Max number of bytes per character + * @param priority MysqlCharset with highest lever of this param will be used for Java + * encoding --> Mysql charsets conversion. + * @param javaEncodings List of Java encodings corresponding to this MySQL charset; the first + * name in list is the default for mysql --> java data conversion + */ + public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings) { + this.charsetName = charsetName; + this.mblen = mblen; + this.priority = priority; + + for (int i = 0; i < javaEncodings.length; i++) { + String encoding = javaEncodings[i]; + try { + Charset cs = Charset.forName(encoding); + addEncodingMapping(cs.name()); - if (!this.javaEncodingsUc.contains(encodingUc)) { - this.javaEncodingsUc.add(encodingUc); + Set als = cs.aliases(); + Iterator ali = als.iterator(); + while (ali.hasNext()) { + addEncodingMapping(ali.next()); + } + } catch (Exception exc) { + // if there is no support of this charset in JVM it's still possible to use our converter + // for 1-byte charsets + if (mblen == 1) { + addEncodingMapping(encoding); } + } } - public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, int major, int minor) { - this(charsetName, mblen, priority, javaEncodings); - this.major = major; - this.minor = minor; + if (this.javaEncodingsUc.size() == 0) { + if (mblen > 1) { + addEncodingMapping("UTF-8"); + } else { + addEncodingMapping("Cp1252"); + } } + } - public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, int major, int minor, int subminor) { - this(charsetName, mblen, priority, javaEncodings); - this.major = major; - this.minor = minor; - this.subminor = subminor; + private void addEncodingMapping(String encoding) { + String encodingUc = encoding.toUpperCase(Locale.ENGLISH); + + if (this.defaultEncoding == null) { + this.defaultEncoding = encodingUc; } - @Override - public String toString() { - StringBuilder asString = new StringBuilder(); - asString.append("["); - asString.append("charsetName="); - asString.append(this.charsetName); - asString.append(",mblen="); - asString.append(this.mblen); - // asString.append(",javaEncoding="); - // asString.append(this.javaEncodings.toString()); - asString.append("]"); - return asString.toString(); + if (!this.javaEncodingsUc.contains(encodingUc)) { + this.javaEncodingsUc.add(encodingUc); } + } - /** - * If javaEncoding parameter value is one of available java encodings for this charset - * then returns javaEncoding value as is. Otherwise returns first available java encoding name. - * - * @param javaEncoding - * @throws SQLException - */ - String getMatchingJavaEncoding(String javaEncoding) { - if (javaEncoding != null && this.javaEncodingsUc.contains(javaEncoding.toUpperCase(Locale.ENGLISH))) { - return javaEncoding; - } - return this.defaultEncoding; + public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, + int major, int minor) { + this(charsetName, mblen, priority, javaEncodings); + this.major = major; + this.minor = minor; + } + + public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, + int major, int minor, int subminor) { + this(charsetName, mblen, priority, javaEncodings); + this.major = major; + this.minor = minor; + this.subminor = subminor; + } + + @Override + public String toString() { + StringBuilder asString = new StringBuilder(); + asString.append("["); + asString.append("charsetName="); + asString.append(this.charsetName); + asString.append(",mblen="); + asString.append(this.mblen); + // asString.append(",javaEncoding="); + // asString.append(this.javaEncodings.toString()); + asString.append("]"); + return asString.toString(); + } + + /** + * If javaEncoding parameter value is one of available java encodings for this charset then + * returns javaEncoding value as is. Otherwise returns first available java encoding name. + */ + String getMatchingJavaEncoding(String javaEncoding) { + if (javaEncoding != null && this.javaEncodingsUc + .contains(javaEncoding.toUpperCase(Locale.ENGLISH))) { + return javaEncoding; } + return this.defaultEncoding; + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java index 5d4f7fbfaff..c677a376674 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java @@ -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,29 +16,30 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.BeforeClass; - import java.sql.SQLException; import java.util.Properties; +import org.junit.Assert; +import org.junit.BeforeClass; + public class BaseTest { - String dbURL = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace"; - - @BeforeClass - public static void setUp() { - try { - Class.forName("io.vitess.jdbc.VitessDriver"); - } catch (ClassNotFoundException e) { - Assert.fail("Driver is not in the CLASSPATH -> " + e.getMessage()); - } - } - protected VitessConnection getVitessConnection() throws SQLException { - return new VitessConnection(dbURL, new Properties()); - } + String dbURL = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace"; - protected VitessStatement getVitessStatement() throws SQLException { - return new VitessStatement(getVitessConnection()); + @BeforeClass + public static void setUp() { + try { + Class.forName("io.vitess.jdbc.VitessDriver"); + } catch (ClassNotFoundException e) { + Assert.fail("Driver is not in the CLASSPATH -> " + e.getMessage()); } + } + + protected VitessConnection getVitessConnection() throws SQLException { + return new VitessConnection(dbURL, new Properties()); + } + + protected VitessStatement getVitessStatement() throws SQLException { + return new VitessStatement(getVitessConnection()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java index 195b867fa4d..6f5057d97c8 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java @@ -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,6 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vitess.proto.Query; -import io.vitess.proto.Topodata; -import io.vitess.util.Constants; -import io.vitess.util.Constants.ZeroDateTimeBehavior; - -import java.sql.DriverPropertyInfo; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Properties; - import static io.vitess.util.Constants.DEFAULT_EXECUTE_TYPE; import static io.vitess.util.Constants.DEFAULT_INCLUDED_FIELDS; import static io.vitess.util.Constants.DEFAULT_TABLET_TYPE; @@ -41,259 +27,282 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -public class ConnectionPropertiesTest { - - private static final int NUM_PROPS = 39; - - @Test - public void testReflection() throws Exception { - ConnectionProperties props = new ConnectionProperties(); - Properties info = Mockito.spy(Properties.class); - Mockito.doReturn(info).when(info).clone(); - props.initializeProperties(info); - - // Just testing that we are properly picking up all the fields defined in the properties - // For each field we call initializeFrom, which should call getProperty and remove - verify(info, times(NUM_PROPS)).getProperty(anyString()); - verify(info, times(NUM_PROPS)).remove(anyString()); - } - - @Test - public void testDefaults() throws SQLException { - - ConnectionProperties props = new ConnectionProperties(); - props.initializeProperties(new Properties()); - - assertEquals("blobsAreStrings", false, props.getBlobsAreStrings()); - assertEquals("functionsNeverReturnBlobs", false, props.getFunctionsNeverReturnBlobs()); - assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); - assertEquals("yearIsDateType", true, props.getYearIsDateType()); - assertEquals("useBlobToStoreUTF8OutsideBMP", false, props.getUseBlobToStoreUTF8OutsideBMP()); - assertEquals("utf8OutsideBmpIncludedColumnNamePattern", null, props.getUtf8OutsideBmpIncludedColumnNamePattern()); - assertEquals("utf8OutsideBmpExcludedColumnNamePattern", null, props.getUtf8OutsideBmpExcludedColumnNamePattern()); - assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.GARBLE, props.getZeroDateTimeBehavior()); - assertEquals("characterEncoding", null, props.getEncoding()); - assertEquals("executeType", DEFAULT_EXECUTE_TYPE, props.getExecuteType()); - assertEquals("twopcEnabled", false, props.getTwopcEnabled()); - assertEquals("includedFields", DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); - assertEquals("includedFieldsCache", true, props.isIncludeAllFields()); - assertEquals("tabletType", DEFAULT_TABLET_TYPE, props.getTabletType()); - assertEquals("useSSL", false, props.getUseSSL()); - assertEquals("useAffectedRows", true, props.getUseAffectedRows()); - assertEquals("refreshConnection", false, props.getRefreshConnection()); - assertEquals("refreshSeconds", 60, props.getRefreshSeconds()); - } +import io.vitess.proto.Query; +import io.vitess.proto.Topodata; +import io.vitess.util.Constants; +import io.vitess.util.Constants.ZeroDateTimeBehavior; - @Test - public void testInitializeFromProperties() throws SQLException { - - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - info.setProperty("blobsAreStrings", "yes"); - info.setProperty("functionsNeverReturnBlobs", "yes"); - info.setProperty("tinyInt1isBit", "yes"); - info.setProperty("yearIsDateType", "yes"); - info.setProperty("useBlobToStoreUTF8OutsideBMP", "yes"); - info.setProperty("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz"); - info.setProperty("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz"); - info.setProperty("characterEncoding", "utf-8"); - info.setProperty("zeroDateTimeBehavior", "convertToNull"); - info.setProperty("executeType", Constants.QueryExecuteType.STREAM.name()); - info.setProperty("twopcEnabled", "yes"); - info.setProperty("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY.name()); - info.setProperty(Constants.Property.TABLET_TYPE, Topodata.TabletType.BACKUP.name()); - - props.initializeProperties(info); - - assertEquals("blobsAreStrings", true, props.getBlobsAreStrings()); - assertEquals("functionsNeverReturnBlobs", true, props.getFunctionsNeverReturnBlobs()); - assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); - assertEquals("yearIsDateType", true, props.getYearIsDateType()); - assertEquals("useBlobToStoreUTF8OutsideBMP", true, props.getUseBlobToStoreUTF8OutsideBMP()); - assertEquals("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz", props.getUtf8OutsideBmpIncludedColumnNamePattern()); - assertEquals("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz", props.getUtf8OutsideBmpExcludedColumnNamePattern()); - assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.CONVERTTONULL, props.getZeroDateTimeBehavior()); - assertEquals("characterEncoding", "utf-8", props.getEncoding()); - assertEquals("executeType", Constants.QueryExecuteType.STREAM, props.getExecuteType()); - assertEquals("twopcEnabled", true, props.getTwopcEnabled()); - assertEquals("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY, props.getIncludedFields()); - assertEquals("includedFieldsCache", false, props.isIncludeAllFields()); - assertEquals("tabletType", Topodata.TabletType.BACKUP, props.getTabletType()); - } +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Properties; - @Test - public void testEncodingValidation() { - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - - String fakeEncoding = "utf-12345"; - info.setProperty("characterEncoding", fakeEncoding); - try { - props.initializeProperties(info); - fail("should have failed to parse encoding " + fakeEncoding); - } catch (SQLException e) { - assertEquals("Unsupported character encoding: " + fakeEncoding, e.getMessage()); - } - } +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; - @Test - public void testDriverPropertiesOutput() throws SQLException { - Properties info = new Properties(); - DriverPropertyInfo[] infos = ConnectionProperties.exposeAsDriverPropertyInfo(info, 0); - assertEquals(NUM_PROPS, infos.length); - - // Test the expected fields for just 1 - int indexForFullTest = 3; - assertEquals("executeType", infos[indexForFullTest].name); - assertEquals("Query execution type: simple or stream", - infos[indexForFullTest].description); - assertEquals(false, infos[indexForFullTest].required); - Constants.QueryExecuteType[] enumConstants = Constants.QueryExecuteType.values(); - String[] allowed = new String[enumConstants.length]; - for (int i = 0; i < enumConstants.length; i++) { - allowed[i] = enumConstants[i].toString(); - } - Assert.assertArrayEquals(allowed, infos[indexForFullTest].choices); - - // Test that name exists for the others, as a sanity check - assertEquals("dbName", infos[1].name); - assertEquals("characterEncoding", infos[2].name); - assertEquals("executeType", infos[3].name); - assertEquals("functionsNeverReturnBlobs", infos[4].name); - assertEquals("grpcRetriesEnabled", infos[5].name); - assertEquals("grpcRetriesBackoffMultiplier", infos[6].name); - assertEquals("grpcRetriesInitialBackoffMillis", infos[7].name); - assertEquals("grpcRetriesMaxBackoffMillis", infos[8].name); - assertEquals(Constants.Property.INCLUDED_FIELDS, infos[9].name); - assertEquals(Constants.Property.TABLET_TYPE, infos[21].name); - assertEquals(Constants.Property.TWOPC_ENABLED, infos[29].name); - } +public class ConnectionPropertiesTest { - @Test - public void testValidBooleanValues() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - - info.setProperty("blobsAreStrings", "true"); - info.setProperty("functionsNeverReturnBlobs", "yes"); - info.setProperty("tinyInt1isBit", "no"); - - props.initializeProperties(info); - - info.setProperty(Constants.Property.TWOPC_ENABLED, "false-ish"); - try { - props.initializeProperties(info); - fail("should have thrown an exception on bad value false-ish"); - } catch (IllegalArgumentException e) { - String expected = String.format("Property '%s' Value 'false-ish' not in the list of allowable values: [true, false, yes, no]", - Constants.Property.TWOPC_ENABLED); - assertEquals(expected , e.getMessage()); - } + private static final int NUM_PROPS = 39; + + @Test + public void testReflection() throws Exception { + ConnectionProperties props = new ConnectionProperties(); + Properties info = Mockito.spy(Properties.class); + Mockito.doReturn(info).when(info).clone(); + props.initializeProperties(info); + + // Just testing that we are properly picking up all the fields defined in the properties + // For each field we call initializeFrom, which should call getProperty and remove + verify(info, times(NUM_PROPS)).getProperty(anyString()); + verify(info, times(NUM_PROPS)).remove(anyString()); + } + + @Test + public void testDefaults() throws SQLException { + + ConnectionProperties props = new ConnectionProperties(); + props.initializeProperties(new Properties()); + + assertEquals("blobsAreStrings", false, props.getBlobsAreStrings()); + assertEquals("functionsNeverReturnBlobs", false, props.getFunctionsNeverReturnBlobs()); + assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); + assertEquals("yearIsDateType", true, props.getYearIsDateType()); + assertEquals("useBlobToStoreUTF8OutsideBMP", false, props.getUseBlobToStoreUTF8OutsideBMP()); + assertEquals("utf8OutsideBmpIncludedColumnNamePattern", null, + props.getUtf8OutsideBmpIncludedColumnNamePattern()); + assertEquals("utf8OutsideBmpExcludedColumnNamePattern", null, + props.getUtf8OutsideBmpExcludedColumnNamePattern()); + assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.GARBLE, + props.getZeroDateTimeBehavior()); + assertEquals("characterEncoding", null, props.getEncoding()); + assertEquals("executeType", DEFAULT_EXECUTE_TYPE, props.getExecuteType()); + assertEquals("twopcEnabled", false, props.getTwopcEnabled()); + assertEquals("includedFields", DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); + assertEquals("includedFieldsCache", true, props.isIncludeAllFields()); + assertEquals("tabletType", DEFAULT_TABLET_TYPE, props.getTabletType()); + assertEquals("useSSL", false, props.getUseSSL()); + assertEquals("useAffectedRows", true, props.getUseAffectedRows()); + assertEquals("refreshConnection", false, props.getRefreshConnection()); + assertEquals("refreshSeconds", 60, props.getRefreshSeconds()); + } + + @Test + public void testInitializeFromProperties() throws SQLException { + + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + info.setProperty("blobsAreStrings", "yes"); + info.setProperty("functionsNeverReturnBlobs", "yes"); + info.setProperty("tinyInt1isBit", "yes"); + info.setProperty("yearIsDateType", "yes"); + info.setProperty("useBlobToStoreUTF8OutsideBMP", "yes"); + info.setProperty("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz"); + info.setProperty("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz"); + info.setProperty("characterEncoding", "utf-8"); + info.setProperty("zeroDateTimeBehavior", "convertToNull"); + info.setProperty("executeType", Constants.QueryExecuteType.STREAM.name()); + info.setProperty("twopcEnabled", "yes"); + info.setProperty("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY.name()); + info.setProperty(Constants.Property.TABLET_TYPE, Topodata.TabletType.BACKUP.name()); + + props.initializeProperties(info); + + assertEquals("blobsAreStrings", true, props.getBlobsAreStrings()); + assertEquals("functionsNeverReturnBlobs", true, props.getFunctionsNeverReturnBlobs()); + assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); + assertEquals("yearIsDateType", true, props.getYearIsDateType()); + assertEquals("useBlobToStoreUTF8OutsideBMP", true, props.getUseBlobToStoreUTF8OutsideBMP()); + assertEquals("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz", + props.getUtf8OutsideBmpIncludedColumnNamePattern()); + assertEquals("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz", + props.getUtf8OutsideBmpExcludedColumnNamePattern()); + assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.CONVERTTONULL, + props.getZeroDateTimeBehavior()); + assertEquals("characterEncoding", "utf-8", props.getEncoding()); + assertEquals("executeType", Constants.QueryExecuteType.STREAM, props.getExecuteType()); + assertEquals("twopcEnabled", true, props.getTwopcEnabled()); + assertEquals("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY, + props.getIncludedFields()); + assertEquals("includedFieldsCache", false, props.isIncludeAllFields()); + assertEquals("tabletType", Topodata.TabletType.BACKUP, props.getTabletType()); + } + + @Test + public void testEncodingValidation() { + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + + String fakeEncoding = "utf-12345"; + info.setProperty("characterEncoding", fakeEncoding); + try { + props.initializeProperties(info); + fail("should have failed to parse encoding " + fakeEncoding); + } catch (SQLException e) { + assertEquals("Unsupported character encoding: " + fakeEncoding, e.getMessage()); } - - @Test - public void testValidEnumValues() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - - info.setProperty("executeType", "foo"); - try { - props.initializeProperties(info); - fail("should have thrown an exception on bad value foo"); - } catch (IllegalArgumentException e) { - assertEquals( - "Property 'executeType' Value 'foo' not in the list of allowable values: " - + Arrays.toString(Constants.QueryExecuteType.values()) - , e.getMessage()); - } + } + + @Test + public void testDriverPropertiesOutput() throws SQLException { + Properties info = new Properties(); + DriverPropertyInfo[] infos = ConnectionProperties.exposeAsDriverPropertyInfo(info, 0); + assertEquals(NUM_PROPS, infos.length); + + // Test the expected fields for just 1 + int indexForFullTest = 3; + assertEquals("executeType", infos[indexForFullTest].name); + assertEquals("Query execution type: simple or stream", infos[indexForFullTest].description); + assertEquals(false, infos[indexForFullTest].required); + Constants.QueryExecuteType[] enumConstants = Constants.QueryExecuteType.values(); + String[] allowed = new String[enumConstants.length]; + for (int i = 0; i < enumConstants.length; i++) { + allowed[i] = enumConstants[i].toString(); } - - @Test - public void testSettersUpdateCaches() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - props.initializeProperties(new Properties()); - - // included fields and all boolean cache - assertEquals(DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); - assertTrue(props.isIncludeAllFields()); - - // execute type and simple boolean cache - assertEquals(DEFAULT_EXECUTE_TYPE, props.getExecuteType()); - assertEquals(DEFAULT_EXECUTE_TYPE == Constants.QueryExecuteType.SIMPLE, props.isSimpleExecute()); - - // tablet type and twopc - assertEquals(DEFAULT_TABLET_TYPE, props.getTabletType()); - assertFalse(props.getTwopcEnabled()); - - props.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - props.setExecuteType(Constants.QueryExecuteType.STREAM); - props.setTabletType(Topodata.TabletType.BACKUP); - props.setTwopcEnabled(true); - - // included fields and all boolean cache - assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, props.getIncludedFields()); - assertFalse(props.isIncludeAllFields()); - - // execute type and simple boolean cache - assertEquals(Constants.QueryExecuteType.STREAM, props.getExecuteType()); - assertEquals(DEFAULT_EXECUTE_TYPE != Constants.QueryExecuteType.SIMPLE, props.isSimpleExecute()); - - // tablet type and twopc - assertEquals(Topodata.TabletType.BACKUP, props.getTabletType()); - assertTrue(props.getTwopcEnabled()); + Assert.assertArrayEquals(allowed, infos[indexForFullTest].choices); + + // Test that name exists for the others, as a sanity check + assertEquals("dbName", infos[1].name); + assertEquals("characterEncoding", infos[2].name); + assertEquals("executeType", infos[3].name); + assertEquals("functionsNeverReturnBlobs", infos[4].name); + assertEquals("grpcRetriesEnabled", infos[5].name); + assertEquals("grpcRetriesBackoffMultiplier", infos[6].name); + assertEquals("grpcRetriesInitialBackoffMillis", infos[7].name); + assertEquals("grpcRetriesMaxBackoffMillis", infos[8].name); + assertEquals(Constants.Property.INCLUDED_FIELDS, infos[9].name); + assertEquals(Constants.Property.TABLET_TYPE, infos[21].name); + assertEquals(Constants.Property.TWOPC_ENABLED, infos[29].name); + } + + @Test + public void testValidBooleanValues() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + + info.setProperty("blobsAreStrings", "true"); + info.setProperty("functionsNeverReturnBlobs", "yes"); + info.setProperty("tinyInt1isBit", "no"); + + props.initializeProperties(info); + + info.setProperty(Constants.Property.TWOPC_ENABLED, "false-ish"); + try { + props.initializeProperties(info); + fail("should have thrown an exception on bad value false-ish"); + } catch (IllegalArgumentException e) { + String expected = String.format( + "Property '%s' Value 'false-ish' not in the list of allowable values: [true, false, " + + "yes, no]", + Constants.Property.TWOPC_ENABLED); + assertEquals(expected, e.getMessage()); } - - @Test - public void testTarget() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - - // Setting keyspace - Properties info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - props.initializeProperties(info); - assertEquals("target", "test_keyspace@master", props.getTarget()); - - // Setting keyspace and shard - info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - info.setProperty(Constants.Property.SHARD, "80-c0"); - props.initializeProperties(info); - assertEquals("target", "test_keyspace:80-c0@master", props.getTarget()); - - // Setting tablet type - info = new Properties(); - info.setProperty(Constants.Property.TABLET_TYPE, "replica"); - props.initializeProperties(info); - assertEquals("target", "@replica", props.getTarget()); - - // Setting shard which will have no impact without keyspace - info = new Properties(); - info.setProperty(Constants.Property.SHARD, "80-c0"); - props.initializeProperties(info); - assertEquals("target", "@master", props.getTarget()); - - // Setting shard and tablet type. Shard will have no impact. - info = new Properties(); - info.setProperty(Constants.Property.SHARD, "80-c0"); - info.setProperty(Constants.Property.TABLET_TYPE, "replica"); - props.initializeProperties(info); - assertEquals("target", "@replica", props.getTarget()); - - // Setting keyspace, shard and tablet type. - info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - info.setProperty(Constants.Property.SHARD, "80-c0"); - info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); - props.initializeProperties(info); - assertEquals("target", "test_keyspace:80-c0@rdonly", props.getTarget()); - - // Setting keyspace, shard, tablet type and target. Target supersede others. - info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - info.setProperty(Constants.Property.SHARD, "80-c0"); - info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); - info.setProperty(Constants.Property.TARGET, "dummy"); - props.initializeProperties(info); - assertEquals("target", "dummy", props.getTarget()); + } + + @Test + public void testValidEnumValues() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + + info.setProperty("executeType", "foo"); + try { + props.initializeProperties(info); + fail("should have thrown an exception on bad value foo"); + } catch (IllegalArgumentException e) { + assertEquals( + "Property 'executeType' Value 'foo' not in the list of allowable values: " + Arrays + .toString(Constants.QueryExecuteType.values()), e.getMessage()); } + } + + @Test + public void testSettersUpdateCaches() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + props.initializeProperties(new Properties()); + + // included fields and all boolean cache + assertEquals(DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); + assertTrue(props.isIncludeAllFields()); + + // execute type and simple boolean cache + assertEquals(DEFAULT_EXECUTE_TYPE, props.getExecuteType()); + assertEquals(DEFAULT_EXECUTE_TYPE == Constants.QueryExecuteType.SIMPLE, + props.isSimpleExecute()); + + // tablet type and twopc + assertEquals(DEFAULT_TABLET_TYPE, props.getTabletType()); + assertFalse(props.getTwopcEnabled()); + + props.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + props.setExecuteType(Constants.QueryExecuteType.STREAM); + props.setTabletType(Topodata.TabletType.BACKUP); + props.setTwopcEnabled(true); + + // included fields and all boolean cache + assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, props.getIncludedFields()); + assertFalse(props.isIncludeAllFields()); + + // execute type and simple boolean cache + assertEquals(Constants.QueryExecuteType.STREAM, props.getExecuteType()); + assertEquals(DEFAULT_EXECUTE_TYPE != Constants.QueryExecuteType.SIMPLE, + props.isSimpleExecute()); + + // tablet type and twopc + assertEquals(Topodata.TabletType.BACKUP, props.getTabletType()); + assertTrue(props.getTwopcEnabled()); + } + + @Test + public void testTarget() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + + // Setting keyspace + Properties info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + props.initializeProperties(info); + assertEquals("target", "test_keyspace@master", props.getTarget()); + + // Setting keyspace and shard + info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + info.setProperty(Constants.Property.SHARD, "80-c0"); + props.initializeProperties(info); + assertEquals("target", "test_keyspace:80-c0@master", props.getTarget()); + + // Setting tablet type + info = new Properties(); + info.setProperty(Constants.Property.TABLET_TYPE, "replica"); + props.initializeProperties(info); + assertEquals("target", "@replica", props.getTarget()); + + // Setting shard which will have no impact without keyspace + info = new Properties(); + info.setProperty(Constants.Property.SHARD, "80-c0"); + props.initializeProperties(info); + assertEquals("target", "@master", props.getTarget()); + + // Setting shard and tablet type. Shard will have no impact. + info = new Properties(); + info.setProperty(Constants.Property.SHARD, "80-c0"); + info.setProperty(Constants.Property.TABLET_TYPE, "replica"); + props.initializeProperties(info); + assertEquals("target", "@replica", props.getTarget()); + + // Setting keyspace, shard and tablet type. + info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + info.setProperty(Constants.Property.SHARD, "80-c0"); + info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); + props.initializeProperties(info); + assertEquals("target", "test_keyspace:80-c0@rdonly", props.getTarget()); + + // Setting keyspace, shard, tablet type and target. Target supersede others. + info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + info.setProperty(Constants.Property.SHARD, "80-c0"); + info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); + info.setProperty(Constants.Property.TARGET, "dummy"); + props.initializeProperties(info); + assertEquals("target", "dummy", props.getTarget()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java index 863399930a3..a112d3c154f 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java @@ -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,6 +16,13 @@ package io.vitess.jdbc; +import io.vitess.proto.Query; +import io.vitess.util.MysqlDefs; +import io.vitess.util.charset.CharsetMapping; + +import java.sql.SQLException; +import java.sql.Types; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,721 +32,591 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import io.vitess.proto.Query; -import io.vitess.util.MysqlDefs; -import io.vitess.util.charset.CharsetMapping; - -import java.sql.SQLException; -import java.sql.Types; - @PrepareForTest(FieldWithMetadata.class) @RunWith(PowerMockRunner.class) public class FieldWithMetadataTest extends BaseTest { - @Test - public void testImplicitTempTable() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("#sql_my_temptable") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.VARCHAR) - .setName("foo") - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(getVitessConnection(), raw); - - Assert.assertEquals(true, fieldWithMetadata.isImplicitTemporaryTable()); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - - VitessConnection conn = getVitessConnection(); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - - raw = Query.Field.newBuilder() - .setType(Query.Type.VARCHAR) - .setName("foo") - .build(); - - fieldWithMetadata = new FieldWithMetadata(conn, raw); - - Assert.assertEquals(false, fieldWithMetadata.isImplicitTemporaryTable()); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + @Test + public void testImplicitTempTable() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("#sql_my_temptable") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.VARCHAR).setName("foo") + .build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(getVitessConnection(), raw); + + Assert.assertEquals(true, fieldWithMetadata.isImplicitTemporaryTable()); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + + VitessConnection conn = getVitessConnection(); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + + raw = Query.Field.newBuilder().setType(Query.Type.VARCHAR).setName("foo").build(); + + fieldWithMetadata = new FieldWithMetadata(conn, raw); + + Assert.assertEquals(false, fieldWithMetadata.isImplicitTemporaryTable()); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + } + + @Test + public void testBlobRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + conn.setBlobsAreStrings(true); + + Query.Field raw = Query.Field.newBuilder().setTable("#sql_my_temptable") + .setCharset(/* latin1, doesn't matter just dont want utf8 for now */ 5) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.BLOB).setName("foo") + .setOrgName("foo").build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + + conn.setBlobsAreStrings(false); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); + + conn.setFunctionsNeverReturnBlobs(true); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + + conn.setFunctionsNeverReturnBlobs(false); + conn.setUseBlobToStoreUTF8OutsideBMP(true); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setColumnLength(MysqlDefs.LENGTH_BLOB).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + conn.setUtf8OutsideBmpExcludedColumnNamePattern("^fo.*$"); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); + Assert.assertNotEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + conn.setUtf8OutsideBmpIncludedColumnNamePattern("^foo$"); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + raw = raw.toBuilder().setColumnLength(MysqlDefs.LENGTH_LONGBLOB).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + conn.setUseBlobToStoreUTF8OutsideBMP(false); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BLOB, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(null, fieldWithMetadata.getCollation()); + } + + @Test + public void testTinyIntAsBit() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.INT8).setName("foo").setOrgName("foo").build(); + conn.setTinyInt1isBit(true); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setColumnLength(1).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); + } + + @Test + public void testNonNumericNotDateTimeRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.VARBINARY).setName("foo").setOrgName("foo") + .setCharset(/* utf-16 UnicodeBig */35).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(/* remapped by TEXT special case */Types.VARCHAR, + fieldWithMetadata.getJavaType()); + Assert.assertEquals("UTF-16", fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARBINARY, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn = getVitessConnection(); + raw = raw.toBuilder().setType(Query.Type.JSON).setColumnLength(MysqlDefs.LENGTH_LONGBLOB) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).build(); + + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("UTF-8", fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn = getVitessConnection(); + raw = raw.toBuilder().setType(Query.Type.BIT).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + + conn = getVitessConnection(); + raw = raw.toBuilder().setColumnLength(1).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); + Assert.assertEquals(true, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + } + + @Test + public void testVarBinaryToVarCharRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.VARBINARY).setName("foo").setOrgName("foo") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert + .assertEquals("no remapping - base case", Types.VARBINARY, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals("remap to varchar due to non-binary encoding", Types.VARCHAR, + fieldWithMetadata.getJavaType()); + } + + @Test + public void testBinaryToCharRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.BINARY).setName("foo").setOrgName("foo") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals("no remapping - base case", Types.BINARY, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals("remap to char due to non-binary encoding", Types.CHAR, + fieldWithMetadata.getJavaType()); + } + + @Test + public void testNumericAndDateTimeEncoding() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Type[] types = new Query.Type[]{Query.Type.INT8, Query.Type.UINT8, Query.Type.INT16, + Query.Type.UINT16, Query.Type.INT24, Query.Type.UINT24, Query.Type.INT32, Query.Type.UINT32, + Query.Type.INT64, Query.Type.UINT64, Query.Type.DECIMAL, Query.Type.UINT24, + Query.Type.INT32, Query.Type.UINT32, Query.Type.FLOAT32, Query.Type.FLOAT64, + Query.Type.DATE, Query.Type.DATETIME, Query.Type.TIME, Query.Type.TIMESTAMP, + Query.Type.YEAR}; + + for (Query.Type type : types) { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3).setType(type) + .setName("foo").setOrgName("foo").setCharset(/* utf-16 UnicodeBig */35).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(type.name(), "US-ASCII", fieldWithMetadata.getEncoding()); + Assert.assertEquals(type.name(), false, fieldWithMetadata.isSingleBit()); } - @Test - public void testBlobRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - conn.setBlobsAreStrings(true); - - Query.Field raw = Query.Field.newBuilder() - .setTable("#sql_my_temptable") - .setCharset(/* latin1, doesn't matter just dont want utf8 for now */ 5) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.BLOB) - .setName("foo") - .setOrgName("foo") - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - - conn.setBlobsAreStrings(false); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); - - conn.setFunctionsNeverReturnBlobs(true); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - - conn.setFunctionsNeverReturnBlobs(false); - conn.setUseBlobToStoreUTF8OutsideBMP(true); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder() - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setColumnLength(MysqlDefs.LENGTH_BLOB) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - conn.setUtf8OutsideBmpExcludedColumnNamePattern("^fo.*$"); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); - Assert.assertNotEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - conn.setUtf8OutsideBmpIncludedColumnNamePattern("^foo$"); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - raw = raw.toBuilder() - .setColumnLength(MysqlDefs.LENGTH_LONGBLOB) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - conn.setUseBlobToStoreUTF8OutsideBMP(false); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BLOB, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(null, fieldWithMetadata.getCollation()); - } + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - @Test - public void testTinyIntAsBit() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.INT8) - .setName("foo") - .setOrgName("foo") - .build(); - conn.setTinyInt1isBit(true); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder() - .setColumnLength(1) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); - } + for (Query.Type type : types) { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3).setType(type) + .setName("foo").setOrgName("foo").setCharset(/* utf-16 UnicodeBig */35).build(); - @Test - public void testNonNumericNotDateTimeRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.VARBINARY) - .setName("foo") - .setOrgName("foo") - .setCharset(/* utf-16 UnicodeBig */35) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(/* remapped by TEXT special case */Types.VARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("UTF-16", fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARBINARY, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn = getVitessConnection(); - raw = raw.toBuilder() - .setType(Query.Type.JSON) - .setColumnLength(MysqlDefs.LENGTH_LONGBLOB) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .build(); - - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("UTF-8", fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn = getVitessConnection(); - raw = raw.toBuilder() - .setType(Query.Type.BIT) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - - conn = getVitessConnection(); - raw = raw.toBuilder() - .setColumnLength(1) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); - Assert.assertEquals(true, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(type.name(), null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(type.name(), false, fieldWithMetadata.isSingleBit()); } - - @Test - public void testVarBinaryToVarCharRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.VARBINARY) - .setName("foo") - .setOrgName("foo") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("no remapping - base case", Types.VARBINARY, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("remap to varchar due to non-binary encoding", Types.VARCHAR, fieldWithMetadata.getJavaType()); + } + + @Test + public void testPrecisionAdjustFactor() throws SQLException { + VitessConnection conn = getVitessConnection(); + assertPrecisionEquals(conn, Query.Type.FLOAT32, true, 0, 0); + assertPrecisionEquals(conn, Query.Type.FLOAT64, true, 32, 0); + assertPrecisionEquals(conn, Query.Type.BIT, true, 0, 0); + assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 0, -1); + assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 3, -2); + assertPrecisionEquals(conn, Query.Type.INT32, true, /* this can't happen, but just checking */3, + -2); + assertPrecisionEquals(conn, Query.Type.INT32, true, 0, -1); + assertPrecisionEquals(conn, Query.Type.FLOAT32, false, 0, 0); + assertPrecisionEquals(conn, Query.Type.FLOAT64, false, 32, 0); + assertPrecisionEquals(conn, Query.Type.BIT, false, 0, 0); + assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 0, -1); + assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 3, -1); + assertPrecisionEquals(conn, Query.Type.UINT32, false, 0, 0); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (Query.Type type : Query.Type.values()) { + if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION) { + continue; + } + + // All should be 0 + assertPrecisionEquals(conn, type, true, 0, 0); + assertPrecisionEquals(conn, type, false, 0, 0); + assertPrecisionEquals(conn, type, true, 2, 0); + assertPrecisionEquals(conn, type, false, 2, 0); } - - @Test - public void testBinaryToCharRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.BINARY) - .setName("foo") - .setOrgName("foo") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("no remapping - base case", Types.BINARY, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("remap to char due to non-binary encoding", Types.CHAR, fieldWithMetadata.getJavaType()); + } + + private void assertPrecisionEquals(VitessConnection conn, Query.Type fieldType, boolean signed, + int decimals, int expectedPrecisionAdjustFactor) throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3).setType(fieldType) + .setDecimals(decimals).setFlags(signed ? 0 : Query.MySqlFlag.UNSIGNED_FLAG_VALUE) + .setName("foo").setOrgName("foo").build(); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert + .assertEquals(expectedPrecisionAdjustFactor, fieldWithMetadata.getPrecisionAdjustFactor()); + } + + @Test + public void testFlags() throws SQLException { + VitessConnection conn = getVitessConnection(); + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.VARBINARY).setName("foo").setOrgName("foo").build(); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); + Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); + Assert.assertEquals(false, fieldWithMetadata.isNotNull()); + Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); + Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); + Assert.assertEquals(false, fieldWithMetadata.isUnsigned()); + Assert.assertEquals(/* just inverses isUnsigned */true, fieldWithMetadata.isSigned()); + Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); + + int value = 0; + for (Query.MySqlFlag flag : Query.MySqlFlag.values()) { + if (flag == Query.MySqlFlag.UNRECOGNIZED) { + continue; + } + value |= flag.getNumber(); } - - @Test - public void testNumericAndDateTimeEncoding() throws SQLException{ - VitessConnection conn = getVitessConnection(); - - Query.Type[] types = new Query.Type[]{ - Query.Type.INT8, - Query.Type.UINT8, - Query.Type.INT16, - Query.Type.UINT16, - Query.Type.INT24, - Query.Type.UINT24, - Query.Type.INT32, - Query.Type.UINT32, - Query.Type.INT64, - Query.Type.UINT64, - Query.Type.DECIMAL, - Query.Type.UINT24, - Query.Type.INT32, - Query.Type.UINT32, - Query.Type.FLOAT32, - Query.Type.FLOAT64, - Query.Type.DATE, - Query.Type.DATETIME, - Query.Type.TIME, - Query.Type.TIMESTAMP, - Query.Type.YEAR - }; - - - for (Query.Type type : types) { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(type) - .setName("foo") - .setOrgName("foo") - .setCharset(/* utf-16 UnicodeBig */35) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(type.name(),"US-ASCII", fieldWithMetadata.getEncoding()); - Assert.assertEquals(type.name(),false, fieldWithMetadata.isSingleBit()); - } - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - - for (Query.Type type : types) { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(type) - .setName("foo") - .setOrgName("foo") - .setCharset(/* utf-16 UnicodeBig */35) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(type.name(),null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(type.name(),false, fieldWithMetadata.isSingleBit()); - } - } - - @Test - public void testPrecisionAdjustFactor() throws SQLException { - VitessConnection conn = getVitessConnection(); - assertPrecisionEquals(conn, Query.Type.FLOAT32, true, 0, 0); - assertPrecisionEquals(conn, Query.Type.FLOAT64, true, 32, 0); - assertPrecisionEquals(conn, Query.Type.BIT, true, 0, 0); - assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 0, -1); - assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 3, -2); - assertPrecisionEquals(conn, Query.Type.INT32, true, /* this can't happen, but just checking */3, -2); - assertPrecisionEquals(conn, Query.Type.INT32, true, 0, -1); - assertPrecisionEquals(conn, Query.Type.FLOAT32, false, 0, 0); - assertPrecisionEquals(conn, Query.Type.FLOAT64, false, 32, 0); - assertPrecisionEquals(conn, Query.Type.BIT, false, 0, 0); - assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 0, -1); - assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 3, -1); - assertPrecisionEquals(conn, Query.Type.UINT32, false, 0, 0); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (Query.Type type : Query.Type.values()) { - if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION) { - continue; - } - - // All should be 0 - assertPrecisionEquals(conn, type, true, 0, 0); - assertPrecisionEquals(conn, type, false, 0, 0); - assertPrecisionEquals(conn, type, true, 2, 0); - assertPrecisionEquals(conn, type, false, 2, 0); - } - } - - private void assertPrecisionEquals(VitessConnection conn, Query.Type fieldType, boolean signed, int decimals, int expectedPrecisionAdjustFactor) throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(fieldType) - .setDecimals(decimals) - .setFlags(signed ? 0 : Query.MySqlFlag.UNSIGNED_FLAG_VALUE) - .setName("foo") - .setOrgName("foo") - .build(); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(expectedPrecisionAdjustFactor, fieldWithMetadata.getPrecisionAdjustFactor()); - } - - @Test - public void testFlags() throws SQLException { - VitessConnection conn = getVitessConnection(); - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.VARBINARY) - .setName("foo") - .setOrgName("foo") - .build(); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); - Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); - Assert.assertEquals(false, fieldWithMetadata.isNotNull()); - Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); - Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); - Assert.assertEquals(false, fieldWithMetadata.isUnsigned()); - Assert.assertEquals(/* just inverses isUnsigned */true, fieldWithMetadata.isSigned()); - Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); - - int value = 0; - for (Query.MySqlFlag flag : Query.MySqlFlag.values()) { - if (flag == Query.MySqlFlag.UNRECOGNIZED) { - continue; - } - value |= flag.getNumber(); - } - raw = raw.toBuilder() - .setFlags(value) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isBinary()); - Assert.assertEquals(true, fieldWithMetadata.isBlob()); - Assert.assertEquals(true, fieldWithMetadata.isAutoIncrement()); - Assert.assertEquals(true, fieldWithMetadata.isMultipleKey()); - Assert.assertEquals(true, fieldWithMetadata.isNotNull()); - Assert.assertEquals(true, fieldWithMetadata.isPrimaryKey()); - Assert.assertEquals(true, fieldWithMetadata.isUniqueKey()); - Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); - Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); - Assert.assertEquals(true, fieldWithMetadata.isZeroFill()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); - Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); - Assert.assertEquals(true, fieldWithMetadata.isNotNull()); - Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); - Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); - Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); - Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); - Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); - - } - - @Test - public void testOpaqueBinary() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); - - raw = raw.toBuilder() - .setTable("#sql_foo_bar") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - - raw = raw.toBuilder() - .setCharset(/* short circuits collation -> encoding lookup, resulting in null */-1) - .build(); - - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - - conn.setEncoding("binary"); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - } - - @Test - public void testReadOnly() throws SQLException { - VitessConnection conn = getVitessConnection(); - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setOrgTable("foo") - .build(); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); - - raw = raw.toBuilder() - .setOrgName("") - .setOrgTable("foo") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); - - raw = raw.toBuilder() - .setOrgName("foo") - .setOrgTable("") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); - - raw = raw.toBuilder() - .setOrgTable("") - .setOrgName("") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); + raw = raw.toBuilder().setFlags(value).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isBinary()); + Assert.assertEquals(true, fieldWithMetadata.isBlob()); + Assert.assertEquals(true, fieldWithMetadata.isAutoIncrement()); + Assert.assertEquals(true, fieldWithMetadata.isMultipleKey()); + Assert.assertEquals(true, fieldWithMetadata.isNotNull()); + Assert.assertEquals(true, fieldWithMetadata.isPrimaryKey()); + Assert.assertEquals(true, fieldWithMetadata.isUniqueKey()); + Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); + Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); + Assert.assertEquals(true, fieldWithMetadata.isZeroFill()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); + Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); + Assert.assertEquals(true, fieldWithMetadata.isNotNull()); + Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); + Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); + Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); + Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); + Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); + + } + + @Test + public void testOpaqueBinary() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.CHAR).setName("foo").setOrgName("foo") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); + + raw = raw.toBuilder().setTable("#sql_foo_bar").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + + raw = raw.toBuilder() + .setCharset(/* short circuits collation -> encoding lookup, resulting in null */-1).build(); + + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + + conn.setEncoding("binary"); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + } + + @Test + public void testReadOnly() throws SQLException { + VitessConnection conn = getVitessConnection(); + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setOrgTable("foo").build(); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); + + raw = raw.toBuilder().setOrgName("").setOrgTable("foo").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); + + raw = raw.toBuilder().setOrgName("foo").setOrgTable("").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); + + raw = raw.toBuilder().setOrgTable("").setOrgName("").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); + } + + @Test + public void testDefaultsWithoutAllFields() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setName("foo").setOrgName("foo").setTable("foo") + .setOrgTable("foo").setDatabase("foo").setType(Query.Type.CHAR).setFlags( + Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | Query.MySqlFlag.PRI_KEY_FLAG_VALUE + | Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | Query.MySqlFlag.BINARY_FLAG_VALUE + | Query.MySqlFlag.BLOB_FLAG_VALUE | Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE + | Query.MySqlFlag.UNSIGNED_FLAG_VALUE | Query.MySqlFlag.ZEROFILL_FLAG_VALUE) + .build(); + VitessConnection conn = getVitessConnection(); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + FieldWithMetadata field = new FieldWithMetadata(conn, raw); + Assert.assertEquals("foo", field.getName()); + Assert.assertEquals(null, field.getOrgName()); + Assert.assertEquals(null, field.getTable()); + Assert.assertEquals(null, field.getOrgTable()); + Assert.assertEquals(null, field.getDatabase()); + Assert.assertEquals(0, field.getDecimals()); + Assert.assertEquals(0, field.getColumnLength()); + Assert.assertEquals(0, field.getPrecisionAdjustFactor()); + Assert.assertEquals(false, field.isSingleBit()); + Assert.assertEquals(false, field.isAutoIncrement()); + Assert.assertEquals(false, field.isBinary()); + Assert.assertEquals(false, field.isBlob()); + Assert.assertEquals(false, field.isMultipleKey()); + Assert.assertEquals(true, field.isNotNull()); + Assert.assertEquals(false, field.isZeroFill()); + Assert.assertEquals(false, field.isPrimaryKey()); + Assert.assertEquals(false, field.isUniqueKey()); + Assert.assertEquals(true, field.isUnsigned()); + Assert.assertEquals(false, field.isSigned()); + Assert.assertEquals(false, field.isOpaqueBinary()); + Assert.assertEquals(false, field.isReadOnly()); + } + + @Test + public void testToString() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setName("foo").setOrgName("foo").setTable("foo") + .setOrgTable("foo").setDatabase("foo").setType(Query.Type.CHAR).setFlags( + Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | Query.MySqlFlag.PRI_KEY_FLAG_VALUE + | Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | Query.MySqlFlag.BINARY_FLAG_VALUE + | Query.MySqlFlag.BLOB_FLAG_VALUE | Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE + | Query.MySqlFlag.UNSIGNED_FLAG_VALUE | Query.MySqlFlag.ZEROFILL_FLAG_VALUE) + .build(); + FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); + String result = + "io.vitess.jdbc.FieldWithMetadata[catalog=foo," + "tableName=foo,originalTableName=foo," + + "columnName=foo,originalColumnName=foo," + "vitessType=" + Query.Type.CHAR.toString() + + "(1)," + "flags=AUTO_INCREMENT PRIMARY_KEY UNIQUE_KEY BINARY " + + "BLOB MULTI_KEY UNSIGNED ZEROFILL, charsetIndex=0, charsetName=null]"; + Assert.assertEquals(result, field.toString()); + } + + public void testCollations() throws Exception { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + + FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + String first = fieldWithMetadata.getCollation(); + String second = fieldWithMetadata.getCollation(); + + Assert.assertEquals("utf8_general_ci", first); + Assert.assertEquals("cached response is same as first", first, second); + + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)) + .invoke("getCollationIndex"); + + try { + raw = raw.toBuilder() + // value chosen because it's obviously out of bounds for the underlying array + .setCharset(Integer.MAX_VALUE).build(); + + fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + fieldWithMetadata.getCollation(); + Assert.fail("Should have received an array index out of bounds because " + + "charset/collationIndex of Int.MAX is well above size of charset array"); + } catch (SQLException e) { + if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { + Assert.assertEquals("CollationIndex '" + Integer.MAX_VALUE + "' out of bounds for " + + "collationName lookup, should be within 0 and " + + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, e.getMessage()); + } else { + // just rethrow so we fail that way + throw e; + } } - @Test - public void testDefaultsWithoutAllFields() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setName("foo") - .setOrgName("foo") - .setTable("foo") - .setOrgTable("foo") - .setDatabase("foo") - .setType(Query.Type.CHAR) - .setFlags(Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | - Query.MySqlFlag.PRI_KEY_FLAG_VALUE | - Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | - Query.MySqlFlag.BINARY_FLAG_VALUE | - Query.MySqlFlag.BLOB_FLAG_VALUE | - Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE | - Query.MySqlFlag.UNSIGNED_FLAG_VALUE | - Query.MySqlFlag.ZEROFILL_FLAG_VALUE - ) - .build(); - VitessConnection conn = getVitessConnection(); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - FieldWithMetadata field = new FieldWithMetadata(conn, raw); - Assert.assertEquals("foo", field.getName()); - Assert.assertEquals(null, field.getOrgName()); - Assert.assertEquals(null, field.getTable()); - Assert.assertEquals(null, field.getOrgTable()); - Assert.assertEquals(null, field.getDatabase()); - Assert.assertEquals(0, field.getDecimals()); - Assert.assertEquals(0, field.getColumnLength()); - Assert.assertEquals(0, field.getPrecisionAdjustFactor()); - Assert.assertEquals(false, field.isSingleBit()); - Assert.assertEquals(false, field.isAutoIncrement()); - Assert.assertEquals(false, field.isBinary()); - Assert.assertEquals(false, field.isBlob()); - Assert.assertEquals(false, field.isMultipleKey()); - Assert.assertEquals(true, field.isNotNull()); - Assert.assertEquals(false, field.isZeroFill()); - Assert.assertEquals(false, field.isPrimaryKey()); - Assert.assertEquals(false, field.isUniqueKey()); - Assert.assertEquals(true, field.isUnsigned()); - Assert.assertEquals(false, field.isSigned()); - Assert.assertEquals(false, field.isOpaqueBinary()); - Assert.assertEquals(false, field.isReadOnly()); - } - - @Test - public void testToString() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setName("foo") - .setOrgName("foo") - .setTable("foo") - .setOrgTable("foo") - .setDatabase("foo") - .setType(Query.Type.CHAR) - .setFlags(Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | - Query.MySqlFlag.PRI_KEY_FLAG_VALUE | - Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | - Query.MySqlFlag.BINARY_FLAG_VALUE | - Query.MySqlFlag.BLOB_FLAG_VALUE | - Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE | - Query.MySqlFlag.UNSIGNED_FLAG_VALUE | - Query.MySqlFlag.ZEROFILL_FLAG_VALUE - ) - .build(); - FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); - String result = "io.vitess.jdbc.FieldWithMetadata[catalog=foo," + - "tableName=foo,originalTableName=foo," + - "columnName=foo,originalColumnName=foo," + - "vitessType=" + Query.Type.CHAR.toString() + "(1)," + - "flags=AUTO_INCREMENT PRIMARY_KEY UNIQUE_KEY BINARY " + - "BLOB MULTI_KEY UNSIGNED ZEROFILL, charsetIndex=0, charsetName=null]"; - Assert.assertEquals(result, field.toString()); - } - - public void testCollations() throws Exception { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - - FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - String first = fieldWithMetadata.getCollation(); - String second = fieldWithMetadata.getCollation(); - - Assert.assertEquals("utf8_general_ci", first); - Assert.assertEquals("cached response is same as first", first, second); - - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)).invoke("getCollationIndex"); - - try { - raw = raw.toBuilder() - // value chosen because it's obviously out of bounds for the underlying array - .setCharset(Integer.MAX_VALUE) - .build(); - - fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - fieldWithMetadata.getCollation(); - Assert.fail("Should have received an array index out of bounds because " + - "charset/collationIndex of Int.MAX is well above size of charset array"); - } catch (SQLException e) { - if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { - Assert.assertEquals("CollationIndex '" + Integer.MAX_VALUE + "' out of bounds for " + - "collationName lookup, should be within 0 and " + - CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, - e.getMessage()); - } else { - // just rethrow so we fail that way - throw e; - } - } - - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)).invoke("getCollationIndex"); - //Mockito.verify(fieldWithMetadata, Mockito.times(1)).getCollationIndex(); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - Assert.assertEquals("null response when not including all fields", null, fieldWithMetadata.getCollation()); - - // We should not call this at all, because we're short circuiting due to included fields - //Mockito.verify(fieldWithMetadata, Mockito.never()).getCollationIndex(); - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)).invoke("getCollationIndex"); - } - - @Test - public void testMaxBytesPerChar() throws Exception { - VitessConnection conn = PowerMockito.spy(getVitessConnection()); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - - FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - - int first = fieldWithMetadata.getMaxBytesPerCharacter(); - int second = fieldWithMetadata.getMaxBytesPerCharacter(); - - Assert.assertEquals("cached response is same as first", first, second); - // We called getMaxBytesPerCharacter 2 times above, but should only have made 1 call to fieldWithMetadata.getMaxBytesPerChar: - // first - call conn - // second - return cached - Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(1)).getMaxBytesPerChar(33, "UTF-8"); - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)).invoke("getCollationIndex"); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - Assert.assertEquals("0 return value when not including all fields", 0, fieldWithMetadata.getMaxBytesPerCharacter()); - - // We should not call this function because we short circuited due to not including all fields. - Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(0)).getMaxBytesPerChar(33, "UTF-8"); - // Should not be called at all, because it's new for just this test - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)).invoke("getCollationIndex"); - } - - @Test public void testGetEncodingForIndex() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); - - // No default encoding configured, and passing NO_CHARSET_INFO basically says "mysql doesn't know" - // which means don't try looking it up - Assert.assertEquals(null, field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); - // Similarly, a null index or one landing out of bounds for the charset index should return null - Assert.assertEquals(null, field.getEncodingForIndex(Integer.MAX_VALUE)); - Assert.assertEquals(null, field.getEncodingForIndex(-123)); - - // charsetIndex 25 is MYSQL_CHARSET_NAME_greek, which is a charset with multiple names, ISO8859_7 and greek - // Without an encoding configured in the connection, we should return the first (default) encoding for a charset, - // in this case ISO8859_7 - Assert.assertEquals("ISO-8859-7", field.getEncodingForIndex(25)); - field.getConnectionProperties().setEncoding("greek"); - // With an encoding configured, we should return that because it matches one of the names for the charset - Assert.assertEquals("greek", field.getEncodingForIndex(25)); - - field.getConnectionProperties().setEncoding(null); - Assert.assertEquals("UTF-8", field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_utf8)); - Assert.assertEquals("ISO-8859-1", field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_binary)); - - field.getConnectionProperties().setEncoding("NOT_REAL"); - // Same tests as the first one, but testing that when there is a default configured, it falls back to that regardless - Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); - Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(Integer.MAX_VALUE)); - Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(-123)); - } - - @Test public void testGetMaxBytesPerChar() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); - - // Default state when no good info is passed in - Assert.assertEquals(0, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, null)); - // use passed collation index - Assert.assertEquals(3, field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, null)); - // use first, if both are passed and valid - Assert.assertEquals(3, field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, "UnicodeBig")); - // use passed default charset - Assert.assertEquals(2, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, "UnicodeBig")); - } + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)) + .invoke("getCollationIndex"); + //Mockito.verify(fieldWithMetadata, Mockito.times(1)).getCollationIndex(); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + Assert.assertEquals("null response when not including all fields", null, + fieldWithMetadata.getCollation()); + + // We should not call this at all, because we're short circuiting due to included fields + //Mockito.verify(fieldWithMetadata, Mockito.never()).getCollationIndex(); + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)) + .invoke("getCollationIndex"); + } + + @Test + public void testMaxBytesPerChar() throws Exception { + VitessConnection conn = PowerMockito.spy(getVitessConnection()); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + + FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + + int first = fieldWithMetadata.getMaxBytesPerCharacter(); + int second = fieldWithMetadata.getMaxBytesPerCharacter(); + + Assert.assertEquals("cached response is same as first", first, second); + // We called getMaxBytesPerCharacter 2 times above, but should only have made 1 call to + // fieldWithMetadata.getMaxBytesPerChar: + // first - call conn + // second - return cached + Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(1)) + .getMaxBytesPerChar(33, "UTF-8"); + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)) + .invoke("getCollationIndex"); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + Assert.assertEquals("0 return value when not including all fields", 0, + fieldWithMetadata.getMaxBytesPerCharacter()); + + // We should not call this function because we short circuited due to not including all fields. + Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(0)) + .getMaxBytesPerChar(33, "UTF-8"); + // Should not be called at all, because it's new for just this test + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)) + .invoke("getCollationIndex"); + } + + @Test + public void testGetEncodingForIndex() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); + + // No default encoding configured, and passing NO_CHARSET_INFO basically says "mysql doesn't + // know" + // which means don't try looking it up + Assert.assertEquals(null, field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); + // Similarly, a null index or one landing out of bounds for the charset index should return null + Assert.assertEquals(null, field.getEncodingForIndex(Integer.MAX_VALUE)); + Assert.assertEquals(null, field.getEncodingForIndex(-123)); + + // charsetIndex 25 is MYSQL_CHARSET_NAME_greek, which is a charset with multiple names, + // ISO8859_7 and greek + // Without an encoding configured in the connection, we should return the first (default) + // encoding for a charset, + // in this case ISO8859_7 + Assert.assertEquals("ISO-8859-7", field.getEncodingForIndex(25)); + field.getConnectionProperties().setEncoding("greek"); + // With an encoding configured, we should return that because it matches one of the names for + // the charset + Assert.assertEquals("greek", field.getEncodingForIndex(25)); + + field.getConnectionProperties().setEncoding(null); + Assert.assertEquals("UTF-8", + field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_utf8)); + Assert.assertEquals("ISO-8859-1", + field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_binary)); + + field.getConnectionProperties().setEncoding("NOT_REAL"); + // Same tests as the first one, but testing that when there is a default configured, it falls + // back to that regardless + Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); + Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(Integer.MAX_VALUE)); + Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(-123)); + } + + @Test + public void testGetMaxBytesPerChar() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); + + // Default state when no good info is passed in + Assert.assertEquals(0, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, null)); + // use passed collation index + Assert + .assertEquals(3, field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, null)); + // use first, if both are passed and valid + Assert.assertEquals(3, + field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, "UnicodeBig")); + // use passed default charset + Assert.assertEquals(2, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, "UnicodeBig")); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java index 64df7a23a58..73d312521ff 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java @@ -16,11 +16,15 @@ package io.vitess.jdbc; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.modules.junit4.PowerMockRunner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import io.vitess.client.VTSession; import io.vitess.proto.Query; @@ -35,15 +39,11 @@ import java.sql.Statement; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 19/01/16. @@ -51,220 +51,228 @@ @RunWith(PowerMockRunner.class) public class VitessConnectionTest extends BaseTest { - @Test - public void testVitessConnection() throws SQLException { - VitessConnection vitessConnection = new VitessConnection(dbURL, new Properties()); - assertFalse(vitessConnection.isClosed()); - assertNull(vitessConnection.getDbProperties()); - } - - @Test - public void testCreateStatement() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - Statement statement = vitessConnection.createStatement(); - assertEquals(vitessConnection, statement.getConnection()); - } - - @Test - public void testCreateStatementForClose() - throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, vitessConnection::createStatement); - } - - @Test - public void testnativeSQL() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertEquals("query", vitessConnection.nativeSQL("query")); - } - - @Test - public void testCreatePreperedStatement() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - PreparedStatement preparedStatementstatement = vitessConnection.prepareStatement("query"); - assertEquals(vitessConnection, preparedStatementstatement.getConnection()); - } - - @Test - public void testCreatePreparedStatementForClose() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, () -> vitessConnection.prepareStatement("query")); - } - - @Test - public void testDefaultGetAutoCommit() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertTrue(vitessConnection.getAutoCommit()); - } - - @Test - public void testDefaultGetAutoCommitForClose() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, vitessConnection::getAutoCommit); + @Test + public void testVitessConnection() throws SQLException { + VitessConnection vitessConnection = new VitessConnection(dbURL, new Properties()); + assertFalse(vitessConnection.isClosed()); + assertNull(vitessConnection.getDbProperties()); + } + + @Test + public void testCreateStatement() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + Statement statement = vitessConnection.createStatement(); + assertEquals(vitessConnection, statement.getConnection()); + } + + @Test + public void testCreateStatementForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, vitessConnection::createStatement); + } + + @Test + public void testnativeSQL() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertEquals("query", vitessConnection.nativeSQL("query")); + } + + @Test + public void testCreatePreperedStatement() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + PreparedStatement preparedStatementstatement = vitessConnection.prepareStatement("query"); + assertEquals(vitessConnection, preparedStatementstatement.getConnection()); + } + + @Test + public void testCreatePreparedStatementForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, + () -> vitessConnection.prepareStatement("query")); + } + + @Test + public void testDefaultGetAutoCommit() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertTrue(vitessConnection.getAutoCommit()); + } + + @Test + public void testDefaultGetAutoCommitForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, vitessConnection::getAutoCommit); + } + + @Test + public void testDefaultSetAutoCommit() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(false); + assertFalse(vitessConnection.getAutoCommit()); + } + + @Test + public void testDefaultSetAutoCommitForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, () -> vitessConnection.setAutoCommit(false)); + } + + @Test + public void testCommit() throws Exception { + VTSession mockSession = PowerMockito.mock(VTSession.class); + VitessConnection vitessConnection = getVitessConnection(); + Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); + privateVTSessionField.setAccessible(true); + privateVTSessionField.set(vitessConnection, mockSession); + PowerMockito.when(mockSession.isInTransaction()).thenReturn(false); + PowerMockito.when(mockSession.isAutoCommit()).thenReturn(false); + vitessConnection.commit(); + } + + @Test(expected = SQLException.class) + public void testCommitForException() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(true); + vitessConnection.commit(); + } + + @Test + public void testRollback() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(false); + vitessConnection.rollback(); + } + + @Test(expected = SQLException.class) + public void testRollbackForException() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(true); + vitessConnection.rollback(); + } + + @Test + public void testClosed() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(false); + vitessConnection.close(); + assertTrue(vitessConnection.isClosed()); + } + + @Test(expected = SQLException.class) + public void testClosedForException() throws Exception { + VTSession mockSession = PowerMockito.mock(VTSession.class); + VitessConnection vitessConnection = getVitessConnection(); + Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); + privateVTSessionField.setAccessible(true); + privateVTSessionField.set(vitessConnection, mockSession); + PowerMockito.when(mockSession.isInTransaction()).thenReturn(true); + PowerMockito.when(mockSession.isAutoCommit()).thenReturn(true); + vitessConnection.close(); + } + + @Test + public void testGetCatalog() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertEquals("keyspace", vitessConnection.getCatalog()); + } + + @Test + public void testSetCatalog() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setCatalog("myDB"); + assertEquals("myDB", vitessConnection.getCatalog()); + } + + @Test + public void testPropertiesFromJdbcUrl() throws SQLException { + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica" + + "&includedFields=type_and_name&blobsAreStrings=yes"; + VitessConnection conn = new VitessConnection(url, new Properties()); + + // Properties from the url should be passed into the connection properties, and override + // whatever defaults we've defined + assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, conn.getIncludedFields()); + assertFalse(conn.isIncludeAllFields()); + assertEquals(Topodata.TabletType.REPLICA, conn.getTabletType()); + assertTrue(conn.getBlobsAreStrings()); + } + + @Test + public void testClientFoundRows() throws SQLException { + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica" + + "&useAffectedRows=true"; + VitessConnection conn = new VitessConnection(url, new Properties()); + + assertTrue(conn.getUseAffectedRows()); + assertFalse(conn.getVtSession().getSession().getOptions().getClientFoundRows()); + } + + @Test + public void testClientFoundRows2() throws SQLException { + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica" + + "&useAffectedRows=false"; + VitessConnection conn = new VitessConnection(url, new Properties()); + + assertFalse(conn.getUseAffectedRows()); + assertTrue(conn.getVtSession().getSession().getOptions().getClientFoundRows()); + } + + @Test + public void testWorkload() throws SQLException { + for (Query.ExecuteOptions.Workload workload : Query.ExecuteOptions.Workload.values()) { + if (workload == Query.ExecuteOptions.Workload.UNRECOGNIZED) { + continue; + } + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&workload=" + + workload.toString().toLowerCase(); + VitessConnection conn = new VitessConnection(url, new Properties()); + + assertEquals(workload, conn.getWorkload()); + assertEquals(workload, conn.getVtSession().getSession().getOptions().getWorkload()); } - - @Test - public void testDefaultSetAutoCommit() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(false); - assertFalse(vitessConnection.getAutoCommit()); - } - - @Test - public void testDefaultSetAutoCommitForClose() - throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, () -> vitessConnection.setAutoCommit(false)); - } - - @Test - public void testCommit() throws Exception { - VTSession mockSession = PowerMockito.mock(VTSession.class); - VitessConnection vitessConnection = getVitessConnection(); - Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); - privateVTSessionField.setAccessible(true); - privateVTSessionField.set(vitessConnection, mockSession); - PowerMockito.when(mockSession.isInTransaction()).thenReturn(false); - PowerMockito.when(mockSession.isAutoCommit()).thenReturn(false); - vitessConnection.commit(); - } - - @Test(expected = SQLException.class) - public void testCommitForException() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(true); - vitessConnection.commit(); - } - - @Test - public void testRollback() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(false); - vitessConnection.rollback(); - } - - @Test(expected = SQLException.class) - public void testRollbackForException() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(true); - vitessConnection.rollback(); - } - - @Test - public void testClosed() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(false); - vitessConnection.close(); - assertTrue(vitessConnection.isClosed()); - } - - @Test(expected = SQLException.class) - public void testClosedForException() throws Exception { - VTSession mockSession = PowerMockito.mock(VTSession.class); - VitessConnection vitessConnection = getVitessConnection(); - Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); - privateVTSessionField.setAccessible(true); - privateVTSessionField.set(vitessConnection, mockSession); - PowerMockito.when(mockSession.isInTransaction()).thenReturn(true); - PowerMockito.when(mockSession.isAutoCommit()).thenReturn(true); - vitessConnection.close(); - } - - @Test - public void testGetCatalog() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertEquals("keyspace", vitessConnection.getCatalog()); - } - - @Test - public void testSetCatalog() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setCatalog("myDB"); - assertEquals("myDB", vitessConnection.getCatalog()); - } - - @Test - public void testPropertiesFromJdbcUrl() throws SQLException { - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&includedFields=type_and_name&blobsAreStrings=yes"; - VitessConnection conn = new VitessConnection(url, new Properties()); - - // Properties from the url should be passed into the connection properties, and override whatever defaults we've defined - assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, conn.getIncludedFields()); - assertFalse(conn.isIncludeAllFields()); - assertEquals(Topodata.TabletType.REPLICA, conn.getTabletType()); - assertTrue(conn.getBlobsAreStrings()); - } - - @Test - public void testClientFoundRows() throws SQLException { - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&useAffectedRows=true"; - VitessConnection conn = new VitessConnection(url, new Properties()); - - assertTrue(conn.getUseAffectedRows()); - assertFalse(conn.getVtSession().getSession().getOptions().getClientFoundRows()); - } - - @Test - public void testClientFoundRows2() throws SQLException { - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&useAffectedRows=false"; - VitessConnection conn = new VitessConnection(url, new Properties()); - - assertFalse(conn.getUseAffectedRows()); - assertTrue(conn.getVtSession().getSession().getOptions().getClientFoundRows()); - } - - @Test - public void testWorkload() throws SQLException { - for (Query.ExecuteOptions.Workload workload : Query.ExecuteOptions.Workload.values()) { - if (workload == Query.ExecuteOptions.Workload.UNRECOGNIZED) { - continue; - } - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&workload=" + workload.toString().toLowerCase(); - VitessConnection conn = new VitessConnection(url, new Properties()); - - assertEquals(workload, conn.getWorkload()); - assertEquals(workload, conn.getVtSession().getSession().getOptions().getWorkload()); - } - } - - @Test - public void testTransactionIsolation() throws SQLException { - VitessConnection conn = Mockito.spy(getVitessConnection()); - doReturn(new DBProperties("random", "random", "random", Connection.TRANSACTION_REPEATABLE_READ, "random")) - .when(conn) - .getDbProperties(); - doReturn(new VitessMySQLDatabaseMetadata(conn)).when(conn).getMetaData(); - - assertEquals(TransactionIsolation.DEFAULT, conn.getVtSession().getSession().getOptions().getTransactionIsolation()); - assertEquals(Connection.TRANSACTION_REPEATABLE_READ, conn.getTransactionIsolation()); - - conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); - - assertEquals(TransactionIsolation.READ_COMMITTED, conn.getVtSession().getSession().getOptions().getTransactionIsolation()); - assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); - - VitessStatement statement = mock(VitessStatement.class); - when(conn.createStatement()).thenReturn(statement); - when(conn.isInTransaction()).thenReturn(true); - conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); - - verify(statement).executeUpdate("rollback"); - assertEquals(TransactionIsolation.READ_UNCOMMITTED, conn.getVtSession().getSession().getOptions().getTransactionIsolation()); - assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn.getTransactionIsolation()); - } - - interface Runthis { - void run() throws SQLException; - } - - private void assertFailsOnClosedConnection(VitessConnection connection, Runthis failingRunnable) throws SQLException { - connection.close(); - try { - failingRunnable.run(); - fail("expected this to fail on a closed connection"); - } catch (SQLException e) { - assertEquals(e.getMessage(), Constants.SQLExceptionMessages.CONN_CLOSED); - } + } + + @Test + public void testTransactionIsolation() throws SQLException { + VitessConnection conn = Mockito.spy(getVitessConnection()); + doReturn(new DBProperties("random", "random", "random", Connection.TRANSACTION_REPEATABLE_READ, + "random")).when(conn).getDbProperties(); + doReturn(new VitessMySQLDatabaseMetadata(conn)).when(conn).getMetaData(); + + assertEquals(TransactionIsolation.DEFAULT, + conn.getVtSession().getSession().getOptions().getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_REPEATABLE_READ, conn.getTransactionIsolation()); + + conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + + assertEquals(TransactionIsolation.READ_COMMITTED, + conn.getVtSession().getSession().getOptions().getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); + + VitessStatement statement = mock(VitessStatement.class); + when(conn.createStatement()).thenReturn(statement); + when(conn.isInTransaction()).thenReturn(true); + conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); + + verify(statement).executeUpdate("rollback"); + assertEquals(TransactionIsolation.READ_UNCOMMITTED, + conn.getVtSession().getSession().getOptions().getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn.getTransactionIsolation()); + } + + interface Runthis { + + void run() throws SQLException; + } + + private void assertFailsOnClosedConnection(VitessConnection connection, Runthis failingRunnable) + throws SQLException { + connection.close(); + try { + failingRunnable.run(); + fail("expected this to fail on a closed connection"); + } catch (SQLException e) { + assertEquals(e.getMessage(), Constants.SQLExceptionMessages.CONN_CLOSED); } + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java index d930e08d3a7..9da77d6f039 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java @@ -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,12 +19,6 @@ import com.google.common.base.Charsets; import com.google.common.io.CharStreams; import com.google.protobuf.ByteString; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.SimpleCursor; @@ -44,1082 +38,1181 @@ import java.util.Properties; import java.util.Scanner; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + /** * Created by ashudeep.sharma on 08/03/16. */ -@RunWith(PowerMockRunner.class) @PrepareForTest({VitessMySQLDatabaseMetadata.class, VitessConnection.class}) public class VitessDatabaseMetadataTest extends BaseTest { - - private ResultSet resultSet; - - @Test public void getPseudoColumnsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getPseudoColumns(null, null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("COLUMN_NAME", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("COLUMN_SIZE", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(7)); - Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(8)); - Assert.assertEquals("COLUMN_USAGE", resultSetMetaData.getColumnName(9)); - Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(10)); - Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(11)); - Assert.assertEquals("IS_NULLABLE", resultSetMetaData.getColumnName(12)); - } - - @Test public void getClientInfoPropertiesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getClientInfoProperties(); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("NAME", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("MAX_LEN", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("DEFAULT_VALUE", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("DESCRIPTION", resultSetMetaData.getColumnName(4)); - } - - @Test public void getSchemasTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSchemas(null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); - } - - @Test public void getAttributesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getAttributes(null, null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("ATTR_NAME", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("ATTR_TYPE_NAME", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("ATTR_SIZE", resultSetMetaData.getColumnName(7)); - Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(8)); - Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(9)); - Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(10)); - Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(11)); - Assert.assertEquals("ATTR_DEF", resultSetMetaData.getColumnName(12)); - Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(13)); - Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(14)); - Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(15)); - Assert.assertEquals("ORDINAL_POSITION", resultSetMetaData.getColumnName(16)); - Assert.assertEquals("ISNULLABLE", resultSetMetaData.getColumnName(17)); - Assert.assertEquals("SCOPE_CATALOG", resultSetMetaData.getColumnName(18)); - Assert.assertEquals("SCOPE_SCHEMA", resultSetMetaData.getColumnName(19)); - Assert.assertEquals("SCOPE_TABLE", resultSetMetaData.getColumnName(20)); - Assert.assertEquals("SOURCE_DATA_TYPE", resultSetMetaData.getColumnName(21)); - } - - @Test public void getSuperTablesTest() throws SQLException { - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSuperTables(null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("SUPERTABLE_NAME", resultSetMetaData.getColumnName(4)); - } - - @Test public void getSuperTypesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSuperTypes(null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("SUPERTYPE_CAT", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("SUPERTYPE_SCHEM", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("SUPERTYPE_NAME", resultSetMetaData.getColumnName(6)); - } - - @Test public void getUDTsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getUDTs(null, null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("CLASS_NAME", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("BASE_TYPE", resultSetMetaData.getColumnName(7)); - } - - @Test public void getTypeInfoTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getTypeInfo(); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("PRECISION", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("LITERAL_PREFIX", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("LITERAL_SUFFIX", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("CREATE_PARAMS", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(7)); - Assert.assertEquals("CASE_SENSITIVE", resultSetMetaData.getColumnName(8)); - Assert.assertEquals("SEARCHABLE", resultSetMetaData.getColumnName(9)); - Assert.assertEquals("UNSIGNED_ATTRIBUTE", resultSetMetaData.getColumnName(10)); - Assert.assertEquals("FIXED_PREC_SCALE", resultSetMetaData.getColumnName(11)); - Assert.assertEquals("AUTO_INCREMENT", resultSetMetaData.getColumnName(12)); - Assert.assertEquals("LOCAL_TYPE_NAME", resultSetMetaData.getColumnName(13)); - Assert.assertEquals("MINIMUM_SCALE", resultSetMetaData.getColumnName(14)); - Assert.assertEquals("MAXIMUM_SCALE", resultSetMetaData.getColumnName(15)); - Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(16)); - Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(17)); - Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(18)); - - //Check for ResultSet Data as well - } - - @Test public void getTableTypesTest() throws SQLException { - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getTableTypes(); - - ArrayList data = new ArrayList(); - while (resultSet.next()) { - data.add(resultSet.getString("table_type")); - } - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("table_type", resultSetMetaData.getColumnName(1)); - //Checking Data - Assert.assertEquals("LOCAL TEMPORARY", data.get(0)); - Assert.assertEquals("SYSTEM TABLES", data.get(1)); - Assert.assertEquals("SYSTEM VIEW", data.get(2)); - Assert.assertEquals("TABLE", data.get(3)); - Assert.assertEquals("VIEW", data.get(4)); - } - - @Test public void getSchemasTest2() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSchemas(); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); - } - - @Test public void allProceduresAreCallableTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.allProceduresAreCallable()); - } - - @Test public void allTablesAreSelectableTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.allTablesAreSelectable()); - } - - @Test public void nullsAreSortedHighTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.nullsAreSortedHigh()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedHigh()); - } - - @Test public void nullsAreSortedLowTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.nullsAreSortedLow()); - Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedLow()); - } - - @Test public void nullsAreSortedAtStartTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtStart()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedAtStart()); - } - - @Test public void nullsAreSortedAtEndTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtEnd()); - Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedAtEnd()); - } - - @Test public void getDatabaseProductNameTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("MySQL", vitessDatabaseMetaData.getDatabaseProductName()); - } - - @Test public void getDriverVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - StringBuilder driverVersionBuilder = new StringBuilder(); - driverVersionBuilder.append(Constants.DRIVER_MAJOR_VERSION); - driverVersionBuilder.append("."); - driverVersionBuilder.append(Constants.DRIVER_MINOR_VERSION); - Assert.assertEquals(driverVersionBuilder.toString(), - vitessDatabaseMetaData.getDriverVersion()); - } - - @Test public void getDriverMajorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(Constants.DRIVER_MAJOR_VERSION, - vitessDatabaseMetaData.getDriverMajorVersion()); - } - - @Test public void getDriverMinorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(Constants.DRIVER_MINOR_VERSION, - vitessDatabaseMetaData.getDriverMinorVersion()); - } - - @Test public void getSearchStringEscapeTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("\\", vitessDatabaseMetaData.getSearchStringEscape()); - } - - @Test public void getExtraNameCharactersTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("#@", vitessDatabaseMetaData.getExtraNameCharacters()); - } - - @Test public void supportsAlterTableWithAddColumnTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithAddColumn()); - } - - @Test public void supportsAlterTableWithDropColumnTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithDropColumn()); - } - - @Test public void supportsColumnAliasingTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsColumnAliasing()); - } - - @Test public void nullPlusNonNullIsNullTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.nullPlusNonNullIsNull()); - } - - @Test public void supportsExpressionsInOrderByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsExpressionsInOrderBy()); - } - - @Test public void supportsOrderByUnrelatedTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOrderByUnrelated()); - } - - @Test public void supportsGroupByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupBy()); - } - - @Test public void supportsGroupByUnrelatedTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByUnrelated()); - } - - @Test public void supportsGroupByBeyondSelectTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByBeyondSelect()); - } - - @Test public void supportsLikeEscapeClauseTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsLikeEscapeClause()); - } - - @Test public void supportsMultipleResultSetsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsMultipleResultSets()); - } - - @Test public void supportsMultipleTransactionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsMultipleTransactions()); - } - - @Test public void supportsNonNullableColumnsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsNonNullableColumns()); - } - - @Test public void supportsMinimumSQLGrammarTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsMinimumSQLGrammar()); - } - - @Test public void supportsCoreSQLGrammarTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsCoreSQLGrammar()); - } - - @Test public void supportsExtendedSQLGrammarTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsExtendedSQLGrammar()); - } - - @Test public void supportsOuterJoinsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOuterJoins()); - } - - @Test public void supportsFullOuterJoinsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsFullOuterJoins()); - } - - @Test public void supportsLimitedOuterJoinsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsLimitedOuterJoins()); - } - - @Test public void getSchemaTermTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("", vitessDatabaseMetaData.getSchemaTerm()); - } - - @Test public void getProcedureTermTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("procedure", vitessDatabaseMetaData.getProcedureTerm()); - } +@RunWith(PowerMockRunner.class) +@PrepareForTest({VitessMySQLDatabaseMetadata.class, VitessConnection.class}) +public class VitessDatabaseMetadataTest extends BaseTest { + + private ResultSet resultSet; + + @Test + public void getPseudoColumnsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getPseudoColumns(null, null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("COLUMN_NAME", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("COLUMN_SIZE", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(7)); + Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(8)); + Assert.assertEquals("COLUMN_USAGE", resultSetMetaData.getColumnName(9)); + Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(10)); + Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(11)); + Assert.assertEquals("IS_NULLABLE", resultSetMetaData.getColumnName(12)); + } + + @Test + public void getClientInfoPropertiesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getClientInfoProperties(); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("NAME", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("MAX_LEN", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("DEFAULT_VALUE", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("DESCRIPTION", resultSetMetaData.getColumnName(4)); + } + + @Test + public void getSchemasTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSchemas(null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); + } + + @Test + public void getAttributesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getAttributes(null, null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("ATTR_NAME", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("ATTR_TYPE_NAME", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("ATTR_SIZE", resultSetMetaData.getColumnName(7)); + Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(8)); + Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(9)); + Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(10)); + Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(11)); + Assert.assertEquals("ATTR_DEF", resultSetMetaData.getColumnName(12)); + Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(13)); + Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(14)); + Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(15)); + Assert.assertEquals("ORDINAL_POSITION", resultSetMetaData.getColumnName(16)); + Assert.assertEquals("ISNULLABLE", resultSetMetaData.getColumnName(17)); + Assert.assertEquals("SCOPE_CATALOG", resultSetMetaData.getColumnName(18)); + Assert.assertEquals("SCOPE_SCHEMA", resultSetMetaData.getColumnName(19)); + Assert.assertEquals("SCOPE_TABLE", resultSetMetaData.getColumnName(20)); + Assert.assertEquals("SOURCE_DATA_TYPE", resultSetMetaData.getColumnName(21)); + } + + @Test + public void getSuperTablesTest() throws SQLException { + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSuperTables(null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("SUPERTABLE_NAME", resultSetMetaData.getColumnName(4)); + } + + @Test + public void getSuperTypesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSuperTypes(null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("SUPERTYPE_CAT", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("SUPERTYPE_SCHEM", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("SUPERTYPE_NAME", resultSetMetaData.getColumnName(6)); + } + + @Test + public void getUDTsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getUDTs(null, null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("CLASS_NAME", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("BASE_TYPE", resultSetMetaData.getColumnName(7)); + } + + @Test + public void getTypeInfoTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getTypeInfo(); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("PRECISION", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("LITERAL_PREFIX", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("LITERAL_SUFFIX", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("CREATE_PARAMS", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(7)); + Assert.assertEquals("CASE_SENSITIVE", resultSetMetaData.getColumnName(8)); + Assert.assertEquals("SEARCHABLE", resultSetMetaData.getColumnName(9)); + Assert.assertEquals("UNSIGNED_ATTRIBUTE", resultSetMetaData.getColumnName(10)); + Assert.assertEquals("FIXED_PREC_SCALE", resultSetMetaData.getColumnName(11)); + Assert.assertEquals("AUTO_INCREMENT", resultSetMetaData.getColumnName(12)); + Assert.assertEquals("LOCAL_TYPE_NAME", resultSetMetaData.getColumnName(13)); + Assert.assertEquals("MINIMUM_SCALE", resultSetMetaData.getColumnName(14)); + Assert.assertEquals("MAXIMUM_SCALE", resultSetMetaData.getColumnName(15)); + Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(16)); + Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(17)); + Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(18)); + + //Check for ResultSet Data as well + } + + @Test + public void getTableTypesTest() throws SQLException { + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getTableTypes(); + + ArrayList data = new ArrayList(); + while (resultSet.next()) { + data.add(resultSet.getString("table_type")); + } + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("table_type", resultSetMetaData.getColumnName(1)); + //Checking Data + Assert.assertEquals("LOCAL TEMPORARY", data.get(0)); + Assert.assertEquals("SYSTEM TABLES", data.get(1)); + Assert.assertEquals("SYSTEM VIEW", data.get(2)); + Assert.assertEquals("TABLE", data.get(3)); + Assert.assertEquals("VIEW", data.get(4)); + } + + @Test + public void getSchemasTest2() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSchemas(); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); + } + + @Test + public void allProceduresAreCallableTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.allProceduresAreCallable()); + } + + @Test + public void allTablesAreSelectableTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.allTablesAreSelectable()); + } + + @Test + public void nullsAreSortedHighTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.nullsAreSortedHigh()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedHigh()); + } + + @Test + public void nullsAreSortedLowTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(true, vitessDatabaseMetaData.nullsAreSortedLow()); + Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedLow()); + } + + @Test + public void nullsAreSortedAtStartTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtStart()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedAtStart()); + } + + @Test + public void nullsAreSortedAtEndTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtEnd()); + Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedAtEnd()); + } + + @Test + public void getDatabaseProductNameTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals("MySQL", vitessDatabaseMetaData.getDatabaseProductName()); + } + + @Test + public void getDriverVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + StringBuilder driverVersionBuilder = new StringBuilder(); + driverVersionBuilder.append(Constants.DRIVER_MAJOR_VERSION); + driverVersionBuilder.append("."); + driverVersionBuilder.append(Constants.DRIVER_MINOR_VERSION); + Assert.assertEquals(driverVersionBuilder.toString(), vitessDatabaseMetaData.getDriverVersion()); + } - @Test public void getCatalogTermTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getDriverMajorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals("database", vitessDatabaseMetaData.getCatalogTerm()); - } + Assert.assertEquals(Constants.DRIVER_MAJOR_VERSION, + vitessDatabaseMetaData.getDriverMajorVersion()); + } - @Test public void isCatalogAtStartTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getDriverMinorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(true, vitessDatabaseMetaData.isCatalogAtStart()); - } + Assert.assertEquals(Constants.DRIVER_MINOR_VERSION, + vitessDatabaseMetaData.getDriverMinorVersion()); + } - @Test public void getCatalogSeparatorTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getSearchStringEscapeTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(".", vitessDatabaseMetaData.getCatalogSeparator()); - } + Assert.assertEquals("\\", vitessDatabaseMetaData.getSearchStringEscape()); + } - @Test public void supportsSchemasInDataManipulationTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getExtraNameCharactersTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInDataManipulation()); - } + Assert.assertEquals("#@", vitessDatabaseMetaData.getExtraNameCharacters()); + } - @Test public void supportsSchemasInProcedureCallsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsAlterTableWithAddColumnTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInProcedureCalls()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithAddColumn()); + } - @Test public void supportsSchemasInTableDefinitionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsAlterTableWithDropColumnTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInTableDefinitions()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithDropColumn()); + } - @Test public void supportsSchemasInIndexDefinitionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsColumnAliasingTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInIndexDefinitions()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsColumnAliasing()); + } - @Test public void supportsSelectForUpdateTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void nullPlusNonNullIsNullTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSelectForUpdate()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.nullPlusNonNullIsNull()); + } - @Test public void supportsStoredProceduresTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsExpressionsInOrderByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsStoredProcedures()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsExpressionsInOrderBy()); + } - @Test public void supportsSubqueriesInComparisonsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsOrderByUnrelatedTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInComparisons()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOrderByUnrelated()); + } - @Test public void supportsSubqueriesInExistsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsGroupByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInExists()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupBy()); + } - @Test public void supportsSubqueriesInInsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsGroupByUnrelatedTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInIns()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByUnrelated()); + } - @Test public void supportsSubqueriesInQuantifiedsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsGroupByBeyondSelectTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInQuantifieds()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByBeyondSelect()); + } - @Test public void supportsCorrelatedSubqueriesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsLikeEscapeClauseTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsCorrelatedSubqueries()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsLikeEscapeClause()); + } - @Test public void supportsUnionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsMultipleResultSetsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnion()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsMultipleResultSets()); + } - @Test public void supportsUnionAllTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsMultipleTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnionAll()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsMultipleTransactions()); + } - @Test public void supportsOpenCursorsAcrossRollbackTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsNonNullableColumnsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossRollback()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsNonNullableColumns()); + } - @Test public void supportsOpenStatementsAcrossCommitTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsMinimumSQLGrammarTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossCommit()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsMinimumSQLGrammar()); + } - @Test public void supportsOpenStatementsAcrossRollbackTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsCoreSQLGrammarTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossRollback()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsCoreSQLGrammar()); + } - @Test public void supportsOpenCursorsAcrossCommitTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsExtendedSQLGrammarTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossCommit()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsExtendedSQLGrammar()); + } - @Test public void getMaxBinaryLiteralLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsOuterJoinsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxBinaryLiteralLength()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOuterJoins()); + } - @Test public void getMaxCharLiteralLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsFullOuterJoinsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxCharLiteralLength()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsFullOuterJoins()); + } - @Test public void getMaxColumnNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsLimitedOuterJoinsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnNameLength()); - } - - @Test public void getMaxColumnsInGroupByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsLimitedOuterJoins()); + } - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInGroupBy()); - } + @Test + public void getSchemaTermTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxColumnsInIndexTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals("", vitessDatabaseMetaData.getSchemaTerm()); + } - Assert.assertEquals(16, vitessDatabaseMetaData.getMaxColumnsInIndex()); - } + @Test + public void getProcedureTermTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxColumnsInOrderByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInOrderBy()); - } - - @Test public void getMaxColumnsInSelectTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxColumnsInSelect()); - } - - @Test public void getMaxIndexLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxIndexLength()); - } - - @Test public void doesMaxRowSizeIncludeBlobsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.doesMaxRowSizeIncludeBlobs()); - } - - @Test public void getMaxTableNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxTableNameLength()); - } - - @Test public void getMaxTablesInSelectTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxTablesInSelect()); - } - - @Test public void getMaxUserNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(16, vitessDatabaseMetaData.getMaxUserNameLength()); - } - - @Test public void supportsDataDefinitionAndDataManipulationTransactionsTest() - throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsDataDefinitionAndDataManipulationTransactions()); - } - - @Test public void dataDefinitionCausesTransactionCommitTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionCausesTransactionCommit()); - } - - @Test public void dataDefinitionIgnoredInTransactionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionIgnoredInTransactions()); - } - - @Test public void getIdentifierQuoteStringTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("`", vitessDatabaseMetaData.getIdentifierQuoteString()); - } - - @Test public void getProceduresTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(null, vitessDatabaseMetaData.getProcedures(null, null, null)); - } - - @Test public void supportsResultSetTypeTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.CLOSE_CURSORS_AT_COMMIT)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_UPDATABLE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_FORWARD)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_REVERSE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.HOLD_CURSORS_OVER_COMMIT)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_UNKNOWN)); - } - - @Test public void supportsResultSetConcurrencyTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.CLOSE_CURSORS_AT_COMMIT, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.CONCUR_READ_ONLY, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.FETCH_REVERSE, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.HOLD_CURSORS_OVER_COMMIT, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.FETCH_UNKNOWN, ResultSet.CONCUR_READ_ONLY)); - } - - @Test public void getJDBCMajorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(1, vitessDatabaseMetaData.getJDBCMajorVersion()); - } + Assert.assertEquals("procedure", vitessDatabaseMetaData.getProcedureTerm()); + } - @Test public void getJDBCMinorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getCatalogTermTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(0, vitessDatabaseMetaData.getJDBCMinorVersion()); - } + Assert.assertEquals("database", vitessDatabaseMetaData.getCatalogTerm()); + } - @Test public void getNumericFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void isCatalogAtStartTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals( - "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,POWER," - + "RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE", - vitessDatabaseMetaData.getNumericFunctions()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.isCatalogAtStart()); + } - @Test public void getStringFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals( - "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD," - + - "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,LTRIM,MAKE_SET," - + - "MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SPACE," - + - "STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER", - vitessDatabaseMetaData.getStringFunctions()); - } + @Test + public void getCatalogSeparatorTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getSystemFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatbaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(".", vitessDatabaseMetaData.getCatalogSeparator()); + } - Assert.assertEquals( - "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION,PASSWORD,ENCRYPT", - vitessMySQLDatabaseMetadata.getSystemFunctions()); - Assert.assertEquals("DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION", - vitessMariaDBDatbaseMetadata.getSystemFunctions()); - } + @Test + public void supportsSchemasInDataManipulationTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getTimeDateFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInDataManipulation()); + } - Assert.assertEquals( - "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND," - + - "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME," - + - "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,SEC_TO_TIME,TIME_TO_SEC", - vitessDatabaseMetaData.getTimeDateFunctions()); - } + @Test + public void supportsSchemasInProcedureCallsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void autoCommitFailureClosesAllResultSetsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInProcedureCalls()); + } - Assert.assertEquals(false, vitessDatabaseMetaData.autoCommitFailureClosesAllResultSets()); - } + @Test + public void supportsSchemasInTableDefinitionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getUrlTest() throws SQLException { - String connectionUrl = "jdbc:vitess://://"; - VitessJDBCUrl mockUrl = PowerMockito.mock(VitessJDBCUrl.class); - PowerMockito.when(mockUrl.getUrl()).thenReturn(connectionUrl); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInTableDefinitions()); + } - VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); - PowerMockito.when(mockConn.getUrl()).thenReturn(mockUrl); + @Test + public void supportsSchemasInIndexDefinitionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(connectionUrl, mockConn.getUrl().getUrl()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInIndexDefinitions()); + } - @Test public void isReadOnlyTest() throws SQLException { - VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); - PowerMockito.when(mockConn.isReadOnly()).thenReturn(false); - Assert.assertEquals(false, mockConn.isReadOnly()); + @Test + public void supportsSelectForUpdateTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSelectForUpdate()); + } - @Test public void getDriverNameTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + @Test + public void supportsStoredProceduresTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert - .assertEquals("Vitess MySQL JDBC Driver", vitessMySQLDatabaseMetadata.getDriverName()); - Assert.assertEquals("Vitess MariaDB JDBC Driver", - vitessMariaDBDatabaseMetadata.getDriverName()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsStoredProcedures()); + } - @Test public void usesLocalFilesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsSubqueriesInComparisonsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFiles()); - Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFilePerTable()); - Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInComparisons()); + } - @Test public void storeIdentifiersTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsSubqueriesInExistsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInExists()); + } - @Test public void supportsTransactionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(true, vitessDatabaseMetaData.supportsTransactions()); - } + @Test + public void supportsSubqueriesInInsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsTransactionIsolationLevelTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE)); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInIns()); + } - @Test public void getMaxProcedureNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxProcedureNameLength()); - } + @Test + public void supportsSubqueriesInQuantifiedsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxCatalogNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInQuantifieds()); + } - Assert.assertEquals(32, vitessMySqlDatabaseMetaData.getMaxCatalogNameLength()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxCatalogNameLength()); - } + @Test + public void supportsCorrelatedSubqueriesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxRowSizeTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsCorrelatedSubqueries()); + } - Assert.assertEquals(2147483639, vitessMySqlDatabaseMetaData.getMaxRowSize()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxRowSize()); - } + @Test + public void supportsUnionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxStatementLengthTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnion()); + } - Assert.assertEquals(65531, vitessMySqlDatabaseMetaData.getMaxStatementLength()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatementLength()); - } + @Test + public void supportsUnionAllTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxStatementsTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnionAll()); + } - Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxStatements()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatements()); - } + @Test + public void supportsOpenCursorsAcrossRollbackTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsDataManipulationTransactionsOnlyTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossRollback()); + } - Assert.assertEquals(false, - vitessMySqlDatabaseMetaData.supportsDataManipulationTransactionsOnly()); - Assert.assertEquals(false, - vitessMariaDBDatabaseMetadata.supportsDataManipulationTransactionsOnly()); - } + @Test + public void supportsOpenStatementsAcrossCommitTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxSchemaNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossCommit()); + } - Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxSchemaNameLength()); - Assert.assertEquals(32, vitessMariaDBDatabaseMetadata.getMaxSchemaNameLength()); - } + @Test + public void supportsOpenStatementsAcrossRollbackTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsSavepointsTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossRollback()); + } - Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsSavepoints()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsSavepoints()); - } + @Test + public void supportsOpenCursorsAcrossCommitTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsMultipleOpenResultsTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossCommit()); + } - Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsMultipleOpenResults()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsMultipleOpenResults()); - } + @Test + public void getMaxBinaryLiteralLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void locatorsUpdateCopyTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxBinaryLiteralLength()); + } - Assert.assertEquals(true, vitessMySqlDatabaseMetaData.locatorsUpdateCopy()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.locatorsUpdateCopy()); - } + @Test + public void getMaxCharLiteralLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsStatementPooling() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxCharLiteralLength()); + } - Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsStatementPooling()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsStatementPooling()); - } + @Test + public void getMaxColumnNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getCatalogsTest() throws SQLException, Exception { - String sql = "SHOW DATABASES"; - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder().addFields( - Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR).build()) - .addRows(Query.Row.newBuilder().addLengths("vitessDB".length()) - .setValues(ByteString.copyFromUtf8("vitessDB"))).addRows( - Query.Row.newBuilder().addLengths("sampleDB".length()) - .setValues(ByteString.copyFromUtf8("sampleDB"))).addRows( - Query.Row.newBuilder().addLengths("testDB".length()) - .setValues(ByteString.copyFromUtf8("testDB"))).addRows( - Query.Row.newBuilder().addLengths("dummyDB".length()) - .setValues(ByteString.copyFromUtf8("dummyDB"))).build()); - - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - ResultSet resultSet = vitessDatabaseMetaData.getCatalogs(); - ArrayList resultSetList = new ArrayList(); - while (resultSet.next()) { - resultSetList.add(resultSet.getString(1)); - } - Assert.assertEquals("dummyDB", resultSetList.get(0)); - Assert.assertEquals("sampleDB", resultSetList.get(1)); - Assert.assertEquals("testDB", resultSetList.get(2)); - Assert.assertEquals("vitessDB", resultSetList.get(3)); - } + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnNameLength()); + } - @Test public void getTablesTest() throws SQLException, Exception { + @Test + public void getMaxColumnsInGroupByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; - Cursor mockedCursor = getTablesCursor(); + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInGroupBy()); + } - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); + @Test + public void getMaxColumnsInIndexTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(getVitessConnection()); - ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); - ResultSet expectedResultSet = new VitessResultSet(mockedCursor); + Assert.assertEquals(16, vitessDatabaseMetaData.getMaxColumnsInIndex()); + } - assertResultSetEquals(actualResultSet, expectedResultSet); - } + @Test + public void getMaxColumnsInOrderByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getTablesProperResultTypeTest() throws SQLException, Exception { + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInOrderBy()); + } - String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; - Cursor mockedCursor = getTablesCursor(); + @Test + public void getMaxColumnsInSelectTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxColumnsInSelect()); + } - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(getVitessConnection()); - ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); - actualResultSet.next(); - Assert.assertEquals(String.class, actualResultSet.getObject("TABLE_CAT").getClass()); - } + @Test + public void getMaxIndexLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - private Cursor getTablesCursor() throws Exception { - return new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") - .setType(Query.Type.VARCHAR)).addFields( - Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleTable1".length()).addLengths("TABLE".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).addRows( - Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleView1".length()).addLengths("VIEW".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB1SampleView1VIEW"))).addRows( - Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleSystemView".length()).addLengths("SYSTEM VIEW".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemViewSYSTEM VIEW"))) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleSystemTable".length()).addLengths("SYSTEM TABLE".length()) + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxIndexLength()); + } + + @Test + public void doesMaxRowSizeIncludeBlobsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.doesMaxRowSizeIncludeBlobs()); + } + + @Test + public void getMaxTableNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxTableNameLength()); + } + + @Test + public void getMaxTablesInSelectTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxTablesInSelect()); + } + + @Test + public void getMaxUserNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(16, vitessDatabaseMetaData.getMaxUserNameLength()); + } + + @Test + public void supportsDataDefinitionAndDataManipulationTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsDataDefinitionAndDataManipulationTransactions()); + } + + @Test + public void dataDefinitionCausesTransactionCommitTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionCausesTransactionCommit()); + } + + @Test + public void dataDefinitionIgnoredInTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionIgnoredInTransactions()); + } + + @Test + public void getIdentifierQuoteStringTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals("`", vitessDatabaseMetaData.getIdentifierQuoteString()); + } + + @Test + public void getProceduresTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(null, vitessDatabaseMetaData.getProcedures(null, null, null)); + } + + @Test + public void supportsResultSetTypeTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(true, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.CLOSE_CURSORS_AT_COMMIT)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_UPDATABLE)); + Assert + .assertEquals(false, vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_FORWARD)); + Assert + .assertEquals(false, vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_REVERSE)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.HOLD_CURSORS_OVER_COMMIT)); + Assert + .assertEquals(false, vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_UNKNOWN)); + } + + @Test + public void supportsResultSetConcurrencyTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.CLOSE_CURSORS_AT_COMMIT, + ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.CONCUR_READ_ONLY, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.FETCH_REVERSE, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.HOLD_CURSORS_OVER_COMMIT, + ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.FETCH_UNKNOWN, ResultSet.CONCUR_READ_ONLY)); + } + + @Test + public void getJDBCMajorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(1, vitessDatabaseMetaData.getJDBCMajorVersion()); + } + + @Test + public void getJDBCMinorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(0, vitessDatabaseMetaData.getJDBCMinorVersion()); + } + + @Test + public void getNumericFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals( + "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN," + + "MOD,PI,POW,POWER," + + "RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE", + vitessDatabaseMetaData.getNumericFunctions()); + } + + @Test + public void getStringFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals( + "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT," + + "EXPORT_SET,FIELD," + + "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + + "LTRIM,MAKE_SET," + + "MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD," + + "RTRIM,SOUNDEX,SPACE," + + "STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER", + vitessDatabaseMetaData.getStringFunctions()); + } + + @Test + public void getSystemFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatbaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals( + "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION,PASSWORD,ENCRYPT", + vitessMySQLDatabaseMetadata.getSystemFunctions()); + Assert.assertEquals("DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION", + vitessMariaDBDatbaseMetadata.getSystemFunctions()); + } + + @Test + public void getTimeDateFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals( + "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR," + + "MINUTE,SECOND," + + "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE," + + "CURRENT_DATE,CURTIME," + + "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + + "SEC_TO_TIME,TIME_TO_SEC", + vitessDatabaseMetaData.getTimeDateFunctions()); + } + + @Test + public void autoCommitFailureClosesAllResultSetsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.autoCommitFailureClosesAllResultSets()); + } + + @Test + public void getUrlTest() throws SQLException { + String connectionUrl = "jdbc:vitess://://"; + VitessJDBCUrl mockUrl = PowerMockito.mock(VitessJDBCUrl.class); + PowerMockito.when(mockUrl.getUrl()).thenReturn(connectionUrl); + + VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); + PowerMockito.when(mockConn.getUrl()).thenReturn(mockUrl); + + Assert.assertEquals(connectionUrl, mockConn.getUrl().getUrl()); + } + + @Test + public void isReadOnlyTest() throws SQLException { + VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); + PowerMockito.when(mockConn.isReadOnly()).thenReturn(false); + Assert.assertEquals(false, mockConn.isReadOnly()); + + } + + @Test + public void getDriverNameTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals("Vitess MySQL JDBC Driver", vitessMySQLDatabaseMetadata.getDriverName()); + Assert + .assertEquals("Vitess MariaDB JDBC Driver", vitessMariaDBDatabaseMetadata.getDriverName()); + } + + @Test + public void usesLocalFilesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFiles()); + Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFilePerTable()); + Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); + } + + @Test + public void storeIdentifiersTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); + } + + @Test + public void supportsTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(true, vitessDatabaseMetaData.supportsTransactions()); + } + + @Test + public void supportsTransactionIsolationLevelTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE)); + } + + @Test + public void getMaxProcedureNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxProcedureNameLength()); + } + + @Test + public void getMaxCatalogNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(32, vitessMySqlDatabaseMetaData.getMaxCatalogNameLength()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxCatalogNameLength()); + } + + @Test + public void getMaxRowSizeTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(2147483639, vitessMySqlDatabaseMetaData.getMaxRowSize()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxRowSize()); + } + + @Test + public void getMaxStatementLengthTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(65531, vitessMySqlDatabaseMetaData.getMaxStatementLength()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatementLength()); + } + + @Test + public void getMaxStatementsTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxStatements()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatements()); + } + + @Test + public void supportsDataManipulationTransactionsOnlyTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, + vitessMySqlDatabaseMetaData.supportsDataManipulationTransactionsOnly()); + Assert.assertEquals(false, + vitessMariaDBDatabaseMetadata.supportsDataManipulationTransactionsOnly()); + } + + @Test + public void getMaxSchemaNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxSchemaNameLength()); + Assert.assertEquals(32, vitessMariaDBDatabaseMetadata.getMaxSchemaNameLength()); + } + + @Test + public void supportsSavepointsTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsSavepoints()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsSavepoints()); + } + + @Test + public void supportsMultipleOpenResultsTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsMultipleOpenResults()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsMultipleOpenResults()); + } + + @Test + public void locatorsUpdateCopyTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(true, vitessMySqlDatabaseMetaData.locatorsUpdateCopy()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.locatorsUpdateCopy()); + } + + @Test + public void supportsStatementPooling() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsStatementPooling()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsStatementPooling()); + } + + @Test + public void getCatalogsTest() throws SQLException, Exception { + String sql = "SHOW DATABASES"; + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR).build()).addRows( + Query.Row.newBuilder().addLengths("vitessDB".length()) + .setValues(ByteString.copyFromUtf8("vitessDB"))).addRows( + Query.Row.newBuilder().addLengths("sampleDB".length()) + .setValues(ByteString.copyFromUtf8("sampleDB"))).addRows( + Query.Row.newBuilder().addLengths("testDB".length()) + .setValues(ByteString.copyFromUtf8("testDB"))).addRows( + Query.Row.newBuilder().addLengths("dummyDB".length()) + .setValues(ByteString.copyFromUtf8("dummyDB"))).build()); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + ResultSet resultSet = vitessDatabaseMetaData.getCatalogs(); + ArrayList resultSetList = new ArrayList(); + while (resultSet.next()) { + resultSetList.add(resultSet.getString(1)); + } + Assert.assertEquals("dummyDB", resultSetList.get(0)); + Assert.assertEquals("sampleDB", resultSetList.get(1)); + Assert.assertEquals("testDB", resultSetList.get(2)); + Assert.assertEquals("vitessDB", resultSetList.get(3)); + } + + @Test + public void getTablesTest() throws SQLException, Exception { + + String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; + Cursor mockedCursor = getTablesCursor(); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + getVitessConnection()); + ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); + ResultSet expectedResultSet = new VitessResultSet(mockedCursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + @Test + public void getTablesProperResultTypeTest() throws SQLException, Exception { + + String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; + Cursor mockedCursor = getTablesCursor(); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + getVitessConnection()); + ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); + actualResultSet.next(); + Assert.assertEquals(String.class, actualResultSet.getObject("TABLE_CAT").getClass()); + } + + private Cursor getTablesCursor() throws Exception { + return new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") + .setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleTable1".length()).addLengths("TABLE".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleView1".length()).addLengths("VIEW".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemTableSYSTEM TABLE"))) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleLocalTemporary".length()).addLengths("LOCAL TEMPORARY".length()) + .setValues(ByteString.copyFromUtf8("TestDB1SampleView1VIEW"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleSystemView".length()).addLengths("SYSTEM VIEW".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB2SampleLocalTemporaryLOCAL TEMPORARY"))) - .build()); - } - - @Test public void getColumnsTest() throws SQLException, Exception { - - String sql = "SHOW FULL COLUMNS FROM `sampleTable1` FROM `TestDB1` LIKE '%'"; - Cursor mockedTablecursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") - .setType(Query.Type.VARCHAR)).addFields( - Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("sampleTable1".length()).addLengths("TABLE".length()) + .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemViewSYSTEM VIEW"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleSystemTable".length()).addLengths("SYSTEM TABLE".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).build()); - - Cursor actualCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Field").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Type").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Key").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Default").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Extra").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Privileges").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("shipmentid".length()) - .addLengths("bigint".length()).addLengths("NULL".length()).addLengths("NO".length()) - .addLengths("PRI".length()).addLengths("NULL".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemTableSYSTEM TABLE"))) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleLocalTemporary".length()).addLengths("LOCAL TEMPORARY".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB2SampleLocalTemporaryLOCAL TEMPORARY"))) + .build()); + } + + @Test + public void getColumnsTest() throws SQLException, Exception { + + String sql = "SHOW FULL COLUMNS FROM `sampleTable1` FROM `TestDB1` LIKE '%'"; + Cursor mockedTablecursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") + .setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("sampleTable1".length()).addLengths("TABLE".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).build()); + + Cursor actualCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("Field").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Type").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Key").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Default").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Extra").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Privileges").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)).addRows( + Query.Row.newBuilder().addLengths("shipmentid".length()).addLengths("bigint".length()) + .addLengths("NULL".length()).addLengths("NO".length()).addLengths("PRI".length()) + .addLengths("NULL".length()).addLengths("".length()) .addLengths("select,insert,update,references".length()).addLengths("".length()) .setValues(ByteString .copyFromUtf8("shipmentidbigintNULLNOPRINULLselect,insert,update,references"))) - .addRows(Query.Row.newBuilder().addLengths("trackingid".length()) - .addLengths("varchar".length()).addLengths("utf8_general_ci".length()) - .addLengths("YES".length()).addLengths("".length()).addLengths("NULL".length()) - .addLengths("".length()).addLengths("select,insert,update,references".length()) - .addLengths("".length()).setValues(ByteString.copyFromUtf8( - "trackingidvarcharutf8_general_ciYESNULLselect,insert,update,references"))) - .build()); - Cursor expectedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("DATA_TYPE").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_SIZE").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("BUFFER_LENGTH").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("DECIMAL_DIGITS").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("NUM_PREC_RADIX").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("NULLABLE").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_DEF").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SQL_DATA_TYPE").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("SQL_DATETIME_SUB").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("CHAR_OCTET_LENGTH").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("ISNULLABLE").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SCOPE_CATALOG").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SCOPE_SCHEMA").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SCOPE_TABLE").setType(Query.Type.CHAR)) - .addFields( - Query.Field.newBuilder().setName("SOURCE_DATA_TYPE").setType(Query.Type.INT16)) - .addFields( - Query.Field.newBuilder().setName("IS_AUTOINCREMENT").setType(Query.Type.CHAR)) - .addFields( - Query.Field.newBuilder().setName("IS_GENERATEDCOLUMN").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) - .addLengths("sampleTable1".length()).addLengths("shipmentid".length()) - .addLengths("-5".length()).addLengths("BIGINT".length()).addLengths("19".length()) - .addLengths("65535".length()).addLengths("0".length()).addLengths("10".length()) - .addLengths("0".length()).addLengths("Comment".length()).addLengths("NULL".length()) - .addLengths("0".length()).addLengths("0".length()).addLengths("0".length()) - .addLengths("1".length()).addLengths("NO".length()).addLengths(-1).addLengths(-1) - .addLengths(-1).addLengths(-1).addLengths("NO".length()).addLengths("NO".length()) + .addRows( + Query.Row.newBuilder().addLengths("trackingid".length()).addLengths("varchar".length()) + .addLengths("utf8_general_ci".length()).addLengths("YES".length()) + .addLengths("".length()).addLengths("NULL".length()).addLengths("".length()) + .addLengths("select,insert,update,references".length()).addLengths("".length()) .setValues(ByteString.copyFromUtf8( - "TestDB1sampleTable1shipmentid-5BIGINT19655350100CommentNULL0001NONONO"))) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) + "trackingidvarcharutf8_general_ciYESNULLselect,insert,update,references"))) + .build()); + Cursor expectedCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("DATA_TYPE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_SIZE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("BUFFER_LENGTH").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("DECIMAL_DIGITS").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("NUM_PREC_RADIX").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("NULLABLE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_DEF").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SQL_DATA_TYPE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("SQL_DATETIME_SUB").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("CHAR_OCTET_LENGTH").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("ISNULLABLE").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SCOPE_CATALOG").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SCOPE_SCHEMA").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SCOPE_TABLE").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SOURCE_DATA_TYPE").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("IS_AUTOINCREMENT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("IS_GENERATEDCOLUMN").setType(Query.Type.CHAR)) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) + .addLengths("sampleTable1".length()).addLengths("shipmentid".length()) + .addLengths("-5".length()).addLengths("BIGINT".length()).addLengths("19".length()) + .addLengths("65535".length()).addLengths("0".length()).addLengths("10".length()) + .addLengths("0".length()).addLengths("Comment".length()).addLengths("NULL".length()) + .addLengths("0".length()).addLengths("0".length()).addLengths("0".length()) + .addLengths("1".length()).addLengths("NO".length()).addLengths(-1).addLengths(-1) + .addLengths(-1).addLengths(-1).addLengths("NO".length()).addLengths("NO".length()) + .setValues(ByteString.copyFromUtf8( + "TestDB1sampleTable1shipmentid-5BIGINT19655350100CommentNULL0001NONONO"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) .addLengths("sampleTable1".length()).addLengths("trackingid".length()) .addLengths("12".length()).addLengths("VARCHAR".length()).addLengths("255".length()) .addLengths("65535".length()).addLengths(-1).addLengths("10".length()) @@ -1129,398 +1222,405 @@ private Cursor getTablesCursor() throws Exception { .addLengths(-1).addLengths(-1).addLengths("NO".length()).addLengths("NO".length()) .setValues(ByteString.copyFromUtf8( "TestDB1sampleTable1trackingid12VARCHAR25565535101CommentNULL002552YESNONO"))) - .build()); - - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(actualCursor)); - - VitessDatabaseMetaData vitessDatabaseMetaData = - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) - .getColumns("TestDB1", null, null, null); - PowerMockito.when(vitessDatabaseMetaData.getTables("TestDB1", null, "%", new String[0])) - .thenReturn(new VitessResultSet(mockedTablecursor)); - ResultSet actualResultSet = vitessDatabaseMetaData.getColumns("TestDB1", null, null, null); - ResultSet expectedResultSet = new VitessResultSet(expectedCursor); - - assertResultSetEquals(actualResultSet, expectedResultSet); - } - - @Test public void getPrimaryKeysTest() throws SQLException, Exception { - - String sql = "SHOW KEYS FROM `shipment` FROM `vt`"; - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) - .addFields( - Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) - .addLengths("PRIMARY".length()).addLengths("1".length()) - .addLengths("shipmentid".length()).addLengths("A".length()) - .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) - .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) - .build()); - Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("KEY_SEQ").setType(Query.Type.INT16)) - .addFields(Query.Field.newBuilder().setName("PK_NAME").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) + .build()); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(actualCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = PowerMockito + .mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) + .getColumns("TestDB1", null, null, null); + PowerMockito.when(vitessDatabaseMetaData.getTables("TestDB1", null, "%", new String[0])) + .thenReturn(new VitessResultSet(mockedTablecursor)); + ResultSet actualResultSet = vitessDatabaseMetaData.getColumns("TestDB1", null, null, null); + ResultSet expectedResultSet = new VitessResultSet(expectedCursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + @Test + public void getPrimaryKeysTest() throws SQLException, Exception { + + String sql = "SHOW KEYS FROM `shipment` FROM `vt`"; + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) + .addLengths("PRIMARY".length()).addLengths("1".length()) + .addLengths("shipmentid".length()).addLengths("A".length()) + .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) + .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) + .build()); + Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("KEY_SEQ").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("PK_NAME").setType(Query.Type.CHAR)).addRows( + Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) .addLengths("shipment".length()).addLengths("shipmentid".length()) .addLengths("1".length()).addLengths("PRIMARY".length()) .setValues(ByteString.copyFromUtf8("vtshipmentshipmentid1PRIMARY"))).build()); - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - VitessDatabaseMetaData vitessDatabaseMetaData = - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) - .getPrimaryKeys("vt", null, "shipment"); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - ResultSet expectedResultSet = vitessDatabaseMetaData.getPrimaryKeys("vt", null, "shipment"); - ResultSet actualResultSet = new VitessResultSet(expectedcursor); - - assertResultSetEquals(actualResultSet, expectedResultSet); - } - - @Test public void getIndexInfoTest() throws SQLException, Exception { - - String sql = "SHOW INDEX FROM `shipment` FROM `vt`"; - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) - .addFields( - Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) - .addLengths("PRIMARY".length()).addLengths("1".length()) - .addLengths("shipmentid".length()).addLengths("A".length()) - .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) - .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) - .build()); - - Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.BIT)) - .addFields(Query.Field.newBuilder().setName("INDEX_QUALIFIER").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("INDEX_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE").setType(Query.Type.INT16)) - .addFields( - Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT16)) - .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("ASC_OR_DESC").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("CARDINALITY").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("PAGES").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("FILTER_CONDITION").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) - .addLengths("shipment".length()).addLengths("false".length()) - .addLengths("".length()).addLengths("PRIMARY".length()).addLengths("3".length()) - .addLengths("1".length()).addLengths("shipmentid".length()).addLengths("A".length()) - .addLengths("434880".length()).addLengths("0".length()).addLengths(-1) - .setValues(ByteString.copyFromUtf8("vtshipmentfalsePRIMARY31shipmentidA4348800"))) - .build()); - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - VitessDatabaseMetaData vitessDatabaseMetaData = - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) - .getIndexInfo("vt", null, "shipment", true, false); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - ResultSet actualResultSet = - vitessDatabaseMetaData.getIndexInfo("vt", null, "shipment", true, false); - ResultSet expectedResultSet = new VitessResultSet(expectedcursor); - - assertResultSetEquals(actualResultSet, expectedResultSet); - } - - private void assertResultSetEquals(ResultSet actualResultSet, ResultSet expectedResultSet) - throws SQLException { - ResultSetMetaData actualResultSetMetadata = actualResultSet.getMetaData(); - ResultSetMetaData expectedResultSetMetadata = expectedResultSet.getMetaData(); - //Column Count Comparison - Assert.assertEquals(expectedResultSetMetadata.getColumnCount(), - actualResultSetMetadata.getColumnCount()); - //Column Type Comparison - for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals(expectedResultSetMetadata.getColumnType(i + 1), - actualResultSetMetadata.getColumnType(i + 1)); - } - - //Actual Values Comparison - while (expectedResultSet.next() && actualResultSet.next()) { - for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { - switch (expectedResultSetMetadata.getColumnType(i + 1)) { - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - Assert.assertEquals(expectedResultSet.getInt(i + 1), - actualResultSet.getInt(i + 1)); - break; - case Types.BIGINT: - Assert.assertEquals(expectedResultSet.getLong(i + 1), - actualResultSet.getLong(i + 1)); - break; - case Types.FLOAT: - Assert.assertEquals(expectedResultSet.getFloat(i + 1), - actualResultSet.getFloat(i + 1), 0.1); - break; - case Types.DOUBLE: - Assert.assertEquals(expectedResultSet.getDouble(i + 1), - actualResultSet.getDouble(i + 1), 0.1); - break; - case Types.TIME: - Assert.assertEquals(expectedResultSet.getTime(i + 1), - actualResultSet.getTime(i + 1)); - break; - case Types.TIMESTAMP: - Assert.assertEquals(expectedResultSet.getTimestamp(i + 1), - actualResultSet.getTimestamp(i + 1)); - break; - case Types.DATE: - Assert.assertEquals(expectedResultSet.getDate(i + 1), - actualResultSet.getDate(i + 1)); - break; - case Types.BLOB: - Assert.assertEquals(expectedResultSet.getBlob(i + 1), - actualResultSet.getBlob(i + 1)); - break; - case Types.BINARY: - case Types.LONGVARBINARY: - Assert.assertEquals(expectedResultSet.getBytes(i + 1), - actualResultSet.getBytes(i + 1)); - break; - default: - Assert.assertEquals(expectedResultSet.getString(i + 1), - actualResultSet.getString(i + 1)); - break; - } - } - } - } - - @Test public void getUserNameTest() { - try { - VitessConnection vitessConnection = - new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - VitessDatabaseMetaData vitessDatabaseMetaData = - new VitessMySQLDatabaseMetadata(vitessConnection); - Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); - - vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", null); - vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); - Assert.assertEquals(null, vitessDatabaseMetaData.getUserName()); - - Properties properties = new Properties(); - properties.put(Constants.Property.USERNAME, "username"); - vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", properties); - vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); - Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); - - } catch (SQLException e) { - Assert.fail("Exception Occured: " + e.getMessage()); - } - } - - @Test public void testCaseSensitivityIdentifierFuncsMySql() throws Exception { - assertCaseSensitivityForDatabaseType(false); - } - - @Test public void testCaseSensitivityIdentifierFuncsMariaDb() throws Exception { - assertCaseSensitivityForDatabaseType(true); - } - - private void assertCaseSensitivityForDatabaseType(boolean useMariaDb) throws Exception { - VitessConnection connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("0", useMariaDb); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - - connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("1", useMariaDb); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - - connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("2", useMariaDb); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - - connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("something random", useMariaDb); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - } - - private void mockStatementForLowercaseTablesValue(String lcTablesValue, boolean useMariaDb) throws Exception { - String sql = "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', \'lower_case_table_names\')"; - String versionName = "innodb_version"; - String versionValue = "5.7.16-10"; - if (useMariaDb) { - versionValue = versionValue + "-mariadb"; + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + VitessDatabaseMetaData vitessDatabaseMetaData = PowerMockito + .mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) + .getPrimaryKeys("vt", null, "shipment"); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + ResultSet expectedResultSet = vitessDatabaseMetaData.getPrimaryKeys("vt", null, "shipment"); + ResultSet actualResultSet = new VitessResultSet(expectedcursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + @Test + public void getIndexInfoTest() throws SQLException, Exception { + + String sql = "SHOW INDEX FROM `shipment` FROM `vt`"; + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) + .addLengths("PRIMARY".length()).addLengths("1".length()) + .addLengths("shipmentid".length()).addLengths("A".length()) + .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) + .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) + .build()); + + Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.BIT)) + .addFields(Query.Field.newBuilder().setName("INDEX_QUALIFIER").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("INDEX_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("ASC_OR_DESC").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("CARDINALITY").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("PAGES").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("FILTER_CONDITION").setType(Query.Type.CHAR)) + .addRows(Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) + .addLengths("shipment".length()).addLengths("false".length()).addLengths("".length()) + .addLengths("PRIMARY".length()).addLengths("3".length()).addLengths("1".length()) + .addLengths("shipmentid".length()).addLengths("A".length()) + .addLengths("434880".length()).addLengths("0".length()).addLengths(-1) + .setValues(ByteString.copyFromUtf8("vtshipmentfalsePRIMARY31shipmentidA4348800"))) + .build()); + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + VitessDatabaseMetaData vitessDatabaseMetaData = PowerMockito + .mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) + .getIndexInfo("vt", null, "shipment", true, false); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + ResultSet actualResultSet = vitessDatabaseMetaData + .getIndexInfo("vt", null, "shipment", true, false); + ResultSet expectedResultSet = new VitessResultSet(expectedcursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + private void assertResultSetEquals(ResultSet actualResultSet, ResultSet expectedResultSet) + throws SQLException { + ResultSetMetaData actualResultSetMetadata = actualResultSet.getMetaData(); + ResultSetMetaData expectedResultSetMetadata = expectedResultSet.getMetaData(); + //Column Count Comparison + Assert.assertEquals(expectedResultSetMetadata.getColumnCount(), + actualResultSetMetadata.getColumnCount()); + //Column Type Comparison + for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals(expectedResultSetMetadata.getColumnType(i + 1), + actualResultSetMetadata.getColumnType(i + 1)); + } + + //Actual Values Comparison + while (expectedResultSet.next() && actualResultSet.next()) { + for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { + switch (expectedResultSetMetadata.getColumnType(i + 1)) { + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + Assert.assertEquals(expectedResultSet.getInt(i + 1), actualResultSet.getInt(i + 1)); + break; + case Types.BIGINT: + Assert.assertEquals(expectedResultSet.getLong(i + 1), actualResultSet.getLong(i + 1)); + break; + case Types.FLOAT: + Assert.assertEquals(expectedResultSet.getFloat(i + 1), actualResultSet.getFloat(i + 1), + 0.1); + break; + case Types.DOUBLE: + Assert + .assertEquals(expectedResultSet.getDouble(i + 1), actualResultSet.getDouble(i + 1), + 0.1); + break; + case Types.TIME: + Assert.assertEquals(expectedResultSet.getTime(i + 1), actualResultSet.getTime(i + 1)); + break; + case Types.TIMESTAMP: + Assert.assertEquals(expectedResultSet.getTimestamp(i + 1), + actualResultSet.getTimestamp(i + 1)); + break; + case Types.DATE: + Assert.assertEquals(expectedResultSet.getDate(i + 1), actualResultSet.getDate(i + 1)); + break; + case Types.BLOB: + Assert.assertEquals(expectedResultSet.getBlob(i + 1), actualResultSet.getBlob(i + 1)); + break; + case Types.BINARY: + case Types.LONGVARBINARY: + Assert.assertEquals(expectedResultSet.getBytes(i + 1), actualResultSet.getBytes(i + 1)); + break; + default: + Assert + .assertEquals(expectedResultSet.getString(i + 1), actualResultSet.getString(i + 1)); + break; } - String txIsoName = "tx_isolation"; - String txIsoValue = "REPEATABLE-READ"; - String lcTablesName = "lower_case_table_names"; - - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Variable_name").setType(Query.Type.VARCHAR).build()) - .addFields(Query.Field.newBuilder().setName("Value").setType(Query.Type.VARCHAR).build()) - .addRows(Query.Row.newBuilder().addLengths(versionName.length()).addLengths(versionValue.length()).setValues(ByteString.copyFromUtf8(versionName + versionValue))) - .addRows(Query.Row.newBuilder().addLengths(txIsoName.length()).addLengths(txIsoValue.length()).setValues(ByteString.copyFromUtf8(txIsoName + txIsoValue))) - .addRows(Query.Row.newBuilder().addLengths(lcTablesName.length()).addLengths(lcTablesValue.length()).setValues(ByteString.copyFromUtf8(lcTablesName + lcTablesValue))) - .build()); - - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - } - - /** - * Tests that we're properly stitching together the results of SHOW CREATE TABLE. See {@link #extractForeignKeyForTableTest()} - * for more thorough testing of the actual parsing - */ - @Test public void getImportedKeysTest() throws Exception { - try (InputStream resourceAsStream = this.getClass().getResourceAsStream("/getImportedKeysTestCase.sql")) { - String table = "testA"; - String showCreate = CharStreams.toString(new InputStreamReader(resourceAsStream, Charsets.UTF_8)); - - Query.QueryResult queryResult = Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("Create Table").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder() - .addLengths(table.length()) - .addLengths(showCreate.length()) - .setValues(ByteString.copyFromUtf8(table + showCreate))) - .build(); - - String sql = "SHOW CREATE TABLE `testA`"; - VitessConnection vitessConnection = - new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - VitessStatement vitessStatement = PowerMockito.spy(new VitessStatement(vitessConnection)); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.doReturn(new VitessResultSet(new SimpleCursor(queryResult), vitessStatement)) - .when(vitessStatement).executeQuery(sql); - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); - ResultSet importedKeys = vitessDatabaseMetaData.getImportedKeys("test", "test", "testA"); - importedKeys.next(); - Assert.assertEquals("test", importedKeys.getString("PKTABLE_CAT")); - Assert.assertEquals(null, importedKeys.getString("PKTABLE_SCHEM")); - Assert.assertEquals("fTable", importedKeys.getString("PKTABLE_NAME")); - Assert.assertEquals("id", importedKeys.getString("PKCOLUMN_NAME")); - Assert.assertEquals("test", importedKeys.getString("FKTABLE_CAT")); - Assert.assertEquals(null, importedKeys.getString("FKTABLE_SCHEM")); - Assert.assertEquals("testA", importedKeys.getString("FKTABLE_NAME")); - Assert.assertEquals("fIdOne", importedKeys.getString("FKCOLUMN_NAME")); - Assert.assertEquals(1, importedKeys.getInt("KEY_SEQ")); - Assert.assertEquals(3, importedKeys.getInt("UPDATE_RULE")); - Assert.assertEquals(3, importedKeys.getInt("DELETE_RULE")); - Assert.assertEquals("fk_testA", importedKeys.getString("FK_NAME")); - Assert.assertEquals(null, importedKeys.getString("PK_NAME")); - Assert.assertEquals(7, importedKeys.getInt("DEFERRABILITY")); - } - } - - /** - * Tests parsing all the various outputs of SHOW CREATE TABLE for the foreign key constraints. - */ - @Test public void extractForeignKeyForTableTest() throws SQLException, IOException { - VitessConnection vitessConnection = - new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - VitessMySQLDatabaseMetadata vitessDatabaseMetaData = - new VitessMySQLDatabaseMetadata(vitessConnection); - - try (InputStream resourceAsStream = this.getClass().getResourceAsStream("/extractForeignKeyForTableTestCases.sql")) { - Scanner scanner = new Scanner(resourceAsStream); - List> rows = new ArrayList<>(); - String testName = null; - String testExpected = null; - String testInput = ""; - String startTag = "-- name: "; - String expectedTag = "-- expected: "; - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - if (line.startsWith(startTag)) { - if (testName != null) { - rows.clear(); - vitessDatabaseMetaData.extractForeignKeyForTable(rows, testInput, "test", "testA"); - assertForeignKeysOutput(testName, testExpected, rows); - testInput = ""; - } - testName = line.substring(startTag.length()); - } else if (line.startsWith(expectedTag)) { - testExpected = line.substring(expectedTag.length()); - } else if (line.startsWith("--") || line.trim().isEmpty()) { - // Just general comment or whitespace, we can ignore - } else { - testInput += line + "\n"; - } - } - + } + } + } + + @Test + public void getUserNameTest() { + try { + VitessConnection vitessConnection = new VitessConnection( + "jdbc:vitess://username@ip1:port1/keyspace", null); + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + vitessConnection); + Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); + + vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", null); + vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); + Assert.assertEquals(null, vitessDatabaseMetaData.getUserName()); + + Properties properties = new Properties(); + properties.put(Constants.Property.USERNAME, "username"); + vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", properties); + vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); + Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); + + } catch (SQLException e) { + Assert.fail("Exception Occured: " + e.getMessage()); + } + } + + @Test + public void testCaseSensitivityIdentifierFuncsMySql() throws Exception { + assertCaseSensitivityForDatabaseType(false); + } + + @Test + public void testCaseSensitivityIdentifierFuncsMariaDb() throws Exception { + assertCaseSensitivityForDatabaseType(true); + } + + private void assertCaseSensitivityForDatabaseType(boolean useMariaDb) throws Exception { + VitessConnection connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", + null); + mockStatementForLowercaseTablesValue("0", useMariaDb); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + + connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); + mockStatementForLowercaseTablesValue("1", useMariaDb); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + + connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); + mockStatementForLowercaseTablesValue("2", useMariaDb); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + + connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); + mockStatementForLowercaseTablesValue("something random", useMariaDb); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + } + + private void mockStatementForLowercaseTablesValue(String lcTablesValue, boolean useMariaDb) + throws Exception { + String sql = "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', " + + "\'lower_case_table_names\')"; + String versionName = "innodb_version"; + String versionValue = "5.7.16-10"; + if (useMariaDb) { + versionValue = versionValue + "-mariadb"; + } + String txIsoName = "tx_isolation"; + String txIsoValue = "REPEATABLE-READ"; + String lcTablesName = "lower_case_table_names"; + + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("Variable_name").setType(Query.Type.VARCHAR).build()) + .addFields(Query.Field.newBuilder().setName("Value").setType(Query.Type.VARCHAR).build()) + .addRows(Query.Row.newBuilder().addLengths(versionName.length()) + .addLengths(versionValue.length()) + .setValues(ByteString.copyFromUtf8(versionName + versionValue))).addRows( + Query.Row.newBuilder().addLengths(txIsoName.length()).addLengths(txIsoValue.length()) + .setValues(ByteString.copyFromUtf8(txIsoName + txIsoValue))).addRows( + Query.Row.newBuilder().addLengths(lcTablesName.length()) + .addLengths(lcTablesValue.length()) + .setValues(ByteString.copyFromUtf8(lcTablesName + lcTablesValue))).build()); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + } + + /** + * Tests that we're properly stitching together the results of SHOW CREATE TABLE. See {@link + * #extractForeignKeyForTableTest()} for more thorough testing of the actual parsing + */ + @Test + public void getImportedKeysTest() throws Exception { + try (InputStream resourceAsStream = this.getClass() + .getResourceAsStream("/getImportedKeysTestCase.sql")) { + String table = "testA"; + String showCreate = CharStreams + .toString(new InputStreamReader(resourceAsStream, Charsets.UTF_8)); + + Query.QueryResult queryResult = Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("Create Table").setType(Query.Type.CHAR)) + .addRows(Query.Row.newBuilder().addLengths(table.length()).addLengths(showCreate.length()) + .setValues(ByteString.copyFromUtf8(table + showCreate))).build(); + + String sql = "SHOW CREATE TABLE `testA`"; + VitessConnection vitessConnection = new VitessConnection( + "jdbc:vitess://username@ip1:port1/keyspace", null); + VitessStatement vitessStatement = PowerMockito.spy(new VitessStatement(vitessConnection)); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.doReturn(new VitessResultSet(new SimpleCursor(queryResult), vitessStatement)) + .when(vitessStatement).executeQuery(sql); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + vitessConnection); + ResultSet importedKeys = vitessDatabaseMetaData.getImportedKeys("test", "test", "testA"); + importedKeys.next(); + Assert.assertEquals("test", importedKeys.getString("PKTABLE_CAT")); + Assert.assertEquals(null, importedKeys.getString("PKTABLE_SCHEM")); + Assert.assertEquals("fTable", importedKeys.getString("PKTABLE_NAME")); + Assert.assertEquals("id", importedKeys.getString("PKCOLUMN_NAME")); + Assert.assertEquals("test", importedKeys.getString("FKTABLE_CAT")); + Assert.assertEquals(null, importedKeys.getString("FKTABLE_SCHEM")); + Assert.assertEquals("testA", importedKeys.getString("FKTABLE_NAME")); + Assert.assertEquals("fIdOne", importedKeys.getString("FKCOLUMN_NAME")); + Assert.assertEquals(1, importedKeys.getInt("KEY_SEQ")); + Assert.assertEquals(3, importedKeys.getInt("UPDATE_RULE")); + Assert.assertEquals(3, importedKeys.getInt("DELETE_RULE")); + Assert.assertEquals("fk_testA", importedKeys.getString("FK_NAME")); + Assert.assertEquals(null, importedKeys.getString("PK_NAME")); + Assert.assertEquals(7, importedKeys.getInt("DEFERRABILITY")); + } + } + + /** + * Tests parsing all the various outputs of SHOW CREATE TABLE for the foreign key constraints. + */ + @Test + public void extractForeignKeyForTableTest() throws SQLException, IOException { + VitessConnection vitessConnection = new VitessConnection( + "jdbc:vitess://username@ip1:port1/keyspace", null); + VitessMySQLDatabaseMetadata vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + vitessConnection); + + try (InputStream resourceAsStream = this.getClass() + .getResourceAsStream("/extractForeignKeyForTableTestCases.sql")) { + Scanner scanner = new Scanner(resourceAsStream); + List> rows = new ArrayList<>(); + String testName = null; + String testExpected = null; + String testInput = ""; + String startTag = "-- name: "; + String expectedTag = "-- expected: "; + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.startsWith(startTag)) { + if (testName != null) { rows.clear(); - vitessDatabaseMetaData.extractForeignKeyForTable(rows, testExpected, "test", "testA"); + vitessDatabaseMetaData.extractForeignKeyForTable(rows, testInput, "test", "testA"); assertForeignKeysOutput(testName, testExpected, rows); + testInput = ""; + } + testName = line.substring(startTag.length()); + } else if (line.startsWith(expectedTag)) { + testExpected = line.substring(expectedTag.length()); + } else if (line.startsWith("--") || line.trim().isEmpty()) { + // Just general comment or whitespace, we can ignore + } else { + testInput += line + "\n"; } - } - - private void assertForeignKeysOutput(String testName, String expected, List> output) { - // Uncomment below for debugging - //System.out.println("Name: " + testName); - //System.out.println("Expected: " + expected); - //System.out.println("Output: " + String.valueOf(output)); - Assert.assertEquals(testName, expected, String.valueOf(output)); - } + } + + rows.clear(); + vitessDatabaseMetaData.extractForeignKeyForTable(rows, testExpected, "test", "testA"); + assertForeignKeysOutput(testName, testExpected, rows); + } + } + + private void assertForeignKeysOutput(String testName, String expected, + List> output) { + // Uncomment below for debugging + //System.out.println("Name: " + testName); + //System.out.println("Expected: " + expected); + //System.out.println("Output: " + String.valueOf(output)); + Assert.assertEquals(testName, expected, String.valueOf(output)); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java index 326403f8298..37e5d176215 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java @@ -16,8 +16,8 @@ package io.vitess.jdbc; -import org.junit.BeforeClass; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import io.vitess.util.Constants; @@ -26,91 +26,92 @@ import java.sql.SQLException; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import org.junit.BeforeClass; +import org.junit.Test; /** * Created by harshit.gangal on 19/01/16. */ public class VitessDriverTest { - private static VitessDriver driver = new VitessDriver(); + private static VitessDriver driver = new VitessDriver(); - String dbURL = - "jdbc:vitess://localhost:9000/shipment/vt_shipment?tabletType=master&executeType=stream&userName" - + "=user"; + String dbURL = + "jdbc:vitess://localhost:9000/shipment/vt_shipment?tabletType=master&executeType=stream" + + "&userName" + + "=user"; - @BeforeClass - public static void setUp() { - // load Vitess driver - try { - Class.forName("io.vitess.jdbc.VitessDriver"); - } catch (ClassNotFoundException e) { - fail("Driver is not in the CLASSPATH -> " + e); - } + @BeforeClass + public static void setUp() { + // load Vitess driver + try { + Class.forName("io.vitess.jdbc.VitessDriver"); + } catch (ClassNotFoundException e) { + fail("Driver is not in the CLASSPATH -> " + e); } - - @Test - public void testConnect() throws SQLException { - VitessConnection connection = - (VitessConnection) DriverManager.getConnection(dbURL, new Properties()); - assertEquals(connection.getUrl().getUrl(), dbURL); - } - - @Test - public void testAcceptsURL() { - assertEquals(true, driver.acceptsURL(dbURL)); - } - - @Test - public void testAcceptsMalformedURL() { - String url = - "jdbc:MalfromdedUrl://localhost:9000/shipment/vt_shipment?tabletType=master"; - assertEquals(false, driver.acceptsURL(url)); - } - - @Test - public void testGetPropertyInfo() throws SQLException { - // Used to ensure that we're properly adding the below URL-based properties at the beginning - // of the full ConnectionProperties configuration - DriverPropertyInfo[] underlying = ConnectionProperties.exposeAsDriverPropertyInfo(new Properties(), 0); - - int additionalProp = 2; - DriverPropertyInfo[] driverPropertyInfos = driver.getPropertyInfo(dbURL, null); - assertEquals(underlying.length + additionalProp, driverPropertyInfos.length); - - assertEquals(driverPropertyInfos[0].description, Constants.VITESS_HOST); - assertEquals(driverPropertyInfos[0].required, true); - assertEquals(driverPropertyInfos[0].name, Constants.Property.HOST); - assertEquals(driverPropertyInfos[0].value, "localhost"); - - assertEquals(driverPropertyInfos[1].description, Constants.VITESS_PORT); - assertEquals(driverPropertyInfos[1].required, false); - assertEquals(driverPropertyInfos[1].name, Constants.Property.PORT); - assertEquals(driverPropertyInfos[1].value, "9000"); - - // Validate the remainder of the driver properties match up with the underlying - for (int i = additionalProp; i < driverPropertyInfos.length; i++) { - assertEquals(underlying[i - additionalProp].description, driverPropertyInfos[i].description); - assertEquals(underlying[i - additionalProp].required, driverPropertyInfos[i].required); - assertEquals(underlying[i - additionalProp].name, driverPropertyInfos[i].name); - assertEquals(underlying[i - additionalProp].value, driverPropertyInfos[i].value); - } - } - - @Test - public void testGetMajorVersion() { - assertEquals(driver.getMajorVersion(), Constants.DRIVER_MAJOR_VERSION); - } - - @Test - public void testGetMinorVersion() { - assertEquals(driver.getMinorVersion(), Constants.DRIVER_MINOR_VERSION); - } - - @Test - public void testJdbcCompliant() { - assertEquals(false, driver.jdbcCompliant()); + } + + @Test + public void testConnect() throws SQLException { + VitessConnection connection = (VitessConnection) DriverManager + .getConnection(dbURL, new Properties()); + assertEquals(connection.getUrl().getUrl(), dbURL); + } + + @Test + public void testAcceptsURL() { + assertEquals(true, driver.acceptsURL(dbURL)); + } + + @Test + public void testAcceptsMalformedURL() { + String url = "jdbc:MalfromdedUrl://localhost:9000/shipment/vt_shipment?tabletType=master"; + assertEquals(false, driver.acceptsURL(url)); + } + + @Test + public void testGetPropertyInfo() throws SQLException { + // Used to ensure that we're properly adding the below URL-based properties at the beginning + // of the full ConnectionProperties configuration + DriverPropertyInfo[] underlying = ConnectionProperties + .exposeAsDriverPropertyInfo(new Properties(), 0); + + int additionalProp = 2; + DriverPropertyInfo[] driverPropertyInfos = driver.getPropertyInfo(dbURL, null); + assertEquals(underlying.length + additionalProp, driverPropertyInfos.length); + + assertEquals(driverPropertyInfos[0].description, Constants.VITESS_HOST); + assertEquals(driverPropertyInfos[0].required, true); + assertEquals(driverPropertyInfos[0].name, Constants.Property.HOST); + assertEquals(driverPropertyInfos[0].value, "localhost"); + + assertEquals(driverPropertyInfos[1].description, Constants.VITESS_PORT); + assertEquals(driverPropertyInfos[1].required, false); + assertEquals(driverPropertyInfos[1].name, Constants.Property.PORT); + assertEquals(driverPropertyInfos[1].value, "9000"); + + // Validate the remainder of the driver properties match up with the underlying + for (int i = additionalProp; i < driverPropertyInfos.length; i++) { + assertEquals(underlying[i - additionalProp].description, driverPropertyInfos[i].description); + assertEquals(underlying[i - additionalProp].required, driverPropertyInfos[i].required); + assertEquals(underlying[i - additionalProp].name, driverPropertyInfos[i].name); + assertEquals(underlying[i - additionalProp].value, driverPropertyInfos[i].value); } + } + + @Test + public void testGetMajorVersion() { + assertEquals(driver.getMajorVersion(), Constants.DRIVER_MAJOR_VERSION); + } + + @Test + public void testGetMinorVersion() { + assertEquals(driver.getMinorVersion(), Constants.DRIVER_MINOR_VERSION); + } + + @Test + public void testJdbcCompliant() { + assertEquals(false, driver.jdbcCompliant()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java index 130d5bedf31..60cb1829107 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java @@ -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,220 +16,265 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.Test; - import io.vitess.proto.Topodata; import io.vitess.util.Constants; import java.sql.SQLException; import java.util.Properties; +import org.junit.Assert; +import org.junit.Test; + /** * Created by naveen.nahata on 18/02/16. */ public class VitessJDBCUrlTest { - @Test public void testURLwithUserNamePwd() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - - @Test public void testURLwithoutUserNamePwd() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(vitessJDBCUrl.getHostInfos().get(0).getHostname(), "hostname"); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testURLwithUserNamePwdinParams() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://hostname:15991/keyspace/catalog?userName=user&password=password", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testURLwithUserNamePwdinProperties() throws Exception { - Properties info = new Properties(); - info.setProperty("userName", "user"); - info.setProperty("password", "password"); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testURLwithUserNamePwdMultipleHost() throws Exception { - Properties info = new Properties(); - info.setProperty("userName", "user"); - info.setProperty("password", "password"); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://hostname1:15991,hostname2:15991," - + "hostname3:15991/keyspace/catalog?TABLET_TYPE=master", info); - Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); - Assert.assertEquals(Topodata.TabletType.MASTER.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testMulitpleJDBCURlURLwithUserNamePwdMultipleHost() throws Exception { - Properties info = new Properties(); - info.setProperty("userName", "user"); - info.setProperty("password", "password"); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://hostname1:15991,hostname2:15991,hostname3" - + ":15991/keyspace/catalog?TABLET_TYPE=master", info); - VitessJDBCUrl vitessJDBCUrl1 = new VitessJDBCUrl( - "jdbc:vitess://hostname1:15001,hostname2:15001,hostname3" - + ":15001/keyspace/catalog?TABLET_TYPE=master", info); - Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(3, vitessJDBCUrl1.getHostInfos().size()); - Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname1", vitessJDBCUrl1.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl1.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(1).getPort()); - Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); - Assert.assertEquals("hostname3", vitessJDBCUrl1.getHostInfos().get(2).getHostname()); - Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(2).getPort()); - Assert.assertEquals(Topodata.TabletType.MASTER.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testWithKeyspaceandCatalog() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:port/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals("catalog", vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - } - - @Test public void testWithKeyspace() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/keyspace", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - } - - @Test public void testWithoutKeyspace() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - - vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - } - - @Test public void testCompleteURL() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user:pass@hostname1:15991,hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", - info); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals("catalog", vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); - Assert.assertEquals("val2", vitessJDBCUrl.getProperties().getProperty("prop2")); - } - - @Test public void testLeaveOriginalPropertiesAlone() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user:pass@hostname1:15991,hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", - info); - - Assert.assertEquals(null, info.getProperty("prop1")); - Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); - } - - @Test public void testPropertiesTakePrecendenceOverUrl() throws SQLException { - Properties info = new Properties(); - info.setProperty("prop1", "val3"); - info.setProperty("prop2", "val4"); - - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user:pass@hostname1:15991,hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2&prop3=val3", - info); - - Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop1")); - Assert.assertEquals("val4", vitessJDBCUrl.getProperties().getProperty("prop2")); - Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop3")); - } - - @Test public void testJDBCURlURLwithLegacyTabletType() throws Exception { - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://host:12345?TABLET_TYPE=replica", null); - Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE).toUpperCase()); - } - - @Test public void testJDBCURlURLwithNewTabletType() throws Exception { - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://host:12345?tabletType=replica", null); - Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE).toUpperCase()); - } - - @Test public void testJDBCURlURLwithBothTabletType() throws Exception { - //new tablet type should supersede old tablet type. - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://host:12345?TABLET_TYPE=rdonly&tabletType=replica", null); - Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE).toUpperCase()); - } - - @Test public void testCompleteURLWithTarget() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user@h1:8080,h2:8081?target=keyspace:-80@replica&prop=val", - info); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - Assert.assertEquals("h1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(8080, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("h2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(8081, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("keyspace:-80@replica", vitessJDBCUrl.getProperties().getProperty(Constants.Property.TARGET)); - Assert.assertEquals("val", vitessJDBCUrl.getProperties().getProperty("prop")); - } + @Test + public void testURLwithUserNamePwd() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:password@hostname:15991/keyspace/catalog", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + + @Test + public void testURLwithoutUserNamePwd() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", + info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals(vitessJDBCUrl.getHostInfos().get(0).getHostname(), "hostname"); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert + .assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testURLwithUserNamePwdinParams() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://hostname:15991/keyspace/catalog?userName=user&password=password", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testURLwithUserNamePwdinProperties() throws Exception { + Properties info = new Properties(); + info.setProperty("userName", "user"); + info.setProperty("password", "password"); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", + info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testURLwithUserNamePwdMultipleHost() throws Exception { + Properties info = new Properties(); + info.setProperty("userName", "user"); + info.setProperty("password", "password"); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://hostname1:15991,hostname2:15991," + + "hostname3:15991/keyspace/catalog?TABLET_TYPE=master", info); + Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); + Assert.assertEquals(Topodata.TabletType.MASTER.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testMulitpleJDBCURlURLwithUserNamePwdMultipleHost() throws Exception { + Properties info = new Properties(); + info.setProperty("userName", "user"); + info.setProperty("password", "password"); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://hostname1:15991,hostname2:15991,hostname3" + + ":15991/keyspace/catalog?TABLET_TYPE=master", info); + VitessJDBCUrl vitessJDBCUrl1 = new VitessJDBCUrl( + "jdbc:vitess://hostname1:15001,hostname2:15001,hostname3" + + ":15001/keyspace/catalog?TABLET_TYPE=master", info); + Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals(3, vitessJDBCUrl1.getHostInfos().size()); + Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname1", vitessJDBCUrl1.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl1.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(1).getPort()); + Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); + Assert.assertEquals("hostname3", vitessJDBCUrl1.getHostInfos().get(2).getHostname()); + Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(2).getPort()); + Assert.assertEquals(Topodata.TabletType.MASTER.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testWithKeyspaceandCatalog() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:password@hostname:port/keyspace/catalog", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals("catalog", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + } + + @Test + public void testWithKeyspace() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:password@hostname:15991/keyspace", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + } + + @Test + public void testWithoutKeyspace() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991", + info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert + .assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + + vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert + .assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + } + + @Test + public void testCompleteURL() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:pass@hostname1:15991," + + "hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", + info); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals("catalog", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); + Assert.assertEquals("val2", vitessJDBCUrl.getProperties().getProperty("prop2")); + } + + @Test + public void testLeaveOriginalPropertiesAlone() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:pass@hostname1:15991," + + "hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", + info); + + Assert.assertEquals(null, info.getProperty("prop1")); + Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); + } + + @Test + public void testPropertiesTakePrecendenceOverUrl() throws SQLException { + Properties info = new Properties(); + info.setProperty("prop1", "val3"); + info.setProperty("prop2", "val4"); + + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:pass@hostname1:15991," + + "hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2&prop3=val3", + info); + + Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop1")); + Assert.assertEquals("val4", vitessJDBCUrl.getProperties().getProperty("prop2")); + Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop3")); + } + + @Test + public void testJDBCURlURLwithLegacyTabletType() throws Exception { + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://host:12345?TABLET_TYPE=replica", + null); + Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE) + .toUpperCase()); + } + + @Test + public void testJDBCURlURLwithNewTabletType() throws Exception { + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://host:12345?tabletType=replica", + null); + Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE) + .toUpperCase()); + } + + @Test + public void testJDBCURlURLwithBothTabletType() throws Exception { + //new tablet type should supersede old tablet type. + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://host:12345?TABLET_TYPE=rdonly&tabletType=replica", null); + Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE) + .toUpperCase()); + } + + @Test + public void testCompleteURLWithTarget() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user@h1:8080,h2:8081?target=keyspace:-80@replica&prop=val", info); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + Assert.assertEquals("h1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(8080, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("h2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(8081, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("keyspace:-80@replica", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TARGET)); + Assert.assertEquals("val", vitessJDBCUrl.getProperties().getProperty("prop")); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java index 57212aa40d5..a7374dfe47c 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java @@ -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,6 +16,10 @@ package io.vitess.jdbc; +import java.sql.ParameterMetaData; +import java.sql.SQLException; +import java.sql.Types; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,67 +28,68 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import java.sql.ParameterMetaData; -import java.sql.SQLException; -import java.sql.Types; - @RunWith(PowerMockRunner.class) @PrepareForTest(VitessParameterMetaData.class) public class VitessParameterMetaDataTest { - @Test - public void testValidSimpleResponses() throws SQLException { - VitessParameterMetaData metaData = new VitessParameterMetaData(5); - Assert.assertEquals("parameterCount", 5, metaData.getParameterCount()); - Assert.assertEquals("parameterMode", ParameterMetaData.parameterModeIn, metaData.getParameterMode(2)); - Assert.assertEquals("parameterType", Types.VARCHAR, metaData.getParameterType(2)); - Assert.assertEquals("precision", 0, metaData.getPrecision(2)); - Assert.assertEquals("scale", 0, metaData.getScale(2)); - Assert.assertEquals("parameterClassName", "java.lang.String", metaData.getParameterClassName(2)); - Assert.assertEquals("parameterTypeName", "VARCHAR", metaData.getParameterTypeName(2)); - Assert.assertEquals("signed", false, metaData.isSigned(2)); - } + @Test + public void testValidSimpleResponses() throws SQLException { + VitessParameterMetaData metaData = new VitessParameterMetaData(5); + Assert.assertEquals("parameterCount", 5, metaData.getParameterCount()); + Assert.assertEquals("parameterMode", ParameterMetaData.parameterModeIn, + metaData.getParameterMode(2)); + Assert.assertEquals("parameterType", Types.VARCHAR, metaData.getParameterType(2)); + Assert.assertEquals("precision", 0, metaData.getPrecision(2)); + Assert.assertEquals("scale", 0, metaData.getScale(2)); + Assert + .assertEquals("parameterClassName", "java.lang.String", metaData.getParameterClassName(2)); + Assert.assertEquals("parameterTypeName", "VARCHAR", metaData.getParameterTypeName(2)); + Assert.assertEquals("signed", false, metaData.isSigned(2)); + } - @Test - public void testOutOfBoundsValidation() { - int parameterCount = 1; - VitessParameterMetaData metaData = new VitessParameterMetaData(parameterCount); + @Test + public void testOutOfBoundsValidation() { + int parameterCount = 1; + VitessParameterMetaData metaData = new VitessParameterMetaData(parameterCount); - try { - metaData.getParameterType(0); - Assert.fail(); - } catch (SQLException e) { - Assert.assertEquals("Parameter index of '0' is invalid.", e.getMessage()); - } + try { + metaData.getParameterType(0); + Assert.fail(); + } catch (SQLException e) { + Assert.assertEquals("Parameter index of '0' is invalid.", e.getMessage()); + } - int paramNumber = 2; - try { - metaData.getParameterType(paramNumber); - Assert.fail(); - } catch (SQLException e) { - Assert.assertEquals("Parameter index of '" + paramNumber + "' is greater than number of parameters, which is '" + parameterCount + "'.", e.getMessage()); - } + int paramNumber = 2; + try { + metaData.getParameterType(paramNumber); + Assert.fail(); + } catch (SQLException e) { + Assert.assertEquals("Parameter index of '" + paramNumber + + "' is greater than number of parameters, which is '" + parameterCount + "'.", + e.getMessage()); } + } - @Test - public void testOutOfBoundCoverage() throws Exception { - int param = 2; - VitessParameterMetaData metaData = PowerMockito.spy(new VitessParameterMetaData(5)); + @Test + public void testOutOfBoundCoverage() throws Exception { + int param = 2; + VitessParameterMetaData metaData = PowerMockito.spy(new VitessParameterMetaData(5)); - metaData.getParameterType(param); - metaData.getPrecision(param); - metaData.getScale(param); - metaData.getParameterClassName(param); - metaData.getParameterTypeName(param); - metaData.isSigned(param); + metaData.getParameterType(param); + metaData.getPrecision(param); + metaData.getScale(param); + metaData.getParameterClassName(param); + metaData.getParameterTypeName(param); + metaData.isSigned(param); - PowerMockito.verifyPrivate(metaData, VerificationModeFactory.times(6)).invoke("checkBounds", param); - } + PowerMockito.verifyPrivate(metaData, VerificationModeFactory.times(6)) + .invoke("checkBounds", param); + } - @Test(expected = SQLException.class) - public void testNullableNotAvailable() throws SQLException { - VitessParameterMetaData metaData = new VitessParameterMetaData(5); - metaData.isNullable(3); - Assert.fail(); - } + @Test(expected = SQLException.class) + public void testNullableNotAvailable() throws SQLException { + VitessParameterMetaData metaData = new VitessParameterMetaData(5); + metaData.isNullable(3); + Assert.fail(); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java index 95512fd6f8d..8d89e4daeea 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java @@ -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,15 +16,15 @@ package io.vitess.jdbc; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.anyString; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + import com.google.common.collect.ImmutableMap; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Matchers; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import io.vitess.client.Context; import io.vitess.client.SQLFuture; @@ -37,7 +37,6 @@ import io.vitess.proto.Vtrpc; import io.vitess.util.Constants; -import javax.sql.rowset.serial.SerialClob; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; @@ -55,707 +54,696 @@ import java.util.Map; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMap; -import static org.mockito.Matchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; +import javax.sql.rowset.serial.SerialClob; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 09/02/16. */ -@RunWith(PowerMockRunner.class) @PrepareForTest({VTGateConnection.class, - Vtrpc.RPCError.class}) public class VitessPreparedStatementTest { - - private String sqlSelect = "select 1 from test_table"; - private String sqlShow = "show tables"; - private String sqlUpdate = "update test_table set msg = null"; - private String sqlInsert = "insert into test_table(msg) values (?)"; - - @Test public void testStatementExecute() { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement preparedStatement; - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.executeQuery(sqlSelect); - fail("Should have thrown exception for calling this method"); - } catch (SQLException ex) { - assertEquals("This method cannot be called using this class object", - ex.getMessage()); - } - - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.executeUpdate(sqlUpdate); - fail("Should have thrown exception for calling this method"); - } catch (SQLException ex) { - assertEquals("This method cannot be called using this class object", - ex.getMessage()); - } - - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.execute(sqlShow); - fail("Should have thrown exception for calling this method"); - } catch (SQLException ex) { - assertEquals("This method cannot be called using this class object", - ex.getMessage()); - } +@RunWith(PowerMockRunner.class) +@PrepareForTest({VTGateConnection.class, Vtrpc.RPCError.class}) +public class VitessPreparedStatementTest { + + private String sqlSelect = "select 1 from test_table"; + private String sqlShow = "show tables"; + private String sqlUpdate = "update test_table set msg = null"; + private String sqlInsert = "insert into test_table(msg) values (?)"; + + @Test + public void testStatementExecute() { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement preparedStatement; + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.executeQuery(sqlSelect); + fail("Should have thrown exception for calling this method"); + } catch (SQLException ex) { + assertEquals("This method cannot be called using this class object", ex.getMessage()); } - @Test public void testExecuteQuery() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(),any(VTSession.class))). - thenReturn(mockSqlFutureCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - VitessPreparedStatement preparedStatement; - try { - - //Empty Sql Statement - try { - new VitessPreparedStatement(mockConn, ""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - //show query - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - ResultSet rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica with bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica without bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - - //select on master - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - try { - //when returned cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - preparedStatement.executeQuery(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.executeUpdate(sqlUpdate); + fail("Should have thrown exception for calling this method"); + } catch (SQLException ex) { + assertEquals("This method cannot be called using this class object", ex.getMessage()); } - @Test public void testExecuteQueryWithStream() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.STREAM); - - VitessPreparedStatement preparedStatement; - try { - - //Empty Sql Statement - try { - new VitessPreparedStatement(mockConn, ""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - //show query - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - ResultSet rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica with bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica without bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - - //select on master - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - try { - //when returned cursor is null - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(null); - preparedStatement.executeQuery(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.execute(sqlShow); + fail("Should have thrown exception for calling this method"); + } catch (SQLException ex) { + assertEquals("This method cannot be called using this class object", ex.getMessage()); } - - - @Test public void testExecuteUpdate() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List fieldList = mock(ArrayList.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessPreparedStatement preparedStatement; - try { - - //executing dml on master - preparedStatement = - new VitessPreparedStatement(mockConn, sqlUpdate, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - int updateCount = preparedStatement.executeUpdate(); - assertEquals(0, updateCount); - - //tx is null & autoCommit is true - when(mockConn.getAutoCommit()).thenReturn(true); - preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); - updateCount = preparedStatement.executeUpdate(); - assertEquals(0, updateCount); - - //cursor fields is not null - when(mockCursor.getFields()).thenReturn(fieldList); - when(fieldList.isEmpty()).thenReturn(false); - try { - preparedStatement.executeUpdate(); - fail("Should have thrown exception for field not null"); - } catch (SQLException ex) { - assertEquals("ResultSet generation is not allowed through this method", - ex.getMessage()); - } - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - preparedStatement.executeUpdate(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - preparedStatement.executeUpdate(); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - preparedStatement.executeBatch(); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + } + + @Test + public void testExecuteQuery() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))). + thenReturn(mockSqlFutureCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + VitessPreparedStatement preparedStatement; + try { + + //Empty Sql Statement + try { + new VitessPreparedStatement(mockConn, ""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); + } + + //show query + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + ResultSet rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica with bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica without bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on master + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + try { + //when returned cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + preparedStatement.executeQuery(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testExecute() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List mockFieldList = PowerMockito.spy(new ArrayList<>()); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + } + + @Test + public void testExecuteQueryWithStream() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.STREAM); + + VitessPreparedStatement preparedStatement; + try { + + //Empty Sql Statement + try { + new VitessPreparedStatement(mockConn, ""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); + } + + //show query + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + ResultSet rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica with bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica without bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on master + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + try { + //when returned cursor is null when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - - when(mockConn.getAutoCommit()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(mockFieldList); - - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - try { - - int fieldSize = 5; - when(mockCursor.getFields()).thenReturn(mockFieldList); - PowerMockito.doReturn(fieldSize).when(mockFieldList).size(); - PowerMockito.doReturn(false).when(mockFieldList).isEmpty(); - boolean hasResultSet = preparedStatement.execute(); - Assert.assertTrue(hasResultSet); - Assert.assertNotNull(preparedStatement.getResultSet()); - - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - hasResultSet = preparedStatement.execute(); - Assert.assertTrue(hasResultSet); - Assert.assertNotNull(preparedStatement.getResultSet()); - - int mockUpdateCount = 10; - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); - preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); - hasResultSet = preparedStatement.execute(); - Assert.assertFalse(hasResultSet); - Assert.assertNull(preparedStatement.getResultSet()); - assertEquals(mockUpdateCount, preparedStatement.getUpdateCount()); - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.execute(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(null); + preparedStatement.executeQuery(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testExecuteFetchSizeAsStreaming() throws SQLException { - testExecute(5, true, false, true); - testExecute(5, false, false, true); - testExecute(0, true, true, false); - testExecute(0, false, false, true); + } + + + @Test + public void testExecuteUpdate() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List fieldList = mock(ArrayList.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessPreparedStatement preparedStatement; + try { + + //executing dml on master + preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + int updateCount = preparedStatement.executeUpdate(); + assertEquals(0, updateCount); + + //tx is null & autoCommit is true + when(mockConn.getAutoCommit()).thenReturn(true); + preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); + updateCount = preparedStatement.executeUpdate(); + assertEquals(0, updateCount); + + //cursor fields is not null + when(mockCursor.getFields()).thenReturn(fieldList); + when(fieldList.isEmpty()).thenReturn(false); + try { + preparedStatement.executeUpdate(); + fail("Should have thrown exception for field not null"); + } catch (SQLException ex) { + assertEquals("ResultSet generation is not allowed through this method", ex.getMessage()); + } + + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + preparedStatement.executeUpdate(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + preparedStatement.executeUpdate(); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); + } + + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + preparedStatement.executeBatch(); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, boolean shouldRunStreamExecute) throws SQLException { - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - - VitessConnection mockConn = mock(VitessConnection.class); - when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlSelect); - statement.setFetchSize(fetchSize); - statement.executeQuery(); - - if (shouldRunExecute) { - Mockito.verify(mockVtGateConn, Mockito.times(2)).execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } - - if (shouldRunStreamExecute) { - Mockito.verify(mockVtGateConn).streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } + } + + @Test + public void testExecute() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List mockFieldList = PowerMockito.spy(new ArrayList<>()); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + + when(mockConn.getAutoCommit()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(mockFieldList); + + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + try { + + int fieldSize = 5; + when(mockCursor.getFields()).thenReturn(mockFieldList); + PowerMockito.doReturn(fieldSize).when(mockFieldList).size(); + PowerMockito.doReturn(false).when(mockFieldList).isEmpty(); + boolean hasResultSet = preparedStatement.execute(); + Assert.assertTrue(hasResultSet); + Assert.assertNotNull(preparedStatement.getResultSet()); + + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + hasResultSet = preparedStatement.execute(); + Assert.assertTrue(hasResultSet); + Assert.assertNotNull(preparedStatement.getResultSet()); + + int mockUpdateCount = 10; + when(mockCursor.getFields()) + .thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); + preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); + hasResultSet = preparedStatement.execute(); + Assert.assertFalse(hasResultSet); + Assert.assertNull(preparedStatement.getResultSet()); + assertEquals(mockUpdateCount, preparedStatement.getUpdateCount()); + + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.execute(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testGetUpdateCount() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFuture = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFuture); - when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect); - try { - - when(mockCursor.getRowsAffected()).thenReturn(10L); - int updateCount = preparedStatement.executeUpdate(); - assertEquals(10L, updateCount); - assertEquals(10L, preparedStatement.getUpdateCount()); - - // Truncated Update Count - when(mockCursor.getRowsAffected()) - .thenReturn((long) Integer.MAX_VALUE + 10); - updateCount = preparedStatement.executeUpdate(); - assertEquals(Integer.MAX_VALUE, updateCount); - assertEquals(Integer.MAX_VALUE, preparedStatement.getUpdateCount()); - - when(mockConn.isSimpleExecute()).thenReturn(true); - preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + } + + @Test + public void testExecuteFetchSizeAsStreaming() throws SQLException { + testExecute(5, true, false, true); + testExecute(5, false, false, true); + testExecute(0, true, true, false); + testExecute(0, false, false, true); + } + + private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, + boolean shouldRunStreamExecute) throws SQLException { + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + + VitessConnection mockConn = mock(VitessConnection.class); + when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlSelect); + statement.setFetchSize(fetchSize); + statement.executeQuery(); + + if (shouldRunExecute) { + Mockito.verify(mockVtGateConn, Mockito.times(2)) + .execute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - @Test public void testSetParameters() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect); - Boolean boolValue = true; - Byte byteValue = Byte.MAX_VALUE; - Short shortValue = Short.MAX_VALUE; - Integer intValue = Integer.MAX_VALUE; - Long longValue = Long.MAX_VALUE; - Float floatValue = Float.MAX_VALUE; - Double doubleValue = Double.MAX_VALUE; - BigDecimal bigDecimalValue = new BigDecimal(3.14159265358979323846); - BigDecimal expectedDecimalValue = new BigDecimal("3.14159"); - BigInteger bigIntegerValue = new BigInteger("18446744073709551615"); - String stringValue = "vitess"; - byte[] bytesValue = stringValue.getBytes(); - Date dateValue = new Date(0); - // Use a time value that won't go negative after adjusting for time zone. - // The java.sql.Time class does not properly format negative times. - Time timeValue = new Time(12 * 60 * 60 * 1000); - Timestamp timestampValue = new Timestamp(0); - - preparedStatement.setNull(1, Types.INTEGER); - preparedStatement.setBoolean(2, boolValue); - preparedStatement.setByte(3, byteValue); - preparedStatement.setShort(4, shortValue); - preparedStatement.setInt(5, intValue); - preparedStatement.setLong(6, longValue); - preparedStatement.setFloat(7, floatValue); - preparedStatement.setDouble(8, doubleValue); - preparedStatement.setBigDecimal(9, bigDecimalValue); - preparedStatement.setBigInteger(10, bigIntegerValue); - preparedStatement.setString(11, stringValue); - preparedStatement.setBytes(12, bytesValue); - preparedStatement.setDate(13, dateValue); - preparedStatement.setTime(14, timeValue); - preparedStatement.setTimestamp(15, timestampValue); - preparedStatement.setDate(16, dateValue, Calendar.getInstance(TimeZone.getDefault())); - preparedStatement.setTime(17, timeValue, Calendar.getInstance(TimeZone.getDefault())); - preparedStatement - .setTimestamp(18, timestampValue, Calendar.getInstance(TimeZone.getDefault())); - preparedStatement.setObject(19, boolValue); - preparedStatement.setObject(20, byteValue); - preparedStatement.setObject(21, shortValue); - preparedStatement.setObject(22, intValue); - preparedStatement.setObject(23, longValue); - preparedStatement.setObject(24, floatValue); - preparedStatement.setObject(25, doubleValue); - preparedStatement.setObject(26, bigDecimalValue); - preparedStatement.setObject(27, bigIntegerValue); - preparedStatement.setObject(28, stringValue); - preparedStatement.setObject(29, dateValue); - preparedStatement.setObject(30, timeValue); - preparedStatement.setObject(31, timestampValue); - preparedStatement.setObject(32, 'a'); - preparedStatement.setObject(33, null); - preparedStatement.setObject(34, boolValue, Types.BOOLEAN, 0); - preparedStatement.setObject(35, shortValue, Types.SMALLINT, 0); - preparedStatement.setObject(36, longValue, Types.BIGINT, 0); - preparedStatement.setObject(37, floatValue, Types.DOUBLE, 2); - preparedStatement.setObject(38, doubleValue, Types.DOUBLE, 3); - preparedStatement.setObject(39, bigDecimalValue, Types.DECIMAL, 5); - preparedStatement.setObject(40, stringValue, Types.VARCHAR, 0); - preparedStatement.setObject(41, dateValue, Types.DATE, 0); - preparedStatement.setObject(42, timeValue, Types.TIME, 0); - preparedStatement.setObject(43, timestampValue, Types.TIMESTAMP, 0); - preparedStatement.setClob(44, new SerialClob("clob".toCharArray())); - preparedStatement.setObject(45, bytesValue); - Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); - bindVariablesMap.setAccessible(true); - Map bindVariables = - (Map) bindVariablesMap.get(preparedStatement); - assertEquals(null, bindVariables.get("v1")); - assertEquals(boolValue, bindVariables.get("v2")); - assertEquals(byteValue, bindVariables.get("v3")); - assertEquals(shortValue, bindVariables.get("v4")); - assertEquals(intValue, bindVariables.get("v5")); - assertEquals(longValue, bindVariables.get("v6")); - assertEquals(floatValue, bindVariables.get("v7")); - assertEquals(doubleValue, bindVariables.get("v8")); - assertEquals(bigDecimalValue, bindVariables.get("v9")); - assertEquals(bigIntegerValue, bindVariables.get("v10")); - assertEquals(stringValue, bindVariables.get("v11")); - assertEquals(bytesValue, bindVariables.get("v12")); - assertEquals(dateValue.toString(), bindVariables.get("v13")); - assertEquals(timeValue.toString(), bindVariables.get("v14")); - assertEquals(timestampValue.toString(), bindVariables.get("v15")); - assertEquals(dateValue.toString(), bindVariables.get("v16")); - assertEquals(timeValue.toString(), bindVariables.get("v17")); - assertEquals(timestampValue.toString(), bindVariables.get("v18")); - assertEquals(boolValue, bindVariables.get("v19")); - assertEquals(byteValue, bindVariables.get("v20")); - assertEquals(shortValue, bindVariables.get("v21")); - assertEquals(intValue, bindVariables.get("v22")); - assertEquals(longValue, bindVariables.get("v23")); - assertEquals(floatValue, bindVariables.get("v24")); - assertEquals(doubleValue, bindVariables.get("v25")); - assertEquals(bigDecimalValue, bindVariables.get("v26")); - assertEquals(bigIntegerValue, bindVariables.get("v27")); - assertEquals(stringValue, bindVariables.get("v28")); - assertEquals(dateValue.toString(), bindVariables.get("v29")); - assertEquals(timeValue.toString(), bindVariables.get("v30")); - assertEquals(timestampValue.toString(), bindVariables.get("v31")); - assertEquals("a", bindVariables.get("v32")); - assertEquals(null, bindVariables.get("v33")); - assertEquals(true, bindVariables.get("v34")); - assertEquals(shortValue.intValue(), bindVariables.get("v35")); - assertEquals(longValue, bindVariables.get("v36")); - assertEquals((double) floatValue, (double) bindVariables.get("v37"), 0.1); - assertEquals(doubleValue, (double) bindVariables.get("v38"), 0.1); - assertEquals(expectedDecimalValue, bindVariables.get("v39")); - assertEquals(stringValue, bindVariables.get("v40")); - assertEquals(dateValue.toString(), bindVariables.get("v41")); - assertEquals(timeValue.toString(), bindVariables.get("v42")); - assertEquals(timestampValue.toString(), bindVariables.get("v43")); - assertEquals("clob", bindVariables.get("v44")); - Assert.assertArrayEquals(bytesValue, (byte[])bindVariables.get("v45")); - - preparedStatement.clearParameters(); + if (shouldRunStreamExecute) { + Mockito.verify(mockVtGateConn) + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - - @Test public void testTreatUtilDateAsTimestamp() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect); - - java.util.Date utilDateValue = new java.util.Date(System.currentTimeMillis()); - Timestamp timestamp = new Timestamp(utilDateValue.getTime()); - try { - preparedStatement.setObject(1, utilDateValue); - fail("setObject on java.util.Date should have failed with SQLException"); - } catch (SQLException e) { - Assert.assertTrue(e.getMessage().startsWith(Constants.SQLExceptionMessages.SQL_TYPE_INFER)); - } - - preparedStatement.clearParameters(); - - Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); - preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); - preparedStatement.setObject(1, utilDateValue); - - Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); - bindVariablesMap.setAccessible(true); - Map bindVariables = - (Map) bindVariablesMap.get(preparedStatement); - - assertEquals(DateTime.formatTimestamp(timestamp), bindVariables.get("v1")); + } + + @Test + public void testGetUpdateCount() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFuture = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFuture); + when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + try { + + when(mockCursor.getRowsAffected()).thenReturn(10L); + int updateCount = preparedStatement.executeUpdate(); + assertEquals(10L, updateCount); + assertEquals(10L, preparedStatement.getUpdateCount()); + + // Truncated Update Count + when(mockCursor.getRowsAffected()).thenReturn((long) Integer.MAX_VALUE + 10); + updateCount = preparedStatement.executeUpdate(); + assertEquals(Integer.MAX_VALUE, updateCount); + assertEquals(Integer.MAX_VALUE, preparedStatement.getUpdateCount()); + + when(mockConn.isSimpleExecute()).thenReturn(true); + preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testAutoGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - try { - - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122}; - int expectedAffectedRows = 2; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()) - .thenReturn(Long.valueOf(expectedAffectedRows)); - - //Executing Insert Statement - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlInsert, Statement.RETURN_GENERATED_KEYS); - int updateCount = preparedStatement.executeUpdate(); - assertEquals(expectedAffectedRows, updateCount); - - ResultSet rs = preparedStatement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i++], generatedId); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + } + + @Test + public void testSetParameters() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + Boolean boolValue = true; + Byte byteValue = Byte.MAX_VALUE; + Short shortValue = Short.MAX_VALUE; + Integer intValue = Integer.MAX_VALUE; + Long longValue = Long.MAX_VALUE; + Float floatValue = Float.MAX_VALUE; + Double doubleValue = Double.MAX_VALUE; + BigDecimal bigDecimalValue = new BigDecimal(3.14159265358979323846); + BigDecimal expectedDecimalValue = new BigDecimal("3.14159"); + BigInteger bigIntegerValue = new BigInteger("18446744073709551615"); + String stringValue = "vitess"; + byte[] bytesValue = stringValue.getBytes(); + Date dateValue = new Date(0); + // Use a time value that won't go negative after adjusting for time zone. + // The java.sql.Time class does not properly format negative times. + Time timeValue = new Time(12 * 60 * 60 * 1000); + Timestamp timestampValue = new Timestamp(0); + + preparedStatement.setNull(1, Types.INTEGER); + preparedStatement.setBoolean(2, boolValue); + preparedStatement.setByte(3, byteValue); + preparedStatement.setShort(4, shortValue); + preparedStatement.setInt(5, intValue); + preparedStatement.setLong(6, longValue); + preparedStatement.setFloat(7, floatValue); + preparedStatement.setDouble(8, doubleValue); + preparedStatement.setBigDecimal(9, bigDecimalValue); + preparedStatement.setBigInteger(10, bigIntegerValue); + preparedStatement.setString(11, stringValue); + preparedStatement.setBytes(12, bytesValue); + preparedStatement.setDate(13, dateValue); + preparedStatement.setTime(14, timeValue); + preparedStatement.setTimestamp(15, timestampValue); + preparedStatement.setDate(16, dateValue, Calendar.getInstance(TimeZone.getDefault())); + preparedStatement.setTime(17, timeValue, Calendar.getInstance(TimeZone.getDefault())); + preparedStatement.setTimestamp(18, timestampValue, Calendar.getInstance(TimeZone.getDefault())); + preparedStatement.setObject(19, boolValue); + preparedStatement.setObject(20, byteValue); + preparedStatement.setObject(21, shortValue); + preparedStatement.setObject(22, intValue); + preparedStatement.setObject(23, longValue); + preparedStatement.setObject(24, floatValue); + preparedStatement.setObject(25, doubleValue); + preparedStatement.setObject(26, bigDecimalValue); + preparedStatement.setObject(27, bigIntegerValue); + preparedStatement.setObject(28, stringValue); + preparedStatement.setObject(29, dateValue); + preparedStatement.setObject(30, timeValue); + preparedStatement.setObject(31, timestampValue); + preparedStatement.setObject(32, 'a'); + preparedStatement.setObject(33, null); + preparedStatement.setObject(34, boolValue, Types.BOOLEAN, 0); + preparedStatement.setObject(35, shortValue, Types.SMALLINT, 0); + preparedStatement.setObject(36, longValue, Types.BIGINT, 0); + preparedStatement.setObject(37, floatValue, Types.DOUBLE, 2); + preparedStatement.setObject(38, doubleValue, Types.DOUBLE, 3); + preparedStatement.setObject(39, bigDecimalValue, Types.DECIMAL, 5); + preparedStatement.setObject(40, stringValue, Types.VARCHAR, 0); + preparedStatement.setObject(41, dateValue, Types.DATE, 0); + preparedStatement.setObject(42, timeValue, Types.TIME, 0); + preparedStatement.setObject(43, timestampValue, Types.TIMESTAMP, 0); + preparedStatement.setClob(44, new SerialClob("clob".toCharArray())); + preparedStatement.setObject(45, bytesValue); + Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); + bindVariablesMap.setAccessible(true); + Map bindVariables = (Map) bindVariablesMap + .get(preparedStatement); + assertEquals(null, bindVariables.get("v1")); + assertEquals(boolValue, bindVariables.get("v2")); + assertEquals(byteValue, bindVariables.get("v3")); + assertEquals(shortValue, bindVariables.get("v4")); + assertEquals(intValue, bindVariables.get("v5")); + assertEquals(longValue, bindVariables.get("v6")); + assertEquals(floatValue, bindVariables.get("v7")); + assertEquals(doubleValue, bindVariables.get("v8")); + assertEquals(bigDecimalValue, bindVariables.get("v9")); + assertEquals(bigIntegerValue, bindVariables.get("v10")); + assertEquals(stringValue, bindVariables.get("v11")); + assertEquals(bytesValue, bindVariables.get("v12")); + assertEquals(dateValue.toString(), bindVariables.get("v13")); + assertEquals(timeValue.toString(), bindVariables.get("v14")); + assertEquals(timestampValue.toString(), bindVariables.get("v15")); + assertEquals(dateValue.toString(), bindVariables.get("v16")); + assertEquals(timeValue.toString(), bindVariables.get("v17")); + assertEquals(timestampValue.toString(), bindVariables.get("v18")); + assertEquals(boolValue, bindVariables.get("v19")); + assertEquals(byteValue, bindVariables.get("v20")); + assertEquals(shortValue, bindVariables.get("v21")); + assertEquals(intValue, bindVariables.get("v22")); + assertEquals(longValue, bindVariables.get("v23")); + assertEquals(floatValue, bindVariables.get("v24")); + assertEquals(doubleValue, bindVariables.get("v25")); + assertEquals(bigDecimalValue, bindVariables.get("v26")); + assertEquals(bigIntegerValue, bindVariables.get("v27")); + assertEquals(stringValue, bindVariables.get("v28")); + assertEquals(dateValue.toString(), bindVariables.get("v29")); + assertEquals(timeValue.toString(), bindVariables.get("v30")); + assertEquals(timestampValue.toString(), bindVariables.get("v31")); + assertEquals("a", bindVariables.get("v32")); + assertEquals(null, bindVariables.get("v33")); + assertEquals(true, bindVariables.get("v34")); + assertEquals(shortValue.intValue(), bindVariables.get("v35")); + assertEquals(longValue, bindVariables.get("v36")); + assertEquals((double) floatValue, (double) bindVariables.get("v37"), 0.1); + assertEquals(doubleValue, (double) bindVariables.get("v38"), 0.1); + assertEquals(expectedDecimalValue, bindVariables.get("v39")); + assertEquals(stringValue, bindVariables.get("v40")); + assertEquals(dateValue.toString(), bindVariables.get("v41")); + assertEquals(timeValue.toString(), bindVariables.get("v42")); + assertEquals(timestampValue.toString(), bindVariables.get("v43")); + assertEquals("clob", bindVariables.get("v44")); + Assert.assertArrayEquals(bytesValue, (byte[]) bindVariables.get("v45")); + + preparedStatement.clearParameters(); + } + + @Test + public void testTreatUtilDateAsTimestamp() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + + java.util.Date utilDateValue = new java.util.Date(System.currentTimeMillis()); + Timestamp timestamp = new Timestamp(utilDateValue.getTime()); + try { + preparedStatement.setObject(1, utilDateValue); + fail("setObject on java.util.Date should have failed with SQLException"); + } catch (SQLException e) { + Assert.assertTrue(e.getMessage().startsWith(Constants.SQLExceptionMessages.SQL_TYPE_INFER)); } - @Test public void testAddBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); - try { - statement.addBatch(this.sqlInsert); - fail("Should have thrown Exception"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED, ex.getMessage()); - } - statement.setString(1, "string1"); - statement.addBatch(); - try { - Field privateStringField = - VitessPreparedStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - assertEquals("string1", - (((List>) privateStringField.get(statement)).get(0)).get("v1")); - } catch (NoSuchFieldException e) { - fail("Private Field should exists: batchedArgs"); - } catch (IllegalAccessException e) { - fail("Private Field should be accessible: batchedArgs"); - } + preparedStatement.clearParameters(); + + Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + preparedStatement.setObject(1, utilDateValue); + + Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); + bindVariablesMap.setAccessible(true); + Map bindVariables = (Map) bindVariablesMap + .get(preparedStatement); + + assertEquals(DateTime.formatTimestamp(timestamp), bindVariables.get("v1")); + } + + @Test + public void testAutoGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + try { + + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122}; + int expectedAffectedRows = 2; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedAffectedRows)); + + //Executing Insert Statement + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlInsert, + Statement.RETURN_GENERATED_KEYS); + int updateCount = preparedStatement.executeUpdate(); + assertEquals(expectedAffectedRows, updateCount); + + ResultSet rs = preparedStatement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i++], generatedId); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testClearBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); - statement.setString(1, "string1"); - statement.addBatch(); - statement.clearBatch(); - try { - Field privateStringField = - VitessPreparedStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - Assert.assertTrue( - ((List>) privateStringField.get(statement)).isEmpty()); - } catch (NoSuchFieldException e) { - fail("Private Field should exists: batchedArgs"); - } catch (IllegalAccessException e) { - fail("Private Field should be accessible: batchedArgs"); - } + } + + @Test + public void testAddBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); + try { + statement.addBatch(this.sqlInsert); + fail("Should have thrown Exception"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED, ex.getMessage()); } - - @Test public void testExecuteBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); - int[] updateCounts = statement.executeBatch(); - assertEquals(0, updateCounts.length); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockVtGateConn - .executeBatch(any(Context.class), Matchers.anyList(), Matchers.anyList(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError1 = mock(CursorWithError.class); - when(mockCursorWithError1.getError()).thenReturn(null); - when(mockCursorWithError1.getCursor()) - .thenReturn(mock(Cursor.class)); - mockCursorWithErrorList.add(mockCursorWithError1); - - statement.setString(1, "string1"); - statement.addBatch(); - updateCounts = statement.executeBatch(); - assertEquals(1, updateCounts.length); - - CursorWithError mockCursorWithError2 = mock(CursorWithError.class); - Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder().setMessage("preparedStatement execute batch error").build(); - when(mockCursorWithError2.getError()) - .thenReturn(rpcError); - mockCursorWithErrorList.add(mockCursorWithError2); - statement.setString(1, "string1"); - statement.addBatch(); - statement.setString(1, "string2"); - statement.addBatch(); - try { - statement.executeBatch(); - fail("Should have thrown Exception"); - } catch (BatchUpdateException ex) { - assertEquals(rpcError.toString(), ex.getMessage()); - assertEquals(2, ex.getUpdateCounts().length); - assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); - } + statement.setString(1, "string1"); + statement.addBatch(); + try { + Field privateStringField = VitessPreparedStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + assertEquals("string1", + (((List>) privateStringField.get(statement)).get(0)).get("v1")); + } catch (NoSuchFieldException e) { + fail("Private Field should exists: batchedArgs"); + } catch (IllegalAccessException e) { + fail("Private Field should be accessible: batchedArgs"); } - - @Test public void testStatementCount() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Map testCases = ImmutableMap.builder() - .put("select * from foo where a = ?", 1) - .put("select * from foo where a = ? and b = ?", 2) - .put("select * from foo where a = ? and b = \"?\"", 1) - .put("select * from foo where a = ? and b = '?'", 1) - .put("select * from foo where a = ? and b = `?`", 1) - .put("select foo.*, `bar.baz?` from foo, bar where foo.a = ? and bar.b = foo.b", 1) - .put("select * from foo where a = ? and b = \"`?`\"", 1) - .put("select * from foo where a = ? --and b = ?", 1) - .put("select * from foo where a = ? /* and b = ? */ and c = ?", 2) - .put("/* leading comment? */ select * from foo where a = ? and b = ?", 2) - .put("select * from foo where a = ? and b = ? and c = 'test' and d = ?", 3) - .put("select * from foo where a = ? and b = \\`?\\`", 2) // not valid sql but validates escaping - .put("select * from foo where a = ? and b = \\?", 1) // not valid sql but validates escaping - .put("update foo set a = ?, b = ? where c = 'test' and d = ?", 3) - .put("insert into foo (`a`, `b`) values (?, ?), (?, ?) on /* test? */ duplicate key update a = \"?\"", 4) - .put("delete from foo where a = ? and b = '?'", 1) - .build(); - - for (Map.Entry testCase : testCases.entrySet()) { - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, testCase.getKey()); - assertEquals(testCase.getKey(), testCase.getValue().longValue(), statement.getParameterMetaData().getParameterCount()); - } + } + + @Test + public void testClearBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); + statement.setString(1, "string1"); + statement.addBatch(); + statement.clearBatch(); + try { + Field privateStringField = VitessPreparedStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + Assert.assertTrue(((List>) privateStringField.get(statement)).isEmpty()); + } catch (NoSuchFieldException e) { + fail("Private Field should exists: batchedArgs"); + } catch (IllegalAccessException e) { + fail("Private Field should be accessible: batchedArgs"); + } + } + + @Test + public void testExecuteBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); + int[] updateCounts = statement.executeBatch(); + assertEquals(0, updateCounts.length); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when(mockVtGateConn.executeBatch(any(Context.class), Matchers.anyList(), Matchers.anyList(), + any(VTSession.class))).thenReturn(mockSqlFutureCursor); + + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError1 = mock(CursorWithError.class); + when(mockCursorWithError1.getError()).thenReturn(null); + when(mockCursorWithError1.getCursor()).thenReturn(mock(Cursor.class)); + mockCursorWithErrorList.add(mockCursorWithError1); + + statement.setString(1, "string1"); + statement.addBatch(); + updateCounts = statement.executeBatch(); + assertEquals(1, updateCounts.length); + + CursorWithError mockCursorWithError2 = mock(CursorWithError.class); + Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder() + .setMessage("preparedStatement execute batch error").build(); + when(mockCursorWithError2.getError()).thenReturn(rpcError); + mockCursorWithErrorList.add(mockCursorWithError2); + statement.setString(1, "string1"); + statement.addBatch(); + statement.setString(1, "string2"); + statement.addBatch(); + try { + statement.executeBatch(); + fail("Should have thrown Exception"); + } catch (BatchUpdateException ex) { + assertEquals(rpcError.toString(), ex.getMessage()); + assertEquals(2, ex.getUpdateCounts().length); + assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); + } + } + + @Test + public void testStatementCount() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Map testCases = ImmutableMap.builder() + .put("select * from foo where a = ?", 1).put("select * from foo where a = ? and b = ?", 2) + .put("select * from foo where a = ? and b = \"?\"", 1) + .put("select * from foo where a = ? and b = '?'", 1) + .put("select * from foo where a = ? and b = `?`", 1) + .put("select foo.*, `bar.baz?` from foo, bar where foo.a = ? and bar.b = foo.b", 1) + .put("select * from foo where a = ? and b = \"`?`\"", 1) + .put("select * from foo where a = ? --and b = ?", 1) + .put("select * from foo where a = ? /* and b = ? */ and c = ?", 2) + .put("/* leading comment? */ select * from foo where a = ? and b = ?", 2) + .put("select * from foo where a = ? and b = ? and c = 'test' and d = ?", 3) + .put("select * from foo where a = ? and b = \\`?\\`", + 2) // not valid sql but validates escaping + .put("select * from foo where a = ? and b = \\?", 1) // not valid sql but validates escaping + .put("update foo set a = ?, b = ? where c = 'test' and d = ?", 3).put( + "insert into foo (`a`, `b`) values (?, ?), (?, ?) on /* test? */ duplicate key update" + + " a = \"?\"", + 4).put("delete from foo where a = ? and b = '?'", 1).build(); + + for (Map.Entry testCase : testCases.entrySet()) { + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, testCase.getKey()); + assertEquals(testCase.getKey(), testCase.getValue().longValue(), + statement.getParameterMetaData().getParameterCount()); } + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java index 3ac7be7b5eb..4ce4146d97e 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java @@ -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,9 +16,6 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.Test; - import io.vitess.proto.Query; import io.vitess.util.Constants; import io.vitess.util.charset.CharsetMapping; @@ -29,533 +26,640 @@ import java.util.ArrayList; import java.util.List; +import org.junit.Assert; +import org.junit.Test; + /** * Created by ashudeep.sharma on 08/02/16. */ public class VitessResultSetMetadataTest extends BaseTest { - private List fieldList; - - private List generateFieldList() { - List fieldList = new ArrayList<>(); - - fieldList.add(field("col1", "tbl", Query.Type.INT8, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.NOT_NULL_FLAG_VALUE).setOrgName("foo").setOrgTable("foo").build()); - fieldList.add(field("col2", "tbl", Query.Type.UINT8, 3, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col3", "tbl", Query.Type.INT16, 6, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col4", "tbl", Query.Type.UINT16, 5, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col5", "tbl", Query.Type.INT24, 9, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col6", "tbl", Query.Type.UINT24, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col7", "tbl", Query.Type.INT32, 11, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col8", "tbl", Query.Type.UINT32, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col9", "tbl", Query.Type.INT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col10", "tbl", Query.Type.UINT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col11", "tbl", Query.Type.FLOAT32, 12, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setDecimals(31).build()); - fieldList.add(field("col12", "tbl", Query.Type.FLOAT64, 22, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setDecimals(31).build()); - fieldList.add(field("col13", "tbl", Query.Type.TIMESTAMP, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col14", "tbl", Query.Type.DATE, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col15", "tbl", Query.Type.TIME, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col16", "tbl", Query.Type.DATETIME, 19, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col17", "tbl", Query.Type.YEAR, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col18", "tbl", Query.Type.DECIMAL, 7, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setDecimals(2).build()); - fieldList.add(field("col19", "tbl", Query.Type.TEXT, 765, /* utf8_bin -- not case insensitive */ 83).build()); - fieldList.add(field("col20", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + private List fieldList; + + private List generateFieldList() { + List fieldList = new ArrayList<>(); + + fieldList.add( + field("col1", "tbl", Query.Type.INT8, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.NOT_NULL_FLAG_VALUE).setOrgName("foo").setOrgTable("foo") + .build()); + fieldList.add( + field("col2", "tbl", Query.Type.UINT8, 3, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col3", "tbl", Query.Type.INT16, 6, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col4", "tbl", Query.Type.UINT16, 5, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col5", "tbl", Query.Type.INT24, 9, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col6", "tbl", Query.Type.UINT24, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col7", "tbl", Query.Type.INT32, 11, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col8", "tbl", Query.Type.UINT32, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col9", "tbl", Query.Type.INT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col10", "tbl", Query.Type.UINT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col11", "tbl", Query.Type.FLOAT32, 12, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setDecimals(31).build()); + fieldList.add( + field("col12", "tbl", Query.Type.FLOAT64, 22, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setDecimals(31).build()); + fieldList.add( + field("col13", "tbl", Query.Type.TIMESTAMP, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col14", "tbl", Query.Type.DATE, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col15", "tbl", Query.Type.TIME, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col16", "tbl", Query.Type.DATETIME, 19, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col17", "tbl", Query.Type.YEAR, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col18", "tbl", Query.Type.DECIMAL, 7, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setDecimals(2).build()); + fieldList.add( + field("col19", "tbl", Query.Type.TEXT, 765, /* utf8_bin -- not case insensitive */ 83) + .build()); + fieldList.add( + field("col20", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_binary) .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE | Query.MySqlFlag.BLOB_FLAG_VALUE) - .setDecimals(/* this is set to facilitate testing of getScale, since this is non-numeric */2).build()); - fieldList.add(field("col21", "tbl", Query.Type.VARCHAR, 768, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col22", "tbl", Query.Type.VARBINARY, 256, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); - fieldList.add(field("col23", "tbl", Query.Type.CHAR, 48, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col24", "tbl", Query.Type.BINARY, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); - fieldList.add(field("col25", "tbl", Query.Type.BIT, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col26", "tbl", Query.Type.ENUM, 3, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col27", "tbl", Query.Type.SET, 9, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col28", "tbl", Query.Type.TUPLE, 0, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col29", "tbl", Query.Type.VARBINARY, 256, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); - fieldList.add(field("col30", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .setDecimals(/* this is set to facilitate testing of getScale, since this is + non-numeric */ + 2).build()); + fieldList.add( + field("col21", "tbl", Query.Type.VARCHAR, 768, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add(field("col22", "tbl", Query.Type.VARBINARY, 256, + CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) + .build()); + fieldList.add( + field("col23", "tbl", Query.Type.CHAR, 48, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add( + field("col24", "tbl", Query.Type.BINARY, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); + fieldList.add( + field("col25", "tbl", Query.Type.BIT, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col26", "tbl", Query.Type.ENUM, 3, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add( + field("col27", "tbl", Query.Type.SET, 9, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add( + field("col28", "tbl", Query.Type.TUPLE, 0, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add(field("col29", "tbl", Query.Type.VARBINARY, 256, + CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) + .build()); + fieldList.add( + field("col30", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) .setFlags(Query.MySqlFlag.BLOB_FLAG_VALUE).build()); - return fieldList; + return fieldList; + } + + private Query.Field.Builder field(String name, String table, Query.Type type, int length, + int charset) { + return Query.Field.newBuilder().setName(name).setTable(table).setType(type) + .setColumnLength(length).setCharset(charset); + } + + private void initializeFieldList(VitessConnection connection) throws SQLException { + List fields = generateFieldList(); + this.fieldList = new ArrayList<>(fields.size()); + for (Query.Field field : fields) { + this.fieldList.add(new FieldWithMetadata(connection, field)); } + } - private Query.Field.Builder field(String name, String table, Query.Type type, int length, int charset) { - return Query.Field.newBuilder() - .setName(name) - .setTable(table) - .setType(type) - .setColumnLength(length) - .setCharset(charset); - } - - private void initializeFieldList(VitessConnection connection) throws SQLException { - List fields = generateFieldList(); - this.fieldList = new ArrayList<>(fields.size()); - for (Query.Field field : fields) { - this.fieldList.add(new FieldWithMetadata(connection, field)); - } - } - - public List getFieldList() throws SQLException { - return getFieldList(getVitessConnection()); - } - - public List getFieldList(VitessConnection conn) throws SQLException { - initializeFieldList(conn); - return this.fieldList; - } + public List getFieldList() throws SQLException { + return getFieldList(getVitessConnection()); + } - @Test public void testgetColumnCount() throws SQLException { + public List getFieldList(VitessConnection conn) throws SQLException { + initializeFieldList(conn); + return this.fieldList; + } - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals(30, vitessResultSetMetadata.getColumnCount()); - } + @Test + public void testgetColumnCount() throws SQLException { - @Test public void testgetColumnName() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals(30, vitessResultSetMetadata.getColumnCount()); + } - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals("col" + i, vitessResultSetMetadata.getColumnName(i)); - } - } + @Test + public void testgetColumnName() throws SQLException { - @Test public void testgetColumnTypeName() throws SQLException { - - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); - Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); - Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); - Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); - Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); - Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); - Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); - Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); - Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); - Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); - Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); - Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); - Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); - Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); - Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); - Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); - Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); - Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); - Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); - Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); - Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); - Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); - Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); - Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); - Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); - Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); - Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); - Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); - Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(29)); - Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(30)); + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals("col" + i, vitessResultSetMetadata.getColumnName(i)); } - - @Test public void testgetColumnType() throws SQLException { - - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(1)); - Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(2)); - Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(3)); - Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(4)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(5)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(6)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(7)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(8)); - Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(9)); - Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(10)); - Assert.assertEquals("FLOAT", Types.FLOAT, vitessResultSetMetadata.getColumnType(11)); - Assert.assertEquals("DOUBLE", Types.DOUBLE, vitessResultSetMetadata.getColumnType(12)); - Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(13)); - Assert.assertEquals("DATE", Types.DATE, vitessResultSetMetadata.getColumnType(14)); - Assert.assertEquals("TIME", Types.TIME, vitessResultSetMetadata.getColumnType(15)); - Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(16)); - Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(17)); - Assert.assertEquals("DECIMAL", Types.DECIMAL, vitessResultSetMetadata.getColumnType(18)); - Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(19)); - Assert.assertEquals("LONGVARBINARY", Types.LONGVARBINARY, vitessResultSetMetadata.getColumnType(20)); - Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(21)); - Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(22)); - Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(23)); - Assert.assertEquals("BINARY", Types.BINARY, vitessResultSetMetadata.getColumnType(24)); - Assert.assertEquals("BIT", Types.BIT, vitessResultSetMetadata.getColumnType(25)); - Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(26)); - Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(27)); - Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(29)); - Assert.assertEquals("LONGVARCHAR", Types.LONGVARCHAR, vitessResultSetMetadata.getColumnType(30)); - try { - int type = vitessResultSetMetadata.getColumnType(28); - } catch (SQLException ex) { - Assert - .assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE, ex.getMessage()); - } - - try { - int type = vitessResultSetMetadata.getColumnType(0); - } catch (SQLException ex) { - Assert.assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + 0, - ex.getMessage()); - } + } + + @Test + public void testgetColumnTypeName() throws SQLException { + + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); + Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); + Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); + Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); + Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); + Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); + Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); + Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); + Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); + Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); + Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); + Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); + Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); + Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); + Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); + Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); + Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); + Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); + Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); + Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); + Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); + Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); + Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); + Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); + Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); + Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); + Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); + Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); + Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(29)); + Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(30)); + } + + @Test + public void testgetColumnType() throws SQLException { + + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(1)); + Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(2)); + Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(3)); + Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(4)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(5)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(6)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(7)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(8)); + Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(9)); + Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(10)); + Assert.assertEquals("FLOAT", Types.FLOAT, vitessResultSetMetadata.getColumnType(11)); + Assert.assertEquals("DOUBLE", Types.DOUBLE, vitessResultSetMetadata.getColumnType(12)); + Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(13)); + Assert.assertEquals("DATE", Types.DATE, vitessResultSetMetadata.getColumnType(14)); + Assert.assertEquals("TIME", Types.TIME, vitessResultSetMetadata.getColumnType(15)); + Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(16)); + Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(17)); + Assert.assertEquals("DECIMAL", Types.DECIMAL, vitessResultSetMetadata.getColumnType(18)); + Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(19)); + Assert.assertEquals("LONGVARBINARY", Types.LONGVARBINARY, + vitessResultSetMetadata.getColumnType(20)); + Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(21)); + Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(22)); + Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(23)); + Assert.assertEquals("BINARY", Types.BINARY, vitessResultSetMetadata.getColumnType(24)); + Assert.assertEquals("BIT", Types.BIT, vitessResultSetMetadata.getColumnType(25)); + Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(26)); + Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(27)); + Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(29)); + Assert + .assertEquals("LONGVARCHAR", Types.LONGVARCHAR, vitessResultSetMetadata.getColumnType(30)); + try { + int type = vitessResultSetMetadata.getColumnType(28); + } catch (SQLException ex) { + Assert.assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE, ex.getMessage()); } - @Test public void testgetColumnLabel() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); - for (int i = 1; i <= vitessResultSetMetaData.getColumnCount(); i++) { - Assert.assertEquals("col" + i, vitessResultSetMetaData.getColumnLabel(i)); - } + try { + int type = vitessResultSetMetadata.getColumnType(0); + } catch (SQLException ex) { + Assert.assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + 0, + ex.getMessage()); } - - @Test public void testgetTableName() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals(vitessResultSetMetadata.getTableName(i), "tbl"); - } + } + + @Test + public void testgetColumnLabel() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); + for (int i = 1; i <= vitessResultSetMetaData.getColumnCount(); i++) { + Assert.assertEquals("col" + i, vitessResultSetMetaData.getColumnLabel(i)); } - - @Test public void isReadOnlyTest() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals(vitessResultSetMetadata.isReadOnly(1), false); - Assert.assertEquals(vitessResultSetMetadata.isWritable(1), true); - Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(1), true); - - for (int i = 2; i <= vitessResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals(vitessResultSetMetadata.isReadOnly(i), true); - Assert.assertEquals(vitessResultSetMetadata.isWritable(i), false); - Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(i), false); - } + } + + @Test + public void testgetTableName() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals(vitessResultSetMetadata.getTableName(i), "tbl"); } - - @Test public void getColumnTypeNameTest() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); - Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); - Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); - Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); - Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); - Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); - Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); - Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); - Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); - Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); - Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); - Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); - Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); - Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); - Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); - Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); - Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); - Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); - Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); - Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); - Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); - Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); - Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); - Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); - Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); - Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); - Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); - Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); + } + + @Test + public void isReadOnlyTest() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals(vitessResultSetMetadata.isReadOnly(1), false); + Assert.assertEquals(vitessResultSetMetadata.isWritable(1), true); + Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(1), true); + + for (int i = 2; i <= vitessResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals(vitessResultSetMetadata.isReadOnly(i), true); + Assert.assertEquals(vitessResultSetMetadata.isWritable(i), false); + Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(i), false); } - - @Test public void getSchemaNameTest() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); - Assert.assertEquals(vitessResultSetMetaData.getSchemaName(1), ""); - Assert.assertEquals(vitessResultSetMetaData.getCatalogName(1), ""); - Assert.assertEquals(vitessResultSetMetaData.getPrecision(1), 3); - Assert.assertEquals(vitessResultSetMetaData.getScale(1), 0); - Assert.assertEquals(vitessResultSetMetaData.getColumnDisplaySize(1), 4); - Assert.assertEquals(vitessResultSetMetaData.isCurrency(1), false); + } + + @Test + public void getColumnTypeNameTest() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); + Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); + Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); + Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); + Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); + Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); + Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); + Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); + Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); + Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); + Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); + Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); + Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); + Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); + Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); + Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); + Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); + Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); + Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); + Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); + Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); + Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); + Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); + Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); + Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); + Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); + Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); + Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); + } + + @Test + public void getSchemaNameTest() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); + Assert.assertEquals(vitessResultSetMetaData.getSchemaName(1), ""); + Assert.assertEquals(vitessResultSetMetaData.getCatalogName(1), ""); + Assert.assertEquals(vitessResultSetMetaData.getPrecision(1), 3); + Assert.assertEquals(vitessResultSetMetaData.getScale(1), 0); + Assert.assertEquals(vitessResultSetMetaData.getColumnDisplaySize(1), 4); + Assert.assertEquals(vitessResultSetMetaData.isCurrency(1), false); + } + + @Test + public void testCaseSensitivity() throws SQLException { + VitessConnection connection = getVitessConnection(); + List fieldList = getFieldList(connection); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + + // numeric types and date types are not case sensitive + Assert.assertEquals("int8 case sensitivity", false, md.isCaseSensitive(1)); + Assert.assertEquals("uint8 case sensitivity", false, md.isCaseSensitive(2)); + Assert.assertEquals("int16 case sensitivity", false, md.isCaseSensitive(3)); + Assert.assertEquals("uint16 case sensitivity", false, md.isCaseSensitive(4)); + Assert.assertEquals("int24 case sensitivity", false, md.isCaseSensitive(5)); + Assert.assertEquals("uint24 case sensitivity", false, md.isCaseSensitive(6)); + Assert.assertEquals("int32 case sensitivity", false, md.isCaseSensitive(7)); + Assert.assertEquals("uint32 case sensitivity", false, md.isCaseSensitive(8)); + Assert.assertEquals("int64 case sensitivity", false, md.isCaseSensitive(9)); + Assert.assertEquals("uint64 case sensitivity", false, md.isCaseSensitive(10)); + Assert.assertEquals("float32 case sensitivity", false, md.isCaseSensitive(11)); + Assert.assertEquals("float64 case sensitivity", false, md.isCaseSensitive(12)); + Assert.assertEquals("timestamp case sensitivity", false, md.isCaseSensitive(13)); + Assert.assertEquals("date case sensitivity", false, md.isCaseSensitive(14)); + Assert.assertEquals("time case sensitivity", false, md.isCaseSensitive(15)); + Assert.assertEquals("datetime case sensitivity", false, md.isCaseSensitive(16)); + Assert.assertEquals("year case sensitivity", false, md.isCaseSensitive(17)); + Assert.assertEquals("decimal case sensitivity", false, md.isCaseSensitive(18)); + + // These are handled on a case-by-case basis + Assert.assertEquals("text cases sensitivity", /* due to binary */true, md.isCaseSensitive(19)); + Assert.assertEquals("blob case sensitivity", /* due to binary */true, md.isCaseSensitive(20)); + Assert.assertEquals("varchar case sensitivity", /* due to utf-8_ci */ false, + md.isCaseSensitive(21)); + Assert.assertEquals("varbinary case sensitivity", /* due to binary */true, + md.isCaseSensitive(22)); + Assert + .assertEquals("char case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(23)); + Assert.assertEquals("binary case sensitivity", /* due to binary */true, md.isCaseSensitive(24)); + Assert.assertEquals("bit case sensitivity", /* due to numeric type */false, + md.isCaseSensitive(25)); + Assert + .assertEquals("enum case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(26)); + Assert.assertEquals("set case sensitivity", /* due to utf-8_ci, SET == CHAR */ false, + md.isCaseSensitive(27)); + Assert.assertEquals("tuple case sensitivity", /* due to default case */ true, + md.isCaseSensitive(28)); + Assert.assertEquals("varbinary case sensitivity", /* due to binary */ true, + md.isCaseSensitive(29)); + Assert.assertEquals( + "text cases sensitivity", /* due to utf8_bin (not case insensitive) encoding */false, + md.isCaseSensitive(30)); + + connection.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + // with limited included fields, we can really only know about numeric types -- those should + // return false. the rest should return true + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals(fieldList.get(i).getName() + + " - non-numeric case insensitive due to lack of included fields", + i >= 18 && i != 24, + md.isCaseSensitive(i + 1)); } - - @Test public void testCaseSensitivity() throws SQLException { - VitessConnection connection = getVitessConnection(); - List fieldList = getFieldList(connection); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - - // numeric types and date types are not case sensitive - Assert.assertEquals("int8 case sensitivity", false, md.isCaseSensitive(1)); - Assert.assertEquals("uint8 case sensitivity", false, md.isCaseSensitive(2)); - Assert.assertEquals("int16 case sensitivity", false, md.isCaseSensitive(3)); - Assert.assertEquals("uint16 case sensitivity", false, md.isCaseSensitive(4)); - Assert.assertEquals("int24 case sensitivity", false, md.isCaseSensitive(5)); - Assert.assertEquals("uint24 case sensitivity", false, md.isCaseSensitive(6)); - Assert.assertEquals("int32 case sensitivity", false, md.isCaseSensitive(7)); - Assert.assertEquals("uint32 case sensitivity", false, md.isCaseSensitive(8)); - Assert.assertEquals("int64 case sensitivity", false, md.isCaseSensitive(9)); - Assert.assertEquals("uint64 case sensitivity", false, md.isCaseSensitive(10)); - Assert.assertEquals("float32 case sensitivity", false, md.isCaseSensitive(11)); - Assert.assertEquals("float64 case sensitivity", false, md.isCaseSensitive(12)); - Assert.assertEquals("timestamp case sensitivity", false, md.isCaseSensitive(13)); - Assert.assertEquals("date case sensitivity", false, md.isCaseSensitive(14)); - Assert.assertEquals("time case sensitivity", false, md.isCaseSensitive(15)); - Assert.assertEquals("datetime case sensitivity", false, md.isCaseSensitive(16)); - Assert.assertEquals("year case sensitivity", false, md.isCaseSensitive(17)); - Assert.assertEquals("decimal case sensitivity", false, md.isCaseSensitive(18)); - - // These are handled on a case-by-case basis - Assert.assertEquals("text cases sensitivity", /* due to binary */true, md.isCaseSensitive(19)); - Assert.assertEquals("blob case sensitivity", /* due to binary */true, md.isCaseSensitive(20)); - Assert.assertEquals("varchar case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(21)); - Assert.assertEquals("varbinary case sensitivity", /* due to binary */true, md.isCaseSensitive(22)); - Assert.assertEquals("char case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(23)); - Assert.assertEquals("binary case sensitivity", /* due to binary */true, md.isCaseSensitive(24)); - Assert.assertEquals("bit case sensitivity", /* due to numeric type */false, md.isCaseSensitive(25)); - Assert.assertEquals("enum case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(26)); - Assert.assertEquals("set case sensitivity", /* due to utf-8_ci, SET == CHAR */ false, md.isCaseSensitive(27)); - Assert.assertEquals("tuple case sensitivity", /* due to default case */ true, md.isCaseSensitive(28)); - Assert.assertEquals("varbinary case sensitivity", /* due to binary */ true, md.isCaseSensitive(29)); - Assert.assertEquals("text cases sensitivity", /* due to utf8_bin (not case insensitive) encoding */false, md.isCaseSensitive(30)); - - connection.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - // with limited included fields, we can really only know about numeric types -- those should return false. the rest should return true - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - non-numeric case insensitive due to lack of included fields", i >= 18 && i != 24, md.isCaseSensitive(i + 1)); - } + } + + @Test + public void testIsNullable() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("NOT_NULL flag means columnNoNulls (0) value for isNullable", + ResultSetMetaData.columnNoNulls, md.isNullable(1)); + for (int i = 1; i < fieldList.size(); i++) { + Assert.assertEquals("lack of NOT_NULL flag means columnNullable (1) value for isNullable", + ResultSetMetaData.columnNullable, md.isNullable(i + 1)); } - @Test public void testIsNullable() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("NOT_NULL flag means columnNoNulls (0) value for isNullable", ResultSetMetaData.columnNoNulls, md.isNullable(1)); - for (int i = 1; i < fieldList.size(); i++) { - Assert.assertEquals("lack of NOT_NULL flag means columnNullable (1) value for isNullable", ResultSetMetaData.columnNullable, md.isNullable(i + 1)); - } - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - isNullable is columnNullableUnknown (2) for all when lack of included fields", 2, md.isNullable(i + 1)); - } + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals(fieldList.get(i).getName() + + " - isNullable is columnNullableUnknown (2) for all when lack of included fields" + , 2, + md.isNullable(i + 1)); } - - @Test public void testDisplaySize() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - - Assert.assertEquals("int8 display size", 4, md.getColumnDisplaySize(1)); - Assert.assertEquals("uint8 display size", 3, md.getColumnDisplaySize(2)); - Assert.assertEquals("int16 display size", 6, md.getColumnDisplaySize(3)); - Assert.assertEquals("uint16 display size", 5, md.getColumnDisplaySize(4)); - Assert.assertEquals("int24 display size", 9, md.getColumnDisplaySize(5)); - Assert.assertEquals("uint24 display size", 8, md.getColumnDisplaySize(6)); - Assert.assertEquals("int32 display size", 11, md.getColumnDisplaySize(7)); - Assert.assertEquals("uint32 display size", 10, md.getColumnDisplaySize(8)); - Assert.assertEquals("int64 display size", 20, md.getColumnDisplaySize(9)); - // unsigned long gets an extra digit of precision over signed, so display sizes are the same - Assert.assertEquals("uint64 display size", 20, md.getColumnDisplaySize(10)); - Assert.assertEquals("float32 display size", 12, md.getColumnDisplaySize(11)); - Assert.assertEquals("float64 display size", 22, md.getColumnDisplaySize(12)); - Assert.assertEquals("timestamp display size", 10, md.getColumnDisplaySize(13)); - Assert.assertEquals("date display size", 10, md.getColumnDisplaySize(14)); - Assert.assertEquals("time display size", 10, md.getColumnDisplaySize(15)); - Assert.assertEquals("datetime display size", 19, md.getColumnDisplaySize(16)); - Assert.assertEquals("year display size", 4, md.getColumnDisplaySize(17)); - Assert.assertEquals("decimal display size", 7, md.getColumnDisplaySize(18)); - Assert.assertEquals("text display size", 255, md.getColumnDisplaySize(19)); - Assert.assertEquals("blob display size", 65535, md.getColumnDisplaySize(20)); - Assert.assertEquals("varchar display size", 256, md.getColumnDisplaySize(21)); - Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(22)); - Assert.assertEquals("char display size", 16, md.getColumnDisplaySize(23)); - Assert.assertEquals("binary display size", 4, md.getColumnDisplaySize(24)); - Assert.assertEquals("bit display size", 8, md.getColumnDisplaySize(25)); - Assert.assertEquals("enum display size", 1, md.getColumnDisplaySize(26)); - Assert.assertEquals("set display size", 3, md.getColumnDisplaySize(27)); - Assert.assertEquals("tuple display size", 0, md.getColumnDisplaySize(28)); - Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(29)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - getColumnDisplaySize is 0 for all when lack of included fields", 0, md.getColumnDisplaySize(i + 1)); - } + } + + @Test + public void testDisplaySize() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + + Assert.assertEquals("int8 display size", 4, md.getColumnDisplaySize(1)); + Assert.assertEquals("uint8 display size", 3, md.getColumnDisplaySize(2)); + Assert.assertEquals("int16 display size", 6, md.getColumnDisplaySize(3)); + Assert.assertEquals("uint16 display size", 5, md.getColumnDisplaySize(4)); + Assert.assertEquals("int24 display size", 9, md.getColumnDisplaySize(5)); + Assert.assertEquals("uint24 display size", 8, md.getColumnDisplaySize(6)); + Assert.assertEquals("int32 display size", 11, md.getColumnDisplaySize(7)); + Assert.assertEquals("uint32 display size", 10, md.getColumnDisplaySize(8)); + Assert.assertEquals("int64 display size", 20, md.getColumnDisplaySize(9)); + // unsigned long gets an extra digit of precision over signed, so display sizes are the same + Assert.assertEquals("uint64 display size", 20, md.getColumnDisplaySize(10)); + Assert.assertEquals("float32 display size", 12, md.getColumnDisplaySize(11)); + Assert.assertEquals("float64 display size", 22, md.getColumnDisplaySize(12)); + Assert.assertEquals("timestamp display size", 10, md.getColumnDisplaySize(13)); + Assert.assertEquals("date display size", 10, md.getColumnDisplaySize(14)); + Assert.assertEquals("time display size", 10, md.getColumnDisplaySize(15)); + Assert.assertEquals("datetime display size", 19, md.getColumnDisplaySize(16)); + Assert.assertEquals("year display size", 4, md.getColumnDisplaySize(17)); + Assert.assertEquals("decimal display size", 7, md.getColumnDisplaySize(18)); + Assert.assertEquals("text display size", 255, md.getColumnDisplaySize(19)); + Assert.assertEquals("blob display size", 65535, md.getColumnDisplaySize(20)); + Assert.assertEquals("varchar display size", 256, md.getColumnDisplaySize(21)); + Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(22)); + Assert.assertEquals("char display size", 16, md.getColumnDisplaySize(23)); + Assert.assertEquals("binary display size", 4, md.getColumnDisplaySize(24)); + Assert.assertEquals("bit display size", 8, md.getColumnDisplaySize(25)); + Assert.assertEquals("enum display size", 1, md.getColumnDisplaySize(26)); + Assert.assertEquals("set display size", 3, md.getColumnDisplaySize(27)); + Assert.assertEquals("tuple display size", 0, md.getColumnDisplaySize(28)); + Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(29)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals(fieldList.get(i).getName() + + " - getColumnDisplaySize is 0 for all when lack of included fields", 0, + md.getColumnDisplaySize(i + 1)); } - - @Test public void testGetPrecision() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - - Assert.assertEquals("int8 precision", 3, md.getPrecision(1)); - Assert.assertEquals("uint8 precision", 3, md.getPrecision(2)); - Assert.assertEquals("int16 precision", 5, md.getPrecision(3)); - Assert.assertEquals("uint16 precision", 5, md.getPrecision(4)); - Assert.assertEquals("int24 precision", 8, md.getPrecision(5)); - Assert.assertEquals("uint24 precision", 8, md.getPrecision(6)); - Assert.assertEquals("int32 precision", 10, md.getPrecision(7)); - Assert.assertEquals("uint32 precision", 10, md.getPrecision(8)); - Assert.assertEquals("int64 precision", 19, md.getPrecision(9)); - Assert.assertEquals("uint64 precision", 20, md.getPrecision(10)); - Assert.assertEquals("float32 precision", 12, md.getPrecision(11)); - Assert.assertEquals("float64 precision", 22, md.getPrecision(12)); - Assert.assertEquals("timestamp precision", 10, md.getPrecision(13)); - Assert.assertEquals("date precision", 10, md.getPrecision(14)); - Assert.assertEquals("time precision", 10, md.getPrecision(15)); - Assert.assertEquals("datetime precision", 19, md.getPrecision(16)); - Assert.assertEquals("year precision", 4, md.getPrecision(17)); - Assert.assertEquals("decimal precision", 5, md.getPrecision(18)); // 7 - decimal - sign - Assert.assertEquals("text precision", 255, md.getPrecision(19)); - Assert.assertEquals("blob precision", 65535, md.getPrecision(20)); - Assert.assertEquals("varchar precision", 256, md.getPrecision(21)); - Assert.assertEquals("varbinary precision", 256, md.getPrecision(22)); - Assert.assertEquals("char precision", 16, md.getPrecision(23)); - Assert.assertEquals("binary precision", 4, md.getPrecision(24)); - Assert.assertEquals("bit precision", 8, md.getPrecision(25)); - Assert.assertEquals("enum precision", 1, md.getPrecision(26)); - Assert.assertEquals("set precision", 3, md.getPrecision(27)); - Assert.assertEquals("tuple precision", 0, md.getPrecision(28)); - Assert.assertEquals("varbinary precision", 256, md.getPrecision(29)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - getPrecision is 0 for all when lack of included fields", 0, md.getPrecision(i + 1)); - } + } + + @Test + public void testGetPrecision() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + + Assert.assertEquals("int8 precision", 3, md.getPrecision(1)); + Assert.assertEquals("uint8 precision", 3, md.getPrecision(2)); + Assert.assertEquals("int16 precision", 5, md.getPrecision(3)); + Assert.assertEquals("uint16 precision", 5, md.getPrecision(4)); + Assert.assertEquals("int24 precision", 8, md.getPrecision(5)); + Assert.assertEquals("uint24 precision", 8, md.getPrecision(6)); + Assert.assertEquals("int32 precision", 10, md.getPrecision(7)); + Assert.assertEquals("uint32 precision", 10, md.getPrecision(8)); + Assert.assertEquals("int64 precision", 19, md.getPrecision(9)); + Assert.assertEquals("uint64 precision", 20, md.getPrecision(10)); + Assert.assertEquals("float32 precision", 12, md.getPrecision(11)); + Assert.assertEquals("float64 precision", 22, md.getPrecision(12)); + Assert.assertEquals("timestamp precision", 10, md.getPrecision(13)); + Assert.assertEquals("date precision", 10, md.getPrecision(14)); + Assert.assertEquals("time precision", 10, md.getPrecision(15)); + Assert.assertEquals("datetime precision", 19, md.getPrecision(16)); + Assert.assertEquals("year precision", 4, md.getPrecision(17)); + Assert.assertEquals("decimal precision", 5, md.getPrecision(18)); // 7 - decimal - sign + Assert.assertEquals("text precision", 255, md.getPrecision(19)); + Assert.assertEquals("blob precision", 65535, md.getPrecision(20)); + Assert.assertEquals("varchar precision", 256, md.getPrecision(21)); + Assert.assertEquals("varbinary precision", 256, md.getPrecision(22)); + Assert.assertEquals("char precision", 16, md.getPrecision(23)); + Assert.assertEquals("binary precision", 4, md.getPrecision(24)); + Assert.assertEquals("bit precision", 8, md.getPrecision(25)); + Assert.assertEquals("enum precision", 1, md.getPrecision(26)); + Assert.assertEquals("set precision", 3, md.getPrecision(27)); + Assert.assertEquals("tuple precision", 0, md.getPrecision(28)); + Assert.assertEquals("varbinary precision", 256, md.getPrecision(29)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals( + fieldList.get(i).getName() + " - getPrecision is 0 for all when lack of included fields", + 0, md.getPrecision(i + 1)); } - - @Test public void testGetScale() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("int8 precision", 0, md.getScale(1)); - Assert.assertEquals("uint8 precision", 0, md.getScale(2)); - Assert.assertEquals("int16 precision", 0, md.getScale(3)); - Assert.assertEquals("uint16 precision", 0, md.getScale(4)); - Assert.assertEquals("int24 precision", 0, md.getScale(5)); - Assert.assertEquals("uint24 precision", 0, md.getScale(6)); - Assert.assertEquals("int32 precision", 0, md.getScale(7)); - Assert.assertEquals("uint32 precision", 0, md.getScale(8)); - Assert.assertEquals("int64 precision", 0, md.getScale(9)); - Assert.assertEquals("uint64 precision", 0, md.getScale(10)); - Assert.assertEquals("float32 precision", 31, md.getScale(11)); - Assert.assertEquals("float64 precision", 31, md.getScale(12)); - Assert.assertEquals("timestamp precision", 0, md.getScale(13)); - Assert.assertEquals("date precision", 0, md.getScale(14)); - Assert.assertEquals("time precision", 0, md.getScale(15)); - Assert.assertEquals("datetime precision", 0, md.getScale(16)); - Assert.assertEquals("year precision", 0, md.getScale(17)); - Assert.assertEquals("decimal precision", 2, md.getScale(18)); - Assert.assertEquals("text precision", 0, md.getScale(19)); - Assert.assertEquals("blob precision", 0, md.getScale(20)); - Assert.assertEquals("varchar precision", 0, md.getScale(21)); - Assert.assertEquals("varbinary precision", 0, md.getScale(22)); - Assert.assertEquals("char precision", 0, md.getScale(23)); - Assert.assertEquals("binary precision", 0, md.getScale(24)); - Assert.assertEquals("bit precision", 0, md.getScale(25)); - Assert.assertEquals("enum precision", 0, md.getScale(26)); - Assert.assertEquals("set precision", 0, md.getScale(27)); - Assert.assertEquals("tuple precision", 0, md.getScale(28)); - Assert.assertEquals("varbinary precision", 0, md.getScale(29)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - getScale is 0 for all when lack of included fields", 0, md.getScale(i + 1)); - } + } + + @Test + public void testGetScale() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("int8 precision", 0, md.getScale(1)); + Assert.assertEquals("uint8 precision", 0, md.getScale(2)); + Assert.assertEquals("int16 precision", 0, md.getScale(3)); + Assert.assertEquals("uint16 precision", 0, md.getScale(4)); + Assert.assertEquals("int24 precision", 0, md.getScale(5)); + Assert.assertEquals("uint24 precision", 0, md.getScale(6)); + Assert.assertEquals("int32 precision", 0, md.getScale(7)); + Assert.assertEquals("uint32 precision", 0, md.getScale(8)); + Assert.assertEquals("int64 precision", 0, md.getScale(9)); + Assert.assertEquals("uint64 precision", 0, md.getScale(10)); + Assert.assertEquals("float32 precision", 31, md.getScale(11)); + Assert.assertEquals("float64 precision", 31, md.getScale(12)); + Assert.assertEquals("timestamp precision", 0, md.getScale(13)); + Assert.assertEquals("date precision", 0, md.getScale(14)); + Assert.assertEquals("time precision", 0, md.getScale(15)); + Assert.assertEquals("datetime precision", 0, md.getScale(16)); + Assert.assertEquals("year precision", 0, md.getScale(17)); + Assert.assertEquals("decimal precision", 2, md.getScale(18)); + Assert.assertEquals("text precision", 0, md.getScale(19)); + Assert.assertEquals("blob precision", 0, md.getScale(20)); + Assert.assertEquals("varchar precision", 0, md.getScale(21)); + Assert.assertEquals("varbinary precision", 0, md.getScale(22)); + Assert.assertEquals("char precision", 0, md.getScale(23)); + Assert.assertEquals("binary precision", 0, md.getScale(24)); + Assert.assertEquals("bit precision", 0, md.getScale(25)); + Assert.assertEquals("enum precision", 0, md.getScale(26)); + Assert.assertEquals("set precision", 0, md.getScale(27)); + Assert.assertEquals("tuple precision", 0, md.getScale(28)); + Assert.assertEquals("varbinary precision", 0, md.getScale(29)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals( + fieldList.get(i).getName() + " - getScale is 0 for all when lack of included fields", 0, + md.getScale(i + 1)); } - - @Test public void testGetColumnClassName() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(1)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(2)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(3)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(4)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(5)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(6)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(7)); - Assert.assertEquals("java.lang.Long", md.getColumnClassName(8)); - Assert.assertEquals("java.lang.Long", md.getColumnClassName(9)); - Assert.assertEquals("java.math.BigInteger", md.getColumnClassName(10)); - Assert.assertEquals("java.lang.Double", md.getColumnClassName(11)); - Assert.assertEquals("java.lang.Double", md.getColumnClassName(12)); - Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(13)); - Assert.assertEquals("java.sql.Date", md.getColumnClassName(14)); - Assert.assertEquals("java.sql.Time", md.getColumnClassName(15)); - Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(16)); - Assert.assertEquals("java.sql.Date", md.getColumnClassName(17)); - Assert.assertEquals("java.math.BigDecimal", md.getColumnClassName(18)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(19)); - Assert.assertEquals("[B", md.getColumnClassName(20)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(21)); - Assert.assertEquals("[B", md.getColumnClassName(22)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(23)); - Assert.assertEquals("[B", md.getColumnClassName(24)); - Assert.assertEquals("java.lang.Boolean", md.getColumnClassName(25)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(26)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(27)); - Assert.assertEquals("java.lang.Object", md.getColumnClassName(28)); - Assert.assertEquals("[B", md.getColumnClassName(29)); - - conn.setYearIsDateType(false); - md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("java.lang.Short", md.getColumnClassName(17)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - class name is null when no included fields", null, md.getColumnClassName(i + 1)); - } + } + + @Test + public void testGetColumnClassName() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(1)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(2)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(3)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(4)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(5)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(6)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(7)); + Assert.assertEquals("java.lang.Long", md.getColumnClassName(8)); + Assert.assertEquals("java.lang.Long", md.getColumnClassName(9)); + Assert.assertEquals("java.math.BigInteger", md.getColumnClassName(10)); + Assert.assertEquals("java.lang.Double", md.getColumnClassName(11)); + Assert.assertEquals("java.lang.Double", md.getColumnClassName(12)); + Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(13)); + Assert.assertEquals("java.sql.Date", md.getColumnClassName(14)); + Assert.assertEquals("java.sql.Time", md.getColumnClassName(15)); + Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(16)); + Assert.assertEquals("java.sql.Date", md.getColumnClassName(17)); + Assert.assertEquals("java.math.BigDecimal", md.getColumnClassName(18)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(19)); + Assert.assertEquals("[B", md.getColumnClassName(20)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(21)); + Assert.assertEquals("[B", md.getColumnClassName(22)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(23)); + Assert.assertEquals("[B", md.getColumnClassName(24)); + Assert.assertEquals("java.lang.Boolean", md.getColumnClassName(25)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(26)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(27)); + Assert.assertEquals("java.lang.Object", md.getColumnClassName(28)); + Assert.assertEquals("[B", md.getColumnClassName(29)); + + conn.setYearIsDateType(false); + md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("java.lang.Short", md.getColumnClassName(17)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals( + fieldList.get(i).getName() + " - class name is null when no included fields", null, + md.getColumnClassName(i + 1)); } - - /** - * Some of the tests above verify that their particular part honors the IncludedFields.ALL value, but - * this further verifies that when someone has disabled ALL, the values returned by the driver are basically the same - * as what they used to be before we supported returning all fields. - */ - @Test public void testDefaultValuesWithoutIncludedFields() throws SQLException { - VitessConnection conn = getVitessConnection(); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - List fields = getFieldList(conn); - VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fields); - for (int i = 1; i < fields.size() + 1; i++) { - FieldWithMetadata field = fields.get(i - 1); - Assert.assertEquals(false, vitessResultSetMetaData.isAutoIncrement(i)); - boolean shouldBeSensitive = true; - switch (field.getJavaType()) { - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.DATE: - case Types.DECIMAL: - case Types.NUMERIC: - case Types.TIME: - case Types.TIMESTAMP: - shouldBeSensitive = false; - break; - } - Assert.assertEquals(shouldBeSensitive, vitessResultSetMetaData.isCaseSensitive(i)); - Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isSearchable(i)); - Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isCurrency(i)); - Assert.assertEquals(field.getName(), ResultSetMetaData.columnNullableUnknown, vitessResultSetMetaData.isNullable(i)); - Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isSigned(i)); - Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getColumnDisplaySize(i)); - Assert.assertEquals(field.getName(), field.getName(), vitessResultSetMetaData.getColumnLabel(i)); - Assert.assertEquals(field.getName(), field.getName(), vitessResultSetMetaData.getColumnName(i)); - Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getPrecision(i)); - Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getScale(i)); - Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getTableName(i)); - Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getCatalogName(i)); - // These two do not depend on IncludedFields and are covered by tests above - //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnType(i)); - //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnTypeName(i)); - Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isReadOnly(i)); - Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isWritable(i)); - Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isDefinitelyWritable(i)); - Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnClassName(i)); - } + } + + /** + * Some of the tests above verify that their particular part honors the IncludedFields.ALL value, + * but this further verifies that when someone has disabled ALL, the values returned by the driver + * are basically the same as what they used to be before we supported returning all fields. + */ + @Test + public void testDefaultValuesWithoutIncludedFields() throws SQLException { + VitessConnection conn = getVitessConnection(); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + List fields = getFieldList(conn); + VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fields); + for (int i = 1; i < fields.size() + 1; i++) { + FieldWithMetadata field = fields.get(i - 1); + Assert.assertEquals(false, vitessResultSetMetaData.isAutoIncrement(i)); + boolean shouldBeSensitive = true; + switch (field.getJavaType()) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.DATE: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.TIME: + case Types.TIMESTAMP: + shouldBeSensitive = false; + break; + } + Assert.assertEquals(shouldBeSensitive, vitessResultSetMetaData.isCaseSensitive(i)); + Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isSearchable(i)); + Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isCurrency(i)); + Assert.assertEquals(field.getName(), ResultSetMetaData.columnNullableUnknown, + vitessResultSetMetaData.isNullable(i)); + Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isSigned(i)); + Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getColumnDisplaySize(i)); + Assert.assertEquals(field.getName(), field.getName(), + vitessResultSetMetaData.getColumnLabel(i)); + Assert + .assertEquals(field.getName(), field.getName(), vitessResultSetMetaData.getColumnName(i)); + Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getPrecision(i)); + Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getScale(i)); + Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getTableName(i)); + Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getCatalogName(i)); + // These two do not depend on IncludedFields and are covered by tests above + //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnType(i)); + //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnTypeName(i)); + Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isReadOnly(i)); + Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isWritable(i)); + Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isDefinitelyWritable(i)); + Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnClassName(i)); } + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java index ce2c8b79aa2..7c41baf9636 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java @@ -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,15 +16,9 @@ package io.vitess.jdbc; +import static org.junit.Assert.assertEquals; + import com.google.protobuf.ByteString; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Matchers; -import org.mockito.internal.verification.VerificationModeFactory; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.SimpleCursor; @@ -44,7 +38,14 @@ import java.sql.Timestamp; import java.util.Properties; -import static org.junit.Assert.assertEquals; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.internal.verification.VerificationModeFactory; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 19/01/16. @@ -53,7 +54,7 @@ @PrepareForTest(VitessResultSet.class) public class VitessResultSetTest extends BaseTest { - public Cursor getCursorWithRows() { + public Cursor getCursorWithRows() { /* INT8(1, 257), -50 UINT8(2, 770), 50 @@ -85,8 +86,8 @@ public Cursor getCursorWithRows() { TUPLE(28, 28), UNRECOGNIZED(-1, -1); */ - return new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(getField("col1", Query.Type.INT8)) + return new SimpleCursor( + Query.QueryResult.newBuilder().addFields(getField("col1", Query.Type.INT8)) .addFields(getField("col2", Query.Type.UINT8)) .addFields(getField("col3", Query.Type.INT16)) .addFields(getField("col4", Query.Type.UINT16)) @@ -113,8 +114,8 @@ public Cursor getCursorWithRows() { .addFields(getField("col25", Query.Type.BIT)) .addFields(getField("col26", Query.Type.ENUM)) .addFields(getField("col27", Query.Type.SET)) - .addFields(getField("col28", Query.Type.TIMESTAMP)) - .addRows(Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) + .addFields(getField("col28", Query.Type.TIMESTAMP)).addRows( + Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) .addLengths("-23000".length()).addLengths("23000".length()) .addLengths("-100".length()).addLengths("100".length()).addLengths("-100".length()) .addLengths("100".length()).addLengths("-1000".length()).addLengths("1000".length()) @@ -126,23 +127,25 @@ public Cursor getCursorWithRows() { .addLengths("HELLO TDS TEAM".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("N".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("1".length()).addLengths("val123".length()) - .addLengths("val123".length()).addLengths("0000-00-00 00:00:00".length()) - .setValues(ByteString - .copyFromUtf8("-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + - "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS TEAMHELLO TDS TEAMHELLO" - + - " TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM1val123val1230000-00-00 00:00:00"))).build()); - } - - private Query.Field getField(String fieldName, Query.Type typ) { - return Query.Field.newBuilder().setName(fieldName).setType(typ).build(); - } - - private Query.Field getField(String fieldName) { - return Query.Field.newBuilder().setName(fieldName).build(); - } - - public Cursor getCursorWithRowsAsNull() { + .addLengths("val123".length()).addLengths("0000-00-00 00:00:00".length()).setValues( + ByteString.copyFromUtf8( + "-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + + "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS " + + "TEAMHELLO TDS TEAMHELLO" + + " TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM1val123val1230000-00-00 " + + "00:00:00"))) + .build()); + } + + private Query.Field getField(String fieldName, Query.Type typ) { + return Query.Field.newBuilder().setName(fieldName).setType(typ).build(); + } + + private Query.Field getField(String fieldName) { + return Query.Field.newBuilder().setName(fieldName).build(); + } + + public Cursor getCursorWithRowsAsNull() { /* INT8(1, 257), -50 UINT8(2, 770), 50 @@ -174,8 +177,8 @@ public Cursor getCursorWithRowsAsNull() { TUPLE(28, 28), UNRECOGNIZED(-1, -1); */ - return new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(getField("col1", Query.Type.INT8)) + return new SimpleCursor( + Query.QueryResult.newBuilder().addFields(getField("col1", Query.Type.INT8)) .addFields(getField("col2", Query.Type.UINT8)) .addFields(getField("col3", Query.Type.INT16)) .addFields(getField("col4", Query.Type.UINT16)) @@ -201,8 +204,8 @@ public Cursor getCursorWithRowsAsNull() { .addFields(getField("col24", Query.Type.BINARY)) .addFields(getField("col25", Query.Type.BIT)) .addFields(getField("col26", Query.Type.ENUM)) - .addFields(getField("col27", Query.Type.SET)) - .addRows(Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) + .addFields(getField("col27", Query.Type.SET)).addRows( + Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) .addLengths("-23000".length()).addLengths("23000".length()) .addLengths("-100".length()).addLengths("100".length()).addLengths("-100".length()) .addLengths("100".length()).addLengths("-1000".length()).addLengths("1000".length()) @@ -213,621 +216,660 @@ public Cursor getCursorWithRowsAsNull() { .addLengths("HELLO TDS TEAM".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("HELLO TDS TEAM".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("N".length()).addLengths("HELLO TDS TEAM".length()) - .addLengths("0".length()).addLengths("val123".length()).addLengths(-1).setValues(ByteString.copyFromUtf8( - "-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + - "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS TEAMHELLO TDS " + - "TEAMHELLO TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM0val123"))).build()); - } - - @Test public void testNextWithZeroRows() throws Exception { - Cursor cursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(getField("col0")) - .addFields(getField("col1")) + .addLengths("0".length()).addLengths("val123".length()).addLengths(-1).setValues( + ByteString.copyFromUtf8( + "-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + + "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS " + + "TEAMHELLO TDS " + + "TEAMHELLO TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM0val123"))).build()); + } + + @Test + public void testNextWithZeroRows() throws Exception { + Cursor cursor = new SimpleCursor( + Query.QueryResult.newBuilder().addFields(getField("col0")).addFields(getField("col1")) .addFields(getField("col2")).build()); - VitessResultSet vitessResultSet = new VitessResultSet(cursor); - assertEquals(false, vitessResultSet.next()); - } - - @Test public void testNextWithNonZeroRows() throws Exception { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor); - assertEquals(true, vitessResultSet.next()); - assertEquals(false, vitessResultSet.next()); - } - - @Test public void testgetString() throws SQLException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals("-50", vitessResultSet.getString(1)); - assertEquals("50", vitessResultSet.getString(2)); - assertEquals("-23000", vitessResultSet.getString(3)); - assertEquals("23000", vitessResultSet.getString(4)); - assertEquals("-100", vitessResultSet.getString(5)); - assertEquals("100", vitessResultSet.getString(6)); - assertEquals("-100", vitessResultSet.getString(7)); - assertEquals("100", vitessResultSet.getString(8)); - assertEquals("-1000", vitessResultSet.getString(9)); - assertEquals("1000", vitessResultSet.getString(10)); - assertEquals("24.52", vitessResultSet.getString(11)); - assertEquals("100.43", vitessResultSet.getString(12)); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(13)); - assertEquals("2016-02-06", vitessResultSet.getString(14)); - assertEquals("12:34:56", vitessResultSet.getString(15)); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(16)); - assertEquals("2016", vitessResultSet.getString(17)); - assertEquals("1234.56789", vitessResultSet.getString(18)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(19)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(20)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(21)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(22)); - assertEquals("N", vitessResultSet.getString(23)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(24)); - assertEquals("0", vitessResultSet.getString(25)); - assertEquals("val123", vitessResultSet.getString(26)); - assertEquals(null, vitessResultSet.getString(27)); - } - - @Test public void getObjectUint64AsBigInteger() throws SQLException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - - assertEquals(new BigInteger("1000"), vitessResultSet.getObject(10)); - } - - @Test public void getBigInteger() throws SQLException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - - assertEquals(new BigInteger("1000"), vitessResultSet.getBigInteger(10)); - } - - @Test public void testgetBoolean() throws SQLException { - Cursor cursor = getCursorWithRows(); - Cursor cursorWithRowsAsNull = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(true, vitessResultSet.getBoolean(25)); - assertEquals(false, vitessResultSet.getBoolean(1)); - vitessResultSet = new VitessResultSet(cursorWithRowsAsNull, getVitessStatement()); - vitessResultSet.next(); - assertEquals(false, vitessResultSet.getBoolean(25)); - assertEquals(false, vitessResultSet.getBoolean(1)); - } - - @Test public void testgetByte() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-50, vitessResultSet.getByte(1)); - assertEquals(1, vitessResultSet.getByte(25)); - } - - @Test public void testgetShort() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-23000, vitessResultSet.getShort(3)); - } - - @Test public void testgetInt() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-100, vitessResultSet.getInt(7)); - } - - @Test public void testgetLong() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-1000, vitessResultSet.getInt(9)); - } - - @Test public void testgetFloat() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(24.52f, vitessResultSet.getFloat(11), 0.001); - } - - @Test public void testgetDouble() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(100.43, vitessResultSet.getFloat(12), 0.001); - } - - @Test public void testBigDecimal() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), - vitessResultSet.getBigDecimal(18)); - } - - @Test public void testgetBytes() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), vitessResultSet.getBytes(19)); - } - - @Test public void testgetDate() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate(14)); - } - - @Test public void testgetTime() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Time(12, 34, 56), vitessResultSet.getTime(15)); - } - - @Test public void testgetTimestamp() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), - vitessResultSet.getTimestamp(13)); - } - - @Test public void testgetZeroTimestampGarble() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=garble", new Properties()))); - vitessResultSet.next(); - assertEquals("0002-11-30 00:00:00.0", - vitessResultSet.getTimestamp(28).toString()); - } - - @Test public void testgetZeroTimestampConvertToNill() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=convertToNull", new Properties()))); - vitessResultSet.next(); - Assert.assertNull(vitessResultSet.getTimestamp(28)); - } - - @Test public void testgetZeroTimestampException() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=exception", new Properties()))); - vitessResultSet.next(); - try { - vitessResultSet.getTimestamp(28); - Assert.fail("expected getTimestamp to throw an exception"); - } catch (SQLException e) {} - } - - @Test public void testgetZeroTimestampRound() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", new Properties()))); - vitessResultSet.next(); - assertEquals("0001-01-01 00:00:00.0", vitessResultSet.getTimestamp(28).toString()); - } - - @Test public void testgetZeroDateRound() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", new Properties()))); - vitessResultSet.next(); - assertEquals("0001-01-01", vitessResultSet.getDate(28).toString()); - } - - @Test public void testgetStringbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals("-50", vitessResultSet.getString("col1")); - assertEquals("50", vitessResultSet.getString("col2")); - assertEquals("-23000", vitessResultSet.getString("col3")); - assertEquals("23000", vitessResultSet.getString("col4")); - assertEquals("-100", vitessResultSet.getString("col5")); - assertEquals("100", vitessResultSet.getString("col6")); - assertEquals("-100", vitessResultSet.getString("col7")); - assertEquals("100", vitessResultSet.getString("col8")); - assertEquals("-1000", vitessResultSet.getString("col9")); - assertEquals("1000", vitessResultSet.getString("col10")); - assertEquals("24.52", vitessResultSet.getString("col11")); - assertEquals("100.43", vitessResultSet.getString("col12")); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col13")); - assertEquals("2016-02-06", vitessResultSet.getString("col14")); - assertEquals("12:34:56", vitessResultSet.getString("col15")); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col16")); - assertEquals("2016", vitessResultSet.getString("col17")); - assertEquals("1234.56789", vitessResultSet.getString("col18")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col19")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col20")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col21")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col22")); - assertEquals("N", vitessResultSet.getString("col23")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col24")); - assertEquals("1", vitessResultSet.getString("col25")); - assertEquals("val123", vitessResultSet.getString("col26")); - assertEquals("val123", vitessResultSet.getString("col27")); - } - - @Test public void testgetBooleanbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(true, vitessResultSet.getBoolean("col25")); - assertEquals(false, vitessResultSet.getBoolean("col1")); - } - - @Test public void testgetBytebyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-50, vitessResultSet.getByte("col1")); - assertEquals(1, vitessResultSet.getByte("col25")); - } - - @Test public void testgetShortbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-23000, vitessResultSet.getShort("col3")); - } - - @Test public void testgetIntbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-100, vitessResultSet.getInt("col7")); - } - - @Test public void testgetLongbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-1000, vitessResultSet.getInt("col9")); - } - - @Test public void testBigIntegerbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new BigInteger("1000"), - vitessResultSet.getBigInteger("col10")); - } - - @Test public void testgetFloatbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(24.52f, vitessResultSet.getFloat("col11"), 0.001); - } - - @Test public void testgetDoublebyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(100.43, vitessResultSet.getFloat("col12"), 0.001); - } - - @Test public void testBigDecimalbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), - vitessResultSet.getBigDecimal("col18")); - } - - @Test public void testgetBytesbyColumnLabel() - throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), - vitessResultSet.getBytes("col19")); - } - - @Test public void testgetDatebyColumnLabel() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate("col14")); - } - - @Test public void testgetTimebyColumnLabel() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Time(12, 34, 56), vitessResultSet.getTime("col15")); - } - - @Test public void testgetTimestampbyColumnLabel() - throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), - vitessResultSet.getTimestamp("col13")); - } - - @Test public void testgetAsciiStream() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor); - vitessResultSet.next(); - // Need to implement AssertEquivalant - //Assert.assertEquals((InputStream)(new ByteArrayInputStream("HELLO TDS TEAM".getBytes())), vitessResultSet - // .getAsciiStream(19)); - } - - @Test public void testGetBinaryStream() throws SQLException, IOException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - byte[] ba1 = new byte[128]; - new ByteArrayInputStream("HELLO TDS TEAM".getBytes()).read(ba1, 0, 128); - byte[] ba2 = new byte[128]; - vitessResultSet.getBinaryStream(19).read(ba2, 0, 128); - Assert.assertArrayEquals(ba1, ba2); - - byte[] ba3 = new byte[128]; - vitessResultSet.getBinaryStream(22).read(ba3, 0, 128); - Assert.assertArrayEquals(ba1, ba3); - - assertEquals(null, vitessResultSet.getBinaryStream(27)); - } - - @Test public void testEnhancedFieldsFromCursor() throws Exception { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - assertEquals(cursor.getFields().size(), vitessResultSet.getFields().size()); - } - - @Test public void testGetStringUsesEncoding() throws Exception { - VitessConnection conn = getVitessConnection(); - VitessResultSet resultOne = PowerMockito.spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); - resultOne.next(); - // test all ways to get to convertBytesToString - - // Verify that we're going through convertBytesToString for column types that return bytes (string-like), - // but not for those that return a real object - resultOne.getString("col21"); // is a string, should go through convert bytes - resultOne.getString("col13"); // is a datetime, should not - PowerMockito.verifyPrivate(resultOne, VerificationModeFactory.times(1)).invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - VitessResultSet resultTwo = PowerMockito.spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); - resultTwo.next(); - - // neither of these should go through convertBytesToString, because we didn't include all fields - resultTwo.getString("col21"); - resultTwo.getString("col13"); - PowerMockito.verifyPrivate(resultTwo, VerificationModeFactory.times(0)).invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); - } - - @Test public void testGetObjectForBitValues() throws Exception { - VitessConnection conn = getVitessConnection(); - - ByteString.Output value = ByteString.newOutput(); - value.write(new byte[] {1}); - value.write(new byte[] {0}); - value.write(new byte[] {1,2,3,4}); - - Query.QueryResult result = Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("col1").setColumnLength(1).setType(Query.Type.BIT)) - .addFields(Query.Field.newBuilder().setName("col2").setColumnLength(1).setType(Query.Type.BIT)) - .addFields(Query.Field.newBuilder().setName("col3").setColumnLength(4).setType(Query.Type.BIT)) - .addRows(Query.Row.newBuilder() - .addLengths(1) - .addLengths(1) - .addLengths(4) - .setValues(value.toByteString())) - .build(); - - VitessResultSet vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - assertEquals(true, vitessResultSet.getObject(1)); - assertEquals(false, vitessResultSet.getObject(2)); - Assert.assertArrayEquals(new byte[] {1,2,3,4}, (byte[]) vitessResultSet.getObject(3)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(3)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - Assert.assertArrayEquals(new byte[] { 1 }, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(new byte[] { 0 }, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(new byte[] {1,2,3,4}, (byte[]) vitessResultSet.getObject(3)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - } - - @Test public void testGetObjectForVarBinLikeValues() throws Exception { - VitessConnection conn = getVitessConnection(); - - ByteString.Output value = ByteString.newOutput(); - - byte[] binary = new byte[] {1,2,3,4}; - byte[] varbinary = new byte[] {1,2,3,4,5,6,7,8,9,10,11,12,13}; - byte[] blob = new byte[MysqlDefs.LENGTH_BLOB]; - for (int i = 0; i < blob.length; i++) { - blob[i] = 1; - } - byte[] fakeGeometry = new byte[] {2,3,4}; - - value.write(binary); - value.write(varbinary); - value.write(blob); - value.write(fakeGeometry); - - Query.QueryResult result = Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("col1") - .setColumnLength(4) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setType(Query.Type.BINARY) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)) - .addFields(Query.Field.newBuilder().setName("col2") - .setColumnLength(13) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setType(Query.Type.VARBINARY) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)) - .addFields(Query.Field.newBuilder().setName("col3") // should go to LONGVARBINARY due to below settings - .setColumnLength(MysqlDefs.LENGTH_BLOB) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.BLOB)) - .addFields(Query.Field.newBuilder().setName("col4") - .setType(Query.Type.GEOMETRY) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setType(Query.Type.BINARY) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)) - .addRows(Query.Row.newBuilder() - .addLengths(4) - .addLengths(13) - .addLengths(MysqlDefs.LENGTH_BLOB) - .addLengths(3) - .setValues(value.toByteString())) - .build(); - - VitessResultSet vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - // All of these types should pass straight through, returning the direct bytes - Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); - Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); - - // We should still call the function 4 times - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(4)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - // Same as above since this doesn't really do much but pass right through for the varbinary type - Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); - Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); - - // Never call because not including all - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - } - - @Test public void testGetObjectForStringLikeValues() throws Exception { - ByteString.Output value = ByteString.newOutput(); - - String trimmedCharStr = "wasting space"; - String varcharStr = "i have a variable length!"; - String masqueradingBlobStr = "look at me, im a blob"; - String textStr = "an enthralling string of TEXT in some foreign language"; - String jsonStr = "{\"status\": \"ok\"}"; - - int paddedCharColLength = 20; - byte[] trimmedChar = StringUtils.getBytes(trimmedCharStr, "UTF-16"); - byte[] varchar = StringUtils.getBytes(varcharStr, "UTF-8"); - byte[] masqueradingBlob = StringUtils.getBytes(masqueradingBlobStr, "US-ASCII"); - byte[] text = StringUtils.getBytes(textStr, "ISO8859_8"); - byte[] opaqueBinary = new byte[] { 1,2,3,4,5,6,7,8,9}; - byte[] json = StringUtils.getBytes(jsonStr, "UTF-8"); - - value.write(trimmedChar); - value.write(varchar); - value.write(opaqueBinary); - value.write(masqueradingBlob); - value.write(text); - value.write(json); - - Query.QueryResult result = Query.QueryResult.newBuilder() - // This tests CHAR - .addFields(Query.Field.newBuilder().setName("col1") - .setColumnLength(paddedCharColLength) - .setCharset(/* utf-16 collation index from CharsetMapping */ 54) - .setType(Query.Type.CHAR)) - // This tests VARCHAR - .addFields(Query.Field.newBuilder().setName("col2") - .setColumnLength(varchar.length) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8) - .setType(Query.Type.VARCHAR)) - // This tests VARCHAR that is an opaque binary - .addFields(Query.Field.newBuilder().setName("col2") - .setColumnLength(opaqueBinary.length) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.VARCHAR)) - // This tests LONGVARCHAR - .addFields(Query.Field.newBuilder().setName("col3") - .setColumnLength(masqueradingBlob.length) - .setCharset(/* us-ascii collation index from CharsetMapping */11) - .setType(Query.Type.BLOB)) - // This tests TEXT, which falls through the default case of the switch - .addFields(Query.Field.newBuilder().setName("col4") - .setColumnLength(text.length) - .setCharset(/* corresponds to greek, from CharsetMapping */25) - .setType(Query.Type.TEXT)) - .addFields(Query.Field.newBuilder().setName("col5") - .setColumnLength(json.length) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8) - .setType(Query.Type.JSON)) - .addRows(Query.Row.newBuilder() - .addLengths(trimmedChar.length) - .addLengths(varchar.length) - .addLengths(opaqueBinary.length) - .addLengths(masqueradingBlob.length) - .addLengths(text.length) - .addLengths(json.length) - .setValues(value.toByteString())) - .build(); - - VitessConnection conn = getVitessConnection(); - VitessResultSet vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - assertEquals(trimmedCharStr, vitessResultSet.getObject(1)); - assertEquals(varcharStr, vitessResultSet.getObject(2)); - Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); - assertEquals(masqueradingBlobStr, vitessResultSet.getObject(4)); - assertEquals(textStr, vitessResultSet.getObject(5)); - assertEquals(jsonStr, vitessResultSet.getObject(6)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(6)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - Assert.assertArrayEquals(trimmedChar, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(varchar, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); - Assert.assertArrayEquals(masqueradingBlob, (byte[]) vitessResultSet.getObject(4)); - Assert.assertArrayEquals(text, (byte[]) vitessResultSet.getObject(5)); - Assert.assertArrayEquals(json, (byte[]) vitessResultSet.getObject(6)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - } - - @Test public void testGetClob() throws SQLException { - VitessResultSet vitessResultSet = new VitessResultSet( - new String[]{"clob"}, new Query.Type[]{Query.Type.VARCHAR}, - new String[][]{new String[] {"clobValue"}}, - new ConnectionProperties()); - Assert.assertTrue(vitessResultSet.next()); - - Clob clob = vitessResultSet.getClob(1); - assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); - - clob = vitessResultSet.getClob("clob"); - assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); - } + VitessResultSet vitessResultSet = new VitessResultSet(cursor); + assertEquals(false, vitessResultSet.next()); + } + + @Test + public void testNextWithNonZeroRows() throws Exception { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor); + assertEquals(true, vitessResultSet.next()); + assertEquals(false, vitessResultSet.next()); + } + + @Test + public void testgetString() throws SQLException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals("-50", vitessResultSet.getString(1)); + assertEquals("50", vitessResultSet.getString(2)); + assertEquals("-23000", vitessResultSet.getString(3)); + assertEquals("23000", vitessResultSet.getString(4)); + assertEquals("-100", vitessResultSet.getString(5)); + assertEquals("100", vitessResultSet.getString(6)); + assertEquals("-100", vitessResultSet.getString(7)); + assertEquals("100", vitessResultSet.getString(8)); + assertEquals("-1000", vitessResultSet.getString(9)); + assertEquals("1000", vitessResultSet.getString(10)); + assertEquals("24.52", vitessResultSet.getString(11)); + assertEquals("100.43", vitessResultSet.getString(12)); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(13)); + assertEquals("2016-02-06", vitessResultSet.getString(14)); + assertEquals("12:34:56", vitessResultSet.getString(15)); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(16)); + assertEquals("2016", vitessResultSet.getString(17)); + assertEquals("1234.56789", vitessResultSet.getString(18)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(19)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(20)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(21)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(22)); + assertEquals("N", vitessResultSet.getString(23)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(24)); + assertEquals("0", vitessResultSet.getString(25)); + assertEquals("val123", vitessResultSet.getString(26)); + assertEquals(null, vitessResultSet.getString(27)); + } + + @Test + public void getObjectUint64AsBigInteger() throws SQLException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + + assertEquals(new BigInteger("1000"), vitessResultSet.getObject(10)); + } + + @Test + public void getBigInteger() throws SQLException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + + assertEquals(new BigInteger("1000"), vitessResultSet.getBigInteger(10)); + } + + @Test + public void testgetBoolean() throws SQLException { + Cursor cursor = getCursorWithRows(); + Cursor cursorWithRowsAsNull = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(true, vitessResultSet.getBoolean(25)); + assertEquals(false, vitessResultSet.getBoolean(1)); + vitessResultSet = new VitessResultSet(cursorWithRowsAsNull, getVitessStatement()); + vitessResultSet.next(); + assertEquals(false, vitessResultSet.getBoolean(25)); + assertEquals(false, vitessResultSet.getBoolean(1)); + } + + @Test + public void testgetByte() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-50, vitessResultSet.getByte(1)); + assertEquals(1, vitessResultSet.getByte(25)); + } + + @Test + public void testgetShort() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-23000, vitessResultSet.getShort(3)); + } + + @Test + public void testgetInt() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-100, vitessResultSet.getInt(7)); + } + + @Test + public void testgetLong() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-1000, vitessResultSet.getInt(9)); + } + + @Test + public void testgetFloat() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(24.52f, vitessResultSet.getFloat(11), 0.001); + } + + @Test + public void testgetDouble() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(100.43, vitessResultSet.getFloat(12), 0.001); + } + + @Test + public void testBigDecimal() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), + vitessResultSet.getBigDecimal(18)); + } + + @Test + public void testgetBytes() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), vitessResultSet.getBytes(19)); + } + + @Test + public void testgetDate() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate(14)); + } + + @Test + public void testgetTime() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Time(12, 34, 56), vitessResultSet.getTime(15)); + } + + @Test + public void testgetTimestamp() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), vitessResultSet.getTimestamp(13)); + } + + @Test + public void testgetZeroTimestampGarble() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=garble", + new Properties()))); + vitessResultSet.next(); + assertEquals("0002-11-30 00:00:00.0", vitessResultSet.getTimestamp(28).toString()); + } + + @Test + public void testgetZeroTimestampConvertToNill() + throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=convertToNull", + new Properties()))); + vitessResultSet.next(); + Assert.assertNull(vitessResultSet.getTimestamp(28)); + } + + @Test + public void testgetZeroTimestampException() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=exception", + new Properties()))); + vitessResultSet.next(); + try { + vitessResultSet.getTimestamp(28); + Assert.fail("expected getTimestamp to throw an exception"); + } catch (SQLException e) { + } + } + + @Test + public void testgetZeroTimestampRound() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", + new Properties()))); + vitessResultSet.next(); + assertEquals("0001-01-01 00:00:00.0", vitessResultSet.getTimestamp(28).toString()); + } + + @Test + public void testgetZeroDateRound() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", + new Properties()))); + vitessResultSet.next(); + assertEquals("0001-01-01", vitessResultSet.getDate(28).toString()); + } + + @Test + public void testgetStringbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals("-50", vitessResultSet.getString("col1")); + assertEquals("50", vitessResultSet.getString("col2")); + assertEquals("-23000", vitessResultSet.getString("col3")); + assertEquals("23000", vitessResultSet.getString("col4")); + assertEquals("-100", vitessResultSet.getString("col5")); + assertEquals("100", vitessResultSet.getString("col6")); + assertEquals("-100", vitessResultSet.getString("col7")); + assertEquals("100", vitessResultSet.getString("col8")); + assertEquals("-1000", vitessResultSet.getString("col9")); + assertEquals("1000", vitessResultSet.getString("col10")); + assertEquals("24.52", vitessResultSet.getString("col11")); + assertEquals("100.43", vitessResultSet.getString("col12")); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col13")); + assertEquals("2016-02-06", vitessResultSet.getString("col14")); + assertEquals("12:34:56", vitessResultSet.getString("col15")); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col16")); + assertEquals("2016", vitessResultSet.getString("col17")); + assertEquals("1234.56789", vitessResultSet.getString("col18")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col19")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col20")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col21")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col22")); + assertEquals("N", vitessResultSet.getString("col23")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col24")); + assertEquals("1", vitessResultSet.getString("col25")); + assertEquals("val123", vitessResultSet.getString("col26")); + assertEquals("val123", vitessResultSet.getString("col27")); + } + + @Test + public void testgetBooleanbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(true, vitessResultSet.getBoolean("col25")); + assertEquals(false, vitessResultSet.getBoolean("col1")); + } + + @Test + public void testgetBytebyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-50, vitessResultSet.getByte("col1")); + assertEquals(1, vitessResultSet.getByte("col25")); + } + + @Test + public void testgetShortbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-23000, vitessResultSet.getShort("col3")); + } + + @Test + public void testgetIntbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-100, vitessResultSet.getInt("col7")); + } + + @Test + public void testgetLongbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-1000, vitessResultSet.getInt("col9")); + } + + @Test + public void testBigIntegerbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new BigInteger("1000"), vitessResultSet.getBigInteger("col10")); + } + + @Test + public void testgetFloatbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(24.52f, vitessResultSet.getFloat("col11"), 0.001); + } + + @Test + public void testgetDoublebyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(100.43, vitessResultSet.getFloat("col12"), 0.001); + } + + @Test + public void testBigDecimalbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), + vitessResultSet.getBigDecimal("col18")); + } + + @Test + public void testgetBytesbyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), vitessResultSet.getBytes("col19")); + } + + @Test + public void testgetDatebyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate("col14")); + } + + @Test + public void testgetTimebyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Time(12, 34, 56), vitessResultSet.getTime("col15")); + } + + @Test + public void testgetTimestampbyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), vitessResultSet.getTimestamp("col13")); + } + + @Test + public void testgetAsciiStream() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor); + vitessResultSet.next(); + // Need to implement AssertEquivalant + //Assert.assertEquals((InputStream)(new ByteArrayInputStream("HELLO TDS TEAM".getBytes())), + // vitessResultSet + // .getAsciiStream(19)); + } + + @Test + public void testGetBinaryStream() throws SQLException, IOException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + byte[] ba1 = new byte[128]; + new ByteArrayInputStream("HELLO TDS TEAM".getBytes()).read(ba1, 0, 128); + byte[] ba2 = new byte[128]; + vitessResultSet.getBinaryStream(19).read(ba2, 0, 128); + Assert.assertArrayEquals(ba1, ba2); + + byte[] ba3 = new byte[128]; + vitessResultSet.getBinaryStream(22).read(ba3, 0, 128); + Assert.assertArrayEquals(ba1, ba3); + + assertEquals(null, vitessResultSet.getBinaryStream(27)); + } + + @Test + public void testEnhancedFieldsFromCursor() throws Exception { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + assertEquals(cursor.getFields().size(), vitessResultSet.getFields().size()); + } + + @Test + public void testGetStringUsesEncoding() throws Exception { + VitessConnection conn = getVitessConnection(); + VitessResultSet resultOne = PowerMockito + .spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); + resultOne.next(); + // test all ways to get to convertBytesToString + + // Verify that we're going through convertBytesToString for column types that return bytes + // (string-like), + // but not for those that return a real object + resultOne.getString("col21"); // is a string, should go through convert bytes + resultOne.getString("col13"); // is a datetime, should not + PowerMockito.verifyPrivate(resultOne, VerificationModeFactory.times(1)) + .invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + VitessResultSet resultTwo = PowerMockito + .spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); + resultTwo.next(); + + // neither of these should go through convertBytesToString, because we didn't include all fields + resultTwo.getString("col21"); + resultTwo.getString("col13"); + PowerMockito.verifyPrivate(resultTwo, VerificationModeFactory.times(0)) + .invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); + } + + @Test + public void testGetObjectForBitValues() throws Exception { + VitessConnection conn = getVitessConnection(); + + ByteString.Output value = ByteString.newOutput(); + value.write(new byte[]{1}); + value.write(new byte[]{0}); + value.write(new byte[]{1, 2, 3, 4}); + + Query.QueryResult result = Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("col1").setColumnLength(1).setType(Query.Type.BIT)) + .addFields( + Query.Field.newBuilder().setName("col2").setColumnLength(1).setType(Query.Type.BIT)) + .addFields( + Query.Field.newBuilder().setName("col3").setColumnLength(4).setType(Query.Type.BIT)) + .addRows(Query.Row.newBuilder().addLengths(1).addLengths(1).addLengths(4) + .setValues(value.toByteString())).build(); + + VitessResultSet vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + assertEquals(true, vitessResultSet.getObject(1)); + assertEquals(false, vitessResultSet.getObject(2)); + Assert.assertArrayEquals(new byte[]{1, 2, 3, 4}, (byte[]) vitessResultSet.getObject(3)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(3)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + Assert.assertArrayEquals(new byte[]{1}, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(new byte[]{0}, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(new byte[]{1, 2, 3, 4}, (byte[]) vitessResultSet.getObject(3)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + } + + @Test + public void testGetObjectForVarBinLikeValues() throws Exception { + VitessConnection conn = getVitessConnection(); + + ByteString.Output value = ByteString.newOutput(); + + byte[] binary = new byte[]{1, 2, 3, 4}; + byte[] varbinary = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; + byte[] blob = new byte[MysqlDefs.LENGTH_BLOB]; + for (int i = 0; i < blob.length; i++) { + blob[i] = 1; + } + byte[] fakeGeometry = new byte[]{2, 3, 4}; + + value.write(binary); + value.write(varbinary); + value.write(blob); + value.write(fakeGeometry); + + Query.QueryResult result = Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("col1").setColumnLength(4) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).setType(Query.Type.BINARY) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)).addFields( + Query.Field.newBuilder().setName("col2").setColumnLength(13) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).setType(Query.Type.VARBINARY) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)).addFields( + Query.Field.newBuilder().setName("col3") // should go to LONGVARBINARY due to below settings + .setColumnLength(MysqlDefs.LENGTH_BLOB) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.BLOB)).addFields( + Query.Field.newBuilder().setName("col4").setType(Query.Type.GEOMETRY) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).setType(Query.Type.BINARY) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)).addRows( + Query.Row.newBuilder().addLengths(4).addLengths(13).addLengths(MysqlDefs.LENGTH_BLOB) + .addLengths(3).setValues(value.toByteString())).build(); + + VitessResultSet vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + // All of these types should pass straight through, returning the direct bytes + Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); + Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); + + // We should still call the function 4 times + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(4)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + // Same as above since this doesn't really do much but pass right through for the varbinary type + Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); + Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); + + // Never call because not including all + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + } + + @Test + public void testGetObjectForStringLikeValues() throws Exception { + ByteString.Output value = ByteString.newOutput(); + + String trimmedCharStr = "wasting space"; + String varcharStr = "i have a variable length!"; + String masqueradingBlobStr = "look at me, im a blob"; + String textStr = "an enthralling string of TEXT in some foreign language"; + String jsonStr = "{\"status\": \"ok\"}"; + + int paddedCharColLength = 20; + byte[] trimmedChar = StringUtils.getBytes(trimmedCharStr, "UTF-16"); + byte[] varchar = StringUtils.getBytes(varcharStr, "UTF-8"); + byte[] masqueradingBlob = StringUtils.getBytes(masqueradingBlobStr, "US-ASCII"); + byte[] text = StringUtils.getBytes(textStr, "ISO8859_8"); + byte[] opaqueBinary = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] json = StringUtils.getBytes(jsonStr, "UTF-8"); + + value.write(trimmedChar); + value.write(varchar); + value.write(opaqueBinary); + value.write(masqueradingBlob); + value.write(text); + value.write(json); + + Query.QueryResult result = Query.QueryResult.newBuilder() + // This tests CHAR + .addFields(Query.Field.newBuilder().setName("col1").setColumnLength(paddedCharColLength) + .setCharset(/* utf-16 collation index from CharsetMapping */ 54) + .setType(Query.Type.CHAR)) + // This tests VARCHAR + .addFields(Query.Field.newBuilder().setName("col2").setColumnLength(varchar.length) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).setType(Query.Type.VARCHAR)) + // This tests VARCHAR that is an opaque binary + .addFields(Query.Field.newBuilder().setName("col2").setColumnLength(opaqueBinary.length) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.VARCHAR)) + // This tests LONGVARCHAR + .addFields(Query.Field.newBuilder().setName("col3").setColumnLength(masqueradingBlob.length) + .setCharset(/* us-ascii collation index from CharsetMapping */11) + .setType(Query.Type.BLOB)) + // This tests TEXT, which falls through the default case of the switch + .addFields(Query.Field.newBuilder().setName("col4").setColumnLength(text.length) + .setCharset(/* corresponds to greek, from CharsetMapping */25).setType(Query.Type.TEXT)) + .addFields(Query.Field.newBuilder().setName("col5").setColumnLength(json.length) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).setType(Query.Type.JSON)) + .addRows(Query.Row.newBuilder().addLengths(trimmedChar.length).addLengths(varchar.length) + .addLengths(opaqueBinary.length).addLengths(masqueradingBlob.length) + .addLengths(text.length).addLengths(json.length).setValues(value.toByteString())) + .build(); + + VitessConnection conn = getVitessConnection(); + VitessResultSet vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + assertEquals(trimmedCharStr, vitessResultSet.getObject(1)); + assertEquals(varcharStr, vitessResultSet.getObject(2)); + Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); + assertEquals(masqueradingBlobStr, vitessResultSet.getObject(4)); + assertEquals(textStr, vitessResultSet.getObject(5)); + assertEquals(jsonStr, vitessResultSet.getObject(6)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(6)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + Assert.assertArrayEquals(trimmedChar, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(varchar, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); + Assert.assertArrayEquals(masqueradingBlob, (byte[]) vitessResultSet.getObject(4)); + Assert.assertArrayEquals(text, (byte[]) vitessResultSet.getObject(5)); + Assert.assertArrayEquals(json, (byte[]) vitessResultSet.getObject(6)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + } + + @Test + public void testGetClob() throws SQLException { + VitessResultSet vitessResultSet = new VitessResultSet(new String[]{"clob"}, + new Query.Type[]{Query.Type.VARCHAR}, new String[][]{new String[]{"clobValue"}}, + new ConnectionProperties()); + Assert.assertTrue(vitessResultSet.next()); + + Clob clob = vitessResultSet.getClob(1); + assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); + + clob = vitessResultSet.getClob("clob"); + assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java index 2880d5ab3fe..4ea49adfcb2 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java @@ -16,12 +16,20 @@ package io.vitess.jdbc; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; import io.vitess.client.Context; import io.vitess.client.SQLFuture; @@ -41,697 +49,671 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyList; -import static org.mockito.Matchers.anyMap; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.verify; -import static org.powermock.api.mockito.PowerMockito.doReturn; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 19/01/16. */ @RunWith(PowerMockRunner.class) -@PrepareForTest({VTGateConnection.class, - Vtrpc.RPCError.class}) +@PrepareForTest({VTGateConnection.class, Vtrpc.RPCError.class}) public class VitessStatementTest { - private String sqlSelect = "select 1 from test_table"; - private String sqlShow = "show tables"; - private String sqlUpdate = "update test_table set msg = null"; - private String sqlInsert = "insert into test_table(msg) values ('abc')"; - private String sqlUpsert = "insert into test_table(msg) values ('abc') on duplicate key update msg = 'def'"; - - - @Test - public void testGetConnection() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(mockConn, statement.getConnection()); + private String sqlSelect = "select 1 from test_table"; + private String sqlShow = "show tables"; + private String sqlUpdate = "update test_table set msg = null"; + private String sqlInsert = "insert into test_table(msg) values ('abc')"; + private String sqlUpsert = "insert into test_table(msg) values ('abc') on duplicate key update " + + "msg = 'def'"; + + + @Test + public void testGetConnection() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(mockConn, statement.getConnection()); + } + + @Test + public void testGetResultSet() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(null, statement.getResultSet()); + } + + @Test + public void testExecuteQuery() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.isSimpleExecute()).thenReturn(true); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + //Empty Sql Statement + try { + statement.executeQuery(""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); } - @Test - public void testGetResultSet() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(null, statement.getResultSet()); + ResultSet rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //autocommit is false and not in transaction + when(mockConn.getAutoCommit()).thenReturn(false); + when(mockConn.isInTransaction()).thenReturn(false); + rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //when returned cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + statement.executeQuery(sqlSelect); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - - @Test - public void testExecuteQuery() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), any( - VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.isSimpleExecute()).thenReturn(true); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - //Empty Sql Statement - try { - statement.executeQuery(""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - ResultSet rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //autocommit is false and not in transaction - when(mockConn.getAutoCommit()).thenReturn(false); - when(mockConn.isInTransaction()).thenReturn(false); - rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //when returned cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - statement.executeQuery(sqlSelect); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } + } + + @Test + public void testExecuteQueryWithStreamExecuteType() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.STREAM); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + //Empty Sql Statement + try { + statement.executeQuery(""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); } - @Test - public void testExecuteQueryWithStreamExecuteType() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.STREAM); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - //Empty Sql Statement - try { - statement.executeQuery(""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - //select on replica - ResultSet rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //show query - rs = statement.executeQuery(sqlShow); - assertEquals(-1, statement.getUpdateCount()); - - //select on master when tx is null and autocommit is false - when(mockConn.getAutoCommit()).thenReturn(false); - when(mockConn.isInTransaction()).thenReturn(false); - rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //when returned cursor is null - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(null); - try { - statement.executeQuery(sqlSelect); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } + //select on replica + ResultSet rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //show query + rs = statement.executeQuery(sqlShow); + assertEquals(-1, statement.getUpdateCount()); + + //select on master when tx is null and autocommit is false + when(mockConn.getAutoCommit()).thenReturn(false); + when(mockConn.isInTransaction()).thenReturn(false); + rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //when returned cursor is null + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(null); + try { + statement.executeQuery(sqlSelect); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - - @Test - public void testExecuteFetchSizeAsStreaming() throws SQLException { - testExecute(5, true, false, true); - testExecute(5, false, false, true); - testExecute(0, true, true, false); - testExecute(0, false, false, true); + } + + @Test + public void testExecuteFetchSizeAsStreaming() throws SQLException { + testExecute(5, true, false, true); + testExecute(5, false, false, true); + testExecute(0, true, true, false); + testExecute(0, false, false, true); + } + + private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, + boolean shouldRunStreamExecute) throws SQLException { + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + + VitessConnection mockConn = mock(VitessConnection.class); + when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + + VitessStatement statement = new VitessStatement(mockConn); + statement.setFetchSize(fetchSize); + statement.executeQuery(sqlSelect); + + if (shouldRunExecute) { + verify(mockVtGateConn, Mockito.times(2)) + .execute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, boolean shouldRunStreamExecute) throws SQLException { - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - - VitessConnection mockConn = mock(VitessConnection.class); - when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - - VitessStatement statement = new VitessStatement(mockConn); - statement.setFetchSize(fetchSize); - statement.executeQuery(sqlSelect); - - if (shouldRunExecute) { - verify(mockVtGateConn, Mockito.times(2)).execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } - - if (shouldRunStreamExecute) { - verify(mockVtGateConn).streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } + if (shouldRunStreamExecute) { + verify(mockVtGateConn) + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - - @Test - public void testExecuteUpdate() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List fieldList = mock(ArrayList.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - //executing dml on master - int updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(0, updateCount); - - //tx is null & autoCommit is true - when(mockConn.getAutoCommit()).thenReturn(true); - updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(0, updateCount); - - //cursor fields is not null - when(mockCursor.getFields()).thenReturn(fieldList); - when(fieldList.isEmpty()).thenReturn(false); - try { - statement.executeUpdate(sqlSelect); - fail("Should have thrown exception for field not null"); - } catch (SQLException ex) { - assertEquals("ResultSet generation is not allowed through this method", - ex.getMessage()); - } - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - statement.executeUpdate(sqlUpdate); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - statement.execute("UPDATE SET foo = 1 ON mytable WHERE id = 1"); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - statement.executeBatch(); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } + } + + @Test + public void testExecuteUpdate() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List fieldList = mock(ArrayList.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + //executing dml on master + int updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(0, updateCount); + + //tx is null & autoCommit is true + when(mockConn.getAutoCommit()).thenReturn(true); + updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(0, updateCount); + + //cursor fields is not null + when(mockCursor.getFields()).thenReturn(fieldList); + when(fieldList.isEmpty()).thenReturn(false); + try { + statement.executeUpdate(sqlSelect); + fail("Should have thrown exception for field not null"); + } catch (SQLException ex) { + assertEquals("ResultSet generation is not allowed through this method", ex.getMessage()); } - @Test - public void testExecute() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List mockFieldList = PowerMockito.spy(new ArrayList<>()); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.getAutoCommit()).thenReturn(true); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(mockFieldList); - - VitessStatement statement = new VitessStatement(mockConn); - int fieldSize = 5; - when(mockCursor.getFields()).thenReturn(mockFieldList); - doReturn(fieldSize).when(mockFieldList).size(); - doReturn(false).when(mockFieldList).isEmpty(); - - boolean hasResultSet = statement.execute(sqlSelect); - assertTrue(hasResultSet); - assertNotNull(statement.getResultSet()); - - hasResultSet = statement.execute(sqlShow); - assertTrue(hasResultSet); - assertNotNull(statement.getResultSet()); - - int mockUpdateCount = 10; - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); - hasResultSet = statement.execute(sqlUpdate); - assertFalse(hasResultSet); - assertNull(statement.getResultSet()); - assertEquals(mockUpdateCount, statement.getUpdateCount()); - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - statement.execute(sqlUpdate); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + statement.executeUpdate(sqlUpdate); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - @Test - public void testGetUpdateCount() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFuture = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFuture); - when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - when(mockCursor.getRowsAffected()).thenReturn(10L); - int updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(10L, updateCount); - assertEquals(10L, statement.getUpdateCount()); - - // Truncated Update Count - when(mockCursor.getRowsAffected()) - .thenReturn((long) Integer.MAX_VALUE + 10); - updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(Integer.MAX_VALUE, updateCount); - assertEquals(Integer.MAX_VALUE, statement.getUpdateCount()); - - when(mockConn.isSimpleExecute()).thenReturn(true); - statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + statement.execute("UPDATE SET foo = 1 ON mytable WHERE id = 1"); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); } - @Test - public void testClose() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - VitessStatement statement = new VitessStatement(mockConn); - ResultSet rs = statement.executeQuery(sqlSelect); - statement.close(); - try { - statement.executeQuery(sqlSelect); - fail("Should have thrown exception for statement closed"); - } catch (SQLException ex) { - assertEquals("Statement is closed", ex.getMessage()); - } + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + statement.executeBatch(); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); } - - @Test - public void testGetMaxFieldSize() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(65535, statement.getMaxFieldSize()); + } + + @Test + public void testExecute() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List mockFieldList = PowerMockito.spy(new ArrayList<>()); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.getAutoCommit()).thenReturn(true); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(mockFieldList); + + VitessStatement statement = new VitessStatement(mockConn); + int fieldSize = 5; + when(mockCursor.getFields()).thenReturn(mockFieldList); + doReturn(fieldSize).when(mockFieldList).size(); + doReturn(false).when(mockFieldList).isEmpty(); + + boolean hasResultSet = statement.execute(sqlSelect); + assertTrue(hasResultSet); + assertNotNull(statement.getResultSet()); + + hasResultSet = statement.execute(sqlShow); + assertTrue(hasResultSet); + assertNotNull(statement.getResultSet()); + + int mockUpdateCount = 10; + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); + hasResultSet = statement.execute(sqlUpdate); + assertFalse(hasResultSet); + assertNull(statement.getResultSet()); + assertEquals(mockUpdateCount, statement.getUpdateCount()); + + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + statement.execute(sqlUpdate); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - - @Test - public void testGetMaxRows() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - - statement.setMaxRows(10); - assertEquals(10, statement.getMaxRows()); - - try { - statement.setMaxRows(-1); - fail("Should have thrown exception for wrong value"); - } catch (SQLException ex) { - assertEquals("Illegal value for max row", ex.getMessage()); - } - + } + + @Test + public void testGetUpdateCount() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFuture = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFuture); + when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + when(mockCursor.getRowsAffected()).thenReturn(10L); + int updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(10L, updateCount); + assertEquals(10L, statement.getUpdateCount()); + + // Truncated Update Count + when(mockCursor.getRowsAffected()).thenReturn((long) Integer.MAX_VALUE + 10); + updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(Integer.MAX_VALUE, updateCount); + assertEquals(Integer.MAX_VALUE, statement.getUpdateCount()); + + when(mockConn.isSimpleExecute()).thenReturn(true); + statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + } + + @Test + public void testClose() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + VitessStatement statement = new VitessStatement(mockConn); + ResultSet rs = statement.executeQuery(sqlSelect); + statement.close(); + try { + statement.executeQuery(sqlSelect); + fail("Should have thrown exception for statement closed"); + } catch (SQLException ex) { + assertEquals("Statement is closed", ex.getMessage()); } + } - @Test - public void testGetQueryTimeout() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); + @Test + public void testGetMaxFieldSize() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(30, statement.getQueryTimeout()); - } + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(65535, statement.getMaxFieldSize()); + } - @Test - public void testGetQueryTimeoutZeroDefault() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTimeout()).thenReturn(0L); + @Test + public void testGetMaxRows() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(0, statement.getQueryTimeout()); - } - - @Test - public void testSetQueryTimeout() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); - - VitessStatement statement = new VitessStatement(mockConn); - - int queryTimeout = 10; - statement.setQueryTimeout(queryTimeout); - assertEquals(queryTimeout, statement.getQueryTimeout()); - try { - queryTimeout = -1; - statement.setQueryTimeout(queryTimeout); - fail("Should have thrown exception for wrong value"); - } catch (SQLException ex) { - assertEquals("Illegal value for query timeout", ex.getMessage()); - } - - statement.setQueryTimeout(0); - assertEquals(30, statement.getQueryTimeout()); - } + VitessStatement statement = new VitessStatement(mockConn); - @Test - public void testGetWarnings() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); + statement.setMaxRows(10); + assertEquals(10, statement.getMaxRows()); - VitessStatement statement = new VitessStatement(mockConn); - assertNull(statement.getWarnings()); + try { + statement.setMaxRows(-1); + fail("Should have thrown exception for wrong value"); + } catch (SQLException ex) { + assertEquals("Illegal value for max row", ex.getMessage()); } - @Test - public void testGetFetchDirection() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); + } + + @Test + public void testGetQueryTimeout() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(30, statement.getQueryTimeout()); + } + + @Test + public void testGetQueryTimeoutZeroDefault() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTimeout()).thenReturn(0L); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(0, statement.getQueryTimeout()); + } + + @Test + public void testSetQueryTimeout() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); + + VitessStatement statement = new VitessStatement(mockConn); + + int queryTimeout = 10; + statement.setQueryTimeout(queryTimeout); + assertEquals(queryTimeout, statement.getQueryTimeout()); + try { + queryTimeout = -1; + statement.setQueryTimeout(queryTimeout); + fail("Should have thrown exception for wrong value"); + } catch (SQLException ex) { + assertEquals("Illegal value for query timeout", ex.getMessage()); } - @Test - public void testGetFetchSize() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(0, statement.getFetchSize()); + statement.setQueryTimeout(0); + assertEquals(30, statement.getQueryTimeout()); + } + + @Test + public void testGetWarnings() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertNull(statement.getWarnings()); + } + + @Test + public void testGetFetchDirection() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); + } + + @Test + public void testGetFetchSize() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(0, statement.getFetchSize()); + } + + @Test + public void testGetResultSetConcurrency() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(ResultSet.CONCUR_READ_ONLY, statement.getResultSetConcurrency()); + } + + @Test + public void testGetResultSetType() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(ResultSet.TYPE_FORWARD_ONLY, statement.getResultSetType()); + } + + @Test + public void testIsClosed() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertFalse(statement.isClosed()); + statement.close(); + assertTrue(statement.isClosed()); + } + + @Test + public void testAutoGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; + int expectedAffectedRows = 5; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedAffectedRows)); + + //Executing Insert Statement + int updateCount = statement.executeUpdate(sqlInsert, Statement.RETURN_GENERATED_KEYS); + assertEquals(expectedAffectedRows, updateCount); + + ResultSet rs = statement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i++], generatedId); } - @Test - public void testGetResultSetConcurrency() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(ResultSet.CONCUR_READ_ONLY, statement.getResultSetConcurrency()); + //Fetching Generated Keys without notifying the driver + statement.executeUpdate(sqlInsert); + try { + statement.getGeneratedKeys(); + fail("Should have thrown exception for not setting autoGeneratedKey flag"); + } catch (SQLException ex) { + assertEquals("Generated keys not requested. You need to specify Statement" + + ".RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection" + + ".prepareStatement()", + ex.getMessage()); } - @Test - public void testGetResultSetType() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(ResultSet.TYPE_FORWARD_ONLY, statement.getResultSetType()); + //Fetching Generated Keys on update query + expectedFirstGeneratedId = 0; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + updateCount = statement.executeUpdate(sqlUpdate, Statement.RETURN_GENERATED_KEYS); + assertEquals(expectedAffectedRows, updateCount); + + rs = statement.getGeneratedKeys(); + assertFalse(rs.next()); + } + + @Test + public void testAddBatch() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + statement.addBatch(sqlInsert); + Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + assertEquals(sqlInsert, ((List) privateStringField.get(statement)).get(0)); + } + + @Test + public void testClearBatch() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + statement.addBatch(sqlInsert); + statement.clearBatch(); + Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + assertTrue(((List) privateStringField.get(statement)).isEmpty()); + } + + @Test + public void testExecuteBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + int[] updateCounts = statement.executeBatch(); + assertEquals(0, updateCounts.length); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when( + mockVtGateConn.executeBatch(any(Context.class), anyList(), anyList(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError1 = mock(CursorWithError.class); + when(mockCursorWithError1.getError()).thenReturn(null); + when(mockCursorWithError1.getCursor()).thenReturn(mock(Cursor.class)); + mockCursorWithErrorList.add(mockCursorWithError1); + + statement.addBatch(sqlUpdate); + updateCounts = statement.executeBatch(); + assertEquals(1, updateCounts.length); + + CursorWithError mockCursorWithError2 = mock(CursorWithError.class); + Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder() + .setMessage("statement execute batch error").build(); + when(mockCursorWithError2.getError()).thenReturn(rpcError); + mockCursorWithErrorList.add(mockCursorWithError2); + statement.addBatch(sqlUpdate); + statement.addBatch(sqlUpdate); + try { + statement.executeBatch(); + fail("Should have thrown Exception"); + } catch (BatchUpdateException ex) { + assertEquals(rpcError.toString(), ex.getMessage()); + assertEquals(2, ex.getUpdateCounts().length); + assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); } - @Test - public void testIsClosed() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertFalse(statement.isClosed()); - statement.close(); - assertTrue(statement.isClosed()); + } + + @Test + public void testBatchGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + when( + mockVtGateConn.executeBatch(any(Context.class), anyList(), anyList(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError = mock(CursorWithError.class); + when(mockCursorWithError.getError()).thenReturn(null); + when(mockCursorWithError.getCursor()).thenReturn(mockCursor); + mockCursorWithErrorList.add(mockCursorWithError); + + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); + + statement.addBatch(sqlInsert); + statement.executeBatch(); + + ResultSet rs = statement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i++], generatedId); } - - @Test - public void testAutoGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; - int expectedAffectedRows = 5; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()) - .thenReturn(Long.valueOf(expectedAffectedRows)); - - //Executing Insert Statement - int updateCount = statement.executeUpdate(sqlInsert, Statement.RETURN_GENERATED_KEYS); - assertEquals(expectedAffectedRows, updateCount); - - ResultSet rs = statement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i++], generatedId); - } - - //Fetching Generated Keys without notifying the driver - statement.executeUpdate(sqlInsert); - try { - statement.getGeneratedKeys(); - fail("Should have thrown exception for not setting autoGeneratedKey flag"); - } catch (SQLException ex) { - assertEquals("Generated keys not requested. You need to specify Statement" - + ".RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection.prepareStatement()", - ex.getMessage()); - } - - //Fetching Generated Keys on update query - expectedFirstGeneratedId = 0; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - updateCount = statement.executeUpdate(sqlUpdate, Statement.RETURN_GENERATED_KEYS); - assertEquals(expectedAffectedRows, updateCount); - - rs = statement.getGeneratedKeys(); - assertFalse(rs.next()); + } + + @Test + public void testBatchUpsertGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + when( + mockVtGateConn.executeBatch(any(Context.class), anyList(), anyList(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError = mock(CursorWithError.class); + when(mockCursorWithError.getError()).thenReturn(null); + when(mockCursorWithError.getCursor()).thenReturn(mockCursor); + mockCursorWithErrorList.add(mockCursorWithError); + + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122}; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); + + statement.addBatch(sqlUpsert); + statement.executeBatch(); + + ResultSet rs = statement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i], generatedId); + assertEquals(i, 0); // we should only have one + i++; } - @Test - public void testAddBatch() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - statement.addBatch(sqlInsert); - Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - assertEquals(sqlInsert, ((List) privateStringField.get(statement)).get(0)); - } - - @Test - public void testClearBatch() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - statement.addBatch(sqlInsert); - statement.clearBatch(); - Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - assertTrue(((List) privateStringField.get(statement)).isEmpty()); - } - - @Test - public void testExecuteBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - int[] updateCounts = statement.executeBatch(); - assertEquals(0, updateCounts.length); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockVtGateConn - .executeBatch(any(Context.class), anyList(), anyList(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError1 = mock(CursorWithError.class); - when(mockCursorWithError1.getError()).thenReturn(null); - when(mockCursorWithError1.getCursor()) - .thenReturn(mock(Cursor.class)); - mockCursorWithErrorList.add(mockCursorWithError1); - - statement.addBatch(sqlUpdate); - updateCounts = statement.executeBatch(); - assertEquals(1, updateCounts.length); - - CursorWithError mockCursorWithError2 = mock(CursorWithError.class); - Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder().setMessage("statement execute batch error").build(); - when(mockCursorWithError2.getError()) - .thenReturn(rpcError); - mockCursorWithErrorList.add(mockCursorWithError2); - statement.addBatch(sqlUpdate); - statement.addBatch(sqlUpdate); - try { - statement.executeBatch(); - fail("Should have thrown Exception"); - } catch (BatchUpdateException ex) { - assertEquals(rpcError.toString(), ex.getMessage()); - assertEquals(2, ex.getUpdateCounts().length); - assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); - } + VitessStatement noUpdate = new VitessStatement(mockConn); + when(mockCursor.getInsertId()).thenReturn(0L); + when(mockCursor.getRowsAffected()).thenReturn(1L); - } - - @Test - public void testBatchGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - when(mockVtGateConn - .executeBatch(any(Context.class), - anyList(), - anyList(), - any(VTSession.class))) - .thenReturn(mockSqlFutureCursor); - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError = mock(CursorWithError.class); - when(mockCursorWithError.getError()).thenReturn(null); - when(mockCursorWithError.getCursor()).thenReturn(mockCursor); - mockCursorWithErrorList.add(mockCursorWithError); - - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); - - statement.addBatch(sqlInsert); - statement.executeBatch(); - - ResultSet rs = statement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i++], generatedId); - } - } + noUpdate.addBatch(sqlUpsert); + noUpdate.executeBatch(); - @Test - public void testBatchUpsertGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - when(mockVtGateConn - .executeBatch(any(Context.class), - anyList(), - anyList(), - any(VTSession.class))) - .thenReturn(mockSqlFutureCursor); - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError = mock(CursorWithError.class); - when(mockCursorWithError.getError()).thenReturn(null); - when(mockCursorWithError.getCursor()).thenReturn(mockCursor); - mockCursorWithErrorList.add(mockCursorWithError); - - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122}; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); - - statement.addBatch(sqlUpsert); - statement.executeBatch(); - - ResultSet rs = statement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i], generatedId); - assertEquals(i, 0); // we should only have one - i++; - } - - VitessStatement noUpdate = new VitessStatement(mockConn); - when(mockCursor.getInsertId()).thenReturn(0L); - when(mockCursor.getRowsAffected()).thenReturn(1L); - - noUpdate.addBatch(sqlUpsert); - noUpdate.executeBatch(); - - ResultSet empty = noUpdate.getGeneratedKeys(); - assertFalse(empty.next()); - } + ResultSet empty = noUpdate.getGeneratedKeys(); + assertFalse(empty.next()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java index 86eb64f43d7..5509e50aa9a 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java @@ -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,81 +16,90 @@ package io.vitess.jdbc; -import org.joda.time.Duration; -import org.junit.Assert; -import org.junit.Test; - import io.vitess.client.Context; import io.vitess.client.RpcClient; import io.vitess.client.VTGateConnection; import io.vitess.client.grpc.GrpcClientFactory; import io.vitess.proto.Vtrpc; +import org.joda.time.Duration; + import java.io.IOException; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +import org.junit.Assert; +import org.junit.Test; + /** * Created by naveen.nahata on 29/02/16. */ public class VitessVTGateManagerTest { - public VTGateConnection getVtGateConn() { - Vtrpc.CallerID callerId = Vtrpc.CallerID.newBuilder().setPrincipal("username").build(); - Context ctx = - Context.getDefault().withDeadlineAfter(Duration.millis(500)).withCallerId(callerId); - RpcClient client = new GrpcClientFactory().create(ctx, "host:80"); - return new VTGateConnection(client); - } + public VTGateConnection getVtGateConn() { + Vtrpc.CallerID callerId = Vtrpc.CallerID.newBuilder().setPrincipal("username").build(); + Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(500)) + .withCallerId(callerId); + RpcClient client = new GrpcClientFactory().create(ctx, "host:80"); + return new VTGateConnection(client); + } - @Test public void testVtGateConnectionsConstructorMultipleVtGateConnections() - throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { - VitessVTGateManager.close(); - Properties info = new Properties(); - info.setProperty("username", "user"); - VitessConnection connection = new VitessConnection( - "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" - + ".233:15991/shipment/shipment?tabletType=master", info); - VitessVTGateManager.VTGateConnections vtGateConnections = - new VitessVTGateManager.VTGateConnections(connection); + @Test + public void testVtGateConnectionsConstructorMultipleVtGateConnections() + throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { + VitessVTGateManager.close(); + Properties info = new Properties(); + info.setProperty("username", "user"); + VitessConnection connection = new VitessConnection( + "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" + + ".233:15991/shipment/shipment?tabletType=master", info); + VitessVTGateManager.VTGateConnections vtGateConnections = + new VitessVTGateManager.VTGateConnections( + connection); - info.setProperty("username", "user"); - VitessConnection connection1 = new VitessConnection( - "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,11.33.17" - + ".233:15991/shipment/shipment?tabletType=master", info); - VitessVTGateManager.VTGateConnections vtGateConnections1 = - new VitessVTGateManager.VTGateConnections(connection1); + info.setProperty("username", "user"); + VitessConnection connection1 = new VitessConnection( + "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,11.33.17" + + ".233:15991/shipment/shipment?tabletType=master", info); + VitessVTGateManager.VTGateConnections vtGateConnections1 = + new VitessVTGateManager.VTGateConnections( + connection1); - Field privateMapField = VitessVTGateManager.class. - getDeclaredField("vtGateConnHashMap"); - privateMapField.setAccessible(true); - ConcurrentHashMap map = - (ConcurrentHashMap) privateMapField.get(VitessVTGateManager.class); - Assert.assertEquals(4, map.size()); - VitessVTGateManager.close(); - } + Field privateMapField = VitessVTGateManager.class. + getDeclaredField("vtGateConnHashMap"); + privateMapField.setAccessible(true); + ConcurrentHashMap map = (ConcurrentHashMap) privateMapField + .get(VitessVTGateManager.class); + Assert.assertEquals(4, map.size()); + VitessVTGateManager.close(); + } - @Test public void testVtGateConnectionsConstructor() - throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { - VitessVTGateManager.close(); - Properties info = new Properties(); - info.setProperty("username", "user"); - VitessConnection connection = new VitessConnection( - "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" - + ".233:15991/shipment/shipment?tabletType=master", info); - VitessVTGateManager.VTGateConnections vtGateConnections = - new VitessVTGateManager.VTGateConnections(connection); - Assert.assertEquals(vtGateConnections.getVtGateConnInstance() instanceof VTGateConnection, true); - VTGateConnection vtGateConn = vtGateConnections.getVtGateConnInstance(); - Field privateMapField = VitessVTGateManager.class. - getDeclaredField("vtGateConnHashMap"); - privateMapField.setAccessible(true); - ConcurrentHashMap map = - (ConcurrentHashMap) privateMapField.get(VitessVTGateManager.class); - Assert.assertEquals(3, map.size()); - VitessVTGateManager.close(); - } + @Test + public void testVtGateConnectionsConstructor() + throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { + VitessVTGateManager.close(); + Properties info = new Properties(); + info.setProperty("username", "user"); + VitessConnection connection = new VitessConnection( + "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" + + ".233:15991/shipment/shipment?tabletType=master", info); + VitessVTGateManager.VTGateConnections vtGateConnections = + new VitessVTGateManager.VTGateConnections( + connection); + Assert + .assertEquals(vtGateConnections.getVtGateConnInstance() instanceof VTGateConnection, true); + VTGateConnection vtGateConn = vtGateConnections.getVtGateConnInstance(); + Field privateMapField = VitessVTGateManager.class. + getDeclaredField("vtGateConnHashMap"); + privateMapField.setAccessible(true); + ConcurrentHashMap map = (ConcurrentHashMap) privateMapField + .get(VitessVTGateManager.class); + Assert.assertEquals(3, map.size()); + VitessVTGateManager.close(); + } } diff --git a/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java b/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java index a76a9aacb3a..9b87e0fce20 100644 --- a/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java +++ b/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java @@ -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.util; import com.google.common.collect.Lists; + import org.junit.Assert; import org.junit.Test; @@ -40,10 +41,14 @@ public void quoteIdentifierTest() { Assert.assertEquals("'this is a test'", StringUtils.quoteIdentifier("this is a test", "'")); Assert.assertEquals("'this is a test'", StringUtils.quoteIdentifier("'this is a test'", "'")); Assert.assertEquals("'this is'' a test'", StringUtils.quoteIdentifier("this is' a test", "'")); - Assert.assertEquals("'this is'''' a test'", StringUtils.quoteIdentifier("this is'' a test", "'")); - Assert.assertEquals("'this is'' a test'", StringUtils.quoteIdentifier("'this is'' a test'", "'")); - Assert.assertEquals("'this is a ''test'''", StringUtils.quoteIdentifier("this is a 'test'", "'")); - Assert.assertEquals("'this is a ''test'''", StringUtils.quoteIdentifier("'this is a ''test'''", "'")); + Assert + .assertEquals("'this is'''' a test'", StringUtils.quoteIdentifier("this is'' a test", "'")); + Assert + .assertEquals("'this is'' a test'", StringUtils.quoteIdentifier("'this is'' a test'", "'")); + Assert + .assertEquals("'this is a ''test'''", StringUtils.quoteIdentifier("this is a 'test'", "'")); + Assert.assertEquals("'this is a ''test'''", + StringUtils.quoteIdentifier("'this is a ''test'''", "'")); Assert.assertEquals(null, StringUtils.quoteIdentifier(null, "'")); Assert.assertEquals("this is a test", StringUtils.quoteIdentifier("this is a test", "")); Assert.assertEquals("this is a test", StringUtils.quoteIdentifier("this is a test", " ")); @@ -54,16 +59,24 @@ public void unQuoteIdentifierTest() { Assert.assertEquals(null, StringUtils.unQuoteIdentifier(null, "'")); Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", "")); Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", " ")); - Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", "\"")); + Assert + .assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", "\"")); Assert.assertEquals("this is a test'", StringUtils.unQuoteIdentifier("this is a test'", "'")); Assert.assertEquals("this is a test", StringUtils.unQuoteIdentifier("'this is a test'", "'")); - Assert.assertEquals("this is 'a' test", StringUtils.unQuoteIdentifier("'this is ''a'' test'", "'")); - Assert.assertEquals("this is 'a'' test", StringUtils.unQuoteIdentifier("'this is ''a'''' test'", "'")); - Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'''this is a test'''", "'")); - Assert.assertEquals("this is a test", StringUtils.unQuoteIdentifier("``this is a test``", "``")); - Assert.assertEquals("``this is ``a test``", StringUtils.unQuoteIdentifier("``this is ``a test``", "``")); - Assert.assertEquals("this is ``a test", StringUtils.unQuoteIdentifier("``this is ````a test``", "``")); - Assert.assertEquals("'this is ''a' test'", StringUtils.unQuoteIdentifier("'this is ''a' test'", "'")); + Assert.assertEquals("this is 'a' test", + StringUtils.unQuoteIdentifier("'this is ''a'' test'", "'")); + Assert.assertEquals("this is 'a'' test", + StringUtils.unQuoteIdentifier("'this is ''a'''' test'", "'")); + Assert.assertEquals("'this is a test'", + StringUtils.unQuoteIdentifier("'''this is a test'''", "'")); + Assert + .assertEquals("this is a test", StringUtils.unQuoteIdentifier("``this is a test``", "``")); + Assert.assertEquals("``this is ``a test``", + StringUtils.unQuoteIdentifier("``this is ``a test``", "``")); + Assert.assertEquals("this is ``a test", + StringUtils.unQuoteIdentifier("``this is ````a test``", "``")); + Assert.assertEquals("'this is ''a' test'", + StringUtils.unQuoteIdentifier("'this is ''a' test'", "'")); } @Test @@ -74,9 +87,11 @@ public void indexOfIgnoreCaseTestDefault() { Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(8, "this is a test", "this", "`", "`")); Assert.assertEquals(7, StringUtils.indexOfIgnoreCase(0, "this is a test", " a ", "`", "`")); Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "this is `a` test", "a", "`", "`")); - Assert.assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is \\`a\\` test", "a", "`", "`")); + Assert + .assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is \\`a\\` test", "a", "`", "`")); Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "this `is \\`a` test", "a", "`", "`")); - Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "th'is' `is` a test", "is", "`'", "`'")); + Assert + .assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "th'is' `is` a test", "is", "`'", "`'")); Assert.assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is a test", "TEST", "`", "`")); Assert.assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is ``a` test", "a", "`", "`")); @@ -103,26 +118,39 @@ public void splitTest() { } catch (IllegalArgumentException ignored) { // expected } - Assert.assertEquals(Lists.newArrayList("one", "two", "three"), StringUtils.split("one,two,three", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "`two,three`"), StringUtils.split("one,`two,three`", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "{tw{o,t}hree}"), StringUtils.split("one,{tw{o,t}hree}", ",", "{", "}")); - Assert.assertEquals(Lists.newArrayList("one", "/*two,three*/"), StringUtils.split("one,/*two,three*/", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "-- two,three\n", "four"), StringUtils.split("one,-- two,three\n,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "-- two,three\r\n", "four"), StringUtils.split("one,-- two,three\r\n,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "#two,three\n", "four"), StringUtils.split("one,#two,three\n,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "--;two", "three", "four"), StringUtils.split("one,--;two,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "two", "three"), + StringUtils.split("one,two,three", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "`two,three`"), + StringUtils.split("one,`two,three`", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "{tw{o,t}hree}"), + StringUtils.split("one,{tw{o,t}hree}", ",", "{", "}")); + Assert.assertEquals(Lists.newArrayList("one", "/*two,three*/"), + StringUtils.split("one,/*two,three*/", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "-- two,three\n", "four"), + StringUtils.split("one,-- two,three\n,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "-- two,three\r\n", "four"), + StringUtils.split("one,-- two,three\r\n,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "#two,three\n", "four"), + StringUtils.split("one,#two,three\n,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "--;two", "three", "four"), + StringUtils.split("one,--;two,three,four", ",", "`", "`")); // split doesn't use ALLOW_BACKSLASH_ESCAPE, so escaping delimiter doesn't work - Assert.assertEquals(Lists.newArrayList("one", "two\\", "three", "four"), StringUtils.split("one,two\\,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "two\\", "three", "four"), + StringUtils.split("one,two\\,three,four", ",", "`", "`")); // the following comment is a special non-comment block, and it should be split - Assert.assertEquals(Lists.newArrayList("one", "/*!50110 one", " two */two", "three", "four"), StringUtils.split("one,/*!50110 one, two */two,three,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "/*!5011 one", " two */two", "three", "four"), StringUtils.split("one,/*!5011 one, two */two,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "/*!50110 one", " two */two", "three", "four"), + StringUtils.split("one,/*!50110 one, two */two,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "/*!5011 one", " two */two", "three", "four"), + StringUtils.split("one,/*!5011 one, two */two,three,four", ",", "`", "`")); } @Test public void firstAlphaCharUcTest() { - Assert.assertEquals('S', StringUtils.firstAlphaCharUc("(select * from foo) union (select * from bar)", 0)); + Assert.assertEquals('S', + StringUtils.firstAlphaCharUc("(select * from foo) union (select * from bar)", 0)); Assert.assertEquals('R', StringUtils.firstAlphaCharUc("replace into table1 values()", 0)); Assert.assertEquals('S', StringUtils.firstAlphaCharUc("SET replication_speed='ludicrous'", 0)); - Assert.assertEquals('S', StringUtils.firstAlphaCharUc("/* leading comment */ select * from table2 ", 22)); + Assert.assertEquals('S', + StringUtils.firstAlphaCharUc("/* leading comment */ select * from table2 ", 22)); } } From 35372cdcb2215700b8e6c6fb0c892e9b27a2e34e Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Thu, 7 Feb 2019 10:19:38 -0500 Subject: [PATCH 5/9] jdbc: complete checkstyle Signed-off-by: Ze'ev Klapow --- java/checkstyle-suppression.xml | 2 + .../io/vitess/jdbc/ConnectionProperties.java | 2 +- .../io/vitess/jdbc/FieldWithMetadata.java | 2 +- .../java/io/vitess/jdbc/VitessConnection.java | 2 +- .../java/io/vitess/jdbc/VitessDriver.java | 4 +- .../java/io/vitess/jdbc/VitessJDBCUrl.java | 36 +-- .../jdbc/VitessMySQLDatabaseMetadata.java | 22 +- .../vitess/jdbc/VitessPreparedStatement.java | 237 +++++++++--------- .../java/io/vitess/jdbc/VitessResultSet.java | 181 ++++++------- .../vitess/jdbc/VitessResultSetMetaData.java | 6 +- .../java/io/vitess/jdbc/VitessStatement.java | 32 ++- .../io/vitess/jdbc/VitessVTGateManager.java | 4 +- 12 files changed, 271 insertions(+), 259 deletions(-) diff --git a/java/checkstyle-suppression.xml b/java/checkstyle-suppression.xml index ac41584523c..f6131902803 100644 --- a/java/checkstyle-suppression.xml +++ b/java/checkstyle-suppression.xml @@ -16,4 +16,6 @@ + + \ No newline at end of file diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java index 5d172808395..62d451ca9a7 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java @@ -295,7 +295,7 @@ private void checkConfiguredEncodingSupport() throws SQLException { try { String testString = "abc"; StringUtils.getBytes(testString, characterEncodingAsString); - } catch (UnsupportedEncodingException UE) { + } catch (UnsupportedEncodingException uee) { throw new SQLException("Unsupported character encoding: " + characterEncodingAsString); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java index b86b2dd893e..1f1eca52c6f 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java @@ -595,7 +595,7 @@ public String toString() { asString.append(this.encoding); asString.append("]"); return asString.toString(); - } catch (Throwable t) { + } catch (Throwable ignored) { return super.toString(); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java index 88bf7e1eae3..1dac94c92a6 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java @@ -85,7 +85,7 @@ public VitessConnection(String url, Properties connectionProperties) throws SQLE this.vtSession = new VTSession(this.getTarget(), this.getExecuteOptions()); } catch (Exception exc) { throw new SQLException( - Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + e.getMessage(), exc); + Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + exc.getMessage(), exc); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java index 0cb46209e1d..ce6c96c9dd3 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java @@ -41,9 +41,9 @@ public class VitessDriver implements Driver { static { try { DriverManager.registerDriver(new VitessDriver()); - } catch (SQLException e) { + } catch (SQLException exc) { throw new RuntimeException( - Constants.SQLExceptionMessages.INIT_FAILED + " : " + e.getErrorCode() + " - " + e + Constants.SQLExceptionMessages.INIT_FAILED + " : " + exc.getErrorCode() + " - " + exc .getMessage()); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java index 44814416bc5..c91c7a3342d 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java @@ -117,21 +117,21 @@ public String toString() { */ public VitessJDBCUrl(String url, Properties info) throws SQLException { - /* URL pattern e.g. jdbc:vitess://username:password@ip1:port1,ip2:port2/keyspace/catalog? - property1=value1.. - m.group(1) = "vitess" - m.group(2) = "username:password@" - m.group(3) = "username" - m.group(4) = ":password" - m.group(5) = "password" - m.group(6) = "ip1:port1,ip2:port2" - m.group(7) = "/keyspace" - m.group(8) = "keyspace" - m.group(9) = "/catalog" - m.group(10) = "catalog" - m.group(11) = "?property1=value1.." - m.group(12) = "property1=value1.." - */ + /* URL pattern e.g. jdbc:vitess://username:password@ip1:port1,ip2:port2/keyspace/catalog? + property1=value1.. + m.group(1) = "vitess" + m.group(2) = "username:password@" + m.group(3) = "username" + m.group(4) = ":password" + m.group(5) = "password" + m.group(6) = "ip1:port1,ip2:port2" + m.group(7) = "/keyspace" + m.group(8) = "keyspace" + m.group(9) = "/catalog" + m.group(10) = "catalog" + m.group(11) = "?property1=value1.." + m.group(12) = "property1=value1.." + */ final Pattern p = Pattern.compile(Constants.URL_PATTERN); final Matcher m = p.matcher(url); @@ -246,9 +246,9 @@ private static List getURLHostInfos(String hostURLs) throws SQLExcepti StringTokenizer stringTokenizer = new StringTokenizer(hostURLs, ","); while (stringTokenizer.hasMoreTokens()) { String hostString = stringTokenizer.nextToken(); - /* - pattern = ip:port - */ + /* + pattern = ip:port + */ final Pattern p = Pattern.compile("([^/:]+):(\\d+)?"); final Matcher m = p.matcher(hostString); if (!m.find()) { diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java index 0c87ff34d0e..2a04e89aee1 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java @@ -111,10 +111,10 @@ public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData implemen "OF", "VIEW", "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", "WHERE", "ELSE", "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", "WRITE", "ESCAPE", "OUTER", "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"}; - TreeMap mySQLKeywordMap = new TreeMap(); + TreeMap mySqlKeywordMap = new TreeMap(); for (String allMySQLKeyword : allMySQLKeywords) { - mySQLKeywordMap.put(allMySQLKeyword, null); + mySqlKeywordMap.put(allMySQLKeyword, null); } HashMap sql92KeywordMap = new HashMap(sql92Keywords.length); @@ -126,11 +126,11 @@ public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData implemen Iterator sql92KeywordIterator = sql92KeywordMap.keySet().iterator(); while (sql92KeywordIterator.hasNext()) { - mySQLKeywordMap.remove(sql92KeywordIterator.next()); + mySqlKeywordMap.remove(sql92KeywordIterator.next()); } StringBuffer keywordBuf = new StringBuffer(); - sql92KeywordIterator = mySQLKeywordMap.keySet().iterator(); + sql92KeywordIterator = mySqlKeywordMap.keySet().iterator(); if (sql92KeywordIterator.hasNext()) { keywordBuf.append(sql92KeywordIterator.next().toString()); } @@ -1396,9 +1396,14 @@ public boolean isWrapperFor(Class iface) throws SQLException { /** * Enumeration for Table Types */ - protected enum TableType {LOCAL_TEMPORARY("LOCAL TEMPORARY"), SYSTEM_TABLE( - "SYSTEM TABLE"), SYSTEM_VIEW("SYSTEM VIEW"), TABLE("TABLE", new String[]{"BASE TABLE"}), VIEW( - "VIEW"), UNKNOWN("UNKNOWN"); + protected enum TableType { + LOCAL_TEMPORARY("LOCAL TEMPORARY"), + SYSTEM_TABLE("SYSTEM TABLE"), + SYSTEM_VIEW("SYSTEM VIEW"), + TABLE("TABLE", new String[]{"BASE TABLE"}), + VIEW("VIEW"), + UNKNOWN("UNKNOWN"), + ; private String name; private byte[] nameAsBytes; @@ -1452,7 +1457,8 @@ boolean compliesWith(String tableTypeName) { } } return false; - }} + } + } /** diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java index eef8b6f2078..19142fd4884 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java @@ -104,17 +104,15 @@ public VitessPreparedStatement(VitessConnection vitessConnection, String sql, in } public ResultSet executeQuery() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - checkOpen(); closeOpenResultSetAndResetCount(); //Setting to default value this.generatedId = -1; - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + Cursor cursor; try { if (vitessConnection.isSimpleExecute() && this.fetchSize == 0) { checkAndBeginTransaction(); @@ -140,16 +138,14 @@ public ResultSet executeQuery() throws SQLException { } public int executeUpdate() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; - checkOpen(); checkNotReadOnly(); closeOpenResultSetAndResetCount(); - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + int truncatedUpdateCount; + Cursor cursor; try { checkAndBeginTransaction(); Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); @@ -205,135 +201,136 @@ public void setNull(int parameterIndex, int sqlType) throws SQLException { this.bindVariables.put(Constants.LITERAL_V + parameterIndex, null); } - public void setBoolean(int parameterIndex, boolean x) throws SQLException { + public void setBoolean(int parameterIndex, boolean ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setByte(int parameterIndex, byte x) throws SQLException { + public void setByte(int parameterIndex, byte ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setShort(int parameterIndex, short x) throws SQLException { + public void setShort(int parameterIndex, short ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setInt(int parameterIndex, int x) throws SQLException { + public void setInt(int parameterIndex, int ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setLong(int parameterIndex, long x) throws SQLException { + public void setLong(int parameterIndex, long ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setFloat(int parameterIndex, float x) throws SQLException { + public void setFloat(int parameterIndex, float ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setDouble(int parameterIndex, double x) throws SQLException { + public void setDouble(int parameterIndex, double ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + public void setBigDecimal(int parameterIndex, BigDecimal ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException { + public void setBigInteger(int parameterIndex, BigInteger ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setString(int parameterIndex, String x) throws SQLException { + public void setString(int parameterIndex, String ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setBytes(int parameterIndex, byte[] x) throws SQLException { + public void setBytes(int parameterIndex, byte[] ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setDate(int parameterIndex, Date x) throws SQLException { + public void setDate(int parameterIndex, Date date) throws SQLException { checkOpen(); - String date = DateTime.formatDate(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + String dateString = DateTime.formatDate(date); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, dateString); } - public void setTime(int parameterIndex, Time x) throws SQLException { + public void setTime(int parameterIndex, Time time) throws SQLException { checkOpen(); - String time = DateTime.formatTime(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + String timeString = DateTime.formatTime(time); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeString); } - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + public void setTimestamp(int parameterIndex, Timestamp timestamp) throws SQLException { checkOpen(); - String timeStamp = DateTime.formatTimestamp(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + String timestampString = DateTime.formatTimestamp(timestamp); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timestampString); } - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + public void setDate(int parameterIndex, Date date, Calendar cal) throws SQLException { checkOpen(); - String date = DateTime.formatDate(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + String formattedDate = DateTime.formatDate(date, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, formattedDate); } - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + public void setTime(int parameterIndex, Time time, Calendar cal) throws SQLException { checkOpen(); - String time = DateTime.formatTime(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + String formattedTime = DateTime.formatTime(time, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, formattedTime); } - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + public void setTimestamp(int parameterIndex, Timestamp timestamp, Calendar cal) + throws SQLException { checkOpen(); - String timeStamp = DateTime.formatTimestamp(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + String formattedTimestamp = DateTime.formatTimestamp(timestamp, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, formattedTimestamp); } - public void setObject(int parameterIndex, Object x) throws SQLException { - if (x == null) { + public void setObject(int parameterIndex, Object object) throws SQLException { + if (object == null) { setNull(parameterIndex, Types.NULL); - } else if (x instanceof String) { - setString(parameterIndex, (String) x); - } else if (x instanceof Short) { - setShort(parameterIndex, (Short) x); - } else if (x instanceof Integer) { - setInt(parameterIndex, (Integer) x); - } else if (x instanceof Long) { - setLong(parameterIndex, (Long) x); - } else if (x instanceof Float) { - setFloat(parameterIndex, (Float) x); - } else if (x instanceof Double) { - setDouble(parameterIndex, (Double) x); - } else if (x instanceof Boolean) { - setBoolean(parameterIndex, (Boolean) x); - } else if (x instanceof Byte) { - setByte(parameterIndex, (Byte) x); - } else if (x instanceof Character) { - setString(parameterIndex, String.valueOf(x)); - } else if (x instanceof Date) { - setDate(parameterIndex, (Date) x); - } else if (x instanceof Time) { - setTime(parameterIndex, (Time) x); - } else if (x instanceof Timestamp) { - setTimestamp(parameterIndex, (Timestamp) x); - } else if (x instanceof BigDecimal) { - setBigDecimal(parameterIndex, (BigDecimal) x); - } else if (x instanceof BigInteger) { - setBigInteger(parameterIndex, (BigInteger) x); - } else if (x instanceof byte[]) { - setBytes(parameterIndex, (byte[]) x); - } else if (getConnection().getTreatUtilDateAsTimestamp() && x instanceof java.util.Date) { - setTimestamp(parameterIndex, new Timestamp(((java.util.Date) x).getTime())); + } else if (object instanceof String) { + setString(parameterIndex, (String) object); + } else if (object instanceof Short) { + setShort(parameterIndex, (Short) object); + } else if (object instanceof Integer) { + setInt(parameterIndex, (Integer) object); + } else if (object instanceof Long) { + setLong(parameterIndex, (Long) object); + } else if (object instanceof Float) { + setFloat(parameterIndex, (Float) object); + } else if (object instanceof Double) { + setDouble(parameterIndex, (Double) object); + } else if (object instanceof Boolean) { + setBoolean(parameterIndex, (Boolean) object); + } else if (object instanceof Byte) { + setByte(parameterIndex, (Byte) object); + } else if (object instanceof Character) { + setString(parameterIndex, String.valueOf(object)); + } else if (object instanceof Date) { + setDate(parameterIndex, (Date) object); + } else if (object instanceof Time) { + setTime(parameterIndex, (Time) object); + } else if (object instanceof Timestamp) { + setTimestamp(parameterIndex, (Timestamp) object); + } else if (object instanceof BigDecimal) { + setBigDecimal(parameterIndex, (BigDecimal) object); + } else if (object instanceof BigInteger) { + setBigInteger(parameterIndex, (BigInteger) object); + } else if (object instanceof byte[]) { + setBytes(parameterIndex, (byte[]) object); + } else if (getConnection().getTreatUtilDateAsTimestamp() && object instanceof java.util.Date) { + setTimestamp(parameterIndex, new Timestamp(((java.util.Date) object).getTime())); } else { throw new SQLException( - Constants.SQLExceptionMessages.SQL_TYPE_INFER + x.getClass().getCanonicalName()); + Constants.SQLExceptionMessages.SQL_TYPE_INFER + object.getClass().getCanonicalName()); } } @@ -446,20 +443,20 @@ private int calculateParameterCount() throws SQLException { int statementStartPos = StringUtils.findStartOfStatement(sql); for (int i = statementStartPos; i < statementLength; ++i) { - char c = sql.charAt(i); + char curChar = sql.charAt(i); - if (c == '\\' && i < (statementLength - 1)) { + if (curChar == '\\' && i < (statementLength - 1)) { i++; continue; // next character is escaped } // are we in a quoted identifier? (only valid when the id is not inside a 'string') - if (!inQuotes && c == quotedIdentifierChar) { + if (!inQuotes && curChar == quotedIdentifierChar) { inQuotedId = !inQuotedId; } else if (!inQuotedId) { - // only respect quotes when not in a quoted identifier + //only respect quotes when not in a quoted identifier if (inQuotes) { - if (((c == '\'') || (c == '"')) && c == currentQuoteChar) { + if (((curChar == '\'') || (curChar == '"')) && curChar == currentQuoteChar) { if (i < (statementLength - 1) && sql.charAt(i + 1) == currentQuoteChar) { i++; continue; // inline quote escape @@ -469,35 +466,38 @@ private int calculateParameterCount() throws SQLException { currentQuoteChar = 0; } } else { - if (c == '#' || (c == '-' && (i + 1) < statementLength && sql.charAt(i + 1) == '-')) { + if (curChar == '#' + || (curChar == '-' + && (i + 1) < statementLength + && sql.charAt(i + 1) == '-')) { // comment, run out to end of statement, or newline, whichever comes first int endOfStmt = statementLength - 1; for (; i < endOfStmt; i++) { - c = sql.charAt(i); + curChar = sql.charAt(i); - if (c == '\r' || c == '\n') { + if (curChar == '\r' || curChar == '\n') { break; } } continue; - } else if (c == '/' && (i + 1) < statementLength) { + } else if (curChar == '/' && (i + 1) < statementLength) { // Comment? - char cNext = sql.charAt(i + 1); - if (cNext == '*') { + char nextChar = sql.charAt(i + 1); + if (nextChar == '*') { i += 2; for (int j = i; j < statementLength; j++) { i++; - cNext = sql.charAt(j); + nextChar = sql.charAt(j); - if (cNext == '*' && (j + 1) < statementLength) { + if (nextChar == '*' && (j + 1) < statementLength) { if (sql.charAt(j + 1) == '/') { i++; if (i < statementLength) { - c = sql.charAt(i); + curChar = sql.charAt(i); } break; // comment done @@ -505,14 +505,14 @@ private int calculateParameterCount() throws SQLException { } } } - } else if ((c == '\'') || (c == '"')) { + } else if ((curChar == '\'') || (curChar == '"')) { inQuotes = true; - currentQuoteChar = c; + currentQuoteChar = curChar; } } } - if ((c == '?') && !inQuotes && !inQuotedId) { + if ((curChar == '?') && !inQuotes && !inQuotedId) { statementCount++; } } @@ -525,12 +525,13 @@ public void setNull(int parameterIndex, int sqlType, String typeName) throws SQL Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + public void setAsciiStream(int parameterIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + public void setBinaryStream(int parameterIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -653,12 +654,14 @@ public void setObject(int parameterIndex, Object parameterObject, int targetSqlT } } - public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + public void setAsciiStream(int parameterIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + public void setBinaryStream(int parameterIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -669,34 +672,35 @@ public void setCharacterStream(int parameterIndex, Reader reader, long length) Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + public void setUnicodeStream(int parameterIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setRef(int parameterIndex, Ref x) throws SQLException { + public void setRef(int parameterIndex, Ref ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBlob(int parameterIndex, Blob x) throws SQLException { + public void setBlob(int parameterIndex, Blob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setClob(int parameterIndex, Clob x) throws SQLException { + public void setClob(int parameterIndex, Clob clob) throws SQLException { checkOpen(); - if (x.length() > Integer.MAX_VALUE) { + if (clob.length() > Integer.MAX_VALUE) { throw new SQLFeatureNotSupportedException( String.format("Clob size over %d not support", Integer.MAX_VALUE), Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } // Clob uses 1-based indexing! this.bindVariables - .put(Constants.LITERAL_V + parameterIndex, x.getSubString(1, (int) x.length())); + .put(Constants.LITERAL_V + parameterIndex, clob.getSubString(1, (int) clob.length())); } - public void setArray(int parameterIndex, Array x) throws SQLException { + public void setArray(int parameterIndex, Array ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -706,12 +710,12 @@ public ResultSetMetaData getMetaData() throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setURL(int parameterIndex, URL x) throws SQLException { + public void setURL(int parameterIndex, URL ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setRowId(int parameterIndex, RowId x) throws SQLException { + public void setRowId(int parameterIndex, RowId ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -753,12 +757,13 @@ public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + public void setAsciiStream(int parameterIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + public void setBinaryStream(int parameterIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java index 7c025010612..4b026a5fa0c 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java @@ -89,8 +89,8 @@ public VitessResultSet(Cursor cursor, VitessStatement vitessStatement) throws SQ try { this.fields = enhancedFieldsFromCursor( vitessStatement == null ? null : vitessStatement.getConnection()); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } catch (SQLException exc) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, exc); } this.currentRow = 0; if (null != vitessStatement) { @@ -116,9 +116,9 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][ Query.Row.Builder queryRow = Query.Row.newBuilder(); StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); + for (String singleRowData : rowData) { + sb.append(singleRowData); + queryRow.addLengths(singleRowData.length()); } queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); queryResultBuilder.addRows(queryRow); @@ -129,8 +129,8 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][ this.vitessStatement = null; try { this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } catch (SQLException exc) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, exc); } this.currentRow = 0; } @@ -151,10 +151,10 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, Query.Row.Builder queryRow = Query.Row.newBuilder(); StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - if (null != aRowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); + for (String singleRowData : rowData) { + if (null != singleRowData) { + sb.append(singleRowData); + queryRow.addLengths(singleRowData.length()); } else { queryRow.addLengths(-1); } @@ -167,8 +167,8 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, this.vitessStatement = null; try { this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } catch (SQLException exc) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, exc); } this.currentRow = 0; } @@ -203,7 +203,7 @@ public void close() throws SQLException { if (!this.closed) { try { this.cursor.close(); - } catch (Exception e) { + } catch (Exception exc) { throw new SQLException(Constants.SQLExceptionMessages.VITESS_CURSOR_CLOSE_ERROR); } finally { //Dereferencing all the objects @@ -249,9 +249,6 @@ public String getString(int columnIndex) throws SQLException { } public boolean getBoolean(int columnIndex) throws SQLException { - String boolString; - int bool; - preAccessor(columnIndex); if (isNull(columnIndex)) { @@ -265,7 +262,8 @@ public boolean getBoolean(int columnIndex) throws SQLException { return byteArrayToBoolean(columnIndex); } - boolString = this.getString(columnIndex); + int bool; + String boolString = this.getString(columnIndex); try { bool = Integer.valueOf(boolString); } catch (NumberFormatException nfe) { @@ -275,9 +273,6 @@ public boolean getBoolean(int columnIndex) throws SQLException { } public byte getByte(int columnIndex) throws SQLException { - String byteString; - byte value; - preAccessor(columnIndex); if (isNull(columnIndex)) { return 0; @@ -290,7 +285,8 @@ public byte getByte(int columnIndex) throws SQLException { return (byte) object; } - byteString = this.getString(columnIndex); + byte value; + String byteString = this.getString(columnIndex); try { value = Byte.parseByte(byteString); } catch (NumberFormatException nfe) { @@ -449,9 +445,6 @@ public BigInteger getBigInteger(int columnIndex) throws SQLException { } public byte[] getBytes(int columnIndex) throws SQLException { - String bytesString; - byte[] value; - preAccessor(columnIndex); if (isNull(columnIndex)) { return null; @@ -463,7 +456,8 @@ public byte[] getBytes(int columnIndex) throws SQLException { return (byte[]) object; } - bytesString = this.getString(columnIndex); + byte[] value; + String bytesString = this.getString(columnIndex); try { value = bytesString.getBytes(); } catch (Exception ex) { @@ -631,8 +625,8 @@ private String convertBytesToString(byte[] bytes, String encoding) throws SQLExc } else { try { return StringUtils.toString(bytes, 0, bytes.length, encoding); - } catch (UnsupportedEncodingException e) { - throw new SQLException("Unsupported character encoding: " + encoding, e); + } catch (UnsupportedEncodingException exc) { + throw new SQLException("Unsupported character encoding: " + encoding, exc); } } } @@ -998,92 +992,95 @@ public void updateNull(int columnIndex) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBoolean(int columnIndex, boolean x) throws SQLException { + public void updateBoolean(int columnIndex, boolean ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateByte(int columnIndex, byte x) throws SQLException { + public void updateByte(int columnIndex, byte ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateShort(int columnIndex, short x) throws SQLException { + public void updateShort(int columnIndex, short ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateInt(int columnIndex, int x) throws SQLException { + public void updateInt(int columnIndex, int ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateLong(int columnIndex, long x) throws SQLException { + public void updateLong(int columnIndex, long ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateFloat(int columnIndex, float x) throws SQLException { + public void updateFloat(int columnIndex, float ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDouble(int columnIndex, double x) throws SQLException { + public void updateDouble(int columnIndex, double ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + public void updateBigDecimal(int columnIndex, BigDecimal ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateString(int columnIndex, String x) throws SQLException { + public void updateString(int columnIndex, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBytes(int columnIndex, byte[] x) throws SQLException { + public void updateBytes(int columnIndex, byte[] ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDate(int columnIndex, Date x) throws SQLException { + public void updateDate(int columnIndex, Date ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTime(int columnIndex, Time x) throws SQLException { + public void updateTime(int columnIndex, Time ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + public void updateTimestamp(int columnIndex, Timestamp ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { + public void updateObject(int columnIndex, Object ignored, int scaleOrLength) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(int columnIndex, Object x) throws SQLException { + public void updateObject(int columnIndex, Object ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1093,77 +1090,78 @@ public void updateNull(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBoolean(String columnLabel, boolean x) throws SQLException { + public void updateBoolean(String columnLabel, boolean ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateByte(String columnLabel, byte x) throws SQLException { + public void updateByte(String columnLabel, byte ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateShort(String columnLabel, short x) throws SQLException { + public void updateShort(String columnLabel, short ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateInt(String columnLabel, int x) throws SQLException { + public void updateInt(String columnLabel, int ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateLong(String columnLabel, long x) throws SQLException { + public void updateLong(String columnLabel, long ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateFloat(String columnLabel, float x) throws SQLException { + public void updateFloat(String columnLabel, float ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDouble(String columnLabel, double x) throws SQLException { + public void updateDouble(String columnLabel, double ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { + public void updateBigDecimal(String columnLabel, BigDecimal ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateString(String columnLabel, String x) throws SQLException { + public void updateString(String columnLabel, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBytes(String columnLabel, byte[] x) throws SQLException { + public void updateBytes(String columnLabel, byte[] ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDate(String columnLabel, Date x) throws SQLException { + public void updateDate(String columnLabel, Date ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTime(String columnLabel, Time x) throws SQLException { + public void updateTime(String columnLabel, Time ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { + public void updateTimestamp(String columnLabel, Timestamp ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { + public void updateAsciiStream(String columnLabel, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(String columnLabel, InputStream x, int length) + public void updateBinaryStream(String columnLabel, InputStream ignored, int length) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); @@ -1175,12 +1173,13 @@ public void updateCharacterStream(String columnLabel, Reader reader, int length) Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { + public void updateObject(String columnLabel, Object ignored, int scaleOrLength) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(String columnLabel, Object x) throws SQLException { + public void updateObject(String columnLabel, Object ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1285,42 +1284,42 @@ public URL getURL(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRef(int columnIndex, Ref x) throws SQLException { + public void updateRef(int columnIndex, Ref ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRef(String columnLabel, Ref x) throws SQLException { + public void updateRef(String columnLabel, Ref ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBlob(int columnIndex, Blob x) throws SQLException { + public void updateBlob(int columnIndex, Blob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBlob(String columnLabel, Blob x) throws SQLException { + public void updateBlob(String columnLabel, Blob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateClob(int columnIndex, Clob x) throws SQLException { + public void updateClob(int columnIndex, Clob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateClob(String columnLabel, Clob x) throws SQLException { + public void updateClob(String columnLabel, Clob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateArray(int columnIndex, Array x) throws SQLException { + public void updateArray(int columnIndex, Array ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateArray(String columnLabel, Array x) throws SQLException { + public void updateArray(String columnLabel, Array ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1335,12 +1334,12 @@ public RowId getRowId(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRowId(int columnIndex, RowId x) throws SQLException { + public void updateRowId(int columnIndex, RowId ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRowId(String columnLabel, RowId x) throws SQLException { + public void updateRowId(String columnLabel, RowId ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1350,22 +1349,22 @@ public int getHoldability() throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNString(int columnIndex, String nString) throws SQLException { + public void updateNString(int columnIndex, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNString(String columnLabel, String nString) throws SQLException { + public void updateNString(String columnLabel, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + public void updateNClob(int columnIndex, NClob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNClob(String columnLabel, NClob nClob) throws SQLException { + public void updateNClob(String columnLabel, NClob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1420,7 +1419,8 @@ public Reader getNCharacterStream(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + public void updateNCharacterStream(int columnIndex, Reader ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1431,28 +1431,31 @@ public void updateNCharacterStream(String columnLabel, Reader reader, long lengt Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(String columnLabel, InputStream x, long length) + public void updateAsciiStream(String columnLabel, InputStream ignored, long length) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(String columnLabel, InputStream x, long length) + public void updateBinaryStream(String columnLabel, InputStream ignored, long length) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); @@ -1496,7 +1499,7 @@ public void updateNClob(String columnLabel, Reader reader, long length) throws S Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { + public void updateNCharacterStream(int columnIndex, Reader ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1506,27 +1509,27 @@ public void updateNCharacterStream(String columnLabel, Reader reader) throws SQL Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { + public void updateAsciiStream(String columnLabel, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { + public void updateBinaryStream(String columnLabel, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java index 93a260ebab5..eaa54e9d570 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java @@ -75,11 +75,11 @@ public boolean isCaseSensitive(int column) throws SQLException { try { String collationName = field.getCollation(); return collationName != null && !collationName.endsWith("_ci"); - } catch (SQLException e) { - if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { + } catch (SQLException exc) { + if (exc.getCause() instanceof ArrayIndexOutOfBoundsException) { return false; } else { - throw e; + throw exc; } } default: diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java index de76f81038d..0ebc0cb0635 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java @@ -92,9 +92,6 @@ public VitessStatement(VitessConnection vitessConnection, int resultSetType, * @return ResultSet */ public ResultSet executeQuery(String sql) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - checkOpen(); checkSQLNullOrEmpty(sql); closeOpenResultSetAndResetCount(); @@ -107,8 +104,9 @@ public ResultSet executeQuery(String sql) throws SQLException { this.retrieveGeneratedKeys = false; this.generatedId = -1; - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + Cursor cursor; if ((vitessConnection.isSimpleExecute() && this.fetchSize == 0) || vitessConnection .isInTransaction()) { checkAndBeginTransaction(); @@ -202,14 +200,14 @@ public int getMaxFieldSize() throws SQLException { } public void setMaxFieldSize(int max) throws SQLException { - /* Currently not used - checkOpen(); - if (max < 0 || max > Constants.MAX_BUFFER_SIZE) { - throw new SQLException( - Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max field size"); - } - this.maxFieldSize = max; - */ + /* Currently not used + checkOpen(); + if (max < 0 || max > Constants.MAX_BUFFER_SIZE) { + throw new SQLException( + Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max field size"); + } + this.maxFieldSize = max; + */ throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -386,10 +384,6 @@ public ResultSet getGeneratedKeys() throws SQLException { * @return Row Affected Count */ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; - checkOpen(); checkNotReadOnly(); checkSQLNullOrEmpty(sql); @@ -399,11 +393,12 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); } - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); checkAndBeginTransaction(); Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); + Cursor cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()) + .checkedGet(); if (null == cursor) { throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); @@ -423,6 +418,7 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException this.resultCount = cursor.getRowsAffected(); + int truncatedUpdateCount; if (this.resultCount > Integer.MAX_VALUE) { truncatedUpdateCount = Integer.MAX_VALUE; } else { diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java index 6a5b496ee16..ea0113b17ae 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java @@ -228,8 +228,8 @@ public static void close() throws SQLException { for (VTGateConnection vtGateConn : vtGateConnHashMap.values()) { try { vtGateConn.close(); - } catch (IOException e) { - exception = new SQLException(e.getMessage(), e); + } catch (IOException ioe) { + exception = new SQLException(ioe.getMessage(), ioe); } } vtGateConnHashMap.clear(); From a016a721ec3966d36419863035d7ce7086565b5d Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Thu, 7 Feb 2019 10:22:49 -0500 Subject: [PATCH 6/9] example: conform to checkstyle Signed-off-by: Ze'ev Klapow --- .../vitess/example/VitessClientExample.java | 98 ++++--- .../io/vitess/example/VitessJDBCExample.java | 265 +++++++++--------- 2 files changed, 181 insertions(+), 182 deletions(-) diff --git a/java/example/src/main/java/io/vitess/example/VitessClientExample.java b/java/example/src/main/java/io/vitess/example/VitessClientExample.java index 9c51ee42349..de5e95a3e43 100644 --- a/java/example/src/main/java/io/vitess/example/VitessClientExample.java +++ b/java/example/src/main/java/io/vitess/example/VitessClientExample.java @@ -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 @@ import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; + import io.vitess.client.Context; import io.vitess.client.RpcClient; import io.vitess.client.VTGateBlockingConnection; @@ -40,56 +41,53 @@ * examples/local/README.md file. */ public class VitessClientExample { - public static void main(String[] args) { - if (args.length != 1) { - System.out.println("usage: VitessClientExample "); - System.exit(1); - } - Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(5 * 1000)); - try (RpcClient client = new GrpcClientFactory().create(ctx, args[0]); - VTGateBlockingConnection conn = new VTGateBlockingConnection(client)) { - VTSession session = new VTSession("@master", ExecuteOptions.getDefaultInstance()); - // Insert some messages on random pages. - System.out.println("Inserting into master..."); - Random rand = new Random(); - for (int i = 0; i < 3; i++) { - Instant timeCreated = Instant.now(); - Map bindVars = - new ImmutableMap.Builder() - .put("page", rand.nextInt(100) + 1) - .put("time_created_ns", timeCreated.getMillis() * 1000000) - .put("message", "V is for speed") - .build(); + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("usage: VitessClientExample "); + System.exit(1); + } + + Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(5 * 1000)); + try (RpcClient client = new GrpcClientFactory() + .create(ctx, args[0]); VTGateBlockingConnection conn = new VTGateBlockingConnection( + client)) { + VTSession session = new VTSession("@master", ExecuteOptions.getDefaultInstance()); + // Insert some messages on random pages. + System.out.println("Inserting into master..."); + Random rand = new Random(); + for (int i = 0; i < 3; i++) { + Instant timeCreated = Instant.now(); + Map bindVars = new ImmutableMap.Builder() + .put("page", rand.nextInt(100) + 1) + .put("time_created_ns", timeCreated.getMillis() * 1000000) + .put("message", "V is for speed").build(); - conn.execute(ctx, "begin", null, session); - conn.execute( - ctx, - "INSERT INTO messages (page,time_created_ns,message) VALUES (:page,:time_created_ns,:message)", - bindVars, session); - conn.execute(ctx, "commit", null, session); - } + conn.execute(ctx, "begin", null, session); + conn.execute(ctx, + "INSERT INTO messages (page,time_created_ns,message) VALUES (:page,:time_created_ns," + + ":message)", + bindVars, session); + conn.execute(ctx, "commit", null, session); + } - // Read it back from the master. - System.out.println("Reading from master..."); - try (Cursor cursor = - conn.execute( - ctx, - "SELECT page, time_created_ns, message FROM messages", - null, session)) { - Row row; - while ((row = cursor.next()) != null) { - UnsignedLong page = row.getULong("page"); - UnsignedLong timeCreated = row.getULong("time_created_ns"); - byte[] message = row.getBytes("message"); - System.out.format("(%s, %s, %s)\n", page, timeCreated, new String(message)); - } - } - } catch (Exception e) { - System.out.println("Vitess Java example failed."); - System.out.println("Error Details:"); - e.printStackTrace(); - System.exit(2); + // Read it back from the master. + System.out.println("Reading from master..."); + try (Cursor cursor = conn + .execute(ctx, "SELECT page, time_created_ns, message FROM messages", null, session)) { + Row row; + while ((row = cursor.next()) != null) { + UnsignedLong page = row.getULong("page"); + UnsignedLong timeCreated = row.getULong("time_created_ns"); + byte[] message = row.getBytes("message"); + System.out.format("(%s, %s, %s)\n", page, timeCreated, new String(message)); } + } + } catch (Exception exc) { + System.out.println("Vitess Java example failed."); + System.out.println("Error Details:"); + exc.printStackTrace(); + System.exit(2); } + } } diff --git a/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java b/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java index c8ac0fde363..1c6b18a17a9 100644 --- a/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java +++ b/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java @@ -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,6 +16,8 @@ package io.vitess.example; +import org.joda.time.Instant; + import java.sql.BatchUpdateException; import java.sql.Connection; import java.sql.DriverManager; @@ -24,7 +26,6 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.Random; -import org.joda.time.Instant; /** * VitessJDBCExample.java is a sample for using the Vitess JDBC driver. @@ -33,140 +34,140 @@ * examples/local/README.md file. */ public class VitessJDBCExample { - public static void main(String[] args) throws Exception { - if (args.length != 1) { - System.out.println("usage: VitessJDBCExample "); - System.exit(1); - } - - // Connect to vtgate. - String dbURL = "jdbc:vitess://" + args[0]; - try (Connection conn = DriverManager.getConnection(dbURL, null)) { - // Setting AutoCommit to false as VTTablet was not up with enable-autocommit - // Not Required if enable-autocommit flag is set in VTTablet - conn.setAutoCommit(false); - - // Insert some messages on random pages. - System.out.println("Inserting into master..."); - insertData(conn); - - // To Commit Open Transaction - conn.commit(); - - // Read it back from master. - System.out.println("Reading from master..."); - readData(conn); - - // To Commit Open Transaction, - // as select was made on master with autocommit false a transaction was open - conn.commit(); - - // Read it back from replica. - dbURL += "?target=test_keyspace@replica"; - try (Connection connReplica = DriverManager.getConnection(dbURL, null)) { - System.out.println("Reading from replica..."); - readData(connReplica); - } - - // Execute DML Queries in a Batch - batchedQueries(conn); - - // To Commit Open Transaction - conn.commit(); - - } catch (Exception e) { - System.out.println("Vitess JDBC example failed."); - System.out.println("Error Details:"); - e.printStackTrace(); - System.exit(2); - } - } - private static void insertData(Connection conn) throws SQLException { - Random rand = new Random(); - try (PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { - for (int i = 0; i < 3; i++) { - Instant timeCreated = Instant.now(); - int page = rand.nextInt(100) + 1; - stmt.setInt(1, page); - stmt.setLong(2, timeCreated.getMillis() * 1000000); - stmt.setString(3, "V is for speed"); - stmt.execute(); - } - } + public static void main(String[] args) throws Exception { + if (args.length != 1) { + System.out.println("usage: VitessJDBCExample "); + System.exit(1); } - private static void readData(Connection conn) throws SQLException { - String sql = "SELECT page, time_created_ns, message FROM messages"; - try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { - while (rs.next()) { - long page = rs.getLong("page"); - long timeCreated = rs.getLong("time_created_ns"); - String message = rs.getString("message"); - System.out.format("(%s, %s, %s)\n", page, timeCreated, message); - } - } + // Connect to vtgate. + String dbURL = "jdbc:vitess://" + args[0]; + try (Connection conn = DriverManager.getConnection(dbURL, null)) { + // Setting AutoCommit to false as VTTablet was not up with enable-autocommit + // Not Required if enable-autocommit flag is set in VTTablet + conn.setAutoCommit(false); + + // Insert some messages on random pages. + System.out.println("Inserting into master..."); + insertData(conn); + + // To Commit Open Transaction + conn.commit(); + + // Read it back from master. + System.out.println("Reading from master..."); + readData(conn); + + // To Commit Open Transaction, + // as select was made on master with autocommit false a transaction was open + conn.commit(); + + // Read it back from replica. + dbURL += "?target=test_keyspace@replica"; + try (Connection connReplica = DriverManager.getConnection(dbURL, null)) { + System.out.println("Reading from replica..."); + readData(connReplica); + } + + // Execute DML Queries in a Batch + batchedQueries(conn); + + // To Commit Open Transaction + conn.commit(); + + } catch (Exception exc) { + System.out.println("Vitess JDBC example failed."); + System.out.println("Error Details:"); + exc.printStackTrace(); + System.exit(2); + } + } + + private static void insertData(Connection conn) throws SQLException { + Random rand = new Random(); + try (PreparedStatement stmt = conn + .prepareStatement("INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { + for (int i = 0; i < 3; i++) { + Instant timeCreated = Instant.now(); + int page = rand.nextInt(100) + 1; + stmt.setInt(1, page); + stmt.setLong(2, timeCreated.getMillis() * 1000000); + stmt.setString(3, "V is for speed"); + stmt.execute(); + } + } + } + + private static void readData(Connection conn) throws SQLException { + String sql = "SELECT page, time_created_ns, message FROM messages"; + try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + while (rs.next()) { + long page = rs.getLong("page"); + long timeCreated = rs.getLong("time_created_ns"); + String message = rs.getString("message"); + System.out.format("(%s, %s, %s)\n", page, timeCreated, message); + } + } + } + + private static void batchedQueries(Connection conn) throws SQLException { + Random rand = new Random(); + try (PreparedStatement stmt = conn + .prepareStatement("INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { + for (int i = 0; i < 3; i++) { + Instant timeCreated = Instant.now(); + int page = rand.nextInt(100) + 1; + stmt.setInt(1, page); + stmt.setLong(2, timeCreated.getMillis() * 1000000); + stmt.setString(3, "V is for speed"); + stmt.addBatch(); + } + int[] updateCounts; + try { + updateCounts = stmt.executeBatch(); + } catch (BatchUpdateException ex) { + updateCounts = ex.getUpdateCounts(); + } + if (null != updateCounts) { + evalBatchResult(updateCounts); + } } - private static void batchedQueries(Connection conn) throws SQLException { - Random rand = new Random(); - try (PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { - for (int i = 0; i < 3; i++) { - Instant timeCreated = Instant.now(); - int page = rand.nextInt(100) + 1; - stmt.setInt(1, page); - stmt.setLong(2, timeCreated.getMillis() * 1000000); - stmt.setString(3, "V is for speed"); - stmt.addBatch(); - } - int[] updateCounts; - try { - updateCounts = stmt.executeBatch(); - } catch (BatchUpdateException ex) { - updateCounts = ex.getUpdateCounts(); - } - if (null != updateCounts) { - evalBatchResult(updateCounts); - } - } - - try (Statement stmt = conn.createStatement()) { - Instant timeCreated = Instant.now(); - int page = rand.nextInt(100) + 1; - System.out.println("Page selected for all dml operation: " + page); - stmt.addBatch( - "INSERT INTO messages (page,time_created_ns,message) VALUES (" + page + "," - + timeCreated.getMillis() * 1000000 + ",'V is for speed')"); - stmt.addBatch( - "UPDATE messages set message = 'V Batch is for more speed' where page = " + page); - stmt.addBatch("DELETE FROM messages where page = " + page); - int[] updateCounts; - try { - updateCounts = stmt.executeBatch(); - } catch (BatchUpdateException ex) { - updateCounts = ex.getUpdateCounts(); - } - if (null != updateCounts) { - evalBatchResult(updateCounts); - } - } - + try (Statement stmt = conn.createStatement()) { + Instant timeCreated = Instant.now(); + int page = rand.nextInt(100) + 1; + System.out.println("Page selected for all dml operation: " + page); + stmt.addBatch("INSERT INTO messages (page,time_created_ns,message) VALUES (" + page + "," + + timeCreated.getMillis() * 1000000 + ",'V is for speed')"); + stmt.addBatch( + "UPDATE messages set message = 'V Batch is for more speed' where page = " + page); + stmt.addBatch("DELETE FROM messages where page = " + page); + int[] updateCounts; + try { + updateCounts = stmt.executeBatch(); + } catch (BatchUpdateException ex) { + updateCounts = ex.getUpdateCounts(); + } + if (null != updateCounts) { + evalBatchResult(updateCounts); + } } - private static void evalBatchResult(int[] updateCounts) { - for (int i = 0; i < updateCounts.length; i++) { - switch (updateCounts[i]) { - case Statement.EXECUTE_FAILED: - System.out.println("execution failed"); - break; - case Statement.SUCCESS_NO_INFO: - System.out.println("execution success with no result"); - break; - default: - System.out.println("execution success with rows changed: " + updateCounts[i]); - } - } + } + + private static void evalBatchResult(int[] updateCounts) { + for (int i = 0; i < updateCounts.length; i++) { + switch (updateCounts[i]) { + case Statement.EXECUTE_FAILED: + System.out.println("execution failed"); + break; + case Statement.SUCCESS_NO_INFO: + System.out.println("execution success with no result"); + break; + default: + System.out.println("execution success with rows changed: " + updateCounts[i]); + } } + } } From 26cb613c158c0e664e501e9ac633cee0692aa87b Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Fri, 8 Feb 2019 12:15:46 -0500 Subject: [PATCH 7/9] add precommit hook Signed-off-by: Ze'ev Klapow --- misc/git/hooks/checkstyle | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 misc/git/hooks/checkstyle diff --git a/misc/git/hooks/checkstyle b/misc/git/hooks/checkstyle new file mode 100755 index 00000000000..cc0ec070e7d --- /dev/null +++ b/misc/git/hooks/checkstyle @@ -0,0 +1,37 @@ +#!/bin/bash -e +function get_module() { + local path=$1; + while true; do + path=$(dirname $path); + if [ -f "$path/pom.xml" ]; then + echo "$path"; + return; + elif [[ "./" =~ "$path" ]]; then + return; + fi + done +} + +modules=(); + +for file in $(git diff --name-only --cached \*.java); do + module=$(get_module "$file"); + if [ "" != "$module" ] \ + && [[ ! " ${modules[@]} " =~ " $module " ]]; then + modules+=("$module"); + fi +done; + +if [ ${#modules[@]} -eq 0 ]; then + exit; +fi + +modules_arg=$(printf ",%s" "${modules[@]}"); +modules_arg=${modules_arg:1}; + +export MAVEN_OPTS="-client + -XX:+TieredCompilation + -XX:TieredStopAtLevel=1 + -Xverify:none"; + +mvn -q -pl "$modules_arg" checkstyle:check; From b5973f5723366f4066b5ff3cc1cd6245c777a596 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Fri, 8 Feb 2019 12:41:04 -0500 Subject: [PATCH 8/9] fix checkstyle hook Signed-off-by: Ze'ev Klapow --- java/pom.xml | 2 +- misc/git/hooks/checkstyle | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index ac05378c605..e127c984e0c 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -262,7 +262,7 @@ google_checks.xml checkstyle-suppression.xml true - false + true true warning diff --git a/misc/git/hooks/checkstyle b/misc/git/hooks/checkstyle index cc0ec070e7d..777dd512430 100755 --- a/misc/git/hooks/checkstyle +++ b/misc/git/hooks/checkstyle @@ -1,4 +1,7 @@ -#!/bin/bash -e +#!/bin/bash + +set -e + function get_module() { local path=$1; while true; do @@ -12,9 +15,11 @@ function get_module() { done } +cd java; + modules=(); -for file in $(git diff --name-only --cached \*.java); do +for file in $(git diff --relative --name-only --cached \*.java); do module=$(get_module "$file"); if [ "" != "$module" ] \ && [[ ! " ${modules[@]} " =~ " $module " ]]; then @@ -35,3 +40,5 @@ export MAVEN_OPTS="-client -Xverify:none"; mvn -q -pl "$modules_arg" checkstyle:check; + +cd -; From b4bf8070ad8d75ca59056b43d3b907a8e7a71a8b Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Tue, 12 Feb 2019 14:10:17 -0500 Subject: [PATCH 9/9] fix violations Signed-off-by: Ze'ev Klapow --- .../src/main/java/io/vitess/client/grpc/GrpcClient.java | 2 +- .../src/main/java/io/vitess/client/grpc/GrpcClientFactory.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index 11b8266e02c..cf8f8cdc94f 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -129,7 +129,7 @@ public void close() throws IOException { // Now we try hard shutdown channel.shutdownNow(); } - } catch (InterruptedException e) { + } catch (InterruptedException exc) { Thread.currentThread().interrupt(); } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 2a4b9c62f01..f04511039df 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -98,7 +98,8 @@ public RpcClient create(Context ctx, String target) { channel.nameResolverFactory(nameResolverFactory); } return callCredentials != null - ? new GrpcClient(channel.build(), callCredentials, ctx) : new GrpcClient(channel.build(), ctx); + ? new GrpcClient(channel.build(), callCredentials, ctx) + : new GrpcClient(channel.build(), ctx); } /**