From d1660ea0ec11fdd845a9007295dc47ce3c08a38e Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Sun, 1 Jan 2012 10:48:33 +0000 Subject: [PATCH] [#1024] Add Factory.resultQuery(String, Object...) to allow for arbitrary execution modes of plain SQL queries --- .../org/jooq/util/spring/FactoryProxy.java | 11 +++ .../src/org/jooq/test/jOOQAbstractTest.java | 59 +++++++++++ .../main/java/org/jooq/FactoryOperations.java | 97 +++++++++++++++++++ jOOQ/src/main/java/org/jooq/impl/Factory.java | 18 ++++ 4 files changed, 185 insertions(+) diff --git a/jOOQ-spring/src/main/java/org/jooq/util/spring/FactoryProxy.java b/jOOQ-spring/src/main/java/org/jooq/util/spring/FactoryProxy.java index bfa0d577f6..39a7640d12 100644 --- a/jOOQ-spring/src/main/java/org/jooq/util/spring/FactoryProxy.java +++ b/jOOQ-spring/src/main/java/org/jooq/util/spring/FactoryProxy.java @@ -63,6 +63,7 @@ import org.jooq.Query; import org.jooq.QueryPart; import org.jooq.Record; import org.jooq.Result; +import org.jooq.ResultQuery; import org.jooq.SQLDialect; import org.jooq.Schema; import org.jooq.SchemaMapping; @@ -380,6 +381,16 @@ public class FactoryProxy implements FactoryOperations, MethodInterceptor { return getDelegate().fetchOne(sql, bindings); } + @Override + public final ResultQuery resultQuery(String sql) throws DataAccessException { + return getDelegate().resultQuery(sql); + } + + @Override + public final ResultQuery resultQuery(String sql, Object... bindings) throws DataAccessException { + return getDelegate().resultQuery(sql, bindings); + } + @Override public final BigInteger lastID() { return getDelegate().lastID(); diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 7c7bfe7cb8..a50b94ff7d 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -126,6 +126,7 @@ import org.jooq.Record; import org.jooq.RecordHandler; import org.jooq.RenderContext; import org.jooq.Result; +import org.jooq.ResultQuery; import org.jooq.SQLDialect; import org.jooq.Schema; import org.jooq.SchemaMapping; @@ -1721,6 +1722,64 @@ public abstract class jOOQAbstractTest< .fetchOne(0)); } + @Test + public void testPlainSQLResultQuery() throws Exception { + String sql = create().select(param("p", Integer.class).as("p")).getSQL(); + ResultQuery q = create().resultQuery(sql, 10); + + Result fetch1 = q.fetch(); + assertEquals(1, fetch1.size()); + assertEquals(1, fetch1.getFields().size()); + assertEquals("p", fetch1.getField(0).getName()); + assertEquals("p", fetch1.getField("p").getName()); + assertEquals(10, fetch1.getValue(0, 0)); + assertEquals(10, fetch1.getValue(0, "p")); + assertEquals(10, fetch1.getValue(0, fetch1.getField("p"))); + + List fetch2 = q.fetch("p"); + assertEquals(1, fetch2.size()); + assertEquals(10, fetch2.get(0)); + + List fetch3 = q.fetch(0, Long.class); + assertEquals(1, fetch3.size()); + assertEquals(10L, (long) fetch3.get(0)); + + Record fetch4 = q.fetchAny(); + assertEquals(1, fetch4.getFields().size()); + assertEquals("p", fetch4.getField(0).getName()); + assertEquals("p", fetch4.getField("p").getName()); + assertEquals(10, fetch4.getValue(0)); + assertEquals(10, fetch4.getValue("p")); + assertEquals(10, fetch4.getValue(fetch4.getField("p"))); + + Object[] fetch5 = q.fetchArray("p"); + assertEquals(1, fetch5.length); + assertEquals(10, fetch5[0]); + + Object[] fetch6 = q.fetchArray(0); + assertEquals(1, fetch6.length); + assertEquals(10, fetch6[0]); + + Long[] fetch7 = q.fetchArray(0, Long.class); + assertEquals(1, fetch7.length); + assertEquals(10L, (long) fetch7[0]); + + List fetch8 = q.fetchInto(TestPlainSQLResultQuery.class); + assertEquals(1, fetch8.size()); + assertEquals(10, fetch8.get(0).p); + + q.fetchInto(new RecordHandler() { + @Override + public void next(Record record) { + assertEquals(1, record.getFields().size()); + } + }); + } + + public static class TestPlainSQLResultQuery { + public int p; + } + @Test public void testCustomSQL() throws Exception { final Field IDx2 = new CustomField(TBook_ID().getName(), TBook_ID().getDataType()) { diff --git a/jOOQ/src/main/java/org/jooq/FactoryOperations.java b/jOOQ/src/main/java/org/jooq/FactoryOperations.java index 0a4ef4e1b2..3fc9c5f331 100644 --- a/jOOQ/src/main/java/org/jooq/FactoryOperations.java +++ b/jOOQ/src/main/java/org/jooq/FactoryOperations.java @@ -1033,4 +1033,101 @@ public interface FactoryOperations extends Configuration { */ @Support Record fetchOne(String sql, Object... bindings) throws DataAccessException; + + /** + * Create a new query holding plain SQL. There must not be any binding + * variables contained in the SQL + *

+ * Use this method, when you want to take advantage of the many ways to + * fetch results in jOOQ, using {@link ResultQuery}. Some examples: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link ResultQuery#fetchLazy()}Open a cursor and fetch records one by one
{@link ResultQuery#fetchInto(Class)}Fetch records into a custom POJO (optionally annotated with JPA + * annotations)
{@link ResultQuery#fetchInto(RecordHandler)}Fetch records into a custom callback (similar to Spring's RowMapper)
{@link ResultQuery#fetchLater()}Fetch records of a long-running query asynchronously
+ *

+ * 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 An executable query + * @throws DataAccessException if something went wrong executing the query + */ + @Support + ResultQuery resultQuery(String sql) throws DataAccessException; + + /** + * Create a new query holding plain SQL. There must be as many binding + * variables contained in the SQL, as passed in the bindings parameter + *

+ * Use this method, when you want to take advantage of the many ways to + * fetch results in jOOQ, using {@link ResultQuery}. Some examples: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@link ResultQuery#fetchLazy()}Open a cursor and fetch records one by one
{@link ResultQuery#fetchInto(Class)}Fetch records into a custom POJO (optionally annotated with JPA + * annotations)
{@link ResultQuery#fetchInto(RecordHandler)}Fetch records into a custom callback (similar to Spring's RowMapper)
{@link ResultQuery#fetchLater()}Fetch records of a long-running query asynchronously
+ *

+ * 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 An executable query + * @throws DataAccessException if something went wrong executing the query + */ + @Support + ResultQuery resultQuery(String sql, Object... bindings) throws DataAccessException; } diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java index 3637717d23..3dcf7b46c8 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Factory.java +++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java @@ -97,6 +97,7 @@ import org.jooq.QueryPart; import org.jooq.Record; import org.jooq.RenderContext; import org.jooq.Result; +import org.jooq.ResultQuery; import org.jooq.SQLDialect; import org.jooq.Schema; import org.jooq.SchemaMapping; @@ -117,6 +118,7 @@ import org.jooq.UpdateQuery; import org.jooq.UpdateSetStep; import org.jooq.WindowIgnoreNullsStep; import org.jooq.WindowOverStep; +import org.jooq.exception.DataAccessException; import org.jooq.exception.InvalidResultException; import org.jooq.exception.SQLDialectNotSupportedException; import org.jooq.tools.JooqLogger; @@ -820,6 +822,22 @@ public class Factory implements FactoryOperations { return new SQLResultQuery(this, sql, bindings).fetchOne(); } + /** + * {@inheritDoc} + */ + @Override + public final ResultQuery resultQuery(String sql) throws DataAccessException { + return resultQuery(sql, new Object[0]); + } + + /** + * {@inheritDoc} + */ + @Override + public final ResultQuery resultQuery(String sql, Object... bindings) throws DataAccessException { + return new SQLResultQuery(this, sql, bindings); + } + // ------------------------------------------------------------------------- // JDBC convenience methods // -------------------------------------------------------------------------