DB2 returning keys in insert not working - jdbc

I'm having a problem while returning generated keys when insert a row with jdbc in a DB2 database (version 10.1). I tried several ways to do it, but no one works fine.
Method 1:
stmt = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
When executing this line, I get this exception:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: ILLEGAL SYMBOL "". SOME SYMBOLS THAT MIGHT BE LEGAL ARE:. SQLCODE=-104, SQLSTATE=42601, DRIVER=3.61.75
Method 2:
stmt = con.prepareStatement(query, pkMapper.getPkFieldNames());
List<Object> params = getInsertParams(object, pkMapper);
for (int i = 0; i < params.size(); i++) {
Object param = params.get(i);
stmt.setObject(i+1, param);
}
pkMapper.getPkFieldNames() returns an array of string with PK column names. When executing stmt.setObject(i+1, param); I get an exception like this:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: ILLEGAL SYMBOL "". SOME SYMBOLS THAT MIGHT BE LEGAL ARE:. SQLCODE=-104, SQLSTATE=42601, DRIVER=3.61.75
Method 3:
stmt = con.prepareStatement(query);
With this form, insert is executed fine, but no keys are returned with stmt.getGeneratedKeys();
Has anyone any idea of what is happening?

Related

HANA query with dynamic placeholder executed using jdbcTemplate in Spring Boot

I have a few HANA queries that rely on PLACEHOLDER input. The input to this is currently hardcoded which is leading to SQL injection vulnerability being detected by Veracode.
In order to fix that, I am trying to parameterize the value given to PLACEHOLDER using PreparedStatement, but getting the below error :
PreparedStatementCallback; uncategorized SQLException for SQL [SELECT * FROM some_table (PLACEHOLDER.\"$$<IP_SOME_COLUMN>$$\" => ?) WHERE some_flag = ?; ]; SQL state [HY000]; error code [2048]; SAP DBTech JDBC: [2048]: column store error: search table error: [34023] Instantiation of calculation model failed;exception 306002: An internal error occurred\n; nested exception is com.sap.db.jdbc.exceptions.JDBCDriverException: SAP DBTech JDBC: [2048]: column store error: search table error: [34023] Instantiation of calculation model failed;exception 306002: An internal error occurred
I have already checked this solution and gone through the documentation for input parameters in SAP HANA. Below is my code :
String sqlQuery = SELECT * FROM some_table ( PLACEHOLDER.\"$$<IP_SOME_COLUMN>$$\" => ? ) WHERE some_flag = ? ;
PreparedStatementSetter preparedStatementSetter = (PreparedStatement ps) -> {
ps.setString(1, firstInput);
ps.setString(2, secondInput);
}
ResultSetExtractor<T> rse = new DataResultSetExtractor();
getJdbcTemplate().query(sqlQuery, preparedStatementSetter, rse);
The same works well with the hardcoded way (prone to SQL injection) :
StringBuffer sql = new StringBuffer();
sql.append("SELECT * FROM some_table ").append("( 'PLACEHOLDER' = ('$$IP_SOME_COLUMN$$',").append(firstColumnValue).append("))");
//Map<String,Object> paramMap = new HashMap<String,Object>();
//getNamedParameterJdbcTemplate().query(sql.toString(), paramMap, rse);
How do I fix this error?
Figured the issue out. It seems, in the new syntax you need to provide the input parameter in single quotes and not in triple single quotes
Works : 'foo'
Doesn't work : '''bar'''

Calling an Oracle stored procedure in Dapper

I have an application that was calling an Oracle stored procedure by passing a string with the parameters in the string, i.e.
string Query = "CALL MySP(" + Variable1 + ", " + Variable2 + ")";
This worked, or at least the last time I tried it it worked.
I need to rewrite the query using DynamicParameters.
However when I do an Execute(Query, Parms, commandType: CommandType.StoredProcedure), I get errors.
Here is an example of what I tried:
using(OracleConnection conn = new OracleConnection(myConnectionString)
{
string Query = "CALL MySP(:Var1, :Var2)";
DynamicParameters parms = new DynamicParameters();
parms.Add("Var1", Variable1, DbType.String, ParameterDirection.Input);
parms.Add("Var2", Variable2, DbType.String, ParameterDirection.Input);
var results = connection.Execute(Query, parms, commandType: CommandType.StoredProcedure);
}
When I run it with the above query, I get this error:
ORA-06550: line 1, column 12:
PLS-00103: Encountered the symbol "MySP" when expecting one of the following:
:= . ( # % ;
The symbol ":=" was substituted for "MySP" to continue.
If I remove the CALL statement:
Query = "MySP(:Var1, :Var2);
then I get this error message:
ORA-01008: not all variables bound
Can anyone see what I am doing wrong?
The problem is that I keep looking on the C# and Dapper side of the equation. Our Oracle DBA set the permissions on the Stored Procedure and it ran.
However I could not tell Dapper that the CommandType was Stored Procedure and my string to call the stored procedure had to look like:
string Query = "CALL MySP(:Var1, :Var2)";
If I removed "CALL" I got an error. If I added "commandType: CommandType.StoredProcedure" to the Dapper Execute function I got a binding error.
Our DBA said he was going to look more into it to see what he can find out on his end so that we can call the stored procedure using the CommandType.StoreProcedure parameter in the Execute function.

SQLError in JDBC, but works fine in Oracle SQLDeveloper [duplicate]

I'm trying to insert CLOBs into a database (see related question). I can't quite figure out what's wrong. I have a list of about 85 clobs I want to insert into a table. Even when inserting only the first clob I get ORA-00911: invalid character. I can't figure out how to get the statement out of the PreparedStatement before it executes, so I can't be 100% certain that it's right, but if I got it right, then it should look exactly like this:
insert all
into domo_queries values ('select
substr(to_char(max_data),1,4) as year,
substr(to_char(max_data),5,6) as month,
max_data
from dss_fin_user.acq_dashboard_src_load_success
where source = ''CHQ PeopleSoft FS''')
select * from dual;
Ultimately, this insert all statement would have a lot of into's, which is why I just don't do a regular insert statement. I don't see an invalid character in there, do you? (Oh, and that code above runs fine when I run it in my sql developer tool.) And I if I remove the semi-colon in the PreparedStatement, it throws an ORA-00933: SQL command not properly ended error.
In any case, here's my code for executing the query (and the values of the variables for the example above).
public ResultSet executeQuery(String connection, String query, QueryParameter... params) throws DataException, SQLException {
// query at this point = "insert all
//into domo_queries values (?)
//select * from dual;"
Connection conn = ConnectionPool.getInstance().get(connection);
PreparedStatement pstmt = conn.prepareStatement(query);
for (int i = 1; i <= params.length; i++) {
QueryParameter param = params[i - 1];
switch (param.getType()) { //The type in the example is QueryParameter.CLOB
case QueryParameter.CLOB:
Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION);
clob.setString(i, "'" + param.getValue() + "'");
//the value of param.getValue() at this point is:
/*
* select
* substr(to_char(max_data),1,4) as year,
* substr(to_char(max_data),5,6) as month,
* max_data
* from dss_fin_user.acq_dashboard_src_load_success
* where source = ''CHQ PeopleSoft FS''
*/
pstmt.setClob(i, clob);
break;
case QueryParameter.STRING:
pstmt.setString(i, "'" + param.getValue() + "'");
break;
}
}
ResultSet rs = pstmt.executeQuery(); //Obviously, this is where the error is thrown
conn.commit();
ConnectionPool.getInstance().release(conn);
return rs;
}
Is there anything I'm just missing big time?
If you use the string literal exactly as you have shown us, the problem is the ; character at the end. You may not include that in the query string in the JDBC calls.
As you are inserting only a single row, a regular INSERT should be just fine even when inserting multiple rows. Using a batched statement is probable more efficient anywy. No need for INSERT ALL. Additionally you don't need the temporary clob and all that. You can simplify your method to something like this (assuming I got the parameters right):
String query1 = "select substr(to_char(max_data),1,4) as year, " +
"substr(to_char(max_data),5,6) as month, max_data " +
"from dss_fin_user.acq_dashboard_src_load_success " +
"where source = 'CHQ PeopleSoft FS'";
String query2 = ".....";
String sql = "insert into domo_queries (clob_column) values (?)";
PreparedStatement pstmt = con.prepareStatement(sql);
StringReader reader = new StringReader(query1);
pstmt.setCharacterStream(1, reader, query1.length());
pstmt.addBatch();
reader = new StringReader(query2);
pstmt.setCharacterStream(1, reader, query2.length());
pstmt.addBatch();
pstmt.executeBatch();
con.commit();
Of the top of my head, can you try to use the 'q' operator for the string literal
something like
insert all
into domo_queries values (q'[select
substr(to_char(max_data),1,4) as year,
substr(to_char(max_data),5,6) as month,
max_data
from dss_fin_user.acq_dashboard_src_load_success
where source = 'CHQ PeopleSoft FS']')
select * from dual;
Note that the single quotes of your predicate are not escaped, and the string sits between q'[...]'.
One of the reason may be if any one of table column have an underscore(_) in its name . That is considered as invalid characters by the JDBC . Rename the column by a ALTER Command and change in your code SQL , that will fix .
Oracle provide some explanation for ORA-00911. You can got this explanation after executing SQL request in Oracle SQL Developer.
ORA-00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual
But in your case it seems to be double ' character

Can we call sql function in prepared statement?

I have a oracle function. function name is TESTFUNCTION. The code i used is
PreparedStatement pStmt = con.prepareStatement("SELECT dbo.TESTFUNCTION(?,?)") ;
and I set the parameters also.
ResultSet rs = pStmt.executeQuery();
This code will produce the below exception
java.sql.SQLSyntaxErrorException: ORA-00923: FROM keyword not found where expected
Any Help!!
You are missing the FROM keyword. Change to this:
PreparedStatement pStmt = con.prepareStatement("SELECT dbo.TESTFUNCTION(?,?) FROM dual;") ;
A PreparedStatement is useful for SQL queries and not for function call. For function calls and stored procedures, use CallableStatement.
This error occurs when you try to execute a SELECT statement, and you either missed or misplaced the FROM keyword. Try to check for the from keyword.
Check here for details.
Note: It would be preferrable to use Callable Statement instead of prepared statement in such cases.
You could use callable statement in this case as:
String SQL = "{call dbo.TESTFUNCTION(?,?)}";
cstmt = con.prepareCall (SQL);

calling derby (java db) 'show tables' from jdbc

I need to enumerate the tables in a Derby (aka Java DB) database using JDBC in a Java program. All I am aware of for doing this is the SHOW TABLES command.
I first tried with something similar to this...
String strConnectionURL = "jdbc:derby:/path/to/derby/database;create=false";
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection connection = DriverManager.getConnection(strConnectionURL);
Statement statement = connection.createStatement();
boolean boResult = statement.execute("SHOW TABLES");
if (boResult) {
System.out.println("yay!");
}
...but that throws an exception:
java.sql.SQLSyntaxErrorException: Syntax error: Encountered "SHOW" at line 1, column 1.
So next I thought maybe I needed to use a CallableStatement so I tried this...
String strConnectionURL = "jdbc:derby:/path/to/derby/db;create=false";
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection connection = DriverManager.getConnection(strConnectionURL);
CallableStatement statement = connection.prepareCall("SHOW TABLES");
boolean boResult = statement.execute();
if (boResult) {
System.out.println("yippee!");
}
...but that throws the same exception:
java.sql.SQLSyntaxErrorException: Syntax error: Encountered "SHOW" at line 1, column 1.
So, can anyone help me enumerate the tables in my Derby (Java DB) database from JDBC?
EDIT: I'm looking around and starting to get a feeling this may be a general JDBC question. In other words, one could/would enumerate all a db's tables with the DatabaseMetaData object that can be retrieved from the Connection object. Looking into that (and looking forward to responses)...
EDIT 2: I found a pure JDBC solution, but am still happy to hear alternatives...
String strConnectionURL = "jdbc:derby:/path/to/db;create=false";
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection connection = DriverManager.getConnection(strConnectionURL);
DatabaseMetaData dbmd = connection.getMetaData();
ResultSet resultSet = dbmd.getTables(null, null, null, null);
while (resultSet.next()) {
String strTableName = resultSet.getString("TABLE_NAME");
System.out.println("TABLE_NAME is " + strTableName);
}
Show Tables is an ij command, not a base SQL statement, so you can't directly execute it. As you noted in your "EDIT 2", you can use the DatabaseMetaData to do this. Two other ways to do it are: you can select from the system catalogs (see http://db.apache.org/derby/docs/10.8/ref/rrefsistabs24269.html) , or you can use the "ij.runScript" method to run the ij tool from within your program, and pass it the "show tables" command (see http://db.apache.org/derby/docs/10.8/publishedapi/jdbc3/org/apache/derby/tools/ij.html)
As Bryan suggested ij.runScript - the code would look like this:
public void showTbls() throws Exception{
String sqlIn = "SHOW TABLES;";
InputStream stream = new ByteArrayInputStream(sqlIn.getBytes(StandardCharsets.UTF_8));
ij.runScript(conn,stream,StandardCharsets.UTF_8.name(), System.out,"UTF-8");
stream.close();
}
assumming conn is a opened derby Connection
But the disadvantage is that you are getting only string output. Not an ResultSet as you would get from:
Statement stmt = conn.createStatement();
ResultSet results = stmt.executeQuery("SELECT * FROM sys.systables");
or if you want only user table names you can use following SQL:
ResultSet results = stmt.executeQuery("SELECT TABLENAME FROM SYS.SYSTABLES WHERE TABLETYPE='T'");
A very similar output to
SHOW TABLES;
can be produced by using the following jdbc compliant query:
SELECT TABLENAME, (SELECT SCHEMANAME
FROM SYS.SYSSCHEMAS
WHERE SYS.SYSTABLES.SCHEMAID = SYS.SYSSCHEMAS.SCHEMAID)
AS SCHEMANAME
FROM SYS.SYSTABLES WHERE TABLETYPE='T'
It also shows you the probably useful SCHEMA information for each TABLE entry. Skip
TABLETYPE='T'
if you also want to see the system tables of your database as the user before has mentioned already.

Resources