[#1024] Add Factory.resultQuery(String, Object...) to allow for arbitrary execution modes of plain SQL queries

This commit is contained in:
Lukas Eder 2012-01-01 10:48:33 +00:00
parent b7a7442e9e
commit d1660ea0ec
4 changed files with 185 additions and 0 deletions

View File

@ -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<Record> resultQuery(String sql) throws DataAccessException {
return getDelegate().resultQuery(sql);
}
@Override
public final ResultQuery<Record> resultQuery(String sql, Object... bindings) throws DataAccessException {
return getDelegate().resultQuery(sql, bindings);
}
@Override
public final BigInteger lastID() {
return getDelegate().lastID();

View File

@ -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<Record> q = create().resultQuery(sql, 10);
Result<Record> 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<Long> 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<TestPlainSQLResultQuery> fetch8 = q.fetchInto(TestPlainSQLResultQuery.class);
assertEquals(1, fetch8.size());
assertEquals(10, fetch8.get(0).p);
q.fetchInto(new RecordHandler<Record>() {
@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<Integer> IDx2 = new CustomField<Integer>(TBook_ID().getName(), TBook_ID().getDataType()) {

View File

@ -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
* <p>
* Use this method, when you want to take advantage of the many ways to
* fetch results in jOOQ, using {@link ResultQuery}. Some examples:
* <p>
* <table border="1">
* <tr>
* <td> {@link ResultQuery#fetchLazy()}</td>
* <td>Open a cursor and fetch records one by one</td>
* </tr>
* <tr>
* <td> {@link ResultQuery#fetchInto(Class)}</td>
* <td>Fetch records into a custom POJO (optionally annotated with JPA
* annotations)</td>
* </tr>
* <tr>
* <td> {@link ResultQuery#fetchInto(RecordHandler)}</td>
* <td>Fetch records into a custom callback (similar to Spring's RowMapper)</td>
* </tr>
* <tr>
* <td> {@link ResultQuery#fetchLater()}</td>
* <td>Fetch records of a long-running query asynchronously</td>
* </tr>
* </table>
* <p>
* Example (Postgres):
* <p>
* <code><pre>
* String sql = "FETCH ALL IN \"<unnamed cursor 1>\"";</pre></code> Example
* (SQLite):
* <p>
* <code><pre>
* String sql = "pragma table_info('my_table')";</pre></code>
* <p>
* <b>NOTE</b>: 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<Record> 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
* <p>
* Use this method, when you want to take advantage of the many ways to
* fetch results in jOOQ, using {@link ResultQuery}. Some examples:
* <p>
* <table border="1">
* <tr>
* <td> {@link ResultQuery#fetchLazy()}</td>
* <td>Open a cursor and fetch records one by one</td>
* </tr>
* <tr>
* <td> {@link ResultQuery#fetchInto(Class)}</td>
* <td>Fetch records into a custom POJO (optionally annotated with JPA
* annotations)</td>
* </tr>
* <tr>
* <td> {@link ResultQuery#fetchInto(RecordHandler)}</td>
* <td>Fetch records into a custom callback (similar to Spring's RowMapper)</td>
* </tr>
* <tr>
* <td> {@link ResultQuery#fetchLater()}</td>
* <td>Fetch records of a long-running query asynchronously</td>
* </tr>
* </table>
* <p>
* Example (Postgres):
* <p>
* <code><pre>
* String sql = "FETCH ALL IN \"<unnamed cursor 1>\"";</pre></code> Example
* (SQLite):
* <p>
* <code><pre>
* String sql = "pragma table_info('my_table')";</pre></code>
* <p>
* <b>NOTE</b>: 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<Record> resultQuery(String sql, Object... bindings) throws DataAccessException;
}

View File

@ -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<Record> resultQuery(String sql) throws DataAccessException {
return resultQuery(sql, new Object[0]);
}
/**
* {@inheritDoc}
*/
@Override
public final ResultQuery<Record> resultQuery(String sql, Object... bindings) throws DataAccessException {
return new SQLResultQuery(this, sql, bindings);
}
// -------------------------------------------------------------------------
// JDBC convenience methods
// -------------------------------------------------------------------------