Apache Dbutils changing column name in update Sql - sql

I am having a strange problem with Dbutils , I am trying to run a parameterized update sql, I am supplying correct number of arguments , but dbutils is modifying the timestamp column name by changing the name of modifying it
when timestamp columnname is one alphabet
java.sql.SQLException: Wrong number of parameters: expected 4, was
given 5 Query: UPDATE WEATHER_2 SET WEATHER=? ,
O=TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF') , HUMIDITY=? , TEMP=?
WHERE ID=? Parameters: [804, 2015-06-05 17:21:05.809, 16.0, 25.15,
1347927]
when timestamp columnname is normal..it will ommit the second alphabet
java.sql.SQLException: ORA-00904: "OSTIME": invalid identifier
Query: UPDATE WEATHER_2 SET WEATHER=? , OBSTIME=TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF') , HUMIDITY=? ,
TEMP=? WHERE ID=? Parameters: [804, 2015-06-05 17:27:46.139, 16.0,
25.15, 1347927]
could this be a database thing? Also this is only happening with column whose type is Date or Timestamp.

I had a similar issue. I think it is a bug in the Oracle JDBC 7 Driver (ojdbc7.jar). The bug could be in the PreparedStatement.getParameterMetaData method.
This method is used internally by the Apache DBUtils. So it would not be a bug of DBUtils, but a bug from Oracle JDBC driver distributed with Oracle 12c.
Same Query will probably work fine if you use the Oracle 11g ojdbc6.jar driver. It at least worked for me.
If you want to see how the Query is wrongly processed internally by the Oracle ojdbc7.jar driver, you can use the main method included in the oracle.jdbc.driver.OracleParameterMetaDataParser class. Try this:
java -classpath ojdbc7.jar
oracle.jdbc.driver.OracleParameterMetaDataParser "YOUR SQL HERE"
e.g.
java -classpath ojdbc7.jar
oracle.jdbc.driver.OracleParameterMetaDataParser "UPDATE PERSON SET
LASTNAME=?, FIRSTNAME=? WHERE PERSONID=?"
The output is your SQL Sentence parsed and converted to a SQL Query that is used internally by the driver to identify the parameter datatypes:
SQL:UPDATE PERSON SET LASTNAME=:1 , FIRSTNAME=:2 WHERE PERSONID=:3
SqlKind:UPDATE, Parameter Count=3 Parameter SQL: SELECT LASTNAME, F,
PERSONID FROM PERSON
But as you can see in the sample, the FIRSTNAME is wrongly parsed just as "F".
Using one of the Queries you put in your question, the result is that one of the parameters just disappear... so the parser says "5" params but the internal Query used to get the datatypes has indeed only "4" (HUMIDITY has gone from the SELECT).
java -classpath ojdbc7.jar
oracle.jdbc.driver.OracleParameterMetaDataParser "UPDATE WEATHER_2 SET WEATHER=? , OBSTIME=TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF') , HUMIDITY=? , TEMP=? WHERE ID=?"
output:
SQL:UPDATE WEATHER_2 SET WEATHER=:1 , OBSTIME=TO_TIMESTAMP(:2
,'YYYY-MM-DD HH24:MI:SS.FF') , HUMIDITY=:3 , TEMP=:4 WHERE ID=:5
SqlKind:UPDATE, Parameter Count=5
Parameter SQL: SELECT WEATHER, OBSTIME, TEMP, ID FROM WEATHER_2
How to fixit? No idea, but as I said above, using the Oracle 11g ojdbc6.jar driver, same query works (even connecting with an Oracle 12c database...).
The behaviour is pretty random. It looks like it depends on the first letter of the column used in the UPDATE. If it begins with F and H always fails, but I do not know if there is any other condition.

oracle 12.1.0.1.0 jdbc oracle.jdbc.driver.OracleParameterMetaDataParser suck !
on my test:
oracle.jdbc.driver.OracleParameterMetaDataParser.main(new String[]{"update test set ORDX=?,A123=?,FABCDEFG=? where A2C=?"})
==>
SQL:update test set ORDX=:1 ,A123=:2 ,FABCDEFG=:3 where A2C=:4
SqlKind:UPDATE, Parameter Count=4
Parameter SQL: SELECT OX, A23, F, AC FROM test
field start with "O" will trim 1-2 char
field start with "F" will trim all
field start with "A" will trim 1 char
on oralce 12.1.0.2.0 still have on issue:
field start with "F" will trim all
http://www.oracle.com/technetwork/database/features/jdbc/default-2280470.html

I encounter the same problem, using DBUtils and from ojdbc6 upgrade to ojdbc7. Then I am aware of this is a bug on parameter, so I fill it by myself. As this:
update():
Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql.toUpperCase());
this.fillStatement(ps, param);
int rs = ps.executeUpdate();
ps.close();
conn.close();
fillStatement():
private void fillStatement(PreparedStatement stmt, Object... params) throws SQLException {
int i = 1;
for (Object o: params){
fill(stmt, i, o);
i ++;
}
}
private void fill(PreparedStatement stmt, int index, Object param) throws SQLException {
if (param == null) {
stmt.setObject(index, null);
} else if (param instanceof String) {
stmt.setString(index, (String) param);
} else if (param instanceof Boolean) {
stmt.setBoolean(index, (Boolean) param);
} else if (param instanceof Integer) {
stmt.setInt(index, (Integer) param);
} else if (param instanceof Long) {
stmt.setLong(index, (Long) param);
} else if (param instanceof Double) {
stmt.setDouble(index, (Double) param);
} else if (param instanceof Float) {
stmt.setFloat(index, (Float) param);
} else if (param instanceof Short) {
stmt.setShort(index, (Short) param);
} else if (param instanceof Clob) {
stmt.setClob(index, (Clob) param);
} else if (param instanceof Blob) {
stmt.setBlob(index, (Blob) param);
} else if (param instanceof java.sql.Timestamp) {
stmt.setTimestamp(index, (java.sql.Timestamp) param);
} else if (param instanceof BigDecimal) {
stmt.setBigDecimal(index, (BigDecimal) param);
}else if (param instanceof java.sql.Time) {
stmt.setTime(index, (java.sql.Time) param);
} else if (param instanceof java.sql.Date) {
stmt.setDate(index, (java.sql.Date) param);
} else if (param instanceof Date) {
stmt.setDate(index, new java.sql.Date(((Date) param).getTime()));
} else {
stmt.setObject(index, param);
}
}

Related

is it possible to get the execute sql that contains parameter when debugging mybatis source

I am setting a breakpoint in mybatis source BaseExecutor's queryFromDatabase function in Intellij Idea, this code block look like this:
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
but the boundSql content shows sql like this:
select * from article where channel_id in (?)
is it possible to get the execute sql in the trace? because the channel_id has more than 100 and the sql also contains other filter condition.

Insert data from a JsonArray using updateWithParms in vertx

Is is possible to use updatewithparms() in vertx postgres client to insert data to the using an json array. I tried the following with out any success.
String INSERT_QUERY="INSERT INTO testDb (rid , aid , created_at, expiry_time, strings , strings) VALUES"
private JsonArray preparedParameters(){
//JsonArray params = new JsonArray();
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return new JsonArray()
.add(device.getRecordId().toString())
.add( device.getAccountId())
.add(dateTimeFormat.format(device.getCreatedAt()))
.add(dateTimeFormat.format(device.getExpiresAt()))
.add( device.getEnrollmentId())
.add(device.getHashedEnrollmentId());
}
Then I call functions as follows.
try (SQLConnection connection = connectionResult.result()) {
connection.updateWithParams(INSERT_QUERY,preparedParameters() ,queryRes -> {
if (queryRes.succeeded()) {
booleanFuture.complete(true);
} else {
booleanFuture.complete(false);
}
});
} catch (Exception e) {
booleanFuture.complete(false);
}
I receive the following error.
The query contains 0 parameters but you gave it 6 ("sda","sda",2018-01-22 20:23:26,2018-02-21 20:23:26,"sda","sda")
com.github.mauricio.async.db.exceptions.InsufficientParametersException: The query contains 0 parameters but you gave it 6 ("sda","sda",2018-01-22 20:23:26,2018-02-21 20:23:26,"sda","sda")
Your query is not valid, it misses the parameters.
String INSERT_QUERY="INSERT INTO testDb (rid , aid , created_at, expiry_time, strings , strings) VALUES (?,?,?,?,?,?)"
See the Prepared Statement Updates section of the Vert.x SQL doc.

SQLite Error in statement insert with question mark

Hello I am writing a query to insert values in DB SQLite.
Firstly, I read from my records and searched for two values, for example, then I created a new table and inserted new values in.
My code snippet follows:
try
{
Class.forName("org.sqlite.JDBC");
Connection con=DriverManager.getConnection("jdbc:sqlite:tests.db");
con.setAutoCommit(false);
Statement st=con.createStatement();
st.executeUpdate("delete msearch");
ResultSet res=st.executeQuery("select * from newmobile_details");
Boolean rec=res.next();
if(!rec)
{
JOptionPane.showMessageDialog(null,"لايوجد سجلات");
}
else
{
do
{
String mid=res.getString(1);
String model=res.getString(2);
String name=res.getString(3);
int price=res.getInt(4);
String pcolor=res.getString(5);
String imei=res.getString(6);
java.sql.Date date=res.getDate(7);
String access=res.getString(8);
if(mname.equalsIgnoreCase(name))
{
PreparedStatement prp=con.prepareStatement("insert into msearch values(?,?,?,?,?,?,?,?)");
prp.setString(1,mid);
prp.setString(2,model);
prp.setString(3,name);
prp.setInt(4,price);
prp.setString(5,pcolor);
prp.setString(6,imei);
prp.setDate(7,date);
prp.setString(8,access);
prp.executeUpdate();
System.out.println("iam inside2");
rows++;
b=1;
jTextField2.setText("");
}
}while(res.next());
if(b==0)
{
JOptionPane.showMessageDialog(null,"لم يتم العثور على الموبايل ");
jTextField2.setText("");
}
}
con.commit();
con.close();
}
catch(Exception e)
{
JOptionPane.showMessageDialog(null,"The error is1:" +e);
}
I get only exception as below:
The error is1 :sql error or missing database in msearch syntax error
Larry makes a good point and looking at your code more carefully I believe the problem is with the statement
st.executeUpdate("delete msearch");
It seems to be saying you should be qualifying msearch with a database name.
This is the syntax for an insert statement
INSERT INTO TABLE_NAME (c1, c2, c3,...cN)
VALUES (v1, v2, v3,...vN);
You give a list of column names and a list of values.
You don't have the list of column names.
This can't work.

jdbcTemplate.query works fine when passing few parameters and doesn't work for others

I have a select Oracle SQL that I am hitting using jdbcTemplate.query method. This returns a bean of the values from the table. I am passing a dynamic value to the query that will be used in the WHERE clause. However, the SQL values for few values that i am passing. But when I pass the value as NA it won't work. Any suggestions on this or help me with what am i missing?
private static final String regionSearchSql = "SELECT PRFLID, PRFLNM, RGN_CD FROM %PREFIX%MER_PRFL WHERE RGN_CD = ?";
public List<SearchProfileBean> regionSearchProfile(SearchProfileRequest searchProfileRequest) throws DatabaseQueryException {
try {
return jdbcTemplate.query((QueryUtility.getQueryWithPrefix(regionSearchSql,prefix)), new SearchProfileRowMapper(), searchProfileRequest.getRegionName());
} catch (Exception e) {
throw new DatabaseQueryException(QueryUtility.getQueryWithPrefix(regionSearchSql, prefix), e);
}
}
If i pass 'EMEA', 'LAC', 'JAPA' in searchProfileRequest.getRegionName() - the SQL returns perfect results. But if I pass 'NA' in searchProfileRequest.getRegionName(), it gives empty results. But there are rows in the table for NA.

How to get the ID of inserted row in JDBC with old driver?

I want to get auto increment id of inserted row. I know that there is a lot of examples how to do that:
link1
link2
But I use HSQL 1.8.0.10 and following code:
PreparedStatement ps = conn.prepareStatement("insert into dupa (v1) values(3)", Statement.RETURN_GENERATED_KEYS);
throws expection:
java.sql.SQLException: This function is not supported
How to get id if driver does not support the above solution. Is any other way to get auto increment key of inserted row? I want to handle as much as possible drivers. So want to use obove code in try section and use another way in catch section.
Second question: Is possible that database does not support this feature. So even if I use new driver and old database It will still not work? I tried to use hsql 2.3.2 driver but I can not to connect to 1.8.0.10 database.
The following code illustrates how to retrieve generated keys from HSQLDB 2.2.9 and later using the included JDBC 4 driver. This method returns a two element long[]. The first element contains the number of rows that were updated; the second contains the generated key if any:
static final long[] doUpdate( ... ) {
final long[] k = new long[] {0, KEY_UNDEFINED};
PreparedStatement ps = null;
try {
ps = CXN.get().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
JdbcValue jv;
for (int i = 0; i < data.size(); i++) {
jv = data.get(i);
jv.type().setJdbcParameter(i + 1, ps, jv);
}
k[NUM_OF_ROWS] = (long) ps.executeUpdate();
if (k[NUM_OF_ROWS] > 0L) {
try (ResultSet rs = ps.getGeneratedKeys()) {
final String identColName = idCol.colName();
while (rs.next()) {
if (k[ROW_CREATED] != KEY_UNDEFINED) throw new AssertionError();
k[ROW_CREATED] = rs.getLong(identColName);
}
}
}
} catch (SQLException e) { ... }
finally {
try { if (ps != null) ps.close(); } catch (SQLException e) { }
}
return k;
}
I am unable to say whether this approach will work with old versions of HSQLDB.
You will have to use some vendor-specific solution, i.e. in mysql you would call LAST_INSERT_ID function.
I don't have valid installation of HSQL to test it, but you can give a try to the highest voted solution from this topic: how to return last inserted (auto incremented) row id in HSQL?