Skip to content

Commit 825e6d8

Browse files
committed
Support metadata DELETE in JDBC connectors
1 parent 3013849 commit 825e6d8

File tree

19 files changed

+367
-9
lines changed

19 files changed

+367
-9
lines changed

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/BaseJdbcClient.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.util.Map;
5353
import java.util.Objects;
5454
import java.util.Optional;
55+
import java.util.OptionalLong;
5556
import java.util.Set;
5657
import java.util.UUID;
5758
import java.util.function.BiFunction;
@@ -1003,6 +1004,25 @@ public Map<String, Object> getTableProperties(ConnectorSession session, JdbcTabl
10031004
return emptyMap();
10041005
}
10051006

1007+
@Override
1008+
public OptionalLong delete(ConnectorSession session, JdbcTableHandle handle)
1009+
{
1010+
checkArgument(handle.isNamedRelation(), "Unable to delete from synthetic table: %s", handle);
1011+
checkArgument(handle.getLimit().isEmpty(), "Unable to delete when limit is set: %s", handle);
1012+
checkArgument(handle.getSortOrder().isEmpty(), "Unable to delete when sort order is set: %s", handle);
1013+
try (Connection connection = connectionFactory.openConnection(session)) {
1014+
verify(connection.getAutoCommit());
1015+
QueryBuilder queryBuilder = new QueryBuilder(this);
1016+
PreparedQuery preparedQuery = queryBuilder.prepareDelete(session, connection, handle.getRequiredNamedRelation(), handle.getConstraint());
1017+
try (PreparedStatement preparedStatement = queryBuilder.prepareStatement(session, connection, preparedQuery)) {
1018+
return OptionalLong.of(preparedStatement.executeUpdate());
1019+
}
1020+
}
1021+
catch (SQLException e) {
1022+
throw new TrinoException(JDBC_ERROR, e);
1023+
}
1024+
}
1025+
10061026
protected String quoted(@Nullable String catalog, @Nullable String schema, String table)
10071027
{
10081028
StringBuilder sb = new StringBuilder();

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/CachingJdbcClient.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import java.util.Map;
4949
import java.util.Objects;
5050
import java.util.Optional;
51+
import java.util.OptionalLong;
5152
import java.util.Set;
5253
import java.util.concurrent.Callable;
5354
import java.util.concurrent.ExecutionException;
@@ -451,6 +452,14 @@ public void onDataChanged(JdbcTableHandle handle)
451452
invalidateCache(statisticsCache, key -> key.tableHandle.equals(handle));
452453
}
453454

455+
@Override
456+
public OptionalLong delete(ConnectorSession session, JdbcTableHandle handle)
457+
{
458+
OptionalLong deletedRowsCount = delegate.delete(session, handle);
459+
onDataChanged(handle.getRequiredNamedRelation().getSchemaTableName());
460+
return deletedRowsCount;
461+
}
462+
454463
private JdbcIdentityCacheKey getIdentityKey(ConnectorSession session)
455464
{
456465
return identityMapping.getRemoteUserCacheKey(JdbcIdentity.from(session));

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultJdbcMetadata.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.trino.spi.connector.ConnectorOutputTableHandle;
3131
import io.trino.spi.connector.ConnectorSession;
3232
import io.trino.spi.connector.ConnectorTableHandle;
33+
import io.trino.spi.connector.ConnectorTableLayoutHandle;
3334
import io.trino.spi.connector.ConnectorTableMetadata;
3435
import io.trino.spi.connector.ConnectorTableProperties;
3536
import io.trino.spi.connector.ConnectorTableSchema;
@@ -57,6 +58,7 @@
5758
import io.trino.spi.statistics.ComputedStatistics;
5859
import io.trino.spi.statistics.TableStatistics;
5960

61+
import java.sql.Types;
6062
import java.util.Collection;
6163
import java.util.HashMap;
6264
import java.util.List;
@@ -75,7 +77,9 @@
7577
import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isAggregationPushdownEnabled;
7678
import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isJoinPushdownEnabled;
7779
import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isTopNPushdownEnabled;
80+
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
7881
import static io.trino.spi.StandardErrorCode.PERMISSION_DENIED;
82+
import static io.trino.spi.type.BigintType.BIGINT;
7983
import static java.lang.Math.max;
8084
import static java.util.Objects.requireNonNull;
8185

@@ -660,6 +664,40 @@ public Optional<ConnectorOutputMetadata> finishInsert(ConnectorSession session,
660664
return Optional.empty();
661665
}
662666

667+
@Override
668+
public ColumnHandle getDeleteRowIdColumnHandle(ConnectorSession session, ConnectorTableHandle tableHandle)
669+
{
670+
// The column is used for row-level delete, which is not supported, but it's required during analysis anyway.
671+
return new JdbcColumnHandle(
672+
"$update_row_id",
673+
new JdbcTypeHandle(Types.BIGINT, Optional.of("bigint"), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()),
674+
BIGINT);
675+
}
676+
677+
@Override
678+
public ConnectorTableHandle beginDelete(ConnectorSession session, ConnectorTableHandle tableHandle)
679+
{
680+
throw new TrinoException(NOT_SUPPORTED, "Unsupported delete");
681+
}
682+
683+
@Override
684+
public boolean supportsMetadataDelete(ConnectorSession session, ConnectorTableHandle tableHandle, ConnectorTableLayoutHandle tableLayoutHandle)
685+
{
686+
return true;
687+
}
688+
689+
@Override
690+
public Optional<ConnectorTableHandle> applyDelete(ConnectorSession session, ConnectorTableHandle handle)
691+
{
692+
return Optional.of(handle);
693+
}
694+
695+
@Override
696+
public OptionalLong executeDelete(ConnectorSession session, ConnectorTableHandle handle)
697+
{
698+
return jdbcClient.delete(session, (JdbcTableHandle) handle);
699+
}
700+
663701
@Override
664702
public void setColumnComment(ConnectorSession session, ConnectorTableHandle table, ColumnHandle column, Optional<String> comment)
665703
{

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/ForwardingJdbcClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.List;
3535
import java.util.Map;
3636
import java.util.Optional;
37+
import java.util.OptionalLong;
3738
import java.util.Set;
3839
import java.util.function.Supplier;
3940

@@ -332,4 +333,10 @@ public Optional<TableScanRedirectApplicationResult> getTableScanRedirection(Conn
332333
{
333334
return delegate().getTableScanRedirection(session, tableHandle);
334335
}
336+
337+
@Override
338+
public OptionalLong delete(ConnectorSession session, JdbcTableHandle handle)
339+
{
340+
return delegate().delete(session, handle);
341+
}
335342
}

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.List;
3636
import java.util.Map;
3737
import java.util.Optional;
38+
import java.util.OptionalLong;
3839
import java.util.Set;
3940

4041
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
@@ -171,4 +172,6 @@ default Optional<TableScanRedirectApplicationResult> getTableScanRedirection(Con
171172
{
172173
return Optional.empty();
173174
}
175+
176+
OptionalLong delete(ConnectorSession session, JdbcTableHandle handle);
174177
}

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/QueryBuilder.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ protected static String formatJoinType(JoinType joinType)
158158
throw new IllegalStateException("Unsupported join type: " + joinType);
159159
}
160160

161+
public PreparedQuery prepareDelete(
162+
ConnectorSession session,
163+
Connection connection,
164+
JdbcNamedRelationHandle baseRelation,
165+
TupleDomain<ColumnHandle> tupleDomain)
166+
{
167+
String sql = "DELETE FROM " + getRelation(baseRelation.getRemoteTableName());
168+
169+
ImmutableList.Builder<QueryParameter> accumulator = ImmutableList.builder();
170+
171+
List<String> clauses = toConjuncts(session, connection, tupleDomain, accumulator::add);
172+
if (!clauses.isEmpty()) {
173+
sql += " WHERE " + Joiner.on(" AND ").join(clauses);
174+
}
175+
return new PreparedQuery(sql, accumulator.build());
176+
}
177+
161178
public PreparedStatement prepareStatement(
162179
ConnectorSession session,
163180
Connection connection,

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/jmx/JdbcClientStats.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public final class JdbcClientStats
5252
private final JdbcApiStats toWriteMapping = new JdbcApiStats();
5353
private final JdbcApiStats implementAggregation = new JdbcApiStats();
5454
private final JdbcApiStats getTableScanRedirection = new JdbcApiStats();
55+
private final JdbcApiStats delete = new JdbcApiStats();
5556

5657
@Managed
5758
@Nested
@@ -290,4 +291,11 @@ public JdbcApiStats getGetTableScanRedirection()
290291
{
291292
return getTableScanRedirection;
292293
}
294+
295+
@Managed
296+
@Nested
297+
public JdbcApiStats getDelete()
298+
{
299+
return delete;
300+
}
293301
}

plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/jmx/StatisticsAwareJdbcClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import java.util.List;
5151
import java.util.Map;
5252
import java.util.Optional;
53+
import java.util.OptionalLong;
5354
import java.util.Set;
5455

5556
import static java.util.Objects.requireNonNull;
@@ -351,4 +352,10 @@ public Optional<TableScanRedirectApplicationResult> getTableScanRedirection(Conn
351352
{
352353
return stats.getGetTableScanRedirection().wrap(() -> delegate().getTableScanRedirection(session, tableHandle));
353354
}
355+
356+
@Override
357+
public OptionalLong delete(ConnectorSession session, JdbcTableHandle handle)
358+
{
359+
return stats.getDelete().wrap(() -> delegate().delete(session, handle));
360+
}
354361
}

plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorSmokeTest.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@
1414
package io.trino.plugin.jdbc;
1515

1616
import io.trino.testing.BaseConnectorSmokeTest;
17+
import io.trino.testing.TestingConnectorBehavior;
1718

1819
public abstract class BaseJdbcConnectorSmokeTest
19-
extends BaseConnectorSmokeTest {}
20+
extends BaseConnectorSmokeTest
21+
{
22+
@Override
23+
protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
24+
{
25+
switch (connectorBehavior) {
26+
case SUPPORTS_DELETE:
27+
return true;
28+
29+
default:
30+
return super.hasBehavior(connectorBehavior);
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)