[#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:
parent
4f82b414e3
commit
e45657bffa
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user