diff --git a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java index 59e9c9d75f5e..794f2dea0976 100644 --- a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java +++ b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java @@ -1861,13 +1861,13 @@ public void testUpdateWithPredicates() public void testConstantUpdateWithVarcharEqualityPredicates() { skipTestUnless(hasBehavior(SUPPORTS_CREATE_TABLE) && hasBehavior(SUPPORTS_UPDATE)); - try (TestTable table = new TestTable(getQueryRunner()::execute, "test_update_varchar", "(col1 INT, col2 varchar(1))", ImmutableList.of("1, 'a'", "2, 'A'"))) { - if (!hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY)) { + try (TestTable table = createTestTableForWrites("test_update_varchar", "(col1 INT, col2 varchar(1), pk INT)", ImmutableList.of("1, 'a', 1", "2, 'A', 2"), "pk")) { + if (!hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY) && !hasBehavior(SUPPORTS_ROW_LEVEL_UPDATE)) { assertQueryFails("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 = 'A'", MODIFYING_ROWS_MESSAGE); return; } assertUpdate("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 = 'A'", 1); - assertQuery("SELECT * FROM " + table.getName(), "VALUES (1, 'a'), (20, 'A')"); + assertQuery("SELECT * FROM " + table.getName(), "VALUES (1, 'a', 1), (20, 'A', 2)"); } } @@ -1875,14 +1875,14 @@ public void testConstantUpdateWithVarcharEqualityPredicates() public void testConstantUpdateWithVarcharInequalityPredicates() { skipTestUnless(hasBehavior(SUPPORTS_CREATE_TABLE) && hasBehavior(SUPPORTS_UPDATE)); - try (TestTable table = createTestTableForWrites("test_update_varchar", "(col1 INT, col2 varchar(1))", ImmutableList.of("1, 'a'", "2, 'A'"), "col2")) { + try (TestTable table = createTestTableForWrites("test_update_varchar", "(col1 INT, col2 varchar(1), pk INT)", ImmutableList.of("1, 'a', 1", "2, 'A', 2"), "pk")) { if (!hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY) && !hasBehavior(SUPPORTS_ROW_LEVEL_UPDATE)) { assertQueryFails("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 != 'A'", MODIFYING_ROWS_MESSAGE); return; } assertUpdate("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 != 'A'", 1); - assertQuery("SELECT * FROM " + table.getName(), "VALUES (20, 'a'), (2, 'A')"); + assertQuery("SELECT * FROM " + table.getName(), "VALUES (20, 'a', 1), (2, 'A', 2)"); } } @@ -1890,7 +1890,7 @@ public void testConstantUpdateWithVarcharInequalityPredicates() public void testConstantUpdateWithVarcharGreaterAndLowerPredicate() { skipTestUnless(hasBehavior(SUPPORTS_CREATE_TABLE) && hasBehavior(SUPPORTS_UPDATE)); - try (TestTable table = createTestTableForWrites("test_update_varchar", "(col1 INT, col2 varchar(1))", ImmutableList.of("1, 'a'", "2, 'A'"), "col2")) { + try (TestTable table = createTestTableForWrites("test_update_varchar", "(col1 INT, col2 varchar(1), pk INT)", ImmutableList.of("1, 'a', 1", "2, 'A', 2"), "pk")) { if (!hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY) && !hasBehavior(SUPPORTS_ROW_LEVEL_UPDATE)) { assertQueryFails("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 > 'A'", MODIFYING_ROWS_MESSAGE); assertQueryFails("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 < 'A'", MODIFYING_ROWS_MESSAGE); @@ -1898,10 +1898,10 @@ public void testConstantUpdateWithVarcharGreaterAndLowerPredicate() } assertUpdate("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 > 'A'", 1); - assertQuery("SELECT * FROM " + table.getName(), "VALUES (20, 'a'), (2, 'A')"); + assertQuery("SELECT * FROM " + table.getName(), "VALUES (20, 'a', 1), (2, 'A', 2)"); assertUpdate("UPDATE " + table.getName() + " SET col1 = 20 WHERE col2 < 'a'", 1); - assertQuery("SELECT * FROM " + table.getName(), "VALUES (20, 'a'), (20, 'A')"); + assertQuery("SELECT * FROM " + table.getName(), "VALUES (20, 'a', 1), (20, 'A', 2)"); } } @@ -1927,14 +1927,14 @@ public void testDeleteWithVarcharEqualityPredicate() { skipTestUnless(hasBehavior(SUPPORTS_CREATE_TABLE) && hasBehavior(SUPPORTS_ROW_LEVEL_DELETE)); // TODO (https://github.com/trinodb/trino/issues/5901) Use longer table name once Oracle version is updated - try (TestTable table = new TestTable(getQueryRunner()::execute, "test_delete_varchar", "(col varchar(1))", ImmutableList.of("'a'", "'A'", "null"))) { - if (!hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY)) { + try (TestTable table = createTestTableForWrites( "test_delete_varchar", "(col varchar(1), pk INT)", ImmutableList.of("'a', 1", "'A', 2", "null, 3"), "pk")) { + if (!hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY) && !hasBehavior(SUPPORTS_ROW_LEVEL_UPDATE)) { assertQueryFails("DELETE FROM " + table.getName() + " WHERE col = 'A'", MODIFYING_ROWS_MESSAGE); return; } assertUpdate("DELETE FROM " + table.getName() + " WHERE col = 'A'", 1); - assertQuery("SELECT * FROM " + table.getName(), "VALUES 'a', null"); + assertQuery("SELECT col FROM " + table.getName(), "VALUES 'a', null"); } } diff --git a/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java b/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java index 2dc971ec3e09..ec9b65310eec 100644 --- a/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java +++ b/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java @@ -111,9 +111,11 @@ import java.time.OffsetDateTime; import java.util.AbstractMap.SimpleEntry; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.BiFunction; import java.util.stream.Stream; @@ -975,6 +977,12 @@ public boolean isLimitGuaranteed(ConnectorSession session) return true; } + @Override + public boolean supportsMerge() + { + return true; + } + @Override public boolean supportsTopN(ConnectorSession session, JdbcTableHandle handle, List sortOrder) { @@ -1159,6 +1167,50 @@ private TableStatistics readTableStatistics(ConnectorSession session, JdbcTableH } } + @Override + public List getPrimaryKeys(ConnectorSession session, RemoteTableName remoteTableName) + { + SchemaTableName tableName = new SchemaTableName(remoteTableName.getCatalogName().orElse(null), remoteTableName.getTableName()); + List columns = getColumns(session, tableName, remoteTableName); + try (Connection connection = connectionFactory.openConnection(session)) { + DatabaseMetaData metaData = connection.getMetaData(); + + ResultSet primaryKeys = metaData.getPrimaryKeys(remoteTableName.getCatalogName().orElse(null), remoteTableName.getSchemaName().orElse(null), remoteTableName.getTableName()); + + Set primaryKeyNames = new HashSet<>(); + while (primaryKeys.next()) { + String columnName = primaryKeys.getString("COLUMN_NAME"); + primaryKeyNames.add(columnName); + } + if (primaryKeyNames.isEmpty()) { + return ImmutableList.of(); + } + ImmutableList.Builder primaryKeysBuilder = ImmutableList.builder(); + for (JdbcColumnHandle columnHandle : columns) { + String name = columnHandle.getColumnName(); + if (!primaryKeyNames.contains(name)) { + continue; + } + JdbcTypeHandle handle = columnHandle.getJdbcTypeHandle(); + CaseSensitivity caseSensitivity = handle.caseSensitivity().orElse(CASE_INSENSITIVE); + if (caseSensitivity == CASE_INSENSITIVE) { + primaryKeysBuilder.add(new JdbcColumnHandle( + name, + // make sure the primary keys that are varchar/char relate types can be pushdown + new JdbcTypeHandle(handle.jdbcType(), handle.jdbcTypeName(), handle.columnSize(), handle.decimalDigits(), handle.arrayDimensions(), Optional.of(CASE_SENSITIVE)), + columnHandle.getColumnType())); + } + else { + primaryKeysBuilder.add(columnHandle); + } + } + return primaryKeysBuilder.build(); + } + catch (SQLException e) { + throw new TrinoException(JDBC_ERROR, e); + } + } + private static Optional getColumnHistogram(Map columnHistograms, String columnName) { return Optional.ofNullable(columnHistograms.get(columnName)) diff --git a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java index 31e3801153fb..51dc6647d677 100644 --- a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java +++ b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java @@ -30,15 +30,19 @@ import java.sql.ResultSet; import java.time.LocalDate; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.OptionalInt; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static com.google.common.base.Strings.nullToEmpty; -import static io.trino.spi.connector.ConnectorMetadata.MODIFYING_ROWS_MESSAGE; +import static io.trino.plugin.jdbc.JdbcWriteSessionProperties.NON_TRANSACTIONAL_MERGE; import static io.trino.spi.type.VarcharType.VARCHAR; import static io.trino.sql.planner.assertions.PlanMatchPattern.node; import static io.trino.sql.planner.assertions.PlanMatchPattern.tableScan; import static io.trino.testing.MaterializedResult.resultBuilder; +import static io.trino.testing.TestingNames.randomNameSuffix; import static io.trino.testing.TestingSession.testSessionBuilder; import static java.lang.String.format; import static java.util.stream.Collectors.joining; @@ -56,7 +60,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) { return switch (connectorBehavior) { case SUPPORTS_AGGREGATION_PUSHDOWN, - SUPPORTS_JOIN_PUSHDOWN -> true; + SUPPORTS_JOIN_PUSHDOWN, + SUPPORTS_MERGE, + SUPPORTS_ROW_LEVEL_UPDATE -> true; case SUPPORTS_ADD_COLUMN_WITH_COMMENT, SUPPORTS_AGGREGATION_PUSHDOWN_CORRELATION, SUPPORTS_AGGREGATION_PUSHDOWN_COUNT_DISTINCT, @@ -79,6 +85,32 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) }; } + @Override + protected Session getSession() + { + Session session = super.getSession(); + return Session.builder(session) + .setCatalogSessionProperty(session.getCatalog().orElseThrow(), NON_TRANSACTIONAL_MERGE, "true") + .build(); + } + + @Test + public void testMergeTargetWithNoPrimaryKeys() + { + String tableName = "test_merge_target_no_pks_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + tableName + " (a int, b int)"); + assertUpdate("INSERT INTO " + tableName + " VALUES(1, 1), (2, 2)", 2); + + assertQueryFails(format("DELETE FROM %s WHERE a IS NOT NULL AND abs(a + b) > 10", tableName), "The connector can not perform merge on the target table without primary keys"); + assertQueryFails(format("UPDATE %s SET a = a+b WHERE a IS NOT NULL AND (a + b) > 10", tableName), "The connector can not perform merge on the target table without primary keys"); + assertQueryFails(format("MERGE INTO %s t USING (VALUES (3, 3)) AS s(x, y) " + + " ON t.a = s.x " + + " WHEN MATCHED THEN UPDATE SET b = y " + + " WHEN NOT MATCHED THEN INSERT (a, b) VALUES (s.x, s.y) ", tableName), "The connector can not perform merge on the target table without primary keys"); + + assertUpdate("DROP TABLE " + tableName); + } + @Override protected TestTable createTableWithDefaultColumns() { @@ -181,14 +213,6 @@ public void testShowCreateTable() ")"); } - @Test - @Override - public void testDeleteWithLike() - { - assertThatThrownBy(super::testDeleteWithLike) - .hasStackTraceContaining("TrinoException: " + MODIFYING_ROWS_MESSAGE); - } - @Test public void testViews() { @@ -628,4 +652,45 @@ public void verifyMySqlJdbcDriverNegativeDateHandling() } } } + + @Override + protected void createTableForWrites(String createTable, String tableName, Optional primaryKey, OptionalInt updateCount) + { + super.createTableForWrites(createTable, tableName, primaryKey, updateCount); + primaryKey.ifPresent(key -> addPrimaryKey(createTable, tableName, key)); + } + + private void addPrimaryKey(String createTable, String tableName, String primaryKey) + { + Matcher matcher = Pattern.compile("CREATE TABLE .* \\(.*\\b" + primaryKey + "\\b\\s+([a-zA-Z0-9()]+).*", Pattern.CASE_INSENSITIVE).matcher(createTable); + if (matcher.matches()) { + String type = matcher.group(1).toLowerCase(Locale.ENGLISH); + if (type.contains("varchar") || type.contains("char")) { + // Mysql requires the primary keys must hava a fixed length, here use the 255 length that is just long enough for the test + onRemoteDatabase().execute(format("ALTER TABLE %s ADD PRIMARY KEY (%s(255))", tableName, primaryKey)); + return; + } + } + + // ctas or the type is not varchar/char + onRemoteDatabase().execute(format("ALTER TABLE %s ADD PRIMARY KEY (%s)", tableName, primaryKey)); + } + + @Override + protected TestTable createTestTableForWrites(String namePrefix, String tableDefinition, String primaryKey) + { + TestTable testTable = super.createTestTableForWrites(namePrefix, tableDefinition, primaryKey); + String tableName = testTable.getName(); + onRemoteDatabase().execute(format("ALTER TABLE %s ADD PRIMARY KEY (%s)", tableName, primaryKey)); + return testTable; + } + + @Override + protected TestTable createTestTableForWrites(String namePrefix, String tableDefinition, List rowsToInsert, String primaryKey) + { + TestTable testTable = super.createTestTableForWrites(namePrefix, tableDefinition, rowsToInsert, primaryKey); + String tableName = testTable.getName(); + onRemoteDatabase().execute(format("ALTER TABLE %s ADD PRIMARY KEY (%s)", tableName, primaryKey)); + return testTable; + } } diff --git a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlFailureRecoveryTest.java b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlFailureRecoveryTest.java index 1b474e83f11c..9423041b4f24 100644 --- a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlFailureRecoveryTest.java +++ b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlFailureRecoveryTest.java @@ -15,6 +15,7 @@ import com.google.common.collect.ImmutableMap; import com.google.inject.Module; +import io.trino.Session; import io.trino.operator.RetryPolicy; import io.trino.plugin.exchange.filesystem.FileSystemExchangePlugin; import io.trino.plugin.jdbc.BaseJdbcFailureRecoveryTest; @@ -32,6 +33,8 @@ public abstract class BaseMySqlFailureRecoveryTest extends BaseJdbcFailureRecoveryTest { + private TestingMySqlServer mySqlServer; + public BaseMySqlFailureRecoveryTest(RetryPolicy retryPolicy) { super(retryPolicy); @@ -45,7 +48,8 @@ protected QueryRunner createQueryRunner( Module failureInjectionModule) throws Exception { - return MySqlQueryRunner.builder(closeAfterClass(new TestingMySqlServer())) + this.mySqlServer = new TestingMySqlServer(); + return MySqlQueryRunner.builder(closeAfterClass(mySqlServer)) .setExtraProperties(configProperties) .setCoordinatorProperties(coordinatorProperties) .setAdditionalSetup(runner -> { @@ -58,6 +62,13 @@ protected QueryRunner createQueryRunner( .build(); } + @Test + @Override + protected void testDeleteWithSubquery() + { + assertThatThrownBy(super::testDeleteWithSubquery).hasMessageContaining("Non-transactional MERGE is disabled"); + } + @Test @Override protected void testUpdateWithSubquery() @@ -66,6 +77,13 @@ protected void testUpdateWithSubquery() abort("skipped"); } + @Test + @Override + protected void testMerge() + { + assertThatThrownBy(super::testMerge).hasMessageContaining("Non-transactional MERGE is disabled"); + } + @Test @Override protected void testUpdate() @@ -81,4 +99,10 @@ protected void testUpdate() .withCleanupQuery(cleanupQuery) .isCoordinatorOnly(); } + + @Override + protected void addPrimaryKeyForMergeTarget(Session session, String tableName, String primaryKey) + { + mySqlServer.execute("ALTER TABLE %s ADD PRIMARY KEY (%s)".formatted(tableName, primaryKey)); + } } diff --git a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/TestMySqlGlobalTransactionMyConnectorSmokeTest.java b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/TestMySqlGlobalTransactionMyConnectorSmokeTest.java index c2f01c8921de..3c7761e5a903 100644 --- a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/TestMySqlGlobalTransactionMyConnectorSmokeTest.java +++ b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/TestMySqlGlobalTransactionMyConnectorSmokeTest.java @@ -13,9 +13,14 @@ */ package io.trino.plugin.mysql; +import io.trino.Session; import io.trino.plugin.jdbc.BaseJdbcConnectorSmokeTest; import io.trino.testing.QueryRunner; import io.trino.testing.TestingConnectorBehavior; +import io.trino.testing.sql.TestTable; + +import static io.trino.plugin.jdbc.JdbcWriteSessionProperties.NON_TRANSACTIONAL_MERGE; +import static java.lang.String.format; public class TestMySqlGlobalTransactionMyConnectorSmokeTest extends BaseJdbcConnectorSmokeTest @@ -32,6 +37,15 @@ protected QueryRunner createQueryRunner() .build(); } + @Override + protected Session getSession() + { + Session session = super.getSession(); + return Session.builder(session) + .setCatalogSessionProperty(session.getCatalog().orElseThrow(), NON_TRANSACTIONAL_MERGE, "true") + .build(); + } + @Override protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) { @@ -39,8 +53,21 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_RENAME_SCHEMA: return false; + case SUPPORTS_ROW_LEVEL_UPDATE: + case SUPPORTS_MERGE: + return true; + default: return super.hasBehavior(connectorBehavior); } } + + @Override + protected TestTable createTestTableForWrites(String tablePrefix) + { + TestTable table = super.createTestTableForWrites(tablePrefix); + String tableName = table.getName(); + mySqlServer.execute(format("ALTER TABLE %s ADD PRIMARY KEY (a)", tableName)); + return table; + } } diff --git a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorSmokeTest.java b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorSmokeTest.java index b491e6ab375c..f1ada9ffb3e7 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorSmokeTest.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorSmokeTest.java @@ -152,6 +152,11 @@ public void testCreateTable() assertUpdate("DROP TABLE " + tableName); } + protected TestTable createTestTableForWrites(String tablePrefix) + { + return new TestTable(getQueryRunner()::execute, tablePrefix, getCreateTableDefaultDefinition()); + } + protected String getCreateTableDefaultDefinition() { return "(a bigint, b double)"; @@ -318,7 +323,7 @@ public void testRowLevelUpdate() throw new AssertionError("Cannot test UPDATE without INSERT"); } - try (TestTable table = new TestTable(getQueryRunner()::execute, "test_update_", getCreateTableDefaultDefinition())) { + try (TestTable table = createTestTableForWrites("test_update_")) { assertUpdate("INSERT INTO " + table.getName() + " (a, b) SELECT regionkey, regionkey * 2.5 FROM region", "SELECT count(*) FROM region"); assertThat(query("SELECT a, b FROM " + table.getName())) .matches(expectedValues("(0, 0.0), (1, 2.5), (2, 5.0), (3, 7.5), (4, 10.0)")); @@ -344,7 +349,7 @@ public void testMerge() throw new AssertionError("Cannot test MERGE without INSERT"); } - try (TestTable table = new TestTable(getQueryRunner()::execute, "test_merge_", getCreateTableDefaultDefinition())) { + try (TestTable table = createTestTableForWrites("test_merge_")) { assertUpdate("INSERT INTO " + table.getName() + " (a, b) SELECT regionkey, regionkey * 2.5 FROM region", "SELECT count(*) FROM region"); assertThat(query("SELECT a, b FROM " + table.getName())) .matches(expectedValues("(0, 0.0), (1, 2.5), (2, 5.0), (3, 7.5), (4, 10.0)")); diff --git a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java index e53c808fa9bf..11b335852685 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java @@ -4776,7 +4776,7 @@ public void testDeleteWithLike() { skipTestUnless(hasBehavior(SUPPORTS_DELETE)); - try (TestTable table = new TestTable(getQueryRunner()::execute, "test_with_like_", "AS SELECT * FROM nation")) { + try (TestTable table = createTestTableForWrites("test_with_like_", "AS SELECT * FROM nation", "nationkey")) { assertUpdate("DELETE FROM " + table.getName() + " WHERE name LIKE '%a%'", "VALUES 0"); assertUpdate("DELETE FROM " + table.getName() + " WHERE name LIKE '%A%'", "SELECT count(*) FROM nation WHERE name LIKE '%A%'"); } @@ -5023,7 +5023,7 @@ public void testRowLevelUpdate() return; } - try (TestTable table = createTestTableForWrites("test_update", "AS TABLE tpch.tiny.nation", "name,regionkey")) { + try (TestTable table = createTestTableForWrites("test_update", "AS TABLE tpch.tiny.nation", "nationkey,regionkey")) { String tableName = table.getName(); assertUpdate("UPDATE " + tableName + " SET nationkey = 100 + nationkey WHERE regionkey = 2", 5); assertThat(query("SELECT * FROM " + tableName))