From 4c31bbac508cea8a4911d7f191e0f3b3731df217 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Mon, 7 Jul 2025 16:31:44 -0400 Subject: [PATCH 1/7] Partially working yaml tests for transaction setup Introduces a setup query config to have code executed transactionally with the query itself. Also, a way to define the setup in one place, and reuse it. Also, fix some issues with transacitonal code. This gets it working for embedded and jdbc-in-process --- .../jdbc/JDBCRelationalConnection.java | 3 +- .../jdbc/v1/TransactionRequestHandler.java | 10 ++- .../yamltests/CustomYamlConstructor.java | 4 ++ .../relational/yamltests/Matchers.java | 2 +- .../yamltests/SimpleYamlConnection.java | 17 +++++ .../relational/yamltests/YamlConnection.java | 3 + .../yamltests/YamlExecutionContext.java | 13 ++++ .../relational/yamltests/block/Block.java | 2 + .../block/TransactionSetupsBlock.java | 43 +++++++++++++ .../yamltests/command/QueryCommand.java | 3 + .../yamltests/command/QueryConfig.java | 18 +++++- .../yamltests/command/QueryExecutor.java | 62 +++++++++++++++---- .../yamltests/command/SQLSupplier.java | 30 +++++++++ .../MultiServerConnectionFactory.java | 6 ++ .../test/resources/transactions-tests.yamsql | 14 ++++- 15 files changed, 208 insertions(+), 22 deletions(-) create mode 100644 yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/TransactionSetupsBlock.java create mode 100644 yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java diff --git a/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java b/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java index 1fef8d7109..821466294a 100644 --- a/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java +++ b/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java @@ -345,7 +345,8 @@ public void setAutoCommit(boolean autoCommit) throws SQLException { this.autoCommit = false; } else { // commit any remaining work - commit(); + // TODO do we need better protection if there is uncommitted work + // does the autoCommit-ness need to be passed down this.autoCommit = true; serverConnection.close(); serverConnection = null; diff --git a/fdb-relational-server/src/main/java/com/apple/foundationdb/relational/server/jdbc/v1/TransactionRequestHandler.java b/fdb-relational-server/src/main/java/com/apple/foundationdb/relational/server/jdbc/v1/TransactionRequestHandler.java index 9ff6a9e494..fec7a096cc 100644 --- a/fdb-relational-server/src/main/java/com/apple/foundationdb/relational/server/jdbc/v1/TransactionRequestHandler.java +++ b/fdb-relational-server/src/main/java/com/apple/foundationdb/relational/server/jdbc/v1/TransactionRequestHandler.java @@ -82,9 +82,13 @@ public void onNext(final TransactionalRequest transactionRequest) { final FRL.Response response = frl.transactionalExecute(transactionalToken, request.getSql(), request.getParameters().getParameterList(), fromProto(request.getOptions())); - StatementResponse.Builder statementResponseBuilder = StatementResponse.newBuilder() - .setResultSet(response.getResultSet()) - .setRowCount(response.getRowCount()); + StatementResponse.Builder statementResponseBuilder = StatementResponse.newBuilder(); + if (response.isQuery()) { + statementResponseBuilder.setResultSet(response.getResultSet()); + } + if (response.isMutation()) { + statementResponseBuilder.setRowCount(response.getRowCount()); + } responseBuilder.setExecuteResponse(statementResponseBuilder); } else if (transactionRequest.hasInsertRequest()) { diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/CustomYamlConstructor.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/CustomYamlConstructor.java index c5a329f085..eea6b0b7b1 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/CustomYamlConstructor.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/CustomYamlConstructor.java @@ -25,6 +25,7 @@ import com.apple.foundationdb.relational.yamltests.block.FileOptions; import com.apple.foundationdb.relational.yamltests.block.SetupBlock; import com.apple.foundationdb.relational.yamltests.block.TestBlock; +import com.apple.foundationdb.relational.yamltests.block.TransactionSetupsBlock; import com.apple.foundationdb.relational.yamltests.command.Command; import com.apple.foundationdb.relational.yamltests.command.QueryConfig; import org.yaml.snakeyaml.LoaderOptions; @@ -61,6 +62,7 @@ public CustomYamlConstructor(LoaderOptions loaderOptions) { requireLineNumber.add(FileOptions.OPTIONS); requireLineNumber.add(SetupBlock.SETUP_BLOCK); requireLineNumber.add(SetupBlock.SchemaTemplateBlock.SCHEMA_TEMPLATE_BLOCK); + requireLineNumber.add(TransactionSetupsBlock.TRANSACTION_SETUP); requireLineNumber.add(TestBlock.TEST_BLOCK); // commands requireLineNumber.add(Command.COMMAND_LOAD_SCHEMA_TEMPLATE); @@ -78,6 +80,8 @@ public CustomYamlConstructor(LoaderOptions loaderOptions) { requireLineNumber.add(QueryConfig.QUERY_CONFIG_SUPPORTED_VERSION); requireLineNumber.add(QueryConfig.QUERY_CONFIG_INITIAL_VERSION_LESS_THAN); requireLineNumber.add(QueryConfig.QUERY_CONFIG_INITIAL_VERSION_AT_LEAST); + requireLineNumber.add(QueryConfig.QUERY_CONFIG_SETUP); + requireLineNumber.add(QueryConfig.QUERY_CONFIG_SETUP_REFERENCE); } @Override diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/Matchers.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/Matchers.java index 4bc08f2661..fcec19b33f 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/Matchers.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/Matchers.java @@ -116,7 +116,7 @@ public static Object third(@Nonnull final List obj) { return obj.get(2); } - public static String string(@Nonnull final Object obj, @Nonnull final String desc) { + public static String string(@Nullable final Object obj, @Nonnull final String desc) { if (obj instanceof String) { // should return null maybe? return (String) obj; diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java index 9ad65058a4..b2723e597e 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java @@ -35,6 +35,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; +import java.util.function.Function; /** * A simple version of {@link YamlConnection} for interacting with a single {@link RelationalConnection}. @@ -117,6 +118,22 @@ public SemanticVersion getInitialVersion() { return versions.get(0); } + @Override + public T executeTransactionally(final Function transactionalWork) throws SQLException { + underlying.setAutoCommit(false); + T result; + try { + result = transactionalWork.apply(this); + underlying.commit(); + } catch (final SQLException e) { + underlying.rollback(); + throw e; + } finally { + underlying.setAutoCommit(true); + } + return result; + } + @Override public String toString() { return connectionLabel; diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java index bb0c1c41dd..15baeba5ce 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java @@ -32,6 +32,7 @@ import javax.annotation.Nullable; import java.sql.SQLException; import java.util.List; +import java.util.function.Function; /** * A wrapper around {@link java.sql.Connection} to support yaml tests. @@ -104,4 +105,6 @@ public interface YamlConnection extends AutoCloseable { */ @Nonnull SemanticVersion getInitialVersion(); + + T executeTransactionally(Function transactionalWork) throws SQLException; } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlExecutionContext.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlExecutionContext.java index 30cd2c84ea..dfdc87dee4 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlExecutionContext.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlExecutionContext.java @@ -84,6 +84,7 @@ public final class YamlExecutionContext { private final List connectionURIs = new ArrayList<>(); // Additional options that can be set by the runners to impact test execution private final ContextOptions additionalOptions; + private final Map transactionSetups = new HashMap<>(); public static class YamlExecutionError extends RuntimeException { @@ -248,6 +249,18 @@ public URI inferConnectionURI(@Nullable Object connectObject) { } } + public void registerTransactionSetup(final String name, final String command) { + Assert.thatUnchecked(!transactionSetups.containsKey(name), ErrorCode.INTERNAL_ERROR, + () -> "Transaction setup " + name + " is defined multiple times."); + transactionSetups.put(name, command); + } + + public String getTransactionSetup(final Object name) { + return Matchers.notNull( + transactionSetups.get(Matchers.string(name, "setup reference")), + "transaction setup " + name + " is not defined"); + } + @Nonnull public List getFinalizeBlocks() { return finalizeBlocks; diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/Block.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/Block.java index 442e03c584..b2f53da12d 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/Block.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/Block.java @@ -62,6 +62,8 @@ static Block parse(@Nonnull Object document, int blockNumber, @Nonnull YamlExecu switch (blockKey) { case SetupBlock.SETUP_BLOCK: return SetupBlock.ManualSetupBlock.parse(lineNumber, entry.getValue(), executionContext); + case TransactionSetupsBlock.TRANSACTION_SETUP: + return TransactionSetupsBlock.parse(lineNumber, entry.getValue(), executionContext); case TestBlock.TEST_BLOCK: return TestBlock.parse(blockNumber, lineNumber, entry.getValue(), executionContext); case SetupBlock.SchemaTemplateBlock.SCHEMA_TEMPLATE_BLOCK: diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/TransactionSetupsBlock.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/TransactionSetupsBlock.java new file mode 100644 index 0000000000..cbe631c3a7 --- /dev/null +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/block/TransactionSetupsBlock.java @@ -0,0 +1,43 @@ +/* + * TransactionSetupsBlock.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors + * + * 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.apple.foundationdb.relational.yamltests.block; + +import com.apple.foundationdb.relational.yamltests.Matchers; +import com.apple.foundationdb.relational.yamltests.YamlExecutionContext; + +import java.util.Map; + +public class TransactionSetupsBlock { + public static final String TRANSACTION_SETUP = "transaction_setups"; + + public static Block parse(final int lineNumber, + final Object document, + final YamlExecutionContext executionContext) { + final Map map = Matchers.map(document); + for (final Map.Entry entry : map.entrySet()) { + final String transactionSetupName = Matchers.string(entry.getKey(), "transaction setup name"); + final String transactionSetupCommand = Matchers.string(entry.getValue(), "transaction setup command"); + executionContext.registerTransactionSetup(transactionSetupName, transactionSetupCommand); + } + return new NoOpBlock(lineNumber); + } + +} diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryCommand.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryCommand.java index 460e231ca5..4565610e02 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryCommand.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryCommand.java @@ -192,6 +192,9 @@ private void executeInternal(@Nonnull final YamlConnection connection, boolean c } else if (QueryConfig.QUERY_CONFIG_NO_OP.equals(queryConfig.getConfigName())) { // Do nothing for noop execution. continue; + } else if (QueryConfig.QUERY_CONFIG_SETUP.equals(queryConfig.getConfigName())) { + Assert.that(!queryIsRunning, "Transaction setup should not be intermingled with query results"); + executor.addSetup(Matchers.string(queryConfig.getVal(), "Transaction setup")); } else if (!QueryConfig.QUERY_CONFIG_SUPPORTED_VERSION.equals(queryConfig.getConfigName())) { if (QueryConfig.QUERY_CONFIG_ERROR.equals(queryConfig.getConfigName())) { errored = true; diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryConfig.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryConfig.java index 3d70fa16f0..386a4cb5d6 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryConfig.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryConfig.java @@ -85,6 +85,8 @@ public abstract class QueryConfig { public static final String QUERY_CONFIG_INITIAL_VERSION_AT_LEAST = "initialVersionAtLeast"; public static final String QUERY_CONFIG_INITIAL_VERSION_LESS_THAN = "initialVersionLessThan"; public static final String QUERY_CONFIG_NO_OP = "noOp"; + public static final String QUERY_CONFIG_SETUP = "setup"; + public static final String QUERY_CONFIG_SETUP_REFERENCE = "setupReference"; private static final Set RESULT_CONFIGS = ImmutableSet.of(QUERY_CONFIG_ERROR, QUERY_CONFIG_COUNT, QUERY_CONFIG_RESULT, QUERY_CONFIG_UNORDERED_RESULT); private static final Set VERSION_DEPENDENT_RESULT_CONFIGS = ImmutableSet.of(QUERY_CONFIG_INITIAL_VERSION_AT_LEAST, QUERY_CONFIG_INITIAL_VERSION_LESS_THAN); @@ -465,6 +467,16 @@ void checkResultInternal(@Nonnull String currentQuery, @Nonnull Object actual, @ }; } + private static QueryConfig getSetupConfig(final Object value, final int lineNumber, final YamlExecutionContext executionContext) { + return new QueryConfig(QUERY_CONFIG_SETUP, value, lineNumber, executionContext) { + @Override + void checkResultInternal(@Nonnull final String currentQuery, @Nonnull final Object actual, + @Nonnull final String queryDescription) throws SQLException { + Assert.failUnchecked("No results to check on a setup config"); + } + }; + } + @Nonnull public static QueryConfig getSupportedVersionConfig(Object rawVersion, final int lineNumber, final YamlExecutionContext executionContext) { final SupportedVersionCheck check = SupportedVersionCheck.parse(rawVersion, executionContext); @@ -579,8 +591,12 @@ private static QueryConfig parseConfig(String blockName, String key, Object valu return getCheckResultConfig(false, key, value, lineNumber, executionContext); } else if (QUERY_CONFIG_MAX_ROWS.equals(key)) { return getMaxRowConfig(value, lineNumber, executionContext); + } else if (QUERY_CONFIG_SETUP.equals(key)) { + return getSetupConfig(value, lineNumber, executionContext); + } else if (QUERY_CONFIG_SETUP_REFERENCE.equals(key)) { + return getSetupConfig(executionContext.getTransactionSetup(value), lineNumber, executionContext); } else { - throw Assert.failUnchecked("‼️ '%s' is not a valid configuration"); + throw Assert.failUnchecked("‼️ '" + key + "' is not a valid configuration"); } } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java index 4e5e05bb8c..9a7e63e0a2 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java @@ -24,6 +24,7 @@ import com.apple.foundationdb.relational.api.RelationalPreparedStatement; import com.apple.foundationdb.relational.api.RelationalResultSet; import com.apple.foundationdb.relational.api.RelationalResultSetMetaData; +import com.apple.foundationdb.relational.api.RelationalStatement; import com.apple.foundationdb.relational.api.exceptions.RelationalException; import com.apple.foundationdb.relational.api.metrics.RelationalMetric; import com.apple.foundationdb.relational.recordlayer.ContinuationImpl; @@ -69,6 +70,7 @@ public class QueryExecutor { */ @Nullable private final List parameters; + private ArrayList setup = new ArrayList<>(); QueryExecutor(@Nonnull String query, int lineNumber) { this(query, lineNumber, null); @@ -163,23 +165,29 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q try { if (parameters == null) { logger.debug("⏳ Executing query '{}'", this.toString()); - try (var s = connection.createStatement()) { - final var queryResult = executeStatementAndCheckCacheIfNeeded(s, false, connection, currentQuery, checkCache, maxRows); - config.checkResult(currentQuery, queryResult, this.toString(), connection); - if (queryResult instanceof RelationalResultSet) { - continuationAfter = ((RelationalResultSet) queryResult).getContinuation(); + continuationAfter = executeWithSetup(connection, () -> { + try (var s = connection.createStatement()) { + final var queryResult = executeStatementAndCheckCacheIfNeeded(s, false, connection, currentQuery, checkCache, maxRows); + config.checkResult(currentQuery, queryResult, this.toString(), connection); + if (queryResult instanceof RelationalResultSet) { + return ((RelationalResultSet) queryResult).getContinuation(); + } } - } + return null; + }); } else { logger.debug("⏳ Executing query '{}'", this.toString()); - try (var s = connection.prepareStatement(currentQuery)) { - setParametersInPreparedStatement(s); - final var queryResult = executeStatementAndCheckCacheIfNeeded(s, true, connection, currentQuery, checkCache, maxRows); - config.checkResult(currentQuery, queryResult, this.toString(), connection); - if (queryResult instanceof RelationalResultSet) { - continuationAfter = ((RelationalResultSet) queryResult).getContinuation(); + continuationAfter = executeWithSetup(connection, () -> { + try (var s = connection.prepareStatement(currentQuery)) { + setParametersInPreparedStatement(s); + final var queryResult = executeStatementAndCheckCacheIfNeeded(s, true, connection, currentQuery, checkCache, maxRows); + config.checkResult(currentQuery, queryResult, this.toString(), connection); + if (queryResult instanceof RelationalResultSet) { + return ((RelationalResultSet)queryResult).getContinuation(); + } } - } + return null; + }); } logger.debug("👍 Finished executing query '{}'", this.toString()); } catch (SQLException sqle) { @@ -188,6 +196,30 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q return continuationAfter; } + @Nullable + private Continuation executeWithSetup(final @Nonnull YamlConnection connection, + SQLSupplier execute) throws SQLException, RelationalException { + if (!setup.isEmpty()) { + return connection.executeTransactionally(singleConnection -> { + for (var setupStatement : setup) { + try { + final RelationalStatement statement = singleConnection.createStatement(); + statement.execute(setupStatement); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + try { + return execute.get(); + } catch (SQLException | RelationalException e) { + throw new RuntimeException(e); + } + }); + } else { + return execute.get(); + } + } + @Nullable private Continuation executeContinuation(@Nonnull YamlConnection connection, @Nonnull Continuation continuation, @Nonnull QueryConfig config, final @Nonnull String currentQuery, @Nullable Integer maxRows) { @@ -336,4 +368,8 @@ public String toString() { return query + " with parameters (" + String.join(", ", paramList) + ")"; } } + + public void addSetup(final String setupStatement) { + setup.add(setupStatement); + } } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java new file mode 100644 index 0000000000..4f282bcb68 --- /dev/null +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java @@ -0,0 +1,30 @@ +/* + * SQLSupplier.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors + * + * 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.apple.foundationdb.relational.yamltests.command; + +import com.apple.foundationdb.relational.api.exceptions.RelationalException; + +import java.sql.SQLException; + +@FunctionalInterface +public interface SQLSupplier { + T get() throws SQLException, RelationalException; +} diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java index 9821261295..460917cc21 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java @@ -43,6 +43,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -204,6 +205,11 @@ public SemanticVersion getInitialVersion() { return versions.get(0); } + @Override + public T executeTransactionally(final Function transactionalWork) throws SQLException { + return getCurrentConnection(true, "transactional work").executeTransactionally(transactionalWork); + } + @Override public void close() throws SQLException { logger.info("Sending operation {} to all connections", "close"); diff --git a/yaml-tests/src/test/resources/transactions-tests.yamsql b/yaml-tests/src/test/resources/transactions-tests.yamsql index 839964b0fc..8d92481793 100644 --- a/yaml-tests/src/test/resources/transactions-tests.yamsql +++ b/yaml-tests/src/test/resources/transactions-tests.yamsql @@ -40,18 +40,26 @@ options: supported_version: 4.3.5.0 --- schema_template: - create table t1(id bigint, col1 bigint, primary key(id)) + create table table_t1(id bigint, col1 bigint, primary key(id)) +--- +transaction_setups: + t1_less_than_50: create temporary function t1() on commit drop function AS SELECT * FROM table_t1 where id < 50 --- setup: # `connect` is default and defaults to 1. Value 0 has a special meaning and depicts connection to the catalog. connect: 1 steps: - - query: INSERT INTO T1 VALUES (10, 20), (30, 40), (50, 60) + - query: INSERT INTO table_T1 VALUES (10, 20), (30, 40), (50, 60) --- test_block: name: transactions-tests - preset: single_repetition_ordered tests: - - query: select * from t1 where id > 15; + - setupReference: t1_less_than_50 + - result: [{id: 30, col1: 40}] + - + - query: select * from t1 where id > 15; + - setup: create temporary function t1() on commit drop function AS SELECT * FROM table_t1 where id < 30; + - result: [] ... From aa6d8e967800e7d5d7e938103af0abc85525b793 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Mon, 7 Jul 2025 17:13:37 -0400 Subject: [PATCH 2/7] Complete work of transactional yaml tests I also added an ExternalSingleServerConfig to help myself debug, and figured it was worth keeping. --- .../yamltests/YamlTestExtension.java | 6 +- .../yamltests/command/QueryExecutor.java | 22 +++---- .../{SQLSupplier.java => SQLFunction.java} | 4 +- .../configs/ExternalSingleServerConfig.java | 64 +++++++++++++++++++ .../test/resources/transactions-tests.yamsql | 2 +- 5 files changed, 81 insertions(+), 17 deletions(-) rename yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/{SQLSupplier.java => SQLFunction.java} (90%) create mode 100644 yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java index 863ad089e5..90a89e249f 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java @@ -24,7 +24,7 @@ import com.apple.foundationdb.relational.yamltests.configs.CorrectExplainsAndMetrics; import com.apple.foundationdb.relational.yamltests.configs.CorrectMetrics; import com.apple.foundationdb.relational.yamltests.configs.EmbeddedConfig; -import com.apple.foundationdb.relational.yamltests.configs.ExternalMultiServerConfig; +import com.apple.foundationdb.relational.yamltests.configs.ExternalSingleServerConfig; import com.apple.foundationdb.relational.yamltests.configs.ForceContinuations; import com.apple.foundationdb.relational.yamltests.configs.JDBCInProcessConfig; import com.apple.foundationdb.relational.yamltests.configs.JDBCMultiServerConfig; @@ -143,8 +143,8 @@ private Stream externalServerConfigs(final boolean singleExterna // Create an ExternalServer config with two servers of the same version for each server // (with and without forced continuations) .flatMap(server -> - Stream.of(new ExternalMultiServerConfig(0, server, server), - new ForceContinuations(new ExternalMultiServerConfig(0, server, server)))); + Stream.of(new ExternalSingleServerConfig(server), + new ForceContinuations(new ExternalSingleServerConfig(server)))); } else { return servers.stream().flatMap(server -> // (4 configs for each server available) diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java index 9a7e63e0a2..177668e6a8 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java @@ -165,10 +165,10 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q try { if (parameters == null) { logger.debug("⏳ Executing query '{}'", this.toString()); - continuationAfter = executeWithSetup(connection, () -> { - try (var s = connection.createStatement()) { - final var queryResult = executeStatementAndCheckCacheIfNeeded(s, false, connection, currentQuery, checkCache, maxRows); - config.checkResult(currentQuery, queryResult, this.toString(), connection); + continuationAfter = executeWithSetup(connection, singleConnection -> { + try (var s = singleConnection.createStatement()) { + final var queryResult = executeStatementAndCheckCacheIfNeeded(s, false, singleConnection, currentQuery, checkCache, maxRows); + config.checkResult(currentQuery, queryResult, this.toString(), singleConnection); if (queryResult instanceof RelationalResultSet) { return ((RelationalResultSet) queryResult).getContinuation(); } @@ -177,11 +177,11 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q }); } else { logger.debug("⏳ Executing query '{}'", this.toString()); - continuationAfter = executeWithSetup(connection, () -> { - try (var s = connection.prepareStatement(currentQuery)) { + continuationAfter = executeWithSetup(connection, singleConnection -> { + try (var s = singleConnection.prepareStatement(currentQuery)) { setParametersInPreparedStatement(s); - final var queryResult = executeStatementAndCheckCacheIfNeeded(s, true, connection, currentQuery, checkCache, maxRows); - config.checkResult(currentQuery, queryResult, this.toString(), connection); + final var queryResult = executeStatementAndCheckCacheIfNeeded(s, true, singleConnection, currentQuery, checkCache, maxRows); + config.checkResult(currentQuery, queryResult, this.toString(), singleConnection); if (queryResult instanceof RelationalResultSet) { return ((RelationalResultSet)queryResult).getContinuation(); } @@ -198,7 +198,7 @@ private Continuation executeQuery(@Nonnull YamlConnection connection, @Nonnull Q @Nullable private Continuation executeWithSetup(final @Nonnull YamlConnection connection, - SQLSupplier execute) throws SQLException, RelationalException { + SQLFunction execute) throws SQLException, RelationalException { if (!setup.isEmpty()) { return connection.executeTransactionally(singleConnection -> { for (var setupStatement : setup) { @@ -210,13 +210,13 @@ private Continuation executeWithSetup(final @Nonnull YamlConnection connection, } } try { - return execute.get(); + return execute.apply(singleConnection); } catch (SQLException | RelationalException e) { throw new RuntimeException(e); } }); } else { - return execute.get(); + return execute.apply(connection); } } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLFunction.java similarity index 90% rename from yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java rename to yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLFunction.java index 4f282bcb68..23acf72998 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLSupplier.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/SQLFunction.java @@ -25,6 +25,6 @@ import java.sql.SQLException; @FunctionalInterface -public interface SQLSupplier { - T get() throws SQLException, RelationalException; +public interface SQLFunction { + R apply(T t) throws SQLException, RelationalException; } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java new file mode 100644 index 0000000000..d41ad8213d --- /dev/null +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java @@ -0,0 +1,64 @@ +/* + * MultiServerConfig.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors + * + * 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.apple.foundationdb.relational.yamltests.configs; + +import com.apple.foundationdb.relational.yamltests.YamlConnectionFactory; +import com.apple.foundationdb.relational.yamltests.YamlExecutionContext; +import com.apple.foundationdb.relational.yamltests.connectionfactory.ExternalServerYamlConnectionFactory; +import com.apple.foundationdb.relational.yamltests.server.ExternalServer; + +import javax.annotation.Nonnull; + +/** + * Run against multiple external servers, alternating commands that go against each. + */ +public class ExternalSingleServerConfig implements YamlTestConfig { + + private final ExternalServer server; + + public ExternalSingleServerConfig(ExternalServer server) { + this.server = server; + } + + @Override + public void beforeAll() throws Exception { + } + + @Override + public void afterAll() throws Exception { + } + + @Override + public YamlConnectionFactory createConnectionFactory() { + return new ExternalServerYamlConnectionFactory(server); + } + + @Override + public String toString() { + return "ExternalServer (" + server.getVersion() + ")"; + } + + @Override + public @Nonnull YamlExecutionContext.ContextOptions getRunnerOptions() { + return YamlExecutionContext.ContextOptions.EMPTY_OPTIONS; + } + +} diff --git a/yaml-tests/src/test/resources/transactions-tests.yamsql b/yaml-tests/src/test/resources/transactions-tests.yamsql index 8d92481793..ddd0d8b5ef 100644 --- a/yaml-tests/src/test/resources/transactions-tests.yamsql +++ b/yaml-tests/src/test/resources/transactions-tests.yamsql @@ -37,7 +37,7 @@ # whatever statements they want in whichever location. --- options: - supported_version: 4.3.5.0 + supported_version: !current_version --- schema_template: create table table_t1(id bigint, col1 bigint, primary key(id)) From 7d276ffcaf76cbb24aa14cfe4534e159912efec8 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Tue, 8 Jul 2025 12:37:22 -0400 Subject: [PATCH 3/7] Revert to calling commit, like in main --- .../foundationdb/relational/jdbc/JDBCRelationalConnection.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java b/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java index 821466294a..1fef8d7109 100644 --- a/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java +++ b/fdb-relational-jdbc/src/main/java/com/apple/foundationdb/relational/jdbc/JDBCRelationalConnection.java @@ -345,8 +345,7 @@ public void setAutoCommit(boolean autoCommit) throws SQLException { this.autoCommit = false; } else { // commit any remaining work - // TODO do we need better protection if there is uncommitted work - // does the autoCommit-ness need to be passed down + commit(); this.autoCommit = true; serverConnection.close(); serverConnection = null; From 6e3b2ff980e47b41aafdae82845c10391252eac2 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Tue, 8 Jul 2025 12:42:40 -0400 Subject: [PATCH 4/7] Don't manually commit transactional work --- .../relational/yamltests/SimpleYamlConnection.java | 11 +++++++---- .../relational/yamltests/YamlConnection.java | 5 +++-- .../yamltests/command/QueryExecutor.java | 14 +++----------- .../MultiServerConnectionFactory.java | 6 ++++-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java index b2723e597e..8f40d6bff5 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/SimpleYamlConnection.java @@ -24,8 +24,10 @@ import com.apple.foundationdb.relational.api.RelationalConnection; import com.apple.foundationdb.relational.api.RelationalPreparedStatement; import com.apple.foundationdb.relational.api.RelationalStatement; +import com.apple.foundationdb.relational.api.exceptions.RelationalException; import com.apple.foundationdb.relational.api.metrics.MetricCollector; import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection; +import com.apple.foundationdb.relational.yamltests.command.SQLFunction; import com.apple.foundationdb.relational.yamltests.server.SemanticVersion; import com.google.common.collect.Iterables; import org.junit.jupiter.api.Assumptions; @@ -35,7 +37,6 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; -import java.util.function.Function; /** * A simple version of {@link YamlConnection} for interacting with a single {@link RelationalConnection}. @@ -119,16 +120,18 @@ public SemanticVersion getInitialVersion() { } @Override - public T executeTransactionally(final Function transactionalWork) throws SQLException { + public T executeTransactionally(final SQLFunction transactionalWork) throws SQLException, RelationalException { underlying.setAutoCommit(false); T result; try { result = transactionalWork.apply(this); - underlying.commit(); - } catch (final SQLException e) { + } catch (final SQLException | RelationalException e) { underlying.rollback(); throw e; } finally { + // enabling autoCommit will commit if there is outstanding work + // It would probably be good to commit earlier, but https://github.com/FoundationDB/fdb-record-layer/pull/3477 + // causes the setAutoCommit to fail if you do that underlying.setAutoCommit(true); } return result; diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java index 15baeba5ce..e380edaacc 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlConnection.java @@ -24,15 +24,16 @@ import com.apple.foundationdb.relational.api.RelationalConnection; import com.apple.foundationdb.relational.api.RelationalPreparedStatement; import com.apple.foundationdb.relational.api.RelationalStatement; +import com.apple.foundationdb.relational.api.exceptions.RelationalException; import com.apple.foundationdb.relational.api.metrics.MetricCollector; import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection; +import com.apple.foundationdb.relational.yamltests.command.SQLFunction; import com.apple.foundationdb.relational.yamltests.server.SemanticVersion; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.sql.SQLException; import java.util.List; -import java.util.function.Function; /** * A wrapper around {@link java.sql.Connection} to support yaml tests. @@ -106,5 +107,5 @@ public interface YamlConnection extends AutoCloseable { @Nonnull SemanticVersion getInitialVersion(); - T executeTransactionally(Function transactionalWork) throws SQLException; + T executeTransactionally(SQLFunction transactionalWork) throws SQLException, RelationalException; } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java index 177668e6a8..dbeba307f7 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/QueryExecutor.java @@ -202,18 +202,10 @@ private Continuation executeWithSetup(final @Nonnull YamlConnection connection, if (!setup.isEmpty()) { return connection.executeTransactionally(singleConnection -> { for (var setupStatement : setup) { - try { - final RelationalStatement statement = singleConnection.createStatement(); - statement.execute(setupStatement); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - try { - return execute.apply(singleConnection); - } catch (SQLException | RelationalException e) { - throw new RuntimeException(e); + final RelationalStatement statement = singleConnection.createStatement(); + statement.execute(setupStatement); } + return execute.apply(singleConnection); }); } else { return execute.apply(connection); diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java index 460917cc21..02b3d382f7 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/connectionfactory/MultiServerConnectionFactory.java @@ -23,11 +23,13 @@ import com.apple.foundationdb.relational.api.Options; import com.apple.foundationdb.relational.api.RelationalPreparedStatement; import com.apple.foundationdb.relational.api.RelationalStatement; +import com.apple.foundationdb.relational.api.exceptions.RelationalException; import com.apple.foundationdb.relational.api.metrics.MetricCollector; import com.apple.foundationdb.relational.recordlayer.EmbeddedRelationalConnection; import com.apple.foundationdb.relational.util.Assert; import com.apple.foundationdb.relational.yamltests.YamlConnection; import com.apple.foundationdb.relational.yamltests.YamlConnectionFactory; +import com.apple.foundationdb.relational.yamltests.command.SQLFunction; import com.apple.foundationdb.relational.yamltests.server.SemanticVersion; import com.google.common.collect.Iterables; import org.apache.logging.log4j.LogManager; @@ -43,7 +45,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -206,7 +207,8 @@ public SemanticVersion getInitialVersion() { } @Override - public T executeTransactionally(final Function transactionalWork) throws SQLException { + public T executeTransactionally(final SQLFunction transactionalWork) + throws SQLException, RelationalException { return getCurrentConnection(true, "transactional work").executeTransactionally(transactionalWork); } From 0c051d8bca536bf3ca8dc05a1f3bd68c412856d0 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Tue, 8 Jul 2025 17:10:32 -0400 Subject: [PATCH 5/7] Remove ExternalSingleServerConfig reverting back to Multi --- .../yamltests/YamlTestExtension.java | 6 +- .../configs/ExternalMultiServerConfig.java | 3 +- .../configs/ExternalSingleServerConfig.java | 64 ------------------- 3 files changed, 5 insertions(+), 68 deletions(-) delete mode 100644 yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java index 90a89e249f..863ad089e5 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java @@ -24,7 +24,7 @@ import com.apple.foundationdb.relational.yamltests.configs.CorrectExplainsAndMetrics; import com.apple.foundationdb.relational.yamltests.configs.CorrectMetrics; import com.apple.foundationdb.relational.yamltests.configs.EmbeddedConfig; -import com.apple.foundationdb.relational.yamltests.configs.ExternalSingleServerConfig; +import com.apple.foundationdb.relational.yamltests.configs.ExternalMultiServerConfig; import com.apple.foundationdb.relational.yamltests.configs.ForceContinuations; import com.apple.foundationdb.relational.yamltests.configs.JDBCInProcessConfig; import com.apple.foundationdb.relational.yamltests.configs.JDBCMultiServerConfig; @@ -143,8 +143,8 @@ private Stream externalServerConfigs(final boolean singleExterna // Create an ExternalServer config with two servers of the same version for each server // (with and without forced continuations) .flatMap(server -> - Stream.of(new ExternalSingleServerConfig(server), - new ForceContinuations(new ExternalSingleServerConfig(server)))); + Stream.of(new ExternalMultiServerConfig(0, server, server), + new ForceContinuations(new ExternalMultiServerConfig(0, server, server)))); } else { return servers.stream().flatMap(server -> // (4 configs for each server available) diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalMultiServerConfig.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalMultiServerConfig.java index bb44ea18ac..05849cd1ee 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalMultiServerConfig.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalMultiServerConfig.java @@ -1,5 +1,5 @@ /* - * MultiServerConfig.java + * ExternalMultiServerConfig.java * * This source file is part of the FoundationDB open source project * @@ -31,6 +31,7 @@ /** * Run against multiple external servers, alternating commands that go against each. + * Notably, even if the versions are the same, you can catch issues where something is jvm specific (e.g. planHash). */ public class ExternalMultiServerConfig implements YamlTestConfig { diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java deleted file mode 100644 index d41ad8213d..0000000000 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/configs/ExternalSingleServerConfig.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * MultiServerConfig.java - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors - * - * 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.apple.foundationdb.relational.yamltests.configs; - -import com.apple.foundationdb.relational.yamltests.YamlConnectionFactory; -import com.apple.foundationdb.relational.yamltests.YamlExecutionContext; -import com.apple.foundationdb.relational.yamltests.connectionfactory.ExternalServerYamlConnectionFactory; -import com.apple.foundationdb.relational.yamltests.server.ExternalServer; - -import javax.annotation.Nonnull; - -/** - * Run against multiple external servers, alternating commands that go against each. - */ -public class ExternalSingleServerConfig implements YamlTestConfig { - - private final ExternalServer server; - - public ExternalSingleServerConfig(ExternalServer server) { - this.server = server; - } - - @Override - public void beforeAll() throws Exception { - } - - @Override - public void afterAll() throws Exception { - } - - @Override - public YamlConnectionFactory createConnectionFactory() { - return new ExternalServerYamlConnectionFactory(server); - } - - @Override - public String toString() { - return "ExternalServer (" + server.getVersion() + ")"; - } - - @Override - public @Nonnull YamlExecutionContext.ContextOptions getRunnerOptions() { - return YamlExecutionContext.ContextOptions.EMPTY_OPTIONS; - } - -} From 36c2389e737d65d539b7fb5b1e947bd0c8758585 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Tue, 8 Jul 2025 17:13:40 -0400 Subject: [PATCH 6/7] Wrap the lines for the setup --- yaml-tests/src/test/resources/transactions-tests.yamsql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/yaml-tests/src/test/resources/transactions-tests.yamsql b/yaml-tests/src/test/resources/transactions-tests.yamsql index ddd0d8b5ef..f57365dda5 100644 --- a/yaml-tests/src/test/resources/transactions-tests.yamsql +++ b/yaml-tests/src/test/resources/transactions-tests.yamsql @@ -43,7 +43,8 @@ schema_template: create table table_t1(id bigint, col1 bigint, primary key(id)) --- transaction_setups: - t1_less_than_50: create temporary function t1() on commit drop function AS SELECT * FROM table_t1 where id < 50 + t1_less_than_50: create temporary function t1() on commit drop function AS + SELECT * FROM table_t1 where id < 50 --- setup: # `connect` is default and defaults to 1. Value 0 has a special meaning and depicts connection to the catalog. @@ -60,6 +61,7 @@ test_block: - result: [{id: 30, col1: 40}] - - query: select * from t1 where id > 15; - - setup: create temporary function t1() on commit drop function AS SELECT * FROM table_t1 where id < 30; + - setup: create temporary function t1() on commit drop function AS + SELECT * FROM table_t1 where id < 30; - result: [] ... From 34ef2ce260488f0c54978d773ed8b61820530258 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Wed, 9 Jul 2025 23:18:35 -0400 Subject: [PATCH 7/7] Try to create a temporary function with intermingled tables --- yaml-tests/src/test/resources/transactions-tests.yamsql | 1 + 1 file changed, 1 insertion(+) diff --git a/yaml-tests/src/test/resources/transactions-tests.yamsql b/yaml-tests/src/test/resources/transactions-tests.yamsql index f57365dda5..dcc884c2bc 100644 --- a/yaml-tests/src/test/resources/transactions-tests.yamsql +++ b/yaml-tests/src/test/resources/transactions-tests.yamsql @@ -41,6 +41,7 @@ options: --- schema_template: create table table_t1(id bigint, col1 bigint, primary key(id)) + WITH OPTIONS(ENABLE_LONG_ROWS=true, INTERMINGLE_TABLES=true, STORE_ROW_VERSIONS=true) --- transaction_setups: t1_less_than_50: create temporary function t1() on commit drop function AS