Working with a saved Access parameter query under (JDBC-)ODBC - java

In my Java application I have to use data that comes from an Access 2010 database. I used the graphical query creator from Access to create the appropriate query and it works great.
Unfortunately, when I try to use a prepared statement with that query (in order to use a parameter) in my Java application I got an NPE
messageChildrenRequest.setString(1, blockId);
ResultSet result = messageChildrenRequest.executeQuery();
The NPE occurs when i set the parameter with setString() and my query is not execute but when i look with the debugger the statement is not null...
My query given by access is :
SELECT IRSIDD.[BLOCK ID], IRSIDD.[IDENTIFICATION CHIFFREE], IRSIDD.MSG_ID, MAIN.SUB_FIELD_ID, MAIN.ORDER, FIELD.[FIELD NAME], FIELD.TYPE, FIELD.[RC 'TYPE] "
FROM IRSIDD LEFT JOIN (MAIN LEFT JOIN FIELD ON MAIN.SUB_FIELD_ID = FIELD.[FIELD ID]) ON IRSIDD.[BLOCK ID] = MAIN.BLOCK_ID "
WHERE ((IRSIDD.[BLOCK ID])=?)
The StackTrace gives me :
Exception in thread "main"
java.lang.NullPointerException
at sun.jdbc.odbc.JdbcOdbcPreparedStatement.clearParameter(Unknown Source)
at sun.jdbc.odbc.JdbcOdbcPreparedStatement.setChar(Unknown Source)
at sun.jdbc.odbc.JdbcOdbcPreparedStatement.setString(Unknown Source)
When I tried a very simple prepared statement :
SELECT * FROM table1 WHERE table1.id = ?
I didn't get any NPE when setting the parameter so I suspect that Access and java JDBC do not have the same way to deal with join.
Does someone already that kind of problem or can confirm that the structure of my query is the problem here?

Connection connection = null;
CallableStatement callStmt = null;
String myParam = "test";
String statement = "SELECT * FROM table1 WHERE table1.id = ?";
try {
connection = DatabasePoolUtil.getDefaultConnection(); //Connects
callStmt = connection.prepareCall(statement);
callStmt.setString(1,myParam);
callStmt.execute();
}
catch (SQLException ex) {
// Do something
}
finally { // connection has to be closed
if (callStmt != null) {
callStmt.close();
}
if (connection != null) {
connection.close();
}
}

The ODBC (and OLEDB) interfaces to an Access database expose different types of saved Access queries as either "Views" or "Stored Procedures":
Access query appears under ODBC/OLEDB as
------------------------------- ---------------------------
Select query without parameters View
Select query with parameters Stored Procedure
Append query (INSERT) Stored Procedure
Update query Stored Procedure
Delete query Stored Procedure
Since your Access saved query has parameters it will look like a Stored Procedure under ODBC and therefore you need to use a CallableStatement to work with it.
For example, given the following saved parameter query named [myParameterQuery] in Access
PARAMETERS specificID Long;
SELECT Table1.*
FROM Table1
WHERE (((Table1.ID)=[specificID]));
we need to use the following Java code to retrieve the row for ID=3:
String connectionString = "jdbc:odbc:"
+ "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};"
+ "DBQ=C:/Users/Public/32224442.accdb;";
try (Connection conn = DriverManager.getConnection(connectionString)) {
try (CallableStatement cs = conn.prepareCall("{call myParameterQuery(?)}")) {
cs.setInt(1, 3); // set "specificID" parameter to 3
try (ResultSet rs = cs.executeQuery()) {
rs.next();
System.out.println(rs.getInt(1));
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(0);
}
The corresponding C# code would be:
string myConnectionString =
#"Driver={Microsoft Access Driver (*.mdb, *.accdb)};" +
#"Dbq=C:\Users\Public\32224442.accdb;";
using (var con = new OdbcConnection(myConnectionString))
{
con.Open();
using (var cmd = new OdbcCommand("{CALL myParameterQuery (?)}", con))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("?", OdbcType.Int).Value = 3; // set "specificID" parameter to 3
using (OdbcDataReader rdr = cmd.ExecuteReader())
{
rdr.Read();
Console.WriteLine(rdr[0]);
}
}
}

Related

Correct way of calling reference cursors in PostgreSQL 11 and above using JDBC driver

I need some suggestion on how to get the data through PostgreSQL JDBC driver from stored procedures using reference cursors.
Since PostgreSQL 11, it supports stored procedures with create procedure command instead of create function.
I have a scenario in which I want to fetch data from a stored procedure using a reference cursor.
My stored procedure SQL looks like as shown below
CREATE OR REPLACE PROCEDURE public.pr_sampleuser(
p_firstuser character varying,
INOUT p_qusers refcursor)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
OPEN p_qusers FOR
SELECT first_name,last_name,address
FROM public.test_user
WHERE UPPER(first_name) = UPPER(p_firstuser);
END;
$BODY$;
When we want to fetch the data using the JDBC driver, the first thing we need to add to the connection string is escapeSyntaxCallMode=call.
Following is the code-snippet that I am using to fetch the data,
try {
Properties props = new Properties();
props.setProperty("escapeSyntaxCallMode", "call");
Connection conn = DriverManager.getConnection(url,props);
String storedProc = "{call public.pr_sampleuser(?,?)}";
CallableStatement cs = conn.prepareCall(storedProc);
cs.setString(1,"Umesh");
cs.setObject(2,null);
cs.registerOutParameter(2,Types.REF_CURSOR);
conn.setAutoCommit(false);
// run StoredProcedure
cs.execute();
// get refcursor and convert it to ResultSet
ResultSet resultSet = (ResultSet) cs.getObject(2);
while (resultSet.next()) {
String firstName = resultSet.getString("first_name");
String lastname = resultSet.getString("last_name");
String address = resultSet.getString("address");
System.out.println(firstName);
System.out.println(lastname);
System.out.println(address);
}
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
In this I am passing the second parameter as null using
cs.setObject(2,null);
I wanted to check if this is the correct way to fetch or if there is any better way to get the data.

Fetch data from database using procedure

I am trying to read data from oracle database by calling procedure from java code.
If I am running the procedure from sqldeveloper, I can see that the procedure is giving me the correct output.But when I try to run using java program,I am getting error.
Procedure:
CREATE OR REPLACE PACKAGE BODY VISIONEMPLOYEES AS
PROCEDURE Employees(
p_id IN NUMBER,
p_ref_cursor OUT sys_refcursor )
AS
BEGIN
OPEN p_ref_cursor FOR
SELECT id, name, age FROM emp WHERE id = p_id;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END Employees;
END VISIONEMPLOYEES;
Java Code:
public static void callOracleStoredProcOUTParameter()
{
Connection conn = null;
Statement stmt = null;
CallableStatement cb = null;
String qry = "{VISIONEMPLOYEES.Employees(?,?)}";
try {
conn = getDbConnection();
cb = conn.prepareCall(qry);
cb.setInt(1, 1);
cb.registerOutParameter(2, OracleTypes.CURSOR);
cb.executeUpdate();
String userName = cb.getString(2);
System.out.println("UserName is : " + userName);
} catch (Exception e) {
System.out.println(e);
}
}
java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement
Please tell me what is wrong with the above written code.
You're missing the call keyword in your qry String.
String qry = "{call VISIONEMPLOYEES.Employees(?,?)}";
(see https://docs.oracle.com/javase/7/docs/api/java/sql/CallableStatement.html)

Calling PL/SQL package code in a Java Program

I am trying to call a procedure defined with a PL/SQL package in a Java program.
I am aware one can call stored procedures using connection.prepareCall in Jdbc. But there is very little information out there on how to call a procedure within a package.
I am at a stage in development where i am still considering what db framework to use. Just wondering what are the pros and cons of using JDBC for PLSQL ? For this usecase are there better alternatives to JDBC ?
Follow the simple steps below:
public static final String SOME_NAME = "{call schema_name.org_name_pkg.return_something(?,?)}"; // Change the schema name,packagename,and procedure name.
// Simple JDBC Connection Pooling
// Here I am passing param companyId which is IN param to stored procedure which will return me some value.
Connection conn = null;
CallableStatement stmt = null;
ResultSet rset = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://hostname:port/dbname","username", "password");
stmt = conn.prepareCall(SOME_NAME);//We have declared this at the very top
stmt.setString(1, companyid);//Passing CompanyID here
stmt.registerOutParameter(2, OracleTypes.CURSOR);//Refcursor selects the row based upon query results provided in Package.
stmt.execute();
rset = (ResultSet) stmt.getObject(2);
while (rset.next()) {
String orgId=rset.getString("RPT_ORG_ID");
// When using refcursor easy to get the value just by using Column name
String orgName=rset.getString("RPT_ORG_NAME");
// Some Logic based what do you want to do with the data returned back from query
} catch (Exception e) {
LOGGER.error("Error extracting ", e);
} finally {
DBUtils.cleanUp(conn, stmt, rset);
}
// Clean and close you connection

How to Pass Multiple Timestamps as Dynamic Parameters into a Derby Query?

I'm converting a Java application from PostGresSQL to Derby (10.10.1.1). The PG database has many procedures that ideally will transfer to Derby procedures.
One of the PG stored procedures passes an array of Timestamps, similar to this Procedure/SQL:
CREATE FUNCTION getDownloads(_download_array timestamp without time zone[])
LANGUAGE plpgsql AS $$
DECLARE mycurs refcursor;
BEGIN
SELECT * FROM download_time d
WHERE d.downloadtime = ANY(_download_array);
END
RETURN mycurs;
Derby procedures are basically declarations that reference your procedures class that contains public static Java methods. The methods typically use the java.SQL PreparedStatement object, and may contain dynamic parameters. The procedure is called via the java.SQL CallableStatement object, with set param values, executed to return a ResultSet.
I would like to translate the above PG procedure into a Derby procedure that accepts multiple Timestamp values, possibly using the ANY or IN statements. In limited searches, it appears that Derby does not support arrays as dynamic parameters.
Using the Squirrel SQL client, this syntax proves acceptable:
SELECT * FROM download_time d
WHERE d.downloadtime
IN('2011-11-13 13:24:00.0', '2011-11-13 13:28:00.0', '2014-05-06 07:08:09.0')
However in practice, passing comma-delimited Timestamps to the IN or ANY statements does not work, pseudo-code below:
try {
Connection conn = getConnection();
CallableStatement cstmt = null;
cstmt = conn.prepareCall("{ call getDownloads(?) }");
cstmt.setTimestamp(3, "'2011-11-13 13:24:00.0', '2011-11-13 13:28:00.0'");
//Also tried this:
cstmt.setString(3, "2011-11-13 13:24:00.0, 2011-11-13 13:28:00.0");
cstmt.execute();
rs = cstmt.getResultSet();
while (null != rs && rs.next()) {
...
}
} catch (SQLException sqle) {
...handle errors
}
Following the above examples, this error occurs:
java.sql.SQLException:
The syntax of the string representation of a date/time value is incorrect.
I'm in search of alternative methods, and am considering solutions I've found in an excellent article on StackOverflow, PreparedStatement IN clause alternatives?
I would be willing to consider simply writing dynamic SQL instead of a parameterized procedure, but the real query is rather beastly. :)
Since no one offered an answer, I'm posting my solution to the problem. The solution is to pass a String variable, "downloadTimes" containing concatenated date/times in a comma-delimited-like format. For brevity, the NULL-check condition was excluded. If a NULL is passed, that line is simply excluded.
Here is the procedure:
public static void getDownloads(int theId, String downloadTimes, ResultSet[] rs)
throws SQLException {
String DML = null;
PreparedStatement ps = null;
DML = "SELECT d.* FROM download_time d WHERE d.id = ? " +
"AND d.downloadtime IN(" + downloadTimes + ") " : "") + //Add chk null condition
"ORDER BY 1, 2 DESC, 3 ";
ps = conn.prepareStatement(DML);
ps.setInt(1, theId);
rs[0] = ps.executeQuery();
}
Note that the "getDownloads" procedure is declared in Derby later in the same class (see declaration in my original question), left out for simplicity. The procedure is called by a method in a different class:
public Map<GregorianCalendar, List<Fault>> getDownloadFaultList(
Integer theId, String subsystem, List<GregorianCalendar> downloadTimes) {
CallableStatement cstmt = null;
ResultSet rs = null;
String downloadCalListToCsv = null;
// parseGregorianCalListToCsv() creates a CSV string out of dates.
// I.e., "2011-11-13 13:24:00.0, 2011-11-13 13:28:00.0"
if (false == downloadTimes.isEmpty()) {
downloadCalListToCsv = DataTypeConverter
.parseGregorianCalListToCsv(downloadTimes, timestampFormat);
}
try {
cstmt = getConn().prepareCall("{ call getDownloads(?, ?) }");
// Register the parameters
cstmt.setInt(1, theId);
// Get timezone from first entry, assuming all same timezone
if (! downloadTimes.isEmpty()) {
cal.setTimeZone(downloadTimes.get(0).getTimeZone());
}
cstmt.setString(2, downloadCalListToCsv);
cstmt.execute();
rs = cstmt.getResultSet();
while (null != rs && rs.next()) {
//Use the download timestamps here
}
} catch (SQLException sqle) {
//error handling here
} finally {
//Close resources
close(rs, cstmt);
}
return faultMap;
}
The solution is not elegant, but works in practice.

Unable to get value from ResultSet

I am working on a web application using Java and MySQL.
I created a method that is supposed to return an ArrayList of the respective column name based on the various tables in the database.
However, when I debugged the method, I realised the while(rs.next()) causes an error. I used this site for reference, hence I am not sure what went wrong.
This is the code. Thanks.
// Returns the the all the columns in the table
public ArrayList getColumnName(String tableName) throws SQLException {
ResultSet rs = null;
List<String> columnName = new ArrayList<String>();
Statement st = null;
Connection con = null;
try {
// Get a connection from the connection factory
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/information_schema", "root", "xxxx");
// Create a Statement object so we can submit SQL statements to the driver
st = con.createStatement();
StringBuilder sql = new StringBuilder("SELECT column_name FROM information_schema.columns " +
"WHERE table_schema = 'testDB' AND table_name = '");
sql.append(tableName).append("'");
rs = st.executeQuery(sql.toString());
while (rs.next()) { // getting error..
columnName.add(rs.getString("column_name"));
}
} catch (SQLException ex) {
Logger.getLogger(ModificationPage.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (con != null || st != null) {
st.close();
con.close();
}
}
return (ArrayList) columnName;
}
According to the Javadoc of 1.6 (not sure which version of Java you're using):
Throws:
SQLException - if a database access error occurs or this method is called on a closed result set
It's very, very unlikely that if you actually got to the line where rs.next() was called, that a database error occurred just then. So, the most likely result is that the result set was closed.
Please alter your code to the following and see if you still get the error on the same line:
while (!rs.isClosed() && rs.next()) { // getting error..
columnName.add(rs.getString("column_name"));
}
Also, Holy SQL Injection Attack, Batman!
Taking the raw string as you're doing and enclosing it within single quotes leads this code to have an SQL injection vulnerability. Basically all a malicious user has to do is end your query with a single quote (') and run a query of their own afterwards.
So, the exception never happens ?
A query error should be thrown at rs = st.executeQuery(sql.toString()) if that were the case, but if it make it to whileand didn't iterate, it's because of an empty resultset
Maybe you're passing wrong arguments to the query ?

Categories