22 files changed

+568
-50
lines changed
Original file line numberDiff line numberDiff line change
@@ -618,4 +618,23 @@
618618
<className>com/google/cloud/spanner/TransactionContext</className>
619619
<method>com.google.api.core.ApiFuture bufferAsync(java.lang.Iterable)</method>
620620
</difference>
621+
622+
<!-- Query stats optimiser statistics package -->
623+
<!-- These are not breaking changes, since we provide default interface implementation -->
624+
<difference>
625+
<differenceType>7012</differenceType>
626+
<className>com/google/cloud/spanner/SpannerOptions$SpannerEnvironment</className>
627+
<method>java.lang.String getOptimizerStatisticsPackage()</method>
628+
</difference>
629+
<difference>
630+
<differenceType>7012</differenceType>
631+
<className>com/google/cloud/spanner/connection/Connection</className>
632+
<method>java.lang.String getOptimizerStatisticsPackage()</method>
633+
</difference>
634+
<difference>
635+
<differenceType>7012</differenceType>
636+
<className>com/google/cloud/spanner/connection/Connection</className>
637+
<method>void setOptimizerStatisticsPackage(java.lang.String)</method>
638+
</difference>
639+
621640
</differences>
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,15 @@ public interface SpannerEnvironment {
585585
*/
586586
@Nonnull
587587
String getOptimizerVersion();
588+
589+
/**
590+
* The optimizer statistics package to use. Must return an empty string to indicate that no
591+
* value has been set.
592+
*/
593+
@Nonnull
594+
default String getOptimizerStatisticsPackage() {
595+
throw new UnsupportedOperationException("Unimplemented");
596+
}
588597
}
589598

590599
/**
@@ -594,13 +603,21 @@ public interface SpannerEnvironment {
594603
private static class SpannerEnvironmentImpl implements SpannerEnvironment {
595604
private static final SpannerEnvironmentImpl INSTANCE = new SpannerEnvironmentImpl();
596605
private static final String SPANNER_OPTIMIZER_VERSION_ENV_VAR = "SPANNER_OPTIMIZER_VERSION";
606+
private static final String SPANNER_OPTIMIZER_STATISTICS_PACKAGE_ENV_VAR =
607+
"SPANNER_OPTIMIZER_STATISTICS_PACKAGE";
597608

598609
private SpannerEnvironmentImpl() {}
599610

600611
@Override
601612
public String getOptimizerVersion() {
602613
return MoreObjects.firstNonNull(System.getenv(SPANNER_OPTIMIZER_VERSION_ENV_VAR), "");
603614
}
615+
616+
@Override
617+
public String getOptimizerStatisticsPackage() {
618+
return MoreObjects.firstNonNull(
619+
System.getenv(SPANNER_OPTIMIZER_STATISTICS_PACKAGE_ENV_VAR), "");
620+
}
604621
}
605622

606623
/** Builder for {@link SpannerOptions} instances. */
@@ -957,6 +974,7 @@ public Builder setDefaultQueryOptions(DatabaseId database, QueryOptions defaultQ
957974
QueryOptions getEnvironmentQueryOptions() {
958975
return QueryOptions.newBuilder()
959976
.setOptimizerVersion(environment.getOptimizerVersion())
977+
.setOptimizerStatisticsPackage(environment.getOptimizerStatisticsPackage())
960978
.build();
961979
}
962980

Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@
9696
* <li><code>
9797
* SET OPTIMIZER_VERSION='&lt;version&gt;' | 'LATEST'
9898
* </code>: Sets the value of <code>OPTIMIZER_VERSION</code> for this connection.
99+
* <li><code>SHOW OPTIMIZER_STATISTICS_PACKAGE</code>: Returns the current value of <code>
100+
* OPTIMIZER_STATISTICS_PACKAGE</code> of this connection as a {@link ResultSet}
101+
* <li><code>
102+
* SET OPTIMIZER_STATISTICS_PACKAGE='&lt;package&gt;' | ''
103+
* </code>: Sets the value of <code>OPTIMIZER_STATISTICS_PACKAGE</code> for this connection.
99104
* <li><code>BEGIN [TRANSACTION]</code>: Begins a new transaction. This statement is optional when
100105
* the connection is not in autocommit mode, as a new transaction will automatically be
101106
* started when a query or update statement is issued. In autocommit mode, this statement will
@@ -448,6 +453,29 @@ public interface Connection extends AutoCloseable {
448453
*/
449454
String getOptimizerVersion();
450455

456+
/**
457+
* Sets the query optimizer statistics package
458+
*
459+
* @param optimizerStatisticsPackage The query optimizer statistics package to use. Must be a
460+
* string composed of letters, numbers, dashes and underscores or an empty string. The empty
461+
* string will instruct the connection to use the optimizer statistics package that is defined
462+
* the environment variable <code>SPANNER_OPTIMIZER_STATISTICS_PACKAGE</code>. If no value is
463+
* specified in the environment variable, the client level query optimizer is used. If none is
464+
* set, the default query optimizer of Cloud Spanner is used.
465+
*/
466+
default void setOptimizerStatisticsPackage(String optimizerStatisticsPackage) {
467+
throw new UnsupportedOperationException("Unimplemented");
468+
}
469+
470+
/**
471+
* Gets the current query optimizer statistics package of this connection.
472+
*
473+
* @return The query optimizer statistics package that is currently used by this connection.
474+
*/
475+
default String getOptimizerStatisticsPackage() {
476+
throw new UnsupportedOperationException("Unimplemented");
477+
}
478+
451479
/**
452480
* Sets whether this connection should request commit statistics from Cloud Spanner for read/write
453481
* transactions and DML statements in autocommit mode.
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,20 @@ public String getOptimizerVersion() {
433433
return this.queryOptions.getOptimizerVersion();
434434
}
435435

436+
@Override
437+
public void setOptimizerStatisticsPackage(String optimizerStatisticsPackage) {
438+
Preconditions.checkNotNull(optimizerStatisticsPackage);
439+
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
440+
this.queryOptions =
441+
queryOptions.toBuilder().setOptimizerStatisticsPackage(optimizerStatisticsPackage).build();
442+
}
443+
444+
@Override
445+
public String getOptimizerStatisticsPackage() {
446+
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
447+
return this.queryOptions.getOptimizerStatisticsPackage();
448+
}
449+
436450
@Override
437451
public void setStatementTimeout(long timeout, TimeUnit unit) {
438452
Preconditions.checkArgument(timeout > 0L, "Zero or negative timeout values are not allowed");
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ public String[] getValidValues() {
157157
private static final String DEFAULT_NUM_CHANNELS = null;
158158
private static final String DEFAULT_USER_AGENT = null;
159159
private static final String DEFAULT_OPTIMIZER_VERSION = "";
160+
private static final String DEFAULT_OPTIMIZER_STATISTICS_PACKAGE = "";
160161
private static final boolean DEFAULT_RETURN_COMMIT_STATS = false;
161162
private static final boolean DEFAULT_LENIENT = false;
162163

@@ -190,6 +191,9 @@ public String[] getValidValues() {
190191
private static final String USER_AGENT_PROPERTY_NAME = "userAgent";
191192
/** Query optimizer version to use for a connection. */
192193
private static final String OPTIMIZER_VERSION_PROPERTY_NAME = "optimizerVersion";
194+
/** Query optimizer statistics package to use for a connection. */
195+
private static final String OPTIMIZER_STATISTICS_PACKAGE_PROPERTY_NAME =
196+
"optimizerStatisticsPackage";
193197
/** Name of the 'lenientMode' connection property. */
194198
public static final String LENIENT_PROPERTY_NAME = "lenient";
195199

@@ -238,6 +242,8 @@ public String[] getValidValues() {
238242
ConnectionProperty.createStringProperty(
239243
OPTIMIZER_VERSION_PROPERTY_NAME,
240244
"Sets the default query optimizer version to use for this connection."),
245+
ConnectionProperty.createStringProperty(
246+
OPTIMIZER_STATISTICS_PACKAGE_PROPERTY_NAME, ""),
241247
ConnectionProperty.createBooleanProperty("returnCommitStats", "", false),
242248
ConnectionProperty.createBooleanProperty(
243249
"autoConfigEmulator",
@@ -521,6 +527,7 @@ private ConnectionOptions(Builder builder) {
521527
this.userAgent = parseUserAgent(this.uri);
522528
QueryOptions.Builder queryOptionsBuilder = QueryOptions.newBuilder();
523529
queryOptionsBuilder.setOptimizerVersion(parseOptimizerVersion(this.uri));
530+
queryOptionsBuilder.setOptimizerStatisticsPackage(parseOptimizerStatisticsPackage(this.uri));
524531
this.queryOptions = queryOptionsBuilder.build();
525532
this.returnCommitStats = parseReturnCommitStats(this.uri);
526533
this.autoConfigEmulator = parseAutoConfigEmulator(this.uri);
@@ -695,6 +702,12 @@ static String parseOptimizerVersion(String uri) {
695702
return value != null ? value : DEFAULT_OPTIMIZER_VERSION;
696703
}
697704

705+
@VisibleForTesting
706+
static String parseOptimizerStatisticsPackage(String uri) {
707+
String value = parseUriProperty(uri, OPTIMIZER_STATISTICS_PACKAGE_PROPERTY_NAME);
708+
return value != null ? value : DEFAULT_OPTIMIZER_STATISTICS_PACKAGE;
709+
}
710+
698711
@VisibleForTesting
699712
static boolean parseReturnCommitStats(String uri) {
700713
String value = parseUriProperty(uri, "returnCommitStats");
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ interface ConnectionStatementExecutor {
6666

6767
StatementResult statementShowOptimizerVersion();
6868

69+
StatementResult statementSetOptimizerStatisticsPackage(String optimizerStatisticsPackage);
70+
71+
StatementResult statementShowOptimizerStatisticsPackage();
72+
6973
StatementResult statementSetReturnCommitStats(Boolean returnCommitStats);
7074

7175
StatementResult statementShowReturnCommitStats();
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.RUN_BATCH;
2424
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_AUTOCOMMIT;
2525
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_AUTOCOMMIT_DML_MODE;
26+
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_STATISTICS_PACKAGE;
2627
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_VERSION;
2728
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_READONLY;
2829
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_READ_ONLY_STALENESS;
@@ -34,6 +35,7 @@
3435
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_AUTOCOMMIT_DML_MODE;
3536
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_COMMIT_RESPONSE;
3637
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_COMMIT_TIMESTAMP;
38+
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_STATISTICS_PACKAGE;
3739
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_VERSION;
3840
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READONLY;
3941
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_READ_ONLY_STALENESS;
@@ -230,6 +232,20 @@ public StatementResult statementShowOptimizerVersion() {
230232
"OPTIMIZER_VERSION", getConnection().getOptimizerVersion(), SHOW_OPTIMIZER_VERSION);
231233
}
232234

235+
@Override
236+
public StatementResult statementSetOptimizerStatisticsPackage(String optimizerStatisticsPackage) {
237+
getConnection().setOptimizerStatisticsPackage(optimizerStatisticsPackage);
238+
return noResult(SET_OPTIMIZER_STATISTICS_PACKAGE);
239+
}
240+
241+
@Override
242+
public StatementResult statementShowOptimizerStatisticsPackage() {
243+
return resultSet(
244+
"OPTIMIZER_STATISTICS_PACKAGE",
245+
getConnection().getOptimizerStatisticsPackage(),
246+
SHOW_OPTIMIZER_STATISTICS_PACKAGE);
247+
}
248+
233249
@Override
234250
public StatementResult statementSetReturnCommitStats(Boolean returnCommitStats) {
235251
getConnection().setReturnCommitStats(returnCommitStats);
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ enum ClientSideStatementType {
6565
SET_READ_ONLY_STALENESS,
6666
SHOW_OPTIMIZER_VERSION,
6767
SET_OPTIMIZER_VERSION,
68+
SHOW_OPTIMIZER_STATISTICS_PACKAGE,
69+
SET_OPTIMIZER_STATISTICS_PACKAGE,
6870
SHOW_RETURN_COMMIT_STATS,
6971
SET_RETURN_COMMIT_STATS,
7072
BEGIN,
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@
7676
"method": "statementShowOptimizerVersion",
7777
"exampleStatements": ["show variable optimizer_version"]
7878
},
79+
{
80+
"name": "SHOW VARIABLE OPTIMIZER_STATISTICS_PACKAGE",
81+
"executorName": "ClientSideStatementNoParamExecutor",
82+
"resultType": "RESULT_SET",
83+
"regex": "(?is)\\A\\s*show\\s+variable\\s+optimizer_statistics_package\\s*\\z",
84+
"method": "statementShowOptimizerStatisticsPackage",
85+
"exampleStatements": ["show variable optimizer_statistics_package"]
86+
},
7987
{
8088
"name": "SHOW VARIABLE RETURN_COMMIT_STATS",
8189
"executorName": "ClientSideStatementNoParamExecutor",
@@ -281,6 +289,20 @@
281289
"converterName": "ClientSideStatementValueConverters$StringValueConverter"
282290
}
283291
},
292+
{
293+
"name": "SET OPTIMIZER_STATISTICS_PACKAGE = '<package>'|''",
294+
"executorName": "ClientSideStatementSetExecutor",
295+
"resultType": "NO_RESULT",
296+
"regex": "(?is)\\A\\s*set\\s+optimizer_statistics_package\\s*(?:=)\\s*(.*)\\z",
297+
"method": "statementSetOptimizerStatisticsPackage",
298+
"exampleStatements": ["set optimizer_statistics_package='auto_20191128_14_47_22UTC'", "set optimizer_statistics_package=''"],
299+
"setStatement": {
300+
"propertyName": "OPTIMIZER_STATISTICS_PACKAGE",
301+
"separator": "=",
302+
"allowedValues": "'((\\S+)|())'",
303+
"converterName": "ClientSideStatementValueConverters$StringValueConverter"
304+
}
305+
},
284306
{
285307
"name": "SET RETURN_COMMIT_STATS = TRUE|FALSE",
286308
"executorName": "ClientSideStatementSetExecutor",
@@ -296,4 +318,4 @@
296318
}
297319
}
298320
]
299-
}
321+
}
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ public static Collection<Object[]> parameters() {
5252
List<Object[]> params = new ArrayList<>();
5353
params.add(new Object[] {QueryOptions.getDefaultInstance()});
5454
params.add(
55-
new Object[] {QueryOptions.newBuilder().setOptimizerVersion("some-version").build()});
55+
new Object[] {
56+
QueryOptions.newBuilder()
57+
.setOptimizerVersion("some-version")
58+
.setOptimizerStatisticsPackage("some-package")
59+
.build()
60+
});
5661
return params;
5762
}
5863

@@ -134,14 +139,20 @@ public void executeSqlRequestBuilderWithQueryOptions() {
134139
context
135140
.getExecuteSqlRequestBuilder(
136141
Statement.newBuilder("SELECT FOO FROM BAR")
137-
.withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("2.0").build())
142+
.withQueryOptions(
143+
QueryOptions.newBuilder()
144+
.setOptimizerVersion("2.0")
145+
.setOptimizerStatisticsPackage("custom-package")
146+
.build())
138147
.build(),
139148
QueryMode.NORMAL,
140149
Options.fromQueryOptions(),
141150
true)
142151
.build();
143152
assertThat(request.getSql()).isEqualTo("SELECT FOO FROM BAR");
144153
assertThat(request.getQueryOptions().getOptimizerVersion()).isEqualTo("2.0");
154+
assertThat(request.getQueryOptions().getOptimizerStatisticsPackage())
155+
.isEqualTo("custom-package");
145156
}
146157

147158
@Test

0 commit comments

Comments
 (0)