-
Notifications
You must be signed in to change notification settings - Fork 48
/
CloudSpannerJdbcConnection.java
451 lines (405 loc) · 21.3 KB
/
CloudSpannerJdbcConnection.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.cloud.spanner.jdbc;
import com.google.cloud.spanner.AbortedDueToConcurrentModificationException;
import com.google.cloud.spanner.AbortedException;
import com.google.cloud.spanner.CommitResponse;
import com.google.cloud.spanner.CommitStats;
import com.google.cloud.spanner.Dialect;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.Options.QueryOption;
import com.google.cloud.spanner.PartitionOptions;
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.spanner.connection.AutocommitDmlMode;
import com.google.cloud.spanner.connection.SavepointSupport;
import com.google.cloud.spanner.connection.TransactionMode;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Iterator;
/**
* JDBC connection with a number of additional Cloud Spanner specific methods. JDBC connections that
* are returned by the Cloud Spanner {@link JdbcDriver} will implement this interface.
*
* <p>Calling {@link Connection#unwrap(Class)} with {@code CloudSpannerJdbcConnection} class as
* input on a {@link Connection} returned by the Cloud Spanner JDBC Driver will return a {@link
* CloudSpannerJdbcConnection} instance.
*/
public interface CloudSpannerJdbcConnection extends Connection {
/**
* Sets the transaction tag to use for the current transaction. This method may only be called
* when in a transaction, and before the transaction is actually started, i.e. before any
* statements have been executed in the transaction.
*
* <p>The tag will be set as the transaction tag of all statements during the transaction, and as
* the transaction tag of the commit.
*
* <p>The transaction tag will automatically be cleared after the transaction has ended.
*
* @param tag The tag to use.
*/
default void setTransactionTag(String tag) throws SQLException {
throw new UnsupportedOperationException();
}
/** @return The transaction tag of the current transaction. */
default String getTransactionTag() throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Sets the statement tag to use for the next statement that will be executed. The tag is
* automatically cleared after the statement is executed. Statement tags can be used both with
* autocommit=true and autocommit=false, and can be used for partitioned DML.
*
* @param tag The statement tag to use with the next statement that will be executed on this
* connection.
*/
default void setStatementTag(String tag) throws SQLException {
throw new UnsupportedOperationException();
}
/**
* @return The statement tag that will be used with the next statement that is executed on this
* connection.
*/
default String getStatementTag() throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Sets the transaction mode to use for current transaction. This method may only be called when
* in a transaction, and before the transaction is actually started, i.e. before any statements
* have been executed in the transaction.
*
* @param transactionMode The transaction mode to use for the current transaction.
* <ul>
* <li>{@link TransactionMode#READ_ONLY_TRANSACTION} will create a read-only transaction and
* prevent any changes to written to the database through this transaction. The read
* timestamp to be used will be determined based on the current readOnlyStaleness
* setting of this connection. It is recommended to use {@link
* TransactionMode#READ_ONLY_TRANSACTION} instead of {@link
* TransactionMode#READ_WRITE_TRANSACTION} when possible, as read-only transactions do
* not acquire locks on Cloud Spanner, and read-only transactions never abort.
* <li>{@link TransactionMode#READ_WRITE_TRANSACTION} this value is only allowed when the
* connection is not in read-only mode and will create a read-write transaction. If
* {@link CloudSpannerJdbcConnection#isRetryAbortsInternally()} is <code>true</code>,
* each read/write transaction will keep track of a running SHA256 checksum for each
* {@link ResultSet} that is returned in order to be able to retry the transaction in
* case the transaction is aborted by Spanner.
* </ul>
*/
void setTransactionMode(TransactionMode transactionMode) throws SQLException;
/**
* @return the transaction mode of the current transaction. This method may only be called when
* the connection is in a transaction.
*/
TransactionMode getTransactionMode() throws SQLException;
/**
* Sets the mode for executing DML statements in autocommit mode for this connection. This setting
* is only used when the connection is in autocommit mode, and may only be set while the
* transaction is in autocommit mode and not in a temporary transaction. The autocommit
* transaction mode is reset to its default value of {@link AutocommitDmlMode#TRANSACTIONAL} when
* autocommit mode is changed on the connection.
*
* @param mode The DML autocommit mode to use
* <ul>
* <li>{@link AutocommitDmlMode#TRANSACTIONAL} DML statements are executed as single
* read-write transaction. After successful execution, the DML statement is guaranteed
* to have been applied exactly once to the database
* <li>{@link AutocommitDmlMode#PARTITIONED_NON_ATOMIC} DML statements are executed as
* partitioned DML transactions. If an error occurs during the execution of the DML
* statement, it is possible that the statement has been applied to some but not all of
* the rows specified in the statement.
* </ul>
*/
void setAutocommitDmlMode(AutocommitDmlMode mode) throws SQLException;
/**
* @return the current {@link AutocommitDmlMode} setting for this connection. This method may only
* be called on a connection that is in autocommit mode and not while in a temporary
* transaction.
*/
AutocommitDmlMode getAutocommitDmlMode() throws SQLException;
/**
* Sets the staleness to use for the current read-only transaction. This method may only be called
* when the transaction mode of the current transaction is {@link
* TransactionMode#READ_ONLY_TRANSACTION} and there is no transaction that has started, or when
* the connection is in read-only and autocommit mode.
*
* @param staleness The staleness to use for the current but not yet started read-only transaction
*/
void setReadOnlyStaleness(TimestampBound staleness) throws SQLException;
/**
* @return the read-only staleness setting for the current read-only transaction. This method may
* only be called when the current transaction is a read-only transaction, or when the
* connection is in read-only and autocommit mode.
*/
TimestampBound getReadOnlyStaleness() throws SQLException;
/**
* Sets the query optimizer version to use for this connection.
*
* @param optimizerVersion The query optimizer version to use. Must be a valid optimizer version
* number, the string <code>LATEST</code> or an empty string. The empty string will instruct
* the connection to use the optimizer version that is defined in the environment variable
* <code>SPANNER_OPTIMIZER_VERSION</code>. If no value is specified in the environment
* variable, the default query optimizer of Cloud Spanner is used.
*/
void setOptimizerVersion(String optimizerVersion) throws SQLException;
/**
* Gets the current query optimizer version of this connection.
*
* @return The query optimizer version that is currently used by this connection.
*/
String getOptimizerVersion() throws SQLException;
/**
* @return <code>true</code> if this connection has a transaction (that has not necessarily
* started). This method will only return false when the {@link Connection} is in autocommit
* mode and no explicit transaction has been started by executing `BEGIN TRANSACTION`. If the
* {@link Connection} is not in autocommit mode, there will always be a transaction.
*/
boolean isInTransaction() throws SQLException;
/**
* @return <code>true</code> if this connection has a transaction that has started. A transaction
* is automatically started by the first statement that is executed in the transaction.
*/
boolean isTransactionStarted() throws SQLException;
/**
* @return the commit {@link Timestamp} of the last read/write transaction. If the last
* transaction was not a read/write transaction, or a read/write transaction that did not
* return a commit timestamp because the transaction was not committed, the method will throw
* a {@link SQLException}.
*/
Timestamp getCommitTimestamp() throws SQLException;
/**
* @return the {@link CommitResponse} of the last read/write transaction. If the last transaction
* was not a read/write transaction, or a read/write transaction that did not return a {@link
* CommitResponse} because the transaction was not committed, the method will throw a {@link
* SQLException}. The {@link CommitResponse} will include {@link CommitStats} if {@link
* #isReturnCommitStats()} returns true.
*/
CommitResponse getCommitResponse() throws SQLException;
/**
* Sets whether this connection should request commit statistics from Cloud Spanner for read/write
* transactions and for DML statements in autocommit mode.
*/
void setReturnCommitStats(boolean returnCommitStats) throws SQLException;
/** @return true if this connection requests commit statistics from Cloud Spanner. */
boolean isReturnCommitStats() throws SQLException;
/**
* @return the read {@link Timestamp} of the last read-only transaction. If the last transaction
* was not a read-only transaction, or a read-only transaction that did not return a read
* timestamp because no data was read, the method will throw a {@link SQLException}.
*/
Timestamp getReadTimestamp() throws SQLException;
/**
* @return <code>true</code> if this connection will automatically retry read/write transactions
* that abort. This method may only be called when the connection is in read/write
* transactional mode and no transaction has been started yet.
*/
boolean isRetryAbortsInternally() throws SQLException;
/**
* Sets whether this connection will internally retry read/write transactions that abort. The
* default is <code>true</code>. When internal retry is enabled, the {@link Connection} will keep
* track of a running SHA256 checksum of all {@link ResultSet}s that have been returned from Cloud
* Spanner. If the checksum that is calculated during an internal retry differs from the original
* checksum, the transaction will abort with an {@link
* AbortedDueToConcurrentModificationException}.
*
* <p>Note that retries of a read/write transaction that calls a non-deterministic function on
* Cloud Spanner, such as CURRENT_TIMESTAMP(), will never be successful, as the data returned
* during the retry will always be different from the original transaction.
*
* <p>It is also highly recommended that all queries in a read/write transaction have an ORDER BY
* clause that guarantees that the data is returned in the same order as in the original
* transaction if the transaction is internally retried. The most efficient way to achieve this is
* to always include the primary key columns at the end of the ORDER BY clause.
*
* <p>This method may only be called when the connection is in read/write transactional mode and
* no transaction has been started yet.
*
* @param retryAbortsInternally Set to <code>true</code> to internally retry transactions that are
* aborted by Spanner. When set to <code>false</code>, any database call on a transaction that
* has been aborted by Cloud Spanner will throw an {@link AbortedException} instead of being
* retried. Set this to false if your application already uses retry loops to handle {@link
* AbortedException}s.
*/
void setRetryAbortsInternally(boolean retryAbortsInternally) throws SQLException;
/** Returns the current savepoint support for this connection. */
SavepointSupport getSavepointSupport() throws SQLException;
/** Sets how savepoints should be supported on this connection. */
void setSavepointSupport(SavepointSupport savepointSupport) throws SQLException;
/**
* Writes the specified mutation directly to the database and commits the change. The value is
* readable after the successful completion of this method. Writing multiple mutations to a
* database by calling this method multiple times mode is inefficient, as each call will need a
* round trip to the database. Instead, you should consider writing the mutations together by
* calling {@link CloudSpannerJdbcConnection#write(Iterable)}.
*
* <p>Calling this method is only allowed in autocommit mode. See {@link
* CloudSpannerJdbcConnection#bufferedWrite(Iterable)} for writing mutations in transactions.
*
* @param mutation The {@link Mutation} to write to the database.
* @throws SQLException if the {@link Connection} is not in autocommit mode or if the {@link
* Connection} is closed.
*/
void write(Mutation mutation) throws SQLException;
/**
* Writes the specified mutations directly to the database and commits the changes. The values are
* readable after the successful completion of this method.
*
* <p>Calling this method is only allowed in autocommit mode. See {@link
* CloudSpannerJdbcConnection#bufferedWrite(Iterable)} for writing mutations in transactions.
*
* @param mutations The {@link Mutation}s to write to the database.
* @throws SQLException if the {@link Connection} is not in autocommit mode or if the {@link
* Connection} is closed.
*/
void write(Iterable<Mutation> mutations) throws SQLException;
/**
* Buffers the given mutation locally on the current transaction of this {@link Connection}. The
* mutation will be written to the database at the next call to {@link Connection#commit()}. The
* value will not be readable on this {@link Connection} before the transaction is committed.
*
* <p>Calling this method is only allowed when not in autocommit mode. See {@link
* CloudSpannerJdbcConnection#write(Mutation)} for writing mutations in autocommit mode.
*
* @param mutation the {@link Mutation} to buffer for writing to the database on the next commit.
* @throws SQLException if the {@link Connection} is in autocommit mode or the {@link Connection}
* is closed.
*/
void bufferedWrite(Mutation mutation) throws SQLException;
/**
* Buffers the given mutations locally on the current transaction of this {@link Connection}. The
* mutations will be written to the database at the next call to {@link Connection#commit()}. The
* values will not be readable on this {@link Connection} before the transaction is committed.
*
* <p>Calling this method is only allowed when not in autocommit mode. See {@link
* CloudSpannerJdbcConnection#write(Iterable)} for writing mutations in autocommit mode.
*
* @param mutations the {@link Mutation}s to buffer for writing to the database on the next
* commit.
* @throws SQLException if the {@link Connection} is in autocommit mode or the {@link Connection}
* is closed.
*/
void bufferedWrite(Iterable<Mutation> mutations) throws SQLException;
/**
* @return a connection URL that can be used to create a new {@link Connection} that is equal to
* the initial state of this connection. If this connection was initially opened in read-only
* mode, and later changed to read-write, this will not be reflected in the connection URL
* that is returned.
*/
String getConnectionUrl();
/** @return The {@link Dialect} that is used by this connection. */
default Dialect getDialect() {
return Dialect.GOOGLE_STANDARD_SQL;
}
/**
* Enable data boost for partitioned queries. See also {@link
* CloudSpannerJdbcStatement#partitionQuery(String, PartitionOptions, QueryOption...)} and {@link
* CloudSpannerJdbcPreparedStatement#partitionQuery(PartitionOptions, QueryOption...)}.
*/
default void setDataBoostEnabled(boolean dataBoostEnabled) throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Returns whether data boost is enabled for partitioned queries. See also {@link
* CloudSpannerJdbcStatement#partitionQuery(String, PartitionOptions, QueryOption...)} and {@link
* CloudSpannerJdbcPreparedStatement#partitionQuery(PartitionOptions, QueryOption...)}.
*/
default boolean isDataBoostEnabled() throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Sets whether this connection should always use partitioned queries when a query is executed on
* this connection. Setting this flag to <code>true</code> and then executing a query that cannot
* be partitioned, or executing a query in a read/write transaction, will cause an error. Use this
* flag in combination with {@link #setDataBoostEnabled(boolean)} to force all queries on this
* connection to use data boost.
*/
default void setAutoPartitionMode(boolean alwaysUsePartitionedQueries) throws SQLException {
throw new UnsupportedOperationException();
}
/** Returns whether this connection will execute all queries as partitioned queries. */
default boolean isAutoPartitionMode() throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Sets the maximum number of partitions that should be included as a hint to Cloud Spanner when
* partitioning a query on this connection. Note that this is only a hint and Cloud Spanner might
* choose to ignore the hint.
*/
default void setMaxPartitions(int maxPartitions) throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Gets the maximum number of partitions that should be included as a hint to Cloud Spanner when
* partitioning a query on this connection. Note that this is only a hint and Cloud Spanner might
* choose to ignore the hint.
*/
default int getMaxPartitions() throws SQLException {
throw new UnsupportedOperationException();
}
/**
* Sets the maximum degree of parallelism that is used when executing a partitioned query. A
* partitioned query will use up to <code>maxThreads</code> to execute and retrieve the results
* from Cloud Spanner. Set this value to <code>0</code>> to use the number of available processors
* as returned by {@link Runtime#availableProcessors()}.
*/
default void setMaxPartitionedParallelism(int maxThreads) throws SQLException {
throw new UnsupportedOperationException();
}
/** Returns the maximum degree of parallelism that is used for partitioned queries. */
default int getMaxPartitionedParallelism() throws SQLException {
throw new UnsupportedOperationException();
}
/**
* @see
* com.google.cloud.spanner.connection.Connection#addTransactionRetryListener(com.google.cloud.spanner.connection.TransactionRetryListener)
* @throws SQLException if the {@link Connection} is closed.
*/
void addTransactionRetryListener(
com.google.cloud.spanner.connection.TransactionRetryListener listener) throws SQLException;
/**
* Use {@link
* #addTransactionRetryListener(com.google.cloud.spanner.connection.TransactionRetryListener)}
* instead.
*/
@Deprecated
void addTransactionRetryListener(com.google.cloud.spanner.jdbc.TransactionRetryListener listener)
throws SQLException;
/**
* @see
* com.google.cloud.spanner.connection.Connection#removeTransactionRetryListener(com.google.cloud.spanner.connection.TransactionRetryListener)
* @throws SQLException if the {@link Connection} is closed.
*/
boolean removeTransactionRetryListener(
com.google.cloud.spanner.connection.TransactionRetryListener listener) throws SQLException;
/**
* Use {@link
* #removeTransactionRetryListener(com.google.cloud.spanner.connection.TransactionRetryListener)}
* instead.
*/
@Deprecated
boolean removeTransactionRetryListener(
com.google.cloud.spanner.jdbc.TransactionRetryListener listener) throws SQLException;
/** Use {@link #getTransactionRetryListenersFromConnection()} instead. */
@Deprecated
Iterator<com.google.cloud.spanner.jdbc.TransactionRetryListener> getTransactionRetryListeners()
throws SQLException;
/**
* @see com.google.cloud.spanner.connection.Connection#getTransactionRetryListeners()
* @throws SQLException if the {@link Connection} is closed.
*/
Iterator<com.google.cloud.spanner.connection.TransactionRetryListener>
getTransactionRetryListenersFromConnection() throws SQLException;
}