How to pass array of integer to Informix stored procedure - java

In Java, how do I pass values of type set to a procedure. This seems too basic, but I can't solve it, I spent days searching sample Java code on how to pass set values to Informix procedure.
Tools
IBM Informix Dynamic Server Version 12.10.FC13
JDBC 4.10.14, 4.50.7
Java version "1.8.0_172"
Informix procedure
create procedure sp_demo_set_arg(
arg1 set(integer not null)
)
...
end procedure
Java code
#Override
public Integer callProcedure(List<Integer> listOfId) {
String sql = "{ call sp_demo_set_arg(?) }";
#SuppressWarnings("rawtypes")
java.util.HashSet arg1 = new HashSet();
Integer intObject;
int i;
for (i=1; i <= 3; i++)
{
intObject = new Integer(i);
arg1.add(intObject);
}
Connection conn = null;
try {
conn = dataSource.getConnection();
CallableStatement stmt = conn.prepareCall(sql);
stmt.setObject(1, arg1);
stmt.executeUpdate();
return 0;
} catch (SQLException e) {
e.printStackTrace();
}
return 1;
}
Stacktrace
...
java.sql.SQLException: Routine (sp_demo_set_arg) can not be resolved.
at com.informix.jdbc.IfxSqli.addException(IfxSqli.java:3133)
at com.informix.jdbc.IfxSqli.receiveError(IfxSqli.java:3417)
at com.informix.jdbc.IfxSqli.dispatchMsg(IfxSqli.java:2324)
at com.informix.jdbc.IfxSqli.receiveMessage(IfxSqli.java:2249)
at com.informix.jdbc.IfxSqli.executeCommand(IfxSqli.java:850)
at com.informix.jdbc.IfxResultSet.executeUpdate(IfxResultSet.java:230)
at com.informix.jdbc.IfxStatement.executeUpdateImpl(IfxStatement.java:1054)
at com.informix.jdbc.IfxPreparedStatement.executeUpdate(IfxPreparedStatement.java:396)
at
...

Your java code may fail with an -674 "Routine can not be resolved" error because the server may not know the parameter type at execution.
Try giving it some 'hints' changing '?' for a '?::SET(integer not null)'
Something like:
D:\Infx\work\Java>cat t2.java
import java.sql.*;
import java.util.*;
public class t2 {
public static void main( String [] args ) {
Connection conn = null;
ResultSet dbRes = null;
Statement is = null;
try {
Class.forName("com.informix.jdbc.IfxDriver");
conn = DriverManager.getConnection("jdbc:informix-sqli://420ito:9091/stores7:INFORMIXSERVER=ids1410;user=informix;password=passw;SQLIDEBUG=pp;");
is = conn.createStatement();
is.executeUpdate("drop table t2; create table t2 (c1 SET(integer not null) );");
java.util.HashSet arg1 = new HashSet();
Integer intObject;
int i;
for (i=1; i <= 3; i++)
{
intObject = new Integer(i);
arg1.add(intObject);
}
try {
//CallableStatement stmt = conn.prepareCall("{ CALL p2(?)}");
CallableStatement stmt = conn.prepareCall("{ CALL p2(?::SET(integer not null))}");
stmt.setObject(1, arg1);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM t2");
while (rs.next()) {
java.util.HashSet set = (HashSet) rs.getObject(1);
Iterator it = set.iterator();
Object obj;
i = 0;
while (it.hasNext())
{
obj = it.next();
System.out.println(" element[" + i + "] = " + obj.toString());
i++;
}
}
rs.close();
conn.close();
}
catch ( Exception e ) {
System.err.println(e);
e.printStackTrace();
}
}
}
D:\Infx\work\Java>javac t2.java
Note: t2.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
D:\Infx\work\Java>java t2
element[0] = 1
element[1] = 2
element[2] = 3
D:\Infx\work\Java>

Related

How to frame sql queries in java without SQL injection vulnerability? [duplicate]

I am preparing a SQL statement from values passed through a query string. ( I am using the Play! framework. Basically what I'm running into (not really an issue just something I don't like very much) is that when I want to use ? in the SQL string and set them later with dynamic values.
This is what I have:
String sql = "SELECT * FROM foobar_table WHERE";
if ( foo != 0 )
sql += " AND foo=?";
if ( !bar )
sql += " AND bar=?";
try{
PreparedStatement getStmt = con.prepareStatement(sql);
if ( foo != 0 )
getStmt.setInt(1,foo);
if ( foo != 0 && !bar )
getStmt.setBoolean(2, bar);
else
getStmt.setBoolean(1, bar);
} catch (SQLException e ){
e.printStackTrace();
}
This does work but as you can see not very intuitive. It's OK when there are 2 dynamic values but when you get up to 5 or 6 this would just get ridiculous.
Is there an easier way of doing this to make it more flexible so that I would know how to fill in all the ? in a better fashion?
An example (was too long for comment):
String sql = "SELECT * FROM foobar_table WHERE 1 = 1 ";
ArrayList paramList = new ArrayList();
if ( foo != 0 ) {
sql += " AND foo=?";
paramList.add(foo);
}
if ( !bar ) {
sql += " AND bar=?";
paramList.add(bar);
}
try{
PreparedStatement getStmt = con.prepareStatement(sql);
int index = 1;
for (Object param : paramList) {
getStmt.setObject(index, param);
index++;
}
// execute
} catch (SQLException e ){
e.printStackTrace();
}
Something like this maybe (just rough code but you get the idea):
class Param{
final int type;
final Object value;
Param(int type, Object value){
this.type = type;
this.value = value;
}
}
final List<Param> params = new ArrayList<>();
final StringBuilder sql = new StringBuilder("SELECT * FROM bcu_venue_events WHERE 1=1");
int foo = 0;
boolean bar = true;
if (foo != 0){
sql.append(" AND foo=?");
params.add(new Param(Types.INTEGER, foo));
}
if (!bar){
sql.append(" AND bar=?");
params.add(new Param(Types.BOOLEAN, bar));
}
try(Connection conn = null; PreparedStatement getStmt = conn.prepareStatement(sql.toString())) {
for(int i = 0; i < params.size(); i++){
Param p = params.get(i);
getStmt.setObject(i + 1, p.value, p.type);
}
} catch (SQLException e) {
e.printStackTrace();
}
How about this:
String sql = "SELECT * FROM foobar_table WHERE 1=1";
if ( foo != 0 )
sql += " AND foo=" + foo;
if ( !bar )
sql += " AND bar=" + bar;
try{
PreparedStatement getStmt = con.prepareStatement(sql);
} catch (SQLException e ){
e.printStackTrace();
}

Looping try/catch statement

I'm trying to take two random rowid from my database. Everything works but I have a scenario when there is only one rowid. I want to make a loop on my try/catch until there is second number in my database.
What I'm doing wrong? Thank you
public void Kaslaimejo() {
String sql = "SELECT rowid FROM Zaidejai WHERE Pirmas < 4 ORDER BY random() LIMIT 2";
Integer value1 = null, value2 = null;
Integer judesiukas1 = null, judesiukas2 = null;
int a = 0;
int k = 15; // kiek kartu? Reikia infinity padaryti
for (a = 0; a < 3; a++) {
try {
Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
value1 = rs.getInt("rowid");
if (rs.next()) {
value2 = rs.getInt("rowid");
PreparedStatement buvo = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo.setInt(1, i);
buvo.setInt(2, value1);
int buvolala = buvo.executeUpdate ();
PreparedStatement buvo2 = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo2.setInt(1, i);
buvo2.setInt(2, value2);
int buvolala2 = buvo2.executeUpdate ();//
i++;
}
System.out.println("Pirmas zaidejas" + value1); // atspausdina 1 random zaideja is duomenu bazes
System.out.println("Antras zaidejas" + value2); // atspausdina 2 random zaideja is duomenu bazes
}
} catch (SQLException e) {
a--;
//System.out.println(e.getMessage());
}
}
}
Right now my program loops two times and then gives me SQLException. How I can loop my program until there is no SQLException?
OK, I've tried to write what I think you're trying to do.
You wait for ever until someone puts at least two entries in the database.
You extract two values, process them, then wait some more.
Some points to watch out:
1. Object comparisons need to be made with .equals() not with ==
2. You might want to provide some way to break out of the infinite loop I've written (while(true)).
3. Careful with null values. They might produce NullPointerException.
4. Try to break up your code into methods. Each large block of code could go into each own method.
public void Kaslaimejo(){
String sql = "SELECT rowid FROM Zaidejai WHERE Pirmas < 4 ORDER BY random() LIMIT 2";
Integer judesiukas1 = null, judesiukas2 = null;
while(true) {
List<Integer> values = new ArrayList<>();
while (values.size() < 2) {
try (Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if( rs.next() ){
Integer value = rs.getInt("rowid");
values.add(value);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
try( Connection conn = Serveris.connect()) {
PreparedStatement buvo = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo.setInt(1, i);
buvo.setInt(2, values.get(0));
int buvolala = buvo.executeUpdate ();
PreparedStatement buvo2 = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo2.setInt(1, i);
buvo2.setInt(2, values.get(1));
int buvolala2 = buvo2.executeUpdate ();//
i++;
}catch (SQLException e) {
e.printStackTrace();
}
Connection conn = Serveris.connect();
try {
PreparedStatement pstmt = conn.prepareStatement("SELECT Pirmas FROM Zaidejai WHERE rowid = ?");
PreparedStatement pstmt2 = conn.prepareStatement("SELECT Pirmas FROM Zaidejai WHERE rowid = ?");
pstmt.setInt(1, values.get(0));
pstmt2.setInt(1, values.get(1));
ResultSet myrsv = pstmt.executeQuery();
ResultSet myrsv2 = pstmt2.executeQuery();
{
if (myrsv.next()) {
judesiukas1 = myrsv.getInt("Pirmas");
if (myrsv2.next()) {
judesiukas2 = myrsv2.getInt("Pirmas");
}
}
//System.out.println("Pirmo zaidejo veiksmas" + myrsv.getInt("Pirmas"));
//System.out.println("Antro zaidejo veiksmas" + myrsv2.getInt("Pirmas"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (judesiukas1.equals(judesiukas2)) // careful here. NullPointerException may happen.
{
try {
PreparedStatement laim = conn.prepareStatement("UPDATE Zaidejai SET Rezultatas = ? WHERE rowid = ?"); // ble ble update reikia naudoti , o ne insert into. Insert kai sukuriame nauja kazka tik
PreparedStatement laim2 = conn.prepareStatement("UPDATE Zaidejai SET Rezultatas = ? WHERE rowid = ?");
laim.setString(1, "Lygiosios");
laim.setInt(2, values.get(0));
laim2.setString(1, "Lygiosios");
laim2.setInt(2, values.get(1));
int irasyk = laim.executeUpdate (); // kodel executeupdate, o ne executequery????
int irasyk2 = laim2.executeUpdate (); // kodel executeupdate, o ne executequery????
{
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print("Lygiosios");
} else {
// (1) - Rock
// (2) Scissors
// (3) - Paper
switch (values.get(0)){
case 1:
if (judesiukas2 == 2)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
case 2:
if (judesiukas2 == 3)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
case 3:
if (judesiukas2 == 1)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
}
}
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The logic becomes easier if you add the values to a list
var values = new ArrayList<Integer>();
while (values.Count < 2) {
try (Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql))
{
while (values.Count < 2 && rs.next()) {
Integer v = rs.getInt("rowid");
values.Add(v);
}
} catch (SQLException e) {
}
}
//TODO: process the values here
The advantage is, that you can retrieve one value at the first database query and the second at a later one or both in the same round and you don't have to keep track of which one of two variables to use.
(Bear with me with the syntax details, I'm not a Java programmer.)
How i can loop my program until there is no SQLException?
Change this (because, it will only allow to loop two times)
for (a = 0; a < 2; a++) {
to
while(true)
Put everything inside while(true), if exception occurred, then it will come out from the while loop. Something similar :
try
{
while(true)
{
...
...
}
...
}
catch(SQLException e)
{
// do somthing
}

APOSTROPHE issue with java and SQL

I have code, where I have single quote or APOSTROPHE in my search
I have database which is having test table and in name column of value is "my'test"
When running
SELECT * from test WHERE name = 'my''test';
this works fine
If I use the same in a Java program I am not getting any error or any result
But If I give the name with only single quote then it works
SELECT * from test WHERE name = 'my'test';
Could you please help me out to understand.
Java code is
Connection con = null;
PreparedStatement prSt = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.
getConnection("jdbc:oracle:thin:#localhost:1521:orcl"
,"user","pwd");
String query = "SELECT * from "
+ "WHERE name = ? ";
prSt = con.prepareStatement(query);
String value = "my'mobile";
char content[] = new char[value.length()];
value.getChars(0, value.length(), content, 0);
StringBuffer result = new StringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
if (content[i] == '\'')
{
result.append("\'");
result.append("\'");
}
else
{
result.append(content[i]);
}
}
prSt.setObject(1, result.toString());
int count = prSt.executeUpdate();
System.out.println("===============> "+count);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally{
try{
if(prSt != null) prSt.close();
if(con != null) con.close();
} catch(Exception ex){}
}
You don't have to escape anything for the parameter of a PreparedStatement
Just use:
prSt = con.prepareStatement(query);
prSt.setString("my'mobile");
Additionally: if you are using a SELECT statement to retrieve data, you need to use executeQuery() not executeUpdate()
ResultSet rs = prst.executeQuery();
while (rs.next())
{
// process the result here
}
You might want to go through the JDBC tutorial before you continue with your project: http://docs.oracle.com/javase/tutorial/jdbc/index.html

Potential memory leak in this Java code that produces out of heap error

I can't find the reason why this piece of code when run for a long time produces an out of memory heap error. It runs constantly for 1-2 days before crashing. Can anyone see anything?
I only call a static function from another class that should not keep any resources open and then the mysql stuff but I close them all.
note: some of the variable names were changed.
public class Application {
public static void main(String ...args) throws InterruptedException, IOException {
Data.connectDb(); //init
try {
List<Integer> written = new ArrayList<>();
Connection con = Data.getConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM table2 LIMIT 500");
while (rs.next()) {
Integer mId = rs.getInt("mId");
written.add(mId);
}
Map<Integer,String> bs = new HashMap<>();
rs = st.executeQuery("SELECT * FROM b");
while (rs.next()) {
bs.put(rs.getInt("bId"),rs.getString("name"));
}
st.close();
rs.close();
while (true) {
List<String> abers = new ArrayList<>();
st = con.createStatement();
rs = st.executeQuery("SELECT * FROM table1 WHERE enabled = 1");
while (rs.next()) {
String email = rs.getString("email");
abers.add(email);
}
rs.close();
st.close();
ArrayList<Map> abs = Aber.getAbs(false);
ArrayList<Map> toDispatch = new ArrayList<>();
arbs.forEach((ab) -> {
Integer mId = (Integer) ab.get("mId");
if (!written.contains(mId)) {
written.add(mId);
toDispatch.add(arb);
Pair hLine = (Pair) ab.get("hLine");
Pair dLine = (Pair) ab.get("dLine");
Pair aLine = (Pair) ab.get("aLine");
//todo write it to the database not caring if it's already there as we have a unique constraint
try (Statement st2 = con.createStatement()) {
String sql = "INSERT INTO table1")";
st2.executeUpdate(sql);
} catch (SQLException e) {
e.printStackTrace();
}
}
});
if (toDispatch.size() >0) {
Email email = new Email();
abes.forEach(arber -> email.addRecipient(aber, aber, Message.RecipientType.BCC));
String HTML = "<h3>Dear subscribers</h3>";
email.setTextHTML(HTML);
new Mailer(
new ServerConfig("mail.name.com", 587, "info#mm.com", "mmpass"),
TransportStrategy.SMTP_TLS
).sendMail(email);
}
Thread.sleep(600000);
}
} catch (SQLException sqle) {
System.out.println(sqle.getMessage());
}
}
}

Trouble calling SQL Server stored procedure within Java

Below is a generic class I wrote that calls a stored procedure on the server:
public class StoredProc {
Connection con = null;
ResultSet rs = null;
CallableStatement cs = null;
public StoredProc(String jdbcResource, String storedProcName){
this(jdbcResource, storedProcName, new String[0], new String[0]);
}
public StoredProc(String jdbcResource, String storedProcName, String[] params,String[] paramTypes){
Connection con = new databaseConnection(jdbcResource).getConnection();
//Get length of parameters and sets stored procs params (?, ?, ...etc)
String procParams = "";
int paramSize = params.length;
if(paramSize != 0){
for(int i = 0; i < paramSize; i++){
if(i == paramSize){
procParams += "?";
}else{
procParams += "?, ";
}
}
}
try{
CallableStatement cs = this.con.prepareCall("{?=call "+storedProcName+" ("+procParams+")}");
for(int j = 0; j < params.length; j++){
if (paramTypes[j].equalsIgnoreCase("Int")) {
int x = 0;
try{
x = Integer.parseInt(params[j]);
} catch(Exception e) {}
cs.setInt(j, x);
} else if (paramTypes[j].equalsIgnoreCase("Boolean")) {
boolean x = false;
try{
x = (params[j].equalsIgnoreCase("True")) || (params[j].equalsIgnoreCase("T")) || (params[j].equalsIgnoreCase("1")) || (params[j].equalsIgnoreCase("Yes")) || (params[j].equalsIgnoreCase("Y"));
} catch(Exception e) {}
cs.setBoolean(j, x);
} else if (paramTypes[j].equalsIgnoreCase("String")) {
cs.setString(j, params[j]);
}
}
}catch(Exception e){
System.out.println("---------------------------------------------");
System.out.println("Problem constructing callableStatement: "+e);
System.out.println("---------------------------------------------");
}
}
public ResultSet runQuery(){
try{
rs = cs.executeQuery();
}catch(SQLException e){
System.out.println("---------------------------------------------");
System.out.println("Problem executing stored procedure: "+e);
System.out.println("---------------------------------------------");
}
return rs;
}
public void runUpdate(){
try{
cs.executeUpdate();
}catch(SQLException e){
System.out.println("---------------------------------------------");
System.out.println("Problem executing stored procedure: "+e);
System.out.println("---------------------------------------------");
}
}
} //end of class
for some reason I'm getting a NullPointerException on the line I'm trying to construct a CallableStatement --> CallableStatement cs = this.con.prepareCall("{?=call "+storedProcName+" ("+procParams+")}");
The callable statement should look like this at run time:
cs = this.con.prepareCall({?=call getUnlinkedDirectdeposits()});
The stored proc is called this in the database: [dbo].[getUnlinkedDirectdeposits]
Any help would be appreciated!
Thanks in advance,
You are using the wrong "con" variable. In your method you're initialising a variable (local to the method) called con:
Connection con = new databaseConnection(jdbcResource).getConnection();
But then you use this.con, which is the con field of the StoredProc object you're currently executing in. Since it was never initialised, you get a NullPointerException.
Your Connection field is null!
You create a new Connection instance in StoredProc instead of assigning it to the field con of your class. But when trying to created the CallableStatement your are using the this.con which has not been set before.

Categories