From f17a3c48c7f2591c97c9013b8170f28f607cf361 Mon Sep 17 00:00:00 2001 From: lukaseder Date: Mon, 1 Jun 2015 10:26:44 +0200 Subject: [PATCH] [#4339] Add DSLContext.fetchStream(...) similar to the existing DSLContext.fetchLazy(...) API --- jOOQ/src/main/java/org/jooq/DSLContext.java | 223 +++++++++++++++++- .../org/jooq/impl/AbstractResultQuery.java | 14 +- .../java/org/jooq/impl/DefaultDSLContext.java | 67 ++++++ 3 files changed, 290 insertions(+), 14 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java index 8f0c0d3661..1cf9737777 100644 --- a/jOOQ/src/main/java/org/jooq/DSLContext.java +++ b/jOOQ/src/main/java/org/jooq/DSLContext.java @@ -70,6 +70,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; import javax.annotation.Generated; @@ -619,13 +620,126 @@ public interface DSLContext extends Scope { * parts can be injected * @param parts The {@link QueryPart} objects that are rendered at the * {numbered placeholder} locations - * @return The results from the executed query + * @return The results from the executed query. This is never + * null, even if the database returns no + * {@link ResultSet} * @throws DataAccessException if something went wrong executing the query */ @Support @PlainSQL Cursor fetchLazy(String sql, QueryPart... parts) throws DataAccessException; + /* [java-8] */ + /** + * Execute a new query holding plain SQL and "lazily" return the generated + * result. + *

+ * The returned {@link Stream} holds a reference to the executed + * {@link PreparedStatement} and the associated {@link ResultSet}. Data can + * be fetched (or iterated over) lazily, fetching records from the + * {@link ResultSet} one by one. + *

+ * Example (Postgres): + *

+ *

+     * String sql = "FETCH ALL IN \"\"";
Example + * (SQLite): + *

+ *

+     * String sql = "pragma table_info('my_table')";
+ *

+ * NOTE: When inserting plain SQL into jOOQ objects, you must + * guarantee syntax integrity. You may also create the possibility of + * malicious SQL injection. Be sure to properly use bind variables and/or + * escape literals when concatenated into SQL clauses! + * + * @param sql The SQL + * @return The results from the executed query. This is never + * null, even if the database returns no + * {@link ResultSet} + * @throws DataAccessException if something went wrong executing the query + */ + @Support + @PlainSQL + Stream fetchStream(String sql) throws DataAccessException; + + /** + * Execute a new query holding plain SQL and "lazily" return the generated + * result. + *

+ * There must be as many bind variables contained in the SQL, as passed in + * the bindings parameter + *

+ * The returned {@link Stream} holds a reference to the executed + * {@link PreparedStatement} and the associated {@link ResultSet}. Data can + * be fetched (or iterated over) lazily, fetching records from the + * {@link ResultSet} one by one. + *

+ * Example (Postgres): + *

+ *

+     * String sql = "FETCH ALL IN \"\"";
Example + * (SQLite): + *

+ *

+     * String sql = "pragma table_info('my_table')";
+ *

+ * NOTE: When inserting plain SQL into jOOQ objects, you must + * guarantee syntax integrity. You may also create the possibility of + * malicious SQL injection. Be sure to properly use bind variables and/or + * escape literals when concatenated into SQL clauses! + * + * @param sql The SQL + * @param bindings The bindings + * @return The results from the executed query. This is never + * null, even if the database returns no + * {@link ResultSet} + * @throws DataAccessException if something went wrong executing the query + */ + @Support + @PlainSQL + Stream fetchStream(String sql, Object... bindings) throws DataAccessException; + + /** + * Execute a new query holding plain SQL and "lazily" return the generated + * result. + *

+ * The returned {@link Stream} holds a reference to the executed + * {@link PreparedStatement} and the associated {@link ResultSet}. Data can + * be fetched (or iterated over) lazily, fetching records from the + * {@link ResultSet} one by one. + *

+ * Unlike {@link #stream(String, Object...)}, the SQL passed to this + * method should not contain any bind variables. Instead, you can pass + * {@link QueryPart} objects to the method which will be rendered at indexed + * locations of your SQL string as such:

+     * // The following query
+     * fetchLazy("select {0}, {1} from {2}", val(1), inline("test"), name("DUAL"));
+     *
+     * // Will execute this SQL on an Oracle database with RenderNameStyle.QUOTED:
+     * select ?, 'test' from "DUAL"
+     * 
+ *

+ * NOTE: When inserting plain SQL into jOOQ objects, you must + * guarantee syntax integrity. You may also create the possibility of + * malicious SQL injection. Be sure to properly use bind variables and/or + * escape literals when concatenated into SQL clauses! One way to escape + * literals is to use {@link DSL#name(String...)} and similar methods + * + * @param sql The SQL clause, containing {numbered placeholders} where query + * parts can be injected + * @param parts The {@link QueryPart} objects that are rendered at the + * {numbered placeholder} locations + * @return The results from the executed query. This is never + * null, even if the database returns no + * {@link ResultSet} + * @throws DataAccessException if something went wrong executing the query + */ + @Support + @PlainSQL + Stream fetchStream(String sql, QueryPart... parts) throws DataAccessException; + /* [/java-8] */ + /** * Execute a new query holding plain SQL, possibly returning several result * sets. @@ -1872,6 +1986,72 @@ public interface DSLContext extends Scope { @Support Cursor fetchLazy(ResultSet rs, Class... types) throws DataAccessException; + /* [java-8] */ + /** + * Wrap a JDBC {@link ResultSet} into a jOOQ {@link Stream}. + *

+ * Use {@link #fetch(ResultSet)}, to load the entire ResultSet + * into a jOOQ Result at once. + * + * @param rs The JDBC ResultSet to fetch data from + * @return The resulting stream + * @throws DataAccessException if something went wrong executing the query + */ + @Support + Stream fetchStream(ResultSet rs) throws DataAccessException; + + /** + * Wrap a JDBC {@link ResultSet} into a jOOQ {@link Stream}. + *

+ * Use {@link #fetch(ResultSet)}, to load the entire ResultSet + * into a jOOQ Result at once. + *

+ * The additional fields argument is used by jOOQ to coerce + * field names and data types to the desired output + * + * @param rs The JDBC ResultSet to fetch data from + * @param fields The fields to use in the desired output + * @return The resulting stream + * @throws DataAccessException if something went wrong executing the query + */ + @Support + Stream fetchStream(ResultSet rs, Field... fields) throws DataAccessException; + + /** + * Wrap a JDBC {@link ResultSet} into a jOOQ {@link Stream}. + *

+ * Use {@link #fetch(ResultSet)}, to load the entire ResultSet + * into a jOOQ Result at once. + *

+ * The additional types argument is used by jOOQ to coerce data + * types to the desired output + * + * @param rs The JDBC ResultSet to fetch data from + * @param types The data types to use in the desired output + * @return The resulting stream + * @throws DataAccessException if something went wrong executing the query + */ + @Support + Stream fetchStream(ResultSet rs, DataType... types) throws DataAccessException; + + /** + * Wrap a JDBC {@link ResultSet} into a jOOQ {@link Stream}. + *

+ * Use {@link #fetch(ResultSet)}, to load the entire ResultSet + * into a jOOQ Result at once. + *

+ * The additional types argument is used by jOOQ to coerce data + * types to the desired output + * + * @param rs The JDBC ResultSet to fetch data from + * @param types The data types to use in the desired output + * @return The resulting stream + * @throws DataAccessException if something went wrong executing the query + */ + @Support + Stream fetchStream(ResultSet rs, Class... types) throws DataAccessException; + /* [/java-8] */ + /** * Fetch all data from a formatted string. *

@@ -6425,6 +6605,19 @@ public interface DSLContext extends Scope { */ Cursor fetchLazy(ResultQuery query) throws DataAccessException; + /* [java-8] */ + /** + * Execute a {@link ResultQuery} in the context of this DSLContext and return + * a stream. + * + * @param query The query to execute + * @return The stream + * @throws DataAccessException if something went wrong executing the query + * @see ResultQuery#stream() + */ + Stream fetchStream(ResultQuery query) throws DataAccessException; + /* [/java-8] */ + /** * Execute a {@link ResultQuery} in the context of this DSLContext and return * a cursor. @@ -6755,6 +6948,34 @@ public interface DSLContext extends Scope { @Support Cursor fetchLazy(Table table, Condition condition) throws DataAccessException; + /* [java-8] */ + /** + * Execute and return all records lazily for + *

SELECT * FROM [table]
. + *

+ * The result and its contained records are attached to this + * {@link Configuration} by default. Use {@link Settings#isAttachRecords()} + * to override this behaviour. + * + * @throws DataAccessException if something went wrong executing the query + */ + @Support + Stream fetchStream(Table table) throws DataAccessException; + + /** + * Execute and return all records lazily for + *

SELECT * FROM [table] WHERE [condition] 
. + *

+ * The result and its contained records are attached to this + * {@link Configuration} by default. Use {@link Settings#isAttachRecords()} + * to override this behaviour. + * + * @throws DataAccessException if something went wrong executing the query + */ + @Support + Stream fetchStream(Table table, Condition condition) throws DataAccessException; + /* [/java-8] */ + /** * Insert one record. *

diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java index b92b9d0ae3..9813f8dde6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java @@ -60,13 +60,10 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.Spliterator; -import java.util.Spliterators; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.jooq.Configuration; import org.jooq.Converter; @@ -317,16 +314,7 @@ abstract class AbstractResultQuery extends AbstractQuery imple /* [java-8] */ @Override public final Stream stream() throws DataAccessException { - Cursor c = fetchLazy(); - - return StreamSupport.stream( - Spliterators.spliterator( - c.iterator(), - 0, - Spliterator.ORDERED | Spliterator.NONNULL - ), - false - ).onClose(() -> c.close()); + return fetchLazy().stream(); } /* [/java-8] */ diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java index 5bced3e79e..0bfaf1e457 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java @@ -70,6 +70,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.stream.Stream; import javax.annotation.Generated; import javax.sql.DataSource; @@ -522,6 +523,23 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri return resultQuery(sql, parts).fetchLazy(); } + /* [java-8] */ + @Override + public Stream fetchStream(String sql) { + return resultQuery(sql).stream(); + } + + @Override + public Stream fetchStream(String sql, Object... bindings) { + return resultQuery(sql, bindings).stream(); + } + + @Override + public Stream fetchStream(String sql, QueryPart... parts) { + return resultQuery(sql, parts).stream(); + } + /* [/java-8] */ + @Override public List> fetchMany(String sql) { return resultQuery(sql).fetchMany(); @@ -816,6 +834,28 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri return fetchLazy(rs, Utils.dataTypes(types)); } + /* [java-8] */ + @Override + public Stream fetchStream(ResultSet rs) { + return fetchLazy(rs).stream(); + } + + @Override + public Stream fetchStream(ResultSet rs, Field... fields) { + return fetchLazy(rs, fields).stream(); + } + + @Override + public Stream fetchStream(ResultSet rs, DataType... types) { + return fetchLazy(rs, types).stream(); + } + + @Override + public Stream fetchStream(ResultSet rs, Class... types) { + return fetchLazy(rs, types).stream(); + } + /* [/java-8] */ + @Override public Result fetchFromTXT(String string) { return fetchFromTXT(string, "{null}"); @@ -2376,6 +2416,21 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri } } + /* [java-8] */ + @Override + public Stream fetchStream(ResultQuery query) { + final Configuration previous = Utils.getConfiguration(query); + + try { + query.attach(configuration()); + return query.stream(); + } + finally { + query.attach(previous); + } + } + /* [/java-8] */ + @Override public List> fetchMany(ResultQuery query) { final Configuration previous = Utils.getConfiguration(query); @@ -2548,6 +2603,18 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri return selectFrom(table).where(condition).fetchLazy(); } + /* [java-8] */ + @Override + public Stream fetchStream(Table table) { + return fetchStream(table, trueCondition()); + } + + @Override + public Stream fetchStream(Table table, Condition condition) { + return selectFrom(table).where(condition).stream(); + } + /* [/java-8] */ + @Override public > int executeInsert(R record) { InsertQuery insert = insertQuery(record.getTable());