How to map CURSOR to Map in iBatis - java

I'm wondering if is there possibility to map first row from Oracle Cursor to java.util.Map (using column names as keys) in iBatis version 2.3.4.726. I came up to with TypeHandlerCallback:
public class MapResultTypeHandler implements TypeHandlerCallback {
#Override
public void setParameter(final ParameterSetter parameterSetter, final Object o) throws SQLException {
throw new UnsupportedOperationException();
}
#Override
public Map<String, Object> getResult(final ResultGetter resultGetter) throws SQLException {
ResultSet resultSet = resultGetter.getResultSet();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnsNumber = metaData.getColumnCount();
Map<String, Object> result = new HashMap<>(columnsNumber);
do {
for(int i=1; i <= columnsNumber; ++i) {
result.put(metaData.getColumnName(i), resultSet.getObject(i));
}
} while (resultSet.next());
return result;
}
#Override
public Object valueOf(final String s) {
return null;
}
}
Unfortunately method getMetaData throws:
UnsupportedOperationException("CallableStatement does not support this method.");
Is there other possibility to achieve this goal?

I finally managed to map Oracle Cursor to Map! I had to modify first row of getResult method. It should look like:
ResultSet resultSet = (ResultSet) resultGetter.getObject();

Related

com.ibm.db2.jcc.am.SqlException: [jcc][t4][10120][10898][4.19.49] Invalid operation: result set is closed. ERRORCODE=-4470, SQLSTATE=null

In our Struts2 application For Fetching data we got result set is closed. we are using one structure for fetching resulset data. We are using BaseResultSetHandler fetch resulset data in DAO file.I am not able to find cause why resultset is closed. In the below i have mention code kindly help us
we are having BaseResultSetHandler abstract class
public abstract class BaseResultSetHandler {
protected ResultSet resultSet;
public abstract Object handleResult() throws SQLException;
public Object handleResultSet(ResultSet rs) throws SQLException{
setResultSet(rs);
Object obj = handleResult();
return obj;
}
public void setResultSet(ResultSet resultSet) {
this.resultSet = resultSet;
}
public ResultSet getResultSet() {
return resultSet;
}
public Integer getInteger(String columnName,ResultSet resultSet) throws SQLException{
return StringUtility.getInt(resultSet.getInt(columnName));
}
public String getString(String columnName,ResultSet resultSet) throws SQLException{
return StringUtility.getString(resultSet.getString(columnName));
}
public String getString(String columnName) throws SQLException{
return StringUtility.getString(resultSet.getString(columnName));
}
}
We have one DatabaseManger class For handling database operation in that we have function for fetch data from database
protected Object executePreparedQuery(String query, List arguments, BaseResultSetHandler BaseResultSetHandler, Connection useThisConnection)
throws SQLException, InstantiationException, Exception, Throwable
{
ResultSet resultSet = null;
try {
if (ReferenceCheckUtlity.isNull(useThisConnection)) {
this.connection = getConnection();
}else{
this.connection = useThisConnection;
}
this.preparedStatement = this.connection.prepareStatement(query);
if (arguments != null) {
Iterator argumentsIterator = arguments.iterator();
int index = 1;
while (argumentsIterator.hasNext()) {
this.preparedStatement.setObject(index++, argumentsIterator.next());
}
}
resultSet = this.preparedStatement.executeQuery();
Object localObject2 = BaseResultSetHandler.handleResultSet(resultSet);
} finally {
if(resultSet!=null){
resultSet.close();
}
if(this.statement!=null){
this.statement.close();
}
if(this.preparedStatement!=null){
this.preparedStatement.close();
}
if(this.connection!=null){
this.connection.close();
}
}
return localObject2;
}
In DAO File i have share only 2 method here there are lot of method in file approximate 25+ classes using BaseResultSetHandler
public String getCheckId(String Id) throws NumberFormatException, SQLException, InstantiationException, Exception, Throwable {
ArrayList<Object> argumentList=new ArrayList<Object>();
argumentList.add(Id);
int cnt=Integer.parseInt(""+executePreparedQuery(getCheckIdSql(), argumentList, new getCheckIdHandler(), null));
if(cnt==0){
return "N";
}else{
return "Y";
}
}
private String getCheckIdSql() {
StringBuffer query=new StringBuffer();
query.append("select count(1) as cnt from EMPLOYEES where ID=? for read only ");
return query.toString();
}
class getCheckIdHandler extends BaseResultSetHandler {
#Override
public Object handleResult() throws SQLException {
int cnt=0;
while(resultSet.next()){
cnt=getInteger("cnt");
}
return cnt;
}
}
public HashMap<String,String> getMajorData() throws InstantiationException, SQLException, Exception, Throwable{
LinkedHashMap<String,String> list = new LinkedHashMap<String,String>();
list=(LinkedHashMap<String, String>) executePreparedQuery(getMajorDataSql(), null, new getMajorDataHandler(), null);
return list;
}
private String getMajorDataSql() {
StringBuffer query=new StringBuffer();
query.append("select RMH_ode,MH_Name from RECMH order by MH_NM for read only");
return query.toString();
}
class getMajorDataHandler extends BaseResultSetHandler {
#Override
public Object handleResult() throws SQLException {
LinkedHashMap<String,String> list = new LinkedHashMap<String,String>();
while(resultSet.next()){
String RMH_CD=resultSet.getString("RMH_CD");
String MH_NM=resultSet.getString("MH_Name");
list.put(RMH_CD+"*"+MH_Name, RMH_CD+"-"+MH_Name);
}
return list;
}
}
And I have to also know it is sharing BaseResultSetHandler resultSet Object

How can I add an ArrayList to a jtable?

I've been working on a web-service that returns an arraylist. How can I add the returning arraylist to jtable and display?
ArrayList customerDetails = new ArrayList();
try {
String sqlQuery = "SELECT * FROM customer WHERE AccountNumber="+accountNumber;
PreparedStatement stmt = DatabaseConnection.dBconn().prepareStatement(sqlQuery);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
customerDetails.add(rs.getString("Name"));
customerDetails.add(rs.getString("DoB"));
customerDetails.add(rs.getString("Address"));
customerDetails.add(rs.getString("Mobile"));
customerDetails.add(rs.getString("Email"));
customerDetails.add(rs.getString("AccountType"));
customerDetails.add(rs.getString("AccountNumber"));
customerDetails.add(rs.getString("SortCode"));
customerDetails.add(rs.getString("Balance"));
customerDetails.add(rs.getString("Card"));
}
return customerDetails;
} catch (SQLException err) {
System.out.println(err.getMessage());
}
return customerDetails;
Let's start with the fact that your ArrayList is not structured as a row/columns grouping, you will need a List within a List, where the outer list is the rows and the inner list are the column values
While we're at it, let's also make use of the PreparedStatement properly and manage the resources so they are closed properly while we're at it
ArrayList<List<String>> customerDetails = new ArrayList<>(25);
String sqlQuery = "SELECT * FROM customer WHERE AccountNumber=?";
try (PreparedStatement stmt = DatabaseConnection.dBconn().prepareStatement(sqlQuery)) {
stmt.setString(1, accountNumber);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
List<String> rowDetails = new ArrayList<>(10);
rowDetails.add(rs.getString("Name"));
rowDetails.add(rs.getString("DoB"));
rowDetails.add(rs.getString("Address"));
rowDetails.add(rs.getString("Mobile"));
rowDetails.add(rs.getString("Email"));
rowDetails.add(rs.getString("AccountType"));
rowDetails.add(rs.getString("AccountNumber"));
rowDetails.add(rs.getString("SortCode"));
rowDetails.add(rs.getString("Balance"));
rowDetails.add(rs.getString("Card"));
customerDetails.add(rowDetails);
}
}
} catch (SQLException err) {
System.out.println(err.getMessage());
}
return customerDetails;
Have a look at Using Prepared Statements and The try-with-resources Statement for more details
Now, we need a TableModel which can support it, at very basic level...
public class ListTableModel extends AbstractTableModel {
private List<List<String>> rows;
private List<String> columnNames;
public ListTableModel(List<String> columnNames, List<List<String>> rows) {
this.rows = new ArrayList<>(rows);
this.columnNames = columnNames;
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return columnNames.size();
}
#Override
public String getColumnName(int column) {
return columnNames.get(column);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
Class type = String.class;
return type;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
List<String> rowData = rows.get(rowIndex);
return rowData.get(columnIndex);
}
}
This takes a List for the column names and a List<List> for the row data.
Personally, I'd prefer to wrap the data into some kind of Plain Old Java Object (POJO) as it encapsulates the data and provides greater flexibility when displaying it (ie, I need to display all the properties of the object if I don't want to)
Take a look at How to Use Tables for more details

Java SQL safely check if column exists

I need to have dynamic SQL which accepts table and column names from users and uses those in queries. Right now I do this with
public Object doSearch(String table, List<String> columns) {
//... some logic
String.format("SELECT %s from %s", String.join(", ", columns), table");
//... some execution and return
}
The source is NOT trusted, so I want to do a whitelist of table and column names, but that list changes. The list of valid tables is strictly the list of tables on my_schema and the list of valid columns is strictly the columns on that particular table.
I've searched around SO and gotten a solution that looks something like:
private boolean validate(String tableName, List<String> columnNames) throws SQLException {
return tableExist(tableName) && columnNames.stream().allMatch(cn -> columnExistsOnTable(tableName, cn));
}
private boolean tableExist(String tableName) throws SQLException {
try (ResultSet rs = connection.getMetaData().getTables(null, schema, tableName, null)) {
while (rs.next()) {
String tName = rs.getString("TABLE_NAME");
if (tName != null && tName.equals(tableName)) {
return true;
}
}
}
return false;
}
private boolean columnExistsOnTable(String tableName, String columnName) {
try (ResultSet rs = connection.getMetaData().getColumns(null, schema, tableName, columnName)) {
while (rs.next()) {
String tName = rs.getString("COLUMN_NAME");
if (tName != null && tName.equals(tableName)) {
return true;
}
}
} catch (SQLException sqle) {
return false;
}
return false;
}
Is this safe and correct?
For each of those methods, you could do this one time in an initialization method and cache the table/column names so you don't have to do a database check every time... something like this:
private Map<String, Set<String>> tableColNames = new HashMap();
private void initCache(){
// build the cache
// get all tables
// get all columns
// add tables and columns to the map
}
private boolean tableExist(String tableName) throws SQLException {
return tableColNames.containsKey(tableName);
}
private boolean columnExistsOnTable(String tableName, String columnName) {
if(tableExist(tableName)){
return tableColNames.get(tableName).contains(columnName);
} else {
return false;
}
}
// could make a method for checking a list of Strings too...
// return tableColNames.get(tableName).containsAll(columnName);
https://docs.oracle.com/javase/7/docs/api/index.html?java/sql/ResultSetMetaData.html

Why does the new element added into my ArrayList overwrite all previous values?

I retrieve values from a database, create a new Transaction Object and add it to an ArrayList<Transaction>, which I then return.
The problem is that everytime returnList.add(t); is called, instead of just adding the Transaction, it also replaces all old Transactions with the new one.
Where is the error that causes this behaviour?
public ArrayList<Transaction> getTransactions(long intervall, Map<String, String> transactionFields) {
connect();
ArrayList<Transaction> returnList = new ArrayList<Transaction>();
Statement sta;
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
now = now.minusSeconds(intervall);
try {
sta = conn.createStatement();
String Sql = "...";
ResultSet rs = sta.executeQuery(Sql);
while (rs.next()) {
Transaction t = new Transaction(rs.getString("No"), transactionFields);
t.set("AgentName", rs.getString("cname"));
returnList.add(t);
}
} catch (SQLException e) {
...
}
disconnect();
return returnList;
}
Here is the Transaction class:
public class Transaction {
private Map<String, String> fields;
public Transaction(String number, Map<String, String> transactionFields) {
fields = transactionFields;
fields.put("Number", number);
}
public void set(String field, String value) {
fields.put(field, value);
}
public String get(String field) {
return fields.get(field);
}
public Map<String, String> getFieldMap() {
return fields;
}
#Override
public String toString() {
return fields.toString();
You are using the same Map in all your Transaction instances.
Instead, pass in a new one each time:
Transaction t = new Transaction(rs.getString("No"), new HashMap<String, String>());
or just create the Map inside your Transaction class.

JdbcTemplate multiple result sets

I am trying to find an easy way to deal with Stored Procedures / SQL returning multiple result sets. I have been using the SimpleJdbcOperations#queryForList() method however this will only return the first result set as a List<Map<String, Object>>. I need to be able to get multiple result sets, ideally as a Collection of List<Map<String, Object>> or something. The program I am writing is a middleware component so I don't know what the SQL will be, or the form of the result set.
I think I have to use the JdbcOperations class which gives me access to more methods, including execute(CallableStatementCreator csc, CallableStatementCallback<T> action) but now I am stuck.
CallableStatementCallback<T> callback = new CallableStatementCallback<T>() {
#Override
public T doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException
{
boolean results = cs.execute(request);
while(results)
{
ResultSet result = cs.getResultSet();
results = cs.getMoreResults();
}
return null;
}
};
I am not really sure how to use the method though, or what to do with the ResultSet to get my generic List<Map<String, Object>>s.
I managed to get a Set<ResultSet> using this code,
private Set<ResultSet> executeProcedure(final String sql)
{
return jdbc.execute(new CallableStatementCreator() {
#Override
public CallableStatement createCallableStatement(Connection con) throws SQLException
{
return con.prepareCall(sql);
}
}, new CallableStatementCallback<Set<ResultSet>>() {
#Override
public Set<ResultSet> doInCallableStatement(CallableStatement cs) throws SQLException
{
Set<ResultSet> results = new HashSet<>();
boolean resultsAvailable = cs.execute();
while (resultsAvailable)
{
results.add(cs.getResultSet());
resultsAvailable = cs.getMoreResults();
}
return results;
}
});
}
Just going to look at translating a ResultSet into List<Map<String, Object>>.
You can use the resultSet.getMetaData() method to work out what columns are in the data:
ResultSetMetaData meta = resultSet.getMetaData();
int colcount = meta.getColumnCount();
for (int i = 1; i <= colcount; i++)
{
String name = meta.getColumnLabel(i); // This is the name of the column
int type = meta.getColumnType(i); // from java.sql.Types
// Maybe add to a Map,List, etc...
}
You can then do as the other commentors have mentioned do a loop through the ResultSet pulling out the data you need:
while (resultSet.hasNext())
{
resultSet.next();
// Find the columns you want to extract (via the above method maybe) and add to your row.
}
This code might be easier to use in most cases:
Map<String,Object> resultSets = new JdbcTemplate(dataSource)
.call(con -> con.prepareCall(query), new ArrayList<>());
I have used below method to get List of ResultSet in form of List<Map<String, Object>>
public List<List<Map<String, Object>>> executeProcedure(final String sql) {
return jdbcTemplate.execute(new CallableStatementCreator() {
#Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
return con.prepareCall(sql);
}
}, new CallableStatementCallback<List<List<Map<String, Object>>>>() {
#Override
public List<List<Map<String, Object>>> doInCallableStatement(CallableStatement cs) throws SQLException {
boolean resultsAvailable = cs.execute();
List<List<Map<String, Object>>> list = new ArrayList<List<Map<String, Object>>>();
while (resultsAvailable) {
ResultSet resultSet = cs.getResultSet();
List<Map<String, Object>> subList = new ArrayList<Map<String, Object>>();
while (resultSet.next()) {
ResultSetMetaData meta = resultSet.getMetaData();
int colcount = meta.getColumnCount();
Map<String, Object> map = new HashMap<String, Object>();
for (int i = 1; i <= colcount; i++) {
String name = meta.getColumnLabel(i);
map.put(name, resultSet.getString(i));
}
subList.add(map);
}
list.add(subList);
resultsAvailable = cs.getMoreResults();
}
return list;
}
});
}

Categories