Skip to content

Commit c9568aa

Browse files
authored
Optimize statement queries 3 (#3)
* reduced number of requests for Statement * move meta orchestration * detect prepared statement
1 parent b62d85b commit c9568aa

14 files changed

Lines changed: 825 additions & 117 deletions

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightConnection.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,12 @@ public PreparedStatement prepareStatement(
282282
final int resultSetHoldability)
283283
throws SQLException {
284284
checkOpen();
285-
return getMeta()
286-
.createPreparedStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
285+
return ArrowFlightPreparedStatement.builder(this)
286+
.withQuery(sql)
287+
.withGeneratedHandle()
288+
.withResultSetType(resultSetType)
289+
.withResultSetConcurrency(resultSetConcurrency)
290+
.withResultSetHoldability(resultSetHoldability)
291+
.build();
287292
}
288293
}

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightInfoStatement.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcFlightStreamResultSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public final class ArrowFlightJdbcFlightStreamResultSet
6767
throws SQLException {
6868
super(statement, state, signature, resultSetMetaData, timeZone, firstFrame);
6969
this.connection = (ArrowFlightConnection) statement.connection;
70-
this.flightInfo = ((ArrowFlightInfoStatement) statement).executeFlightInfoQuery();
70+
this.flightInfo = ((ArrowFlightMetaStatement) statement).executeFlightInfoQuery();
7171
}
7272

7373
/** Private constructor for fromFlightInfo. */

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightMetaImpl.java

Lines changed: 33 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,7 @@ public ArrowFlightMetaImpl(final AvaticaConnection connection) {
4848

4949
@Override
5050
public void closeStatement(final StatementHandle statementHandle) {
51-
AvaticaStatement statement = connection.statementMap.get(statementHandle.id);
52-
if (statement instanceof ArrowFlightPreparedStatement) {
53-
((ArrowFlightPreparedStatement) statement).closePreparedResources();
54-
}
51+
getMetaStatement(statementHandle).closeStatement();
5552
}
5653

5754
@Override
@@ -64,8 +61,7 @@ public ExecuteResult execute(
6461
final StatementHandle statementHandle,
6562
final List<TypedValue> typedValues,
6663
final long maxRowCount) {
67-
return getPreparedStatementInstance(statementHandle)
68-
.executeWithTypedValues(statementHandle, typedValues, maxRowCount);
64+
return getMetaStatement(statementHandle).execute(statementHandle, typedValues, maxRowCount);
6965
}
7066

7167
@Override
@@ -80,8 +76,7 @@ public ExecuteResult execute(
8076
public ExecuteBatchResult executeBatch(
8177
final StatementHandle statementHandle, final List<List<TypedValue>> parameterValuesList)
8278
throws IllegalStateException {
83-
return getPreparedStatementInstance(statementHandle)
84-
.executeBatchWithTypedValues(statementHandle, parameterValuesList);
79+
return getMetaStatement(statementHandle).executeBatch(statementHandle, parameterValuesList);
8580
}
8681

8782
@Override
@@ -96,31 +91,16 @@ public Frame fetch(
9691
String.format("%s does not use frames.", this), AvaticaConnection.HELPER.unsupported());
9792
}
9893

99-
ArrowFlightPreparedStatement createPreparedStatement(
100-
final String query,
101-
final int resultSetType,
102-
final int resultSetConcurrency,
103-
final int resultSetHoldability)
104-
throws SQLException {
105-
return ArrowFlightPreparedStatement.builder((ArrowFlightConnection) connection)
106-
.withQuery(query)
107-
.withGeneratedHandle()
108-
.withResultSetType(resultSetType)
109-
.withResultSetConcurrency(resultSetConcurrency)
110-
.withResultSetHoldability(resultSetHoldability)
111-
.build();
112-
}
113-
11494
@Override
11595
public StatementHandle prepare(
11696
final ConnectionHandle connectionHandle, final String query, final long maxRowCount) {
11797
try {
118-
return createPreparedStatement(
119-
query,
120-
ResultSet.TYPE_FORWARD_ONLY,
121-
ResultSet.CONCUR_READ_ONLY,
122-
connection.getHoldability())
123-
.handle;
98+
// This is the Avatica entry point used by Connection.prepareStatement(String).
99+
ArrowFlightPreparedStatement stmt =
100+
(ArrowFlightPreparedStatement)
101+
connection.prepareStatement(
102+
query, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
103+
return stmt.handle;
124104
} catch (SQLException e) {
125105
throw new RuntimeException(e);
126106
}
@@ -133,6 +113,7 @@ public ExecuteResult prepareAndExecute(
133113
final long maxRowCount,
134114
final PrepareCallback prepareCallback)
135115
throws NoSuchStatementException {
116+
// This is the Avatica entry point used by Statement.execute(String).
136117
return prepareAndExecute(
137118
statementHandle, query, maxRowCount, -1 /* Not used */, prepareCallback);
138119
}
@@ -146,20 +127,9 @@ public ExecuteResult prepareAndExecute(
146127
final PrepareCallback callback)
147128
throws NoSuchStatementException {
148129
try {
149-
final AvaticaStatement statement = connection.statementMap.get(handle.id);
150-
if (!(statement instanceof ArrowFlightStatement)
151-
&& !(statement instanceof ArrowFlightPreparedStatement)) {
152-
throw new IllegalStateException("Prepared statement not found: " + handle);
153-
}
154-
if (statement instanceof ArrowFlightPreparedStatement) {
155-
((ArrowFlightPreparedStatement) statement).closePreparedResources();
156-
}
157-
final ArrowFlightPreparedStatement preparedStatement =
158-
ArrowFlightPreparedStatement.builder((ArrowFlightConnection) connection)
159-
.withQuery(query)
160-
.withExistingStatement(statement)
161-
.build();
162-
return preparedStatement.prepareAndExecute(callback);
130+
// This is the Avatica entry point used by Statement.execute(String).
131+
return getMetaStatement(handle)
132+
.prepareAndExecute(query, maxRowCount, maxRowsInFirstFrame, callback);
163133
} catch (SQLTimeoutException e) {
164134
// So far AvaticaStatement(executeInternal) only handles NoSuchStatement and
165135
// Runtime
@@ -216,30 +186,37 @@ void setDefaultConnectionProperties() {
216186
.setTransactionIsolation(Connection.TRANSACTION_NONE);
217187
}
218188

219-
private ArrowFlightPreparedStatement getPreparedStatementInstance(
220-
StatementHandle statementHandle) {
189+
private ArrowFlightMetaStatement getMetaStatement(StatementHandle statementHandle) {
221190
AvaticaStatement statement = connection.statementMap.get(statementHandle.id);
222-
if (!(statement instanceof ArrowFlightPreparedStatement)) {
223-
throw new IllegalStateException("Prepared statement not found: " + statementHandle);
191+
if (statement instanceof ArrowFlightMetaStatement) {
192+
return (ArrowFlightMetaStatement) statement;
224193
}
225-
return (ArrowFlightPreparedStatement) statement;
194+
throw new IllegalStateException("Statement not found: " + statementHandle);
226195
}
227196

228-
ArrowFlightPreparedStatement getPreparedStatementInstanceOrNull(StatementHandle statementHandle) {
229-
AvaticaStatement statement = connection.statementMap.get(statementHandle.id);
230-
if (statement instanceof ArrowFlightPreparedStatement) {
231-
return (ArrowFlightPreparedStatement) statement;
232-
}
233-
return null;
197+
public static Signature buildDefaultSignature() {
198+
return buildSignature(null, StatementType.SELECT);
234199
}
235200

236-
public static Signature buildDefaultSignature() {
237-
return buildSignature(null, null, null);
201+
public static Signature buildSignature(final String sql, final StatementType type) {
202+
return buildSignature(sql, null, null, type);
238203
}
239204

240205
/** Builds an Avatica signature from Arrow result and parameter schemas. */
241206
public static Signature buildSignature(
242207
final String sql, final Schema resultSetSchema, final Schema parameterSchema) {
208+
StatementType statementType =
209+
resultSetSchema == null || resultSetSchema.getFields().isEmpty()
210+
? StatementType.IS_DML
211+
: StatementType.SELECT;
212+
return buildSignature(sql, resultSetSchema, parameterSchema, statementType);
213+
}
214+
215+
private static Signature buildSignature(
216+
final String sql,
217+
final Schema resultSetSchema,
218+
final Schema parameterSchema,
219+
final StatementType statementType) {
243220
List<ColumnMetaData> columnMetaData =
244221
resultSetSchema == null
245222
? new ArrayList<>()
@@ -248,10 +225,6 @@ public static Signature buildSignature(
248225
parameterSchema == null
249226
? new ArrayList<>()
250227
: ConvertUtils.convertArrowFieldsToAvaticaParameters(parameterSchema.getFields());
251-
StatementType statementType =
252-
resultSetSchema == null || resultSetSchema.getFields().isEmpty()
253-
? StatementType.IS_DML
254-
: StatementType.SELECT;
255228
return new Signature(
256229
columnMetaData,
257230
sql,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.arrow.driver.jdbc;
18+
19+
import java.sql.SQLException;
20+
import java.sql.Statement;
21+
import java.util.List;
22+
import org.apache.arrow.flight.FlightInfo;
23+
import org.apache.calcite.avatica.Meta.ExecuteBatchResult;
24+
import org.apache.calcite.avatica.Meta.ExecuteResult;
25+
import org.apache.calcite.avatica.Meta.PrepareCallback;
26+
import org.apache.calcite.avatica.Meta.StatementHandle;
27+
import org.apache.calcite.avatica.remote.TypedValue;
28+
29+
/** Statement capabilities used by {@link ArrowFlightMetaImpl}. */
30+
interface ArrowFlightMetaStatement extends Statement {
31+
32+
@Override
33+
ArrowFlightConnection getConnection() throws SQLException;
34+
35+
FlightInfo executeFlightInfoQuery() throws SQLException;
36+
37+
/**
38+
* Avatica routes {@link Statement#execute(String)} through Meta.prepareAndExecute(...), so plain
39+
* statements still need this hook even when they support direct executeQuery/executeUpdate paths.
40+
*/
41+
ExecuteResult prepareAndExecute(
42+
String query, long maxRowCount, int maxRowsInFirstFrame, PrepareCallback callback)
43+
throws SQLException;
44+
45+
default ExecuteResult execute(
46+
final StatementHandle statementHandle,
47+
final List<TypedValue> typedValues,
48+
final long maxRowCount) {
49+
throw new IllegalStateException(
50+
"Statement operation is not supported for handle: " + statementHandle);
51+
}
52+
53+
default ExecuteBatchResult executeBatch(
54+
final StatementHandle statementHandle, final List<List<TypedValue>> parameterValuesList) {
55+
throw new IllegalStateException(
56+
"Statement operation is not supported for handle: " + statementHandle);
57+
}
58+
59+
default void closeStatement() {}
60+
}

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatement.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
/** Arrow Flight JDBC's implementation {@link java.sql.PreparedStatement}. */
3939
public class ArrowFlightPreparedStatement extends AvaticaPreparedStatement
40-
implements ArrowFlightInfoStatement {
40+
implements ArrowFlightMetaStatement {
4141

4242
private ArrowFlightSqlClientHandler.PreparedStatement preparedStatement;
4343

@@ -80,6 +80,21 @@ ExecuteResult prepareAndExecute(final PrepareCallback callback) throws SQLExcept
8080
return new ExecuteResult(Collections.singletonList(metaResultSet));
8181
}
8282

83+
@Override
84+
public ExecuteResult prepareAndExecute(
85+
final String query,
86+
final long maxRowCount,
87+
final int maxRowsInFirstFrame,
88+
final PrepareCallback callback)
89+
throws SQLException {
90+
91+
return ArrowFlightPreparedStatement.builder(getConnection())
92+
.withQuery(query)
93+
.withExistingStatement(this)
94+
.build()
95+
.prepareAndExecute(callback);
96+
}
97+
8398
Schema getDataSetSchema() {
8499
ensurePrepared();
85100
return preparedStatement.getDataSetSchema();
@@ -143,6 +158,25 @@ ExecuteBatchResult executeBatchWithTypedValues(
143158
return new ExecuteBatchResult(updatedCounts);
144159
}
145160

161+
@Override
162+
public ExecuteResult execute(
163+
final StatementHandle statementHandle,
164+
final List<TypedValue> typedValues,
165+
final long maxRowCount) {
166+
return executeWithTypedValues(statementHandle, typedValues, maxRowCount);
167+
}
168+
169+
@Override
170+
public ExecuteBatchResult executeBatch(
171+
final StatementHandle statementHandle, final List<List<TypedValue>> parameterValuesList) {
172+
return executeBatchWithTypedValues(statementHandle, parameterValuesList);
173+
}
174+
175+
@Override
176+
public void closeStatement() {
177+
closePreparedResources();
178+
}
179+
146180
@Override
147181
public FlightInfo executeFlightInfoQuery() throws SQLException {
148182
ensurePrepared();

0 commit comments

Comments
 (0)