h2 getGeneratedKeys throws exception - java

I try to put some Data in my H2 database but I'm a total noob in databases so it throws error over error since more than a hour.
Normaly I can fix it somehow but now I got a new problem I try to use
getGeneratedKeys() first I tried to use AUTO_INCREMENT(1,1) but that didn't works too function but it won't work rigth.
The exception my programm throws is
org.h2.jdbc.JdbcSQLException: Funktion "GETGENERATEDKEYS" nicht gefunden
Function "GETGENERATEDKEYS" not found; SQL statement:
insert into logTbl values( getGeneratedKeys(),Webservice->startThread0: Thread0) [90022-173]
an my database function looks like this
public void createTable(String Log) {
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
System.err.println("TREIBER FEHLER");
e.printStackTrace();
}
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:h2:~/DBtest/Logs");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE IF NOT EXISTS logTbl(ID INT PRIMARY KEY, LOG VARCHAR(255))");
//stat.execute("insert into test values(1, 'Hello')");
for (int i = 0; i < 20; i++) {
stat.execute("insert into logTbl values( getGeneratedKeys()," + Log + ")");
}
stat.close();
conn.close();
} catch (SQLException e) {
System.err.println("SQL FEHLER");
e.printStackTrace();
}
}
hope you can help me to fix my error as I said I'm totaly new and just had some code example as "tutorial" because I don't found a good tutorial

If you want to automatically generate primary key values, you need to first change the definition of your table:
CREATE TABLE IF NOT EXISTS logTbl
(
ID integer AUTO_INCREMENT PRIMARY KEY,
LOG VARCHAR(255)
);
You should also use a PreparedStatement rather than concatenating values.
So your Java code would look something like this:
String insert = "insert into logTbl (log) values(?)";
PreparedStatement pstmt = connection.prepareStatement(insert, Statement.RETURN_GENERATED_KEYS);
pstmt.executeUpdate();
ResultSet rs = pstmt.getGeneratedKeys();
long id = -1;
while (rs.next())
{
rs.getLong(1);
}
It might be that you need to use the overloaded version of prepareStatement() where you supply the column to be returned. Not sure which one works with H2:
prepareStatement(insert, new String[] {"ID"});
Btw: there is nothing "magic" about 255 as the length of a varchar column. There is no performance difference between varchar(500), varchar(20)or varchar(255). You should use the length that you expect you need, not some "magic" limit you think performs better.

Related

How to inject a SQL command to drop a table in java

My java code for SQL Query is
String sqlSt="INSERT INTO users(id,name,place) values ("+null+",'"+request.getParameter("name")+"','"+request.getParameter("place")+"');";
I have tried out
name= a'); DROP TABLE users; --
as well as
place =a'); DROP TABLE users; --
but it returns an Ecxeption as below
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DROP TABLE users; --','chennai')' at line 1
Note: when i tried the same in mysql command line. It worked!!!! i don't know what happens in jdbc
The real problem is actually JDBC, it only allows one sql if you dont tell it otherwise.
Look at this question for more info:
Multiple queries executed in java in single statement
But also i would try this instead, name =
a',''); DROP TABLE users; --
Since you specificed 3 columns in your insert:
(id,name,place)
You need to provide 3 values for the sql to be valid, not just 2.
Also you can sent the text null, sending a java null value is not necessary and i am not even sure how that works. I think this might be better:
String sqlSt="INSERT INTO users(id,name,place) values (null,'"+request.getParameter("name")+"','"+request.getParameter("place")+"');";
Instead of null, use an empty string ''
String sqlSt = "INSERT INTO users(id, name, place) values ('', '" + request.getParameter("name") + "', '" + request.getParameter("place") + "');";
It's better to use prepared statements to avoid confusion.
String sqlSt = "INSERT INTO users(id, name, place) values ('', ?, ?)";
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(query);
ps.setString(1, request.getParameter("name"));
ps.setString(2, request.getParameter("place"));
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
ps.close();
}
The real problem is with your Query. It is better to use a PreparedStatement for executing a query.
Your Code should be :
String sqlSt="INSERT INTO users(id,name,place) values (?,?,?)";
PreparedStatement pstmt = null;
try{
pstmt = dbConnection.prepareStatement(sqlSt);
pstmt.setString(1,null);
pstmt.setString(2,request.getParameter("name"));
pstmt.setString(3,request.getParameter("place"));
pstmt.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
} finally {
pstmt.close();
}
If you don't want to use a PreparedStatement, just remove last ; from your query.
So your query will be :
String sqlSt="INSERT INTO users(id,name,place) values ("+null+",'"+request.getParameter("name")+"','"+request.getParameter("place")+"')";

java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended for INSERT INTO SELECT

I have a below query, which needs to select a row by using a column as key and return generated keys.
INSERT INTO t_tpms_cc_request
(process_identifier,
request_source_id,
amount,
etc_account_id,
retry_count,
status,
store_identifier,
version_no,
next_process_time,
composite_transaction_id,
payment_id,
processed_time,
replenishment_id,
pay_type,
agency_id,
response_code,
file_id,
request_date,
auth_file_id,
auth_date_time,
merc_file_id,
merc_date_time,
cc_num,
cc_expiration_date,
merchant_id,
ext_sys_ref,
encrypt_cc_number,
cc_month_cd,
cc_year_cd,
orig_txn_ref,
auth_code,
avs_code,
cvv_code)
SELECT CC.process_identifier,
CC.request_source_id,
CC.amount,
CC.etc_account_id,
CC.retry_count,
CC.status,
CC.store_identifier,
CC.version_no,
CC.next_process_time,
CC.composite_transaction_id,
CC.payment_id,
CC.processed_time,
CC.replenishment_id,
CC.pay_type,
CC.agency_id,
CC.response_code,
CC.file_id,
CC.request_date,
CC.auth_file_id,
CC.auth_date_time,
CC.merc_file_id,
CC.merc_date_time,
CC.cc_num,
CC.cc_expiration_date,
CC.merchant_id,
CC.ext_sys_ref,
CC.encrypt_cc_number,
CC.cc_month_cd,
CC.cc_year_cd,
CC.orig_txn_ref,
CC.auth_code,
CC.avs_code,
CC.cvv_code
FROM t_tpms_cc_request CC
WHERE CC.order_id = ?
And, I have wrriten a below java code to do this:
String key[] = {"order_id"};
DataSource ds = null;
Connection con = null;
ResultSet rs = null;
try {
ds = jdbcTemplate.getDataSource();
con = ds.getConnection();
PreparedStatement ps =
con.prepareStatement(insertCCRequest.trim(), key);
ps.setString(1, OrderId);
int i= ps.executeUpdate();
rs = ps.getGeneratedKeys();
if (rs.next()) {
return rs.getString(1);
}
} catch (SQLException e) {
logger.debug("SQL exception in RebillDao.insertCCrequest()
method..!! ");
logger.debug("Exception cause: "+e.getMessage());
e.printStackTrace();
throw e;
}
finally {
if(con!=null){
con.close();
}
}
return "";
When i run this, I get below exception:
java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
Please tell me the ways to fix this.
Also, Using JDk 1.6 and ojdbc6-11.2.0.4.jar
I suspect that when you use generated keys with a prepared statement, the Oracle JDBC driver adds the RETURNING INTO clause to the INSERT statement, and that the JDBC driver is too dim to realise that the RETURNING INTO clause can't be used with INSERT INTO ... SELECT ... statements. I get the same ORA-00933 error if I attempt to run an INSERT INTO ... SELECT ... RETURNING ... statement.
What you could try instead is a PL/SQL block where we fetch the 'old' row into a record and then use an INSERT ... VALUES statement with a RETURNING_INTO clause to insert the values into the 'new' row:
DECLARE
l_row t_tpms_cc_request%ROWTYPE;
BEGIN
SELECT * INTO l_row FROM t_tpms_cc_request WHERE order_id = ?;
INSERT INTO t_tpms_cc_request (some_column, some_other_column, ...)
VALUES (l_row.some_column, l_row.some_other_column, ...)
RETURNING order_id INTO ?;
END;
As we're returning values from this, we need to prepare this as a CallableStatement instead of a PreparedStatement, and we need to register parameter 2 as an out parameter. We can then use this out parameter, instead of the getGeneratedKeys() method you're using at the moment, to return the generated key value.
Clearly this approach is Oracle-specific and won't work on other databases. I don't know how much of an issue database portability is to you, nor whether you can return generated keys from an INSERT INTO ... SELECT ... statement in other databases.

Return integer for the last row in MYSQL using JDBC

I'm new to working with JDBC commands. I have a database in MYSQL and each entry gets an ID. As initially created the ID was just a static variable that I iterated when the constructor runs. This was okay until I started deleting entries or running the program a second time. Then I start getting collisions. I need a way to return the highest row in the table and assign it to an integer that I can iterate.
The QuerySELECT MAX(ID) FROM table seems to get the value that I'm looking for. But I'm not sure of the syntax to get that value into an integer so I can return it.
public int getHighestRow() {
PreparedStatement ps;
int highestID = 0;
try {
ps = getSQLDB().prepareStatement("SELECT MAX(studentID) FROM student");
ps.execute();
} catch (SQLException e){
Logger.getLogger(Undergraduate.class.getName()).log(Level.SEVERE, null, e);
}
if (highestID > 0) return highestID;
else return 0;
I have a feeling this is very simple, but I wasn't able to find an existing answer. Or is there a more elegant way to do this in general?
SQL of different providers solve the retrieval of automatic generated keys differently. JDBC provides a standard solution.
Better use this JDBC solution, as it prevents mixing up those keys when insertions are done at the same time.
try (PreparedStatement ps = getSQLDB().prepareStatement(
"INSERT INTO student(....) VALUES(?, ..., ?)",
Statement.RETURN_GENERATED_KEYS)) { // Without StudentId
ps.setString(1, name);
...
ps.executeUpdate();
try (ResultSet rsKeys = ps.getGeneratedKeys()) {
if (rsKeys.next()) { // Only one record inserted
int studentId = rsKeys.getInt(1); // One key generated
}
}
} catch (SQLException e){
Logger.getLogger(Undergraduate.class.getName()).log(Level.SEVERE, null, e);
}
The mechanism with try(...). try-with-resources, ensures that close is called automatically.

SQLServerException: A result set was generated for update

I'm trying to insert a new record into an MS SQL database, and I'm getting an exception I've never seen before. When I call executeUpdate the following exception is thrown:
com.microsoft.sqlserver.jdbc.SQLServerException: A result set was generated for update.
This is the Java code that produces the error:
// addComment method adds a new comment for a given requestId
public CommentBean addComment(CommentBean comment) {
PreparedStatement stmt = null;
INative nat = null;
Connection conn = null;
try {
nat = dbConn.retrieveNative();
conn = (Connection)nat.getNative("java.sql.Connection");
stmt = conn.prepareStatement(ADD_COMMENT);
stmt.setInt(1, comment.getRequestId());
stmt.setString(2, comment.getComment());
stmt.setString(3, new SimpleDateFormat("MM/dd/yyyy").format(comment.getDateCreated()));
stmt.setString(4, comment.getCreatedBy());
comment.setCommentId(stmt.executeUpdate()); // exception
} catch(Exception ex) {
System.err.println("ProjectRegistration::SQLDAO - addComment");
ex.printStackTrace();
} finally {
try {
if (stmt != null) stmt.close();
} catch (Exception e) {}
}
return comment;
}// end addComment
Where ADD_COMMENT is defined as a String:
private static final String ADD_COMMENT = "INSERT INTO RequestComments OUTPUT INSERTED.commentId VALUES(?,?,?,?)";
For the sake of being thorough, the table is defined as:
CREATE TABLE RequestComments (
commentId int NOT NULL PRIMARY KEY IDENTITY(1,1),
requestId int FOREIGN KEY REFERENCES Requests(requestId),
comment varchar(400),
dateCreated date,
createdBy varchar(12)
);
I don't think I'm doing anything terribly complicated here, but I can't think of why I'm getting this exception. I have a method in the same class which does the exact same type of insertion (literally the same query with a different table name and number of values), and it has no issues. Does anyone have any ideas on how to resolve this issue?
This particular error can also be caused by an INSERT-trigger, which has a SELECT-statement as a part of the trigger code.
To test whether this is the case, you can try:
using executeQuery(), instead of executeUpdate() - and display the result.
executing the insert in tool like MySQL Workbench, SQL Server Management Studio, or whatever flavour of database design tools are available for your DBMS, to see whether a result is returned.
Related: sql server error "A result set was generated for update"
I'm hoping this may help others looking at the same error message, as it did for me. My solution was to live with a call to executeQuery(), although it only handles an underlying issue, instead of fixing it.
This instruction stmt.executeUpdate() is not returning the commentId, it returns a ResultSet which you could then get the commentId from. Something like this,
ResultSet rs = stmt.executeQuery(); // Not update, you're returning a ResultSet.
if (rs.next()) {
comment.setCommentId(rs.getInt(1));
}
you are using OUTPUT in your insert query i.e you will get a resultset after your query executes and to hold that you need an object of class ResultSet to hold that data
SqlServer : When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
Connection conn = DriverManager.getConnection(connectDB,user,pwd);
String sql = " set nocount off;INSERT INTO test (name) values (1)";
PreparedStatement prepareStatement = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
System.out.println(prepareStatement.executeUpdate());
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if(generatedKeys.next()){
System.out.println(generatedKeys.getString(1));
}
Related:
set-nocount-on-usage
I've had a similar problem where after a while an insert on a autonumber table would give a "A result set was generated for update." at random. I use connection pooling and somehow the driver can get into a state where executeUpdate in combination with Statement.RETURN_GENERATED_KEYS doesn't work anymore. I found out that in this state an executeQuery does the trick, but in the initial state executeQuery does not work. This lead me to the following workaround:
PreparedStatement psInsert = connection.prepareStatement("INSERT INTO XYZ (A,B,C) VALUES(?,?,?)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = null;
try {
psInsert.setString(1, "A");
psInsert.setString(2, "B");
psInsert.setString(3, "C");
Savepoint savePoint = connection.setSavepoint();
try {
psInsert.executeUpdate();
rs = psInsert.getGeneratedKeys();
} catch (SQLServerException sqe)
{
if (!sqe.getMessage().equals("A result set was generated for update."))
throw sqe;
connection.rollback(savePoint);
rs = psInsert.executeQuery();
}
rs.next();
idField = rs.getInt(1);
} finally {
if(rs != null)
rs.close();
psInsert.close();
}

Inserting preparedstatement to database - PSQL

This seems like a really simple problem, but I cannot figure out what my problem is. I have a method addTask which adds some info to our database as seen in this code:
public static boolean addTask(String name, String question, int accuracy, int type){
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO tasks (name, question, type, accuracy) ");
sql.append("VALUES(?, ?, ?, ?)");
try {
Connection c = DbAdaptor.connect();
PreparedStatement preparedStatement = c.prepareStatement(sql.toString());
preparedStatement.setString(1, name);
preparedStatement.setString(2, question);
preparedStatement.setInt(3, type);
preparedStatement.setInt(4, accuracy);
preparedStatement.execute();
preparedStatement.close();
c.close();
return true;
}
catch (SQLException e) {
e.printStackTrace();
return false;
}
}
my problem is that preparedStatement.execute() always returns false, indicating the information hasnt been added to the database. I can run psql and this confirms that nothing has been written to the db. The connection definitely connects to the correct database (i put in some other printlns etc. to check this). I am trying to insert into a newly initialised table that looks like this:
CREATE TABLE tasks
(
id SERIAL PRIMARY KEY,
submitter INTEGER REFERENCES accounts (id),
name VARCHAR(100) NOT NULL,
question VARCHAR(100) NOT NULL,
accuracy INTEGER NOT NULL,
type INTEGER REFERENCES types (id),
ex_time TIMESTAMP,
date_created TIMESTAMP
);
code for DbAdaptor.connect():
public static Connection connect(){
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Properties properties = new Properties();
properties.setProperty("user", USER);
properties.setProperty("password", PASSWORD);
try {
return DriverManager.getConnection(URL, properties);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
where USER and PASSWORD are static fields in the class
You misunderstood the return value of PreparedStatement#execute().
Please carefully read the javadoc:
Returns:
true if the first result is a ResultSet object; false if the first result is an update count or there is no result.
It thus returns — as fully expected — false on an INSERT query. It returns only true on a SELECT query (for which you'd however usually like to use executeQuery() instead which returns directly a ResultSet).
If you're interested in the affected rows, rather use PreparedStatement#executeUpdate() instead. It returns an int as per the javadoc:
Returns:
either (1) the row count for SQL Data Manipulation Language (DML) statements or (2) 0 for SQL statements that return nothing
A return value of 1 or greater would then indicate a successful insert.
Unrelated to the concrete problem: your code is leaking DB resources. Please carefully read How often should Connection, Statement and ResultSet be closed in JDBC?

Categories

Resources