Skip to content

Commit 502b934

Browse files
authored
Added ability to hand in connection options through the yaml framework and temporary tests that disable all rewrite rules (#3438)
1 parent c0fcb7c commit 502b934

File tree

122 files changed

+19480
-37
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+19480
-37
lines changed

fdb-relational-api/src/main/java/com/apple/foundationdb/relational/api/Options.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.google.common.annotations.VisibleForTesting;
3030
import com.google.common.collect.ImmutableMap;
3131
import com.google.common.collect.ImmutableSet;
32+
import com.google.common.collect.Iterables;
3233
import com.google.common.collect.Maps;
3334

3435
import javax.annotation.Nonnull;
@@ -261,6 +262,11 @@ public enum IndexFetchMethod {
261262
private final Options parentOptions;
262263
private final Map<Name, Object> optionsMap;
263264

265+
@Nonnull
266+
public static Options none() {
267+
return NONE;
268+
}
269+
264270
@Nonnull
265271
public static Map<Name, Object> defaultOptions() {
266272
return OPTIONS_DEFAULT_VALUES;
@@ -316,6 +322,12 @@ private Builder() {
316322
optionsMap = Maps.newHashMap();
317323
}
318324

325+
@Nonnull
326+
public Builder withOptionFromString(Name name, String valueAsString) throws SQLException {
327+
final Object value = parseStringOption(name, valueAsString);
328+
return withOption(name, value);
329+
}
330+
319331
@Nonnull
320332
public Builder withOption(Name name, Object value) throws SQLException {
321333
validateOption(name, value);
@@ -346,6 +358,16 @@ public Options build() {
346358
}
347359
}
348360

361+
@Nullable
362+
private static Object parseStringOption(@Nonnull final Name name, String valueAsString) throws SQLException {
363+
for (OptionContract contract : Objects.requireNonNull(OPTIONS).get(name)) {
364+
if (contract instanceof TypeContract<?>) {
365+
return ((TypeContract<?>)contract).fromString(valueAsString);
366+
}
367+
}
368+
throw new SQLException("option must have at least one type contract", ErrorCode.INTERNAL_ERROR.getErrorCode());
369+
}
370+
349371
private static void validateOption(@Nonnull final Name name, Object value) throws SQLException {
350372
for (OptionContract contract : Objects.requireNonNull(OPTIONS).get(name)) {
351373
contract.validate(name, value);
@@ -362,13 +384,22 @@ private <T> T getOptionInternal(Name name) {
362384
}
363385
}
364386

387+
@Nonnull
388+
public Iterable<? extends Map.Entry<Name, ?>> entries() {
389+
if (parentOptions != null) {
390+
return Iterables.concat(parentOptions.entries(), optionsMap.entrySet());
391+
} else {
392+
return optionsMap.entrySet();
393+
}
394+
}
395+
365396
private static Map<Name, List<OptionContract>> makeContracts() {
366397
EnumMap<Name, List<OptionContract>> data = new EnumMap<>(Name.class);
367-
data.put(Name.CONTINUATION, List.of(new TypeContract<>(Continuation.class)));
398+
data.put(Name.CONTINUATION, List.of(TypeContract.of(Continuation.class, ignored -> { throw new UnsupportedOperationException(); })));
368399
data.put(Name.MAX_ROWS, List.of(TypeContract.intType(), RangeContract.of(0, Integer.MAX_VALUE)));
369-
data.put(Name.INDEX_FETCH_METHOD, List.of(new TypeContract<>(IndexFetchMethod.class)));
400+
data.put(Name.INDEX_FETCH_METHOD, List.of(TypeContract.of(IndexFetchMethod.class, IndexFetchMethod::valueOf)));
370401
data.put(Name.DISABLE_PLANNER_REWRITING, List.of(TypeContract.booleanType()));
371-
data.put(Name.DISABLED_PLANNER_RULES, List.of(new CollectionContract(TypeContract.stringType())));
402+
data.put(Name.DISABLED_PLANNER_RULES, List.of(new CollectionContract<>(TypeContract.stringType())));
372403
data.put(Name.INDEX_HINT, List.of(TypeContract.stringType()));
373404
data.put(Name.PLAN_CACHE_PRIMARY_MAX_ENTRIES, List.of(TypeContract.intType(), RangeContract.of(0, Integer.MAX_VALUE)));
374405
data.put(Name.PLAN_CACHE_PRIMARY_TIME_TO_LIVE_MILLIS, List.of(TypeContract.longType(), RangeContract.of(10L, Long.MAX_VALUE)));

fdb-relational-api/src/main/java/com/apple/foundationdb/relational/api/options/CollectionContract.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,26 @@
2424
import com.apple.foundationdb.relational.api.exceptions.ErrorCode;
2525

2626
import javax.annotation.Nonnull;
27+
import javax.annotation.Nullable;
2728
import java.sql.SQLException;
29+
import java.util.ArrayList;
2830
import java.util.Collection;
31+
import java.util.Collections;
32+
import java.util.List;
2933

3034
/**
3135
* Option contract that ensures that all elements of a collection match some contract.
3236
* The contract is only valid if the elements of the given option are (1) some kind
3337
* of collection type and (2) every element in the collection satisfies the "element
3438
* contract" over which the contract is defined. For example, the child contract
3539
* may be that each element is of a given type or within a particular range.
40+
* @param <T> the type parameter of the collection
3641
*/
37-
public class CollectionContract implements OptionContract {
42+
public class CollectionContract<T> implements OptionContract, OptionContractWithConversion<Collection<T>> {
3843
@Nonnull
39-
private final OptionContract elementContract;
44+
private final TypeContract<T> elementContract;
4045

41-
public CollectionContract(@Nonnull OptionContract elementContract) {
46+
public CollectionContract(@Nonnull TypeContract<T> elementContract) {
4247
this.elementContract = elementContract;
4348
}
4449

@@ -56,4 +61,15 @@ public void validate(final Options.Name name, final Object value) throws SQLExce
5661
throw new SQLException("Element of collection option " + name + " violated contract: " + err.getMessage(), err.getSQLState(), err);
5762
}
5863
}
64+
65+
@Nullable
66+
@Override
67+
public Collection<T> fromString(final String valueAsString) throws SQLException {
68+
final List<T> results = new ArrayList<>(); // not null-phobic
69+
for (final String split : valueAsString.split(",")) {
70+
final String trimmedElementString = split.trim();
71+
results.add(elementContract.fromString(trimmedElementString));
72+
}
73+
return Collections.unmodifiableCollection(results);
74+
}
5975
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* OptionContract.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2021-2024 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb.relational.api.options;
22+
23+
import javax.annotation.Nullable;
24+
import java.sql.SQLException;
25+
26+
public interface OptionContractWithConversion<T> extends OptionContract {
27+
@Nullable
28+
T fromString(String valueAsString) throws SQLException;
29+
}

fdb-relational-api/src/main/java/com/apple/foundationdb/relational/api/options/TypeContract.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,38 @@
2121
package com.apple.foundationdb.relational.api.options;
2222

2323
import com.apple.foundationdb.annotation.API;
24-
2524
import com.apple.foundationdb.relational.api.Options;
2625
import com.apple.foundationdb.relational.api.exceptions.ErrorCode;
2726

2827
import javax.annotation.Nonnull;
28+
import javax.annotation.Nullable;
2929
import java.sql.SQLException;
30+
import java.util.function.Function;
3031

3132
@API(API.Status.EXPERIMENTAL)
32-
public class TypeContract<T> implements OptionContract {
33+
public class TypeContract<T> implements OptionContract, OptionContractWithConversion<T> {
3334

3435
@Nonnull
35-
private static final TypeContract<Boolean> BOOLEAN_TYPE = new TypeContract<>(Boolean.class);
36+
private static final TypeContract<Boolean> BOOLEAN_TYPE = new TypeContract<>(Boolean.class, Boolean::parseBoolean);
3637

3738
@Nonnull
38-
private static final TypeContract<Integer> INTEGER_TYPE = new TypeContract<>(Integer.class);
39+
private static final TypeContract<Integer> INTEGER_TYPE = new TypeContract<>(Integer.class, Integer::parseInt);
3940

4041
@Nonnull
41-
private static final TypeContract<Long> LONG_TYPE = new TypeContract<>(Long.class);
42+
private static final TypeContract<Long> LONG_TYPE = new TypeContract<>(Long.class, Long::parseLong);
4243

4344
@Nonnull
44-
private static final TypeContract<String> STRING_TYPE = new TypeContract<>(String.class);
45+
private static final TypeContract<String> STRING_TYPE = new TypeContract<>(String.class, Function.identity());
4546

47+
@Nonnull
4648
private final Class<T> clazz;
4749

48-
public TypeContract(Class<T> clazz) {
49-
this.clazz = clazz;
50+
@Nonnull
51+
private final Function<String, T> fromStringFunction;
5052

53+
private TypeContract(@Nonnull Class<T> clazz, @Nonnull Function<String, T> fromStringFunction) {
54+
this.clazz = clazz;
55+
this.fromStringFunction = fromStringFunction;
5156
}
5257

5358
@Override
@@ -57,9 +62,15 @@ public void validate(Options.Name name, Object value) throws SQLException {
5762
}
5863
}
5964

65+
@Nullable
66+
@Override
67+
public T fromString(String valueAsString) throws SQLException {
68+
return fromStringFunction.apply(valueAsString);
69+
}
70+
6071
@Nonnull
61-
public static <T> TypeContract<T> of(@Nonnull final Class<T> clazz) {
62-
return new TypeContract<>(clazz);
72+
public static <T> TypeContract<T> of(@Nonnull final Class<T> clazz, @Nonnull Function<String, T> fromStringFunction) {
73+
return new TypeContract<>(clazz, fromStringFunction);
6374
}
6475

6576
@Nonnull
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* EmbeddedSimpleYamlConnection.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2015-2025 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb.relational.yamltests;
22+
23+
import com.apple.foundationdb.relational.api.Options;
24+
import com.apple.foundationdb.relational.api.RelationalConnection;
25+
import com.apple.foundationdb.relational.yamltests.server.SemanticVersion;
26+
27+
import javax.annotation.Nonnull;
28+
import java.sql.Connection;
29+
import java.sql.SQLException;
30+
import java.util.Map;
31+
32+
/**
33+
* A simple version of {@link YamlConnection} for interacting with a single {@link RelationalConnection}.
34+
*/
35+
public class EmbeddedSimpleYamlConnection extends SimpleYamlConnection {
36+
public EmbeddedSimpleYamlConnection(@Nonnull Connection connection, @Nonnull SemanticVersion version) throws SQLException {
37+
super(connection, version, version.toString());
38+
}
39+
40+
public EmbeddedSimpleYamlConnection(@Nonnull Connection connection, @Nonnull SemanticVersion version, @Nonnull String connectionLabel) throws SQLException {
41+
super(connection, version, connectionLabel);
42+
}
43+
44+
@Override
45+
@SuppressWarnings("PMD.CloseResource")
46+
public void setConnectionOptions(@Nonnull final Options connectionOptions) throws SQLException {
47+
final RelationalConnection underlying = getUnderlying();
48+
for (Map.Entry<Options.Name, ?> entry : connectionOptions.entries()) {
49+
underlying.setOption(entry.getKey(), entry.getValue());
50+
}
51+
}
52+
}

yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* YamlConnection.java
2+
* SimpleYamlConnection.java
33
*
44
* This source file is part of the FoundationDB open source project
55
*
@@ -20,12 +20,15 @@
2020

2121
package com.apple.foundationdb.relational.yamltests;
2222

23+
import com.apple.foundationdb.relational.api.Options;
2324
import com.apple.foundationdb.relational.api.RelationalConnection;
2425
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
2526
import com.apple.foundationdb.relational.api.RelationalStatement;
2627
import com.apple.foundationdb.relational.api.metrics.MetricCollector;
2728
import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection;
2829
import com.apple.foundationdb.relational.yamltests.server.SemanticVersion;
30+
import com.google.common.collect.Iterables;
31+
import org.junit.jupiter.api.Assumptions;
2932

3033
import javax.annotation.Nonnull;
3134
import javax.annotation.Nullable;
@@ -54,11 +57,23 @@ public SimpleYamlConnection(@Nonnull Connection connection, @Nonnull SemanticVer
5457
this.connectionLabel = connectionLabel;
5558
}
5659

60+
@Nonnull
61+
protected RelationalConnection getUnderlying() {
62+
return underlying;
63+
}
64+
5765
@Override
5866
public void close() throws SQLException {
5967
underlying.close();
6068
}
6169

70+
@Override
71+
public void setConnectionOptions(@Nonnull final Options connectionOptions) throws SQLException {
72+
if (!Iterables.isEmpty(connectionOptions.entries())) {
73+
Assumptions.abort("only embedded connections support the setting of connection options");
74+
}
75+
}
76+
6277
@Override
6378
public boolean supportsMetricCollector() {
6479
return underlying instanceof EmbeddedRelationalConnection;

yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
package com.apple.foundationdb.relational.yamltests;
2222

23+
import com.apple.foundationdb.relational.api.Options;
2324
import com.apple.foundationdb.relational.api.RelationalConnection;
2425
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
2526
import com.apple.foundationdb.relational.api.RelationalStatement;
@@ -43,6 +44,8 @@ public interface YamlConnection extends AutoCloseable {
4344
@Override
4445
void close() throws SQLException;
4546

47+
void setConnectionOptions(@Nonnull Options connectionOptions) throws SQLException;
48+
4649
/**
4750
* Creates a statement (see {@link RelationalConnection#createStatement()}).
4851
* @return a new statement

yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlExecutionContext.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.logging.log4j.LogManager;
3232
import org.apache.logging.log4j.Logger;
3333
import org.junit.jupiter.api.Assertions;
34+
import org.opentest4j.TestAbortedException;
3435
import org.yaml.snakeyaml.DumperOptions;
3536
import org.yaml.snakeyaml.Yaml;
3637

@@ -265,32 +266,35 @@ public List<Block> getFinalizeBlocks() {
265266
* test_run: lineNumber of query, query run as a simple statement or as prepared statement, parameters (if any)
266267
* test_block: lineNumber of test_block, seed used for randomization, execution properties
267268
*
268-
* @param e the throwable that needs to be wrapped
269+
* @param throwable the throwable that needs to be wrapped
269270
* @param msg additional context
270271
* @param identifier The name of the element type to which the context is associated to.
271272
* @param lineNumber the line number in the YAMSQL file to which the context is associated to.
272273
*
273274
* @return wrapped {@link YamlExecutionError}
274275
*/
275276
@Nonnull
276-
public YamlExecutionError wrapContext(@Nullable Throwable e, @Nonnull Supplier<String> msg, @Nonnull String identifier, int lineNumber) {
277+
public RuntimeException wrapContext(@Nonnull Throwable throwable, @Nonnull Supplier<String> msg, @Nonnull String identifier, int lineNumber) {
277278
String fileName;
278279
if (resourcePath.contains("/")) {
279280
final String[] split = resourcePath.split("/");
280281
fileName = split[split.length - 1];
281282
} else {
282283
fileName = resourcePath;
283284
}
284-
if (e instanceof YamlExecutionError) {
285-
final var oldStackTrace = e.getStackTrace();
285+
286+
if (throwable instanceof TestAbortedException) {
287+
return (TestAbortedException)throwable;
288+
} else if (throwable instanceof YamlExecutionError) {
289+
final var oldStackTrace = throwable.getStackTrace();
286290
final var newStackTrace = new StackTraceElement[oldStackTrace.length + 1];
287291
System.arraycopy(oldStackTrace, 0, newStackTrace, 0, oldStackTrace.length);
288292
newStackTrace[oldStackTrace.length] = new StackTraceElement("YAML_FILE", identifier, fileName, lineNumber);
289-
e.setStackTrace(newStackTrace);
290-
return (YamlExecutionError) e;
293+
throwable.setStackTrace(newStackTrace);
294+
return (YamlExecutionError)throwable;
291295
} else {
292296
// wrap
293-
final var wrapper = new YamlExecutionError(msg.get(), e);
297+
final var wrapper = new YamlExecutionError(msg.get(), throwable);
294298
wrapper.setStackTrace(new StackTraceElement[]{new StackTraceElement("YAML_FILE", identifier, fileName, lineNumber)});
295299
return wrapper;
296300
}

0 commit comments

Comments
 (0)