[#825] Add List<Result<Record>> Factory.fetchMany(String) to allow for fetching several result sets from stored procedures, such as Sybase ASE's "sp_help"

This commit is contained in:
Lukas Eder 2011-09-22 21:24:58 +00:00
parent 4f82b414e3
commit e45657bffa
6 changed files with 161 additions and 69 deletions

View File

@ -35,13 +35,11 @@
*/
package org.jooq.util.ase;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.jooq.Record;
import org.jooq.util.AbstractTableDefinition;
import org.jooq.util.ColumnDefinition;
import org.jooq.util.DataTypeDefinition;
@ -65,47 +63,30 @@ public class ASETableDefinition extends AbstractTableDefinition {
protected List<ColumnDefinition> getElements0() throws SQLException {
List<ColumnDefinition> result = new ArrayList<ColumnDefinition>();
PreparedStatement stmt = null;
try {
stmt = create().getConnection().prepareStatement("sp_help '" + getName() + "'");
stmt.execute();
stmt.getMoreResults();
int position = 1;
for (Record record : create().fetchMany("sp_help '" + getName() + "'").get(1)) {
String p = record.getValueAsString("Prec");
String s = record.getValueAsString("Scale");
stmt.getResultSet().close();
stmt.getMoreResults();
int precision = 0;
int scale = 0;
ResultSet rs = stmt.getResultSet();
if (p != null && !"null".equalsIgnoreCase(p.trim())) precision = Integer.valueOf(p.trim());
if (s != null && !"null".equalsIgnoreCase(s.trim())) scale = Integer.valueOf(s.trim());
int position = 1;
while (rs.next()) {
String p = rs.getString("Prec");
String s = rs.getString("Scale");
DataTypeDefinition type = new DefaultDataTypeDefinition(getDatabase(),
record.getValueAsString("Type"),
precision, scale);
int precision = 0;
int scale = 0;
if (p != null && !"null".equalsIgnoreCase(p.trim())) precision = Integer.valueOf(p.trim());
if (s != null && !"null".equalsIgnoreCase(s.trim())) scale = Integer.valueOf(s.trim());
DataTypeDefinition type = new DefaultDataTypeDefinition(getDatabase(),
rs.getString("Type"),
precision, scale);
result.add(new DefaultColumnDefinition(
getDatabase().getTable(getName()),
rs.getString("Column_name"),
position++,
type,
rs.getBoolean("Identity"),
null));
}
}
finally {
if (stmt != null) {
stmt.getMoreResults(Statement.CLOSE_ALL_RESULTS);
stmt.close();
}
result.add(new DefaultColumnDefinition(
getDatabase().getTable(getName()),
record.getValueAsString("Column_name"),
position++,
type,
record.getValueAsBoolean("Identity", false),
null));
}
return result;
}
}

View File

@ -174,6 +174,9 @@ public abstract class jOOQAbstractTest<
T639 extends UpdatableRecord<T639>,
T785 extends TableRecord<T785>> {
private static final List<Integer> BOOK_IDS = Arrays.asList(1, 2, 3, 4);
private static final List<String> BOOK_TITLES = Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida");
private static final String JDBC_SCHEMA = "jdbc.Schema";
private static final String JDBC_PASSWORD = "jdbc.Password";
private static final String JDBC_USER = "jdbc.User";
@ -882,13 +885,13 @@ public abstract class jOOQAbstractTest<
for (Entry<Integer, B> entry : map1.entrySet()) {
assertEquals(entry.getKey(), entry.getValue().getValue(TBook_ID()));
}
assertEquals(Arrays.asList(1, 2, 3, 4), new ArrayList<Integer>(map1.keySet()));
assertEquals(BOOK_IDS, new ArrayList<Integer>(map1.keySet()));
// Key -> Value Map
// ----------------
Map<Integer, String> map2 = create().selectFrom(TBook()).orderBy(TBook_ID()).fetchMap(TBook_ID(), TBook_TITLE());
assertEquals(Arrays.asList(1, 2, 3, 4), new ArrayList<Integer>(map2.keySet()));
assertEquals(Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida"), new ArrayList<String>(map2.values()));
assertEquals(BOOK_IDS, new ArrayList<Integer>(map2.keySet()));
assertEquals(BOOK_TITLES, new ArrayList<String>(map2.values()));
// List of Map
// -----------
@ -1268,19 +1271,13 @@ public abstract class jOOQAbstractTest<
Result<Record> result = create().select().from("t_book").orderBy(ID).fetch();
assertEquals(4, result.size());
assertEquals(
Arrays.asList(1, 2, 3, 4),
result.getValues(ID));
assertEquals(
Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida"),
result.getValues(TBook_TITLE()));
assertEquals(BOOK_IDS, result.getValues(ID));
assertEquals(BOOK_TITLES, result.getValues(TBook_TITLE()));
// [#271] Aliased plain SQL table
result = create().select(ID).from("(select * from t_book) b").orderBy(ID).fetch();
assertEquals(4, result.size());
assertEquals(
Arrays.asList(1, 2, 3, 4),
result.getValues(ID));
assertEquals(BOOK_IDS, result.getValues(ID));
// [#271] TODO: Aliased plain SQL table
// result = create().select().from("(select * from t_book) b").orderBy(ID).fetch();
@ -1292,9 +1289,7 @@ public abstract class jOOQAbstractTest<
// [#836] Aliased plain SQL table
result = create().select().from(create().table("t_book").as("b")).orderBy(ID).fetch();
assertEquals(4, result.size());
assertEquals(
Arrays.asList(1, 2, 3, 4),
result.getValues(ID));
assertEquals(BOOK_IDS, result.getValues(ID));
// [#271] TODO: Check for aliased nested selects. The DescribeQuery does not seem to work
// [#836] Aliased plain SQL nested select
@ -2342,7 +2337,7 @@ public abstract class jOOQAbstractTest<
.from(TBook())
.where(TBook_ID().in(new Integer[0]))
.fetch(TBook_ID()));
assertEquals(Arrays.asList(1, 2, 3, 4), create().select()
assertEquals(BOOK_IDS, create().select()
.from(TBook())
.where(TBook_ID().notIn(new Integer[0]))
.orderBy(TBook_ID())
@ -2588,6 +2583,25 @@ public abstract class jOOQAbstractTest<
assertEquals("Coelho", record.getValue(TAuthor_LAST_NAME()));
}
@Test
public void testFetchMany() throws Exception {
switch (getDialect()) {
case ORACLE:
case SQLITE:
case SYBASE:
log.info("SKIPPING", "Fetch Many tests");
return;
}
List<Result<Record>> results = create().fetchMany(
"select * from t_book order by " + TBook_ID().getName());
assertEquals(1, results.size());
assertEquals(4, results.get(0).size());
assertEquals(BOOK_IDS, results.get(0).getValues(TBook_ID(), Integer.class));
assertEquals(BOOK_TITLES, results.get(0).getValues(TBook_TITLE()));
}
@Test
public void testFetchIntoWithAnnotations() throws Exception {
// TODO [#791] Fix test data and have all upper case columns everywhere
@ -2731,8 +2745,8 @@ public abstract class jOOQAbstractTest<
final Queue<Integer> ids = new LinkedList<Integer>();
final Queue<String> titles = new LinkedList<String>();
ids.addAll(Arrays.asList(1, 2, 3, 4));
titles.addAll(Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida"));
ids.addAll(BOOK_IDS);
titles.addAll(BOOK_TITLES);
create().selectFrom(TBook())
.orderBy(TBook_ID())
@ -2749,8 +2763,8 @@ public abstract class jOOQAbstractTest<
// Test lazy fetching
// --------------------------------------
ids.addAll(Arrays.asList(1, 2, 3, 4));
titles.addAll(Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida"));
ids.addAll(BOOK_IDS);
titles.addAll(BOOK_TITLES);
create().selectFrom(TBook())
.orderBy(TBook_ID())
@ -2812,7 +2826,7 @@ public abstract class jOOQAbstractTest<
// Check the data
assertEquals(4, result.size());
assertEquals(Arrays.asList(1, 2, 3, 4), result.getValues(TBook_ID()));
assertEquals(BOOK_IDS, result.getValues(TBook_ID()));
// Start new threads
later = create().selectFrom(TBook()).orderBy(TBook_ID()).fetchLater();
@ -3374,7 +3388,7 @@ public abstract class jOOQAbstractTest<
" from " + T725().getName() +
" order by " + T725_ID().getName());
assertEquals(4, result.size());
assertEquals(Arrays.asList(1, 2, 3, 4), result.getValues(0));
assertEquals(BOOK_IDS, result.getValues(0));
assertNull(result.getValue(1, 1));
switch (getDialect()) {
@ -4208,7 +4222,7 @@ public abstract class jOOQAbstractTest<
@Test
public void testOrderByIndirection() throws Exception {
assertEquals(Arrays.asList(1, 2, 3, 4),
assertEquals(BOOK_IDS,
create().selectFrom(TBook())
.orderBy(TBook_ID().sortAsc(), TBook_ID().asc())
.fetch(TBook_ID()));
@ -4512,11 +4526,11 @@ public abstract class jOOQAbstractTest<
List<Integer> ids = create().select(b_ID).from(b).orderBy(b_ID).fetch(b_ID);
assertEquals(4, ids.size());
assertEquals(Arrays.asList(1, 2, 3, 4), ids);
assertEquals(BOOK_IDS, ids);
Result<Record> books = create().select().from(b).orderBy(b_ID).fetch();
assertEquals(4, books.size());
assertEquals(Arrays.asList(1, 2, 3, 4), books.getValues(b_ID));
assertEquals(BOOK_IDS, books.getValues(b_ID));
}
// @Test // TODO [#579] re-enable this test when fixing this bug

View File

@ -92,6 +92,19 @@ public interface ResultQuery<R extends Record> extends Query {
*/
Cursor<R> fetchLazy() throws SQLException;
/**
* Execute a query, possibly returning several result
* sets.
* <p>
* Example (Sybase ASE):
* <p>
* <code><pre>
* String sql = "sp_help 'my_table'";</pre></code>
*
* @return The resulting records
*/
List<Result<Record>> fetchMany() throws SQLException;
/**
* Execute the query and return all values for a field from the generated
* result.

View File

@ -106,6 +106,11 @@ abstract class AbstractDelegatingSelect<R extends Record> extends AbstractQueryP
return query.fetchLazy();
}
@Override
public final List<Result<Record>> fetchMany() throws SQLException {
return query.fetchMany();
}
@Override
public final <T> List<T> fetch(Field<T> field) throws SQLException {
return query.fetch(field);

View File

@ -43,6 +43,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@ -54,6 +55,7 @@ import java.util.concurrent.Future;
import org.jooq.Configuration;
import org.jooq.Cursor;
import org.jooq.Field;
import org.jooq.FieldProvider;
import org.jooq.FutureResult;
import org.jooq.Record;
import org.jooq.RecordHandler;
@ -74,8 +76,10 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
private static final long serialVersionUID = -5588344253566055707L;
private transient boolean lazy;
private transient boolean many;
private transient Cursor<R> cursor;
private Result<R> result;
private List<Result<Record>> results;
AbstractResultQuery(Configuration configuration) {
super(configuration);
@ -103,12 +107,34 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
try {
ResultSet rs = statement.executeQuery();
FieldList fields = new FieldList(getFields(rs.getMetaData()));
cursor = new CursorImpl<R>(configuration, fields, rs, statement, getRecordType());
if (!lazy) {
result = cursor.fetchResult();
cursor = null;
if (!many) {
FieldList fields = new FieldList(getFields(rs.getMetaData()));
cursor = new CursorImpl<R>(configuration, fields, rs, statement, getRecordType());
if (!lazy) {
result = cursor.fetchResult();
cursor = null;
}
}
else {
results = new ArrayList<Result<Record>>();
for (;;) {
FieldProvider fields = new MetaDataFieldProvider(configuration, rs.getMetaData());
Cursor<Record> c = new CursorImpl<Record>(configuration, fields, rs);
results.add(c.fetchResult());
if (statement.getMoreResults()) {
rs = statement.getResultSet();
}
else {
break;
}
}
statement.getMoreResults(Statement.CLOSE_ALL_RESULTS);
statement.close();
}
}
finally {
@ -145,6 +171,15 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
return cursor;
}
@Override
public final List<Result<Record>> fetchMany() throws SQLException {
many = true;
execute();
many = false;
return results;
}
@Override
public final <T> List<T> fetch(Field<T> field) throws SQLException {
return fetch().getValues(field);

View File

@ -1080,6 +1080,50 @@ public class Factory implements Configuration {
return new SQLResultQuery(this, sql, bindings).fetch();
}
/**
* Execute a new query holding plain SQL, possibly returning several result
* sets
* <p>
* Example (Sybase ASE):
* <p>
* <code><pre>
* String sql = "sp_help '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 The results from the executed query
*/
public final List<Result<Record>> fetchMany(String sql) throws SQLException {
return fetchMany(sql, new Object[0]);
}
/**
* Execute a new query holding plain SQL, possibly returning several result
* sets. There must be as many binding variables contained in the SQL, as
* passed in the bindings parameter
* <p>
* Example (Sybase ASE):
* <p>
* <code><pre>
* String sql = "sp_help '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 A query wrapping the plain SQL
*/
public final List<Result<Record>> fetchMany(String sql, Object... bindings) throws SQLException {
return new SQLResultQuery(this, sql, bindings).fetchMany();
}
/**
* Execute a new query holding plain SQL.
* <p>