Skip to content

Commit 6622b00

Browse files
committed
- Added new method in NoSQLHandle: queryIterable() to return the results of a query in an iterable/iterator format. The returned QueryIterableResult should be used in a try-with-resources statement to ensure proper closing of resources.
- Updated NoSQLHandle interface to extend AutoClosable. - Updated examples to show new usage of the queryIterable() method and auto-closable handler. - Fixed a bug in test infrastructure InternalsTest when other tables are present.
1 parent 2d72d77 commit 6622b00

File tree

18 files changed

+466
-85
lines changed

18 files changed

+466
-85
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
All notable changes to this project will be documented in this file.
33
The format is based on [Keep a Changelog](http://keepachangelog.com/).
44

5+
## Unreleased
6+
7+
### Added
8+
- added new method in NoSQLHandle queryIterable to return the results of a
9+
query in an iterable/iterator format. The returned QueryIterableResult should
10+
be used in a try-with-resources statement to ensure proper closing of
11+
resources.
12+
- updated NoSQLHandle interface to extend AutoClosable
13+
514
## [5.3.2] 2022-03-21
615

716
### Added

README.md

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ is required if using Instance Principal or Resource Principal authorization.
184184
*/
185185
186186
import java.io.IOException;
187+
import java.util.ArrayList;
187188
188189
import oracle.nosql.driver.AuthorizationProvider;
189190
import oracle.nosql.driver.NoSQLHandle;
@@ -193,8 +194,11 @@ import oracle.nosql.driver.iam.SignatureProvider;
193194
import oracle.nosql.driver.kv.StoreAccessTokenProvider;
194195
import oracle.nosql.driver.ops.GetRequest;
195196
import oracle.nosql.driver.ops.GetResult;
197+
import oracle.nosql.driver.ops.QueryRequest;
198+
import oracle.nosql.driver.ops.QueryResult;
196199
import oracle.nosql.driver.ops.PutRequest;
197200
import oracle.nosql.driver.ops.PutResult;
201+
import oracle.nosql.driver.ops.QueryIterableResult;
198202
import oracle.nosql.driver.ops.Request;
199203
import oracle.nosql.driver.ops.TableLimits;
200204
import oracle.nosql.driver.ops.TableRequest;
@@ -206,6 +210,8 @@ import oracle.nosql.driver.values.MapValue;
206210
* - create a table
207211
* - put a row
208212
* - get a row
213+
* - run a query using iterable/iterator
214+
* - run a query using partial results
209215
* - drop the table
210216
*
211217
* See the examples for more interesting operations. This quickstart is
@@ -378,8 +384,7 @@ public class Quickstart {
378384
* Configure and get a NoSQLHandle. All service specific configuration
379385
* is handled here
380386
*/
381-
NoSQLHandle handle = qs.getHandle();
382-
try {
387+
try (NoSQLHandle handle = qs.getHandle()) {
383388
384389
/*
385390
* Create a simple table with an integer key, string name and
@@ -427,11 +432,29 @@ public class Quickstart {
427432
System.out.println("Got row, result " + getRes);
428433
429434
/*
430-
* Perform a query
435+
* Perform a query using iterable and iterator
431436
*/
432437
QueryRequest queryRequest = new QueryRequest()
433438
.setStatement("select * from " + tableName);
434439
440+
/*
441+
* To ensure the query resources are closed properly, use
442+
* try-with-resources statement.
443+
*/
444+
try (QueryIterableResult results =
445+
handle.queryIterable(queryRequest)) {
446+
System.out.println("Query results:");
447+
for (MapValue res : results) {
448+
System.out.println("\t" + res);
449+
}
450+
}
451+
452+
/*
453+
* Perform a query using partial results
454+
*/
455+
queryRequest = new QueryRequest()
456+
.setStatement("select * from " + tableName);
457+
435458
/*
436459
* Because a query can return partial results execution must occur
437460
* in a loop, accumulating or processing results
@@ -441,7 +464,7 @@ public class Quickstart {
441464
QueryResult queryResult = handle.query(queryRequest);
442465
results.addAll(queryResult.getResults());
443466
} while (!queryRequest.isDone());
444-
System.out.println("Query results:");
467+
System.out.println("Query results again:");
445468
for (MapValue res : results) {
446469
System.out.println("\t" + res);
447470
}
@@ -456,9 +479,6 @@ public class Quickstart {
456479
20000,
457480
1000);
458481
System.out.println("Dropped table " + tableName + ", done...");
459-
} finally {
460-
/* Shutdown handle so the process can exit. */
461-
handle.close();
462482
}
463483
}
464484
}
@@ -468,7 +488,8 @@ public class Quickstart {
468488

469489
Several example programs are provided in the examples directory to
470490
illustrate the API. They can be found in the release download from GitHub or
471-
directly in [GitHub NoSQL Examples](https://github.com/oracle/nosql-java-sdk/tree/master/examples). These examples can be run against the Oracle NoSQL
491+
directly in [GitHub NoSQL Examples](https://github.com/oracle/nosql-java-sdk/tree/main/examples). These examples can be run
492+
against the Oracle NoSQL
472493
Database, the NoSQL Database Cloud Service or an instance of the Oracle
473494
NoSQL Cloud Simulator. The code that differentiates among the configurations
474495
is in the file Common.java and can be examined to understand the differences.

driver/src/main/java/oracle/nosql/driver/NoSQLHandle.java

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
package oracle.nosql.driver;
99

10-
import oracle.nosql.driver.ops.SystemRequest;
11-
import oracle.nosql.driver.ops.SystemResult;
12-
import oracle.nosql.driver.ops.SystemStatusRequest;
1310
import oracle.nosql.driver.ops.DeleteRequest;
1411
import oracle.nosql.driver.ops.DeleteResult;
1512
import oracle.nosql.driver.ops.GetIndexesRequest;
@@ -26,10 +23,14 @@
2623
import oracle.nosql.driver.ops.PutRequest;
2724
import oracle.nosql.driver.ops.PutRequest.Option;
2825
import oracle.nosql.driver.ops.PutResult;
26+
import oracle.nosql.driver.ops.QueryIterableResult;
2927
import oracle.nosql.driver.ops.QueryRequest;
3028
import oracle.nosql.driver.ops.QueryResult;
3129
import oracle.nosql.driver.ops.Request;
3230
import oracle.nosql.driver.ops.Result;
31+
import oracle.nosql.driver.ops.SystemRequest;
32+
import oracle.nosql.driver.ops.SystemResult;
33+
import oracle.nosql.driver.ops.SystemStatusRequest;
3334
import oracle.nosql.driver.ops.TableRequest;
3435
import oracle.nosql.driver.ops.TableResult;
3536
import oracle.nosql.driver.ops.TableUsageRequest;
@@ -116,7 +117,7 @@
116117
* threads.
117118
* </p>
118119
*/
119-
public interface NoSQLHandle {
120+
public interface NoSQLHandle extends AutoCloseable {
120121

121122
/**
122123
* Deletes a row from a table. The row is identified using a primary key
@@ -311,6 +312,54 @@ public interface NoSQLHandle {
311312
*/
312313
QueryResult query(QueryRequest request);
313314

315+
/**
316+
* Queries a table based on the query statement specified in the
317+
* {@link QueryRequest} while returning an iterable result.
318+
*
319+
* Queries that include a full shard key will execute much more efficiently
320+
* than more distributed queries that must go to multiple shards.
321+
* <p>
322+
* Remote calls, including preparation of a query statement, will not
323+
* occur until the iteration starts. This means that errors such as an
324+
* invalid statement or network issue will be thrown from the iterator
325+
* and not this method.
326+
* <p>
327+
* Table- and system-style queries such as "CREATE TABLE ..." or "DROP TABLE .."
328+
* are not supported by this interfaces. Those operations must be performed using
329+
* {@link #tableRequest} or {@link #systemRequest} as appropriate.
330+
* <p>
331+
* The results are returned through an iterator, if connected to the
332+
* cloud, the SDK uses the read/write rate limits set in the
333+
* NoSQLHandleConfig or they can be overwritten using the
334+
* {@link Request#setReadRateLimiter(RateLimiter)} and
335+
* {@link Request#setWriteRateLimiter(RateLimiter)}.
336+
* <p>
337+
* Note: Since iterators might use resources until they reach the end, it
338+
* is necessary to close the QueryIterableResult or use the
339+
* try-with-resources statement:
340+
* <p><pre>
341+
* QueryRequest qreq = new QueryRequest()
342+
* .setStatement("select * from MyTable");
343+
*
344+
* try (QueryIterableResult qir = handle.queryIterable(qreq)) {
345+
* for( MapValue row : qir) {
346+
* // do something with row
347+
* }
348+
* }
349+
* </pre>
350+
*
351+
* @param request the input parameters for the operation
352+
*
353+
* @return the iterable result of the operation
354+
*
355+
* @throws IllegalArgumentException if any of the parameters are invalid or
356+
* required parameters are missing
357+
*
358+
* @throws NoSQLException if the operation cannot be performed for any other
359+
* reason
360+
*/
361+
QueryIterableResult queryIterable(QueryRequest request);
362+
314363
/**
315364
* Prepares a query for execution and reuse. See {@link #query} for general
316365
* information and restrictions. It is recommended that prepared queries
@@ -374,9 +423,9 @@ public interface NoSQLHandle {
374423
* @throws NoSQLException if the operation cannot be performed for
375424
* any other reason
376425
*/
377-
public TableResult doTableRequest(TableRequest request,
378-
int timeoutMs,
379-
int pollIntervalMs);
426+
TableResult doTableRequest(TableRequest request,
427+
int timeoutMs,
428+
int pollIntervalMs);
380429

381430
/**
382431
* On-premise only.
@@ -567,9 +616,9 @@ public TableResult doTableRequest(TableRequest request,
567616
* @throws NoSQLException if the operation cannot be performed for
568617
* any other reason
569618
*/
570-
public SystemResult doSystemRequest(String statement,
571-
int timeoutMs,
572-
int pollIntervalMs);
619+
SystemResult doSystemRequest(String statement,
620+
int timeoutMs,
621+
int pollIntervalMs);
573622

574623
/**
575624
* Returns an object that allows control over how statistics are collected.
@@ -578,7 +627,7 @@ public SystemResult doSystemRequest(String statement,
578627
*
579628
* @since 5.2.30
580629
*/
581-
public StatsControl getStatsControl();
630+
StatsControl getStatsControl();
582631

583632
/**
584633
* Closes the handle, releasing its memory and network resources. Once

driver/src/main/java/oracle/nosql/driver/http/NoSQLHandleImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.ArrayList;
1111
import java.util.logging.Logger;
12+
1213
import javax.net.ssl.SSLException;
1314

1415
import oracle.nosql.driver.AuthorizationProvider;
@@ -33,6 +34,7 @@
3334
import oracle.nosql.driver.ops.PrepareResult;
3435
import oracle.nosql.driver.ops.PutRequest;
3536
import oracle.nosql.driver.ops.PutResult;
37+
import oracle.nosql.driver.ops.QueryIterableResult;
3638
import oracle.nosql.driver.ops.QueryRequest;
3739
import oracle.nosql.driver.ops.QueryResult;
3840
import oracle.nosql.driver.ops.SystemRequest;
@@ -198,6 +200,12 @@ public QueryResult query(QueryRequest request) {
198200
return (QueryResult) client.execute(request);
199201
}
200202

203+
@Override
204+
public QueryIterableResult queryIterable(QueryRequest request) {
205+
checkClient();
206+
return new QueryIterableResult(request, this);
207+
}
208+
201209
@Override
202210
public PrepareResult prepare(PrepareRequest request) {
203211
checkClient();

driver/src/main/java/oracle/nosql/driver/ops/DurableRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*-
2-
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
33
*
44
* Licensed under the Universal Permissive License v 1.0 as shown at
55
* https://oss.oracle.com/licenses/upl/

driver/src/main/java/oracle/nosql/driver/ops/QueryRequest.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@
2828
* may be reused. This is because prepared queries bypass query compilation.
2929
* They also allow for parameterized queries using bind variables.
3030
* <p>
31+
* There are two ways to get the results of a query: using an iterator or
32+
* loop through partial results.
33+
* <p>
34+
* <b>Iterator</b>
35+
* <p>
36+
* Use {@link NoSQLHandle#queryIterable(QueryRequest)} to get an iterable
37+
* that contains all the results. Usage example:
38+
* <pre>
39+
* NoSQLHandle handle = ...;
40+
*
41+
* QueryRequest qreq = new QueryRequest().setStatement("select * from foo");
42+
*
43+
* for (MapValue row : handle.queryIterable(qreq) ) {
44+
* // do something with row
45+
* }
46+
* </pre>
47+
* <p>
48+
* <b>Partial results</b>
49+
* <p>
3150
* To compute and retrieve the full result set of a query, the same QueryRequest
3251
* instance will, in general, have to be executed multiple times (via
3352
* {@link NoSQLHandle#query}. Each execution returns a {@link QueryResult},
@@ -60,8 +79,9 @@
6079
* application threads need to run the same query concurrently, they must
6180
* create and use their own QueryRequest instances.
6281
*
63-
* @see NoSQLHandle#query
64-
* @see NoSQLHandle#prepare
82+
* @see NoSQLHandle#queryIterable(QueryRequest)
83+
* @see NoSQLHandle#query(QueryRequest)
84+
* @see NoSQLHandle#prepare(PrepareRequest)
6585
*/
6686
public class QueryRequest extends Request {
6787

@@ -129,6 +149,20 @@ public QueryRequest copyInternal() {
129149
return internalReq;
130150
}
131151

152+
/**
153+
* @hidden
154+
* Creates a copy that starts fresh from the beginning.
155+
* @return a copy of the instance in a new object
156+
*/
157+
public QueryRequest copy() {
158+
QueryRequest internalReq = copyInternal();
159+
internalReq.statement = statement;
160+
internalReq.isInternal = false;
161+
internalReq.shardId = -1;
162+
internalReq.driver = null;
163+
return internalReq;
164+
}
165+
132166
/**
133167
* @hidden
134168
*
@@ -295,7 +329,7 @@ public QueryRequest setCompartment(String compartment) {
295329

296330
/**
297331
* Returns the limit on number of items returned by the operation. If
298-
* not set by the application this value will be 0 which means no limit.
332+
* not set by the application this value will be 0 which means no limit set.
299333
*
300334
* @return the limit, or 0 if not set
301335
*/

driver/src/main/java/oracle/nosql/driver/ops/RetryStats.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,20 @@ public RetryStats() {
5151
* @param e the exception class
5252
*/
5353
public void addException(Class<? extends Throwable> e) {
54-
int i = getNumExceptions(e) + 1;
54+
addException(e, 1);
55+
}
56+
57+
/**
58+
* @hidden
59+
* Internal use only.
60+
* Adds an exception class to the stats object.
61+
* This increments the exception count and adds to the count of
62+
* this type of exception class.
63+
* @param e the exception class
64+
* @param n the number of such exceptions
65+
*/
66+
public void addException(Class<? extends Throwable> e, int n) {
67+
int i = getNumExceptions(e) + n;
5568
exceptionMap.put(e, i);
5669
}
5770

driver/src/main/java/oracle/nosql/driver/query/QueryDriver.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
import oracle.nosql.driver.ops.PreparedStatement;
1616
import oracle.nosql.driver.ops.QueryRequest;
1717
import oracle.nosql.driver.ops.QueryResult;
18-
import oracle.nosql.driver.query.PlanIter;
19-
import oracle.nosql.driver.query.RuntimeControlBlock;
2018
import oracle.nosql.driver.values.FieldValue;
2119
import oracle.nosql.driver.values.MapValue;
2220

driver/src/test/java/oracle/nosql/driver/InternalsTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
import java.util.concurrent.CountDownLatch;
1313
import java.util.concurrent.atomic.AtomicInteger;
1414

15+
import oracle.nosql.driver.ops.ListTablesRequest;
16+
1517
import org.junit.Before;
1618
import org.junit.Test;
1719

18-
import oracle.nosql.driver.ops.ListTablesRequest;
19-
2020
public class InternalsTest extends ProxyTestBase {
2121

2222
@Override
@@ -32,6 +32,7 @@ protected void perTestHandleConfig(NoSQLHandleConfig config) {
3232
* is run. The default runs a ListTables request.
3333
*/
3434
public void beforeTest() throws Exception {
35+
super.beforeTest();
3536
handle = getHandle(endpoint);
3637
/* do NOT list tables here */
3738
}

0 commit comments

Comments
 (0)