Using invalidate table in a prepared statement - java

I'm attempting to call:
"invalidate metadata " + table_name
If I execute the query directly, I fall foul of a sonarqube rule that states that the code is vulnerable to a SQL Injection attack. (It isn't, as I've validated the table name elsewhere.)
String query = "invalidate metadata " + table;
try (Connection con = hiveConnectionFactory.getConnection(hiveConnDetailsHelperBean)) {
try (PreparedStatement stmt = con.prepareStatement(query)) {
stmt.execute();
LOGGER.debug("metadata invalidated " + table);
}
} catch (SQLException | MoLiConnectionException e) {
String errorMessage = "Error Running Query: "+ query;
throw new MoLiConnectionException(errorMessage, e);
}
If I attempt to use a prepared statement as suggested by SonarQube I get an exception:
String query = "invalidate metadata ?";
try (Connection con = hiveConnectionFactory.getConnection(hiveConnDetailsHelperBean)) {
try (PreparedStatement stmt = con.prepareStatement(query)) {
stmt.setString(1, table);
stmt.execute();
LOGGER.debug("metadata invalidated " + table);
}
} catch (SQLException | MoLiConnectionException e) {
String errorMessage = "Error Running Query: "+ query;
throw new MoLiConnectionException(errorMessage, e);
}
AnalysisException: Syntax error in line 1:
invalidate metadata 'dru_jhutc.time_test'
^
Encountered: STRING LITERAL
Expected: DEFAULT, IDENTIFIER
CAUSED BY: Exception: Syntax error
My question is: How can I use a prepared statement to get around the sonarqube rule?

Related

MySQLSyntaxErrorException in SQL syntax

I am trying to select data from a table using prepared statement. But it seems like I am getting syntax error which I cannot solve alone.
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mydb";
String dbusername = "root";
String dbpassword = ""; // Change it to your Password
// Setup the connection with the DB
connection = DriverManager.getConnection(url, dbusername,
dbpassword);
String query = "SELECT * FROM admin WHERE username = ? AND password = ?";
try {
// connection.setAutoCommit(false);
selectUser = connection.prepareStatement(query);
selectUser.setString(1, username);
selectUser.setString(2, password);
// Execute preparedstatement
ResultSet rs = selectUser.executeQuery(query);
// Output user details and query
System.out.println("Your user name is " + username);
System.out.println("Your password is " + password);
System.out.println("Query: " + query);
boolean more = rs.next();
// if user does not exist set the validity variable to true
if (!more) {
System.out
.println("Sorry, you are not a registered user! Please sign up first!");
user.setValid(false);
}
// if user exists set the validity variable to true
else if (more) {
String name = rs.getString("name");
System.out.println("Welcome " + name);
user.setName(name);
user.setValid(true);
}
} catch (Exception e) {
System.out.println("Prepared Statement Error! " + e);
}
} catch (Exception e) {
System.out.println("Log in failed: An exception has occured! " + e);
} finally {
}
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
System.out.println("Connection closing exception occured! ");
}
connection = null;
}
return user;
}
I get following error.
Prepared Statement Error! 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 '? AND password = ?' at line 1
But I don't see any error in that code line.
Change
ResultSet rs = selectUser.executeQuery(query);
to
ResultSet rs = selectUser.executeQuery();
when you already prepared the statement in connection.prepareStatement(query); then why to pass the query again in selectUser.executeQuery(query);
what you want to do is use this method
ResultSet rs = selectUser.executeQuery();
You have already loaded your query inside the prepared statement here ,
selectUser = connection.prepareStatement(query);
so execute it by ,
ResultSet rs = selectUser.executeQuery();
Also read ,
How does PreparedStatement.executeQuery work?

PSQLException thrown when trying to execute SELECT query

I have problem with my SQL request, when I run my request, I receive this message error:
org.postgresql.util.PSQLException: A result was returned when none was expected.
Here is my request:
Connexion con = new Connexion();
try {
c = con.Connect();
stmt = c.createStatement();
int sqlCalcul = stmt.executeUpdate(
"SELECT inventaire FROM calcul WHERE designation='" + designation +
"' AND date=(SELECT MAX(date) FROM calcul)");
stmt.close();
// c.commit();
c.close();
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
System.out.println("Records created successfully");
You should use executeQuery instead of executeUpdate:
ResultSet sqlCalcul = stmt.executeQuery("SELECT inventaire...")
executeUpdate is used for a INSERT, UPDATE, or DELETE statement, and will throw an exception if a ResultSet is returned. executeQuery should be used for SELECT statements.
Take a look at PostgreSQL's tutorial using the JDBC driver for more information.

JDBC update using prepared statement

I am trying to update a table using Java JDBC. The method I am using does not throw any errors but the table is not updating. The create table method is below:
public static void Table()
{
Connection c = null;
Statement stmt = null;
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:WalkerTechCars.db");
System.out.println("Opened database successfully");
stmt = c.createStatement();
String sql = "CREATE TABLE IF NOT EXISTS CUSTOMERS2 " +
"(PHONE TEXT PRIMARY KEY NOT NULL," +
" SURNAME TEXT NOT NULL, " +
" FIRSTNAME TEXT NOT NULL, " +
" HOME TEXT, " +
" ADDRESS TEXT, " +
" POSTCODE Text)";
stmt.executeUpdate(sql);
stmt.close();
c.close();
} catch ( Exception e ) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(0);
}
System.out.println("Customers2 created successfully");
}
The update method is below:
public static void updateCustomers()
{
Connection c = null;
PreparedStatement pstmt = null;
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:WalkerTechCars.db");
c.setAutoCommit(false);
System.out.println("Opened database successfully");
String query = "UPDATE CUSTOMERS2 set ADDRESS = ? where PHONE = ? ";
pstmt = c.prepareStatement(query); // create a statement
pstmt.setString(1, "1"); // set input parameter 1
pstmt.setString(2, "DOES THIS WORK"); // set input parameter 2
pstmt.executeUpdate(); // execute update statement
pstmt.close();
c.close();
} catch ( Exception e ) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(0);
}
System.out.println("Update Completed successfully HELLO");
}
I have tried to find some clear instructions on this but cant find any. I do not really understand JDBC and prepared statement very well
When autoCommit is false (c.setAutoCommit(false);), you must manually commit the transaction...
Add...
c.commit()
After pstmt.executeUpdate();
You code also has a flaw, in that if some kind of error occurs during the preparation or execution of the statement, both the Connection and PreparedStatement could be left open, causing a resource leak
If you're using Java 7+ you can use the try-with-resources feature, for example...
try {
Class.forName("org.sqlite.JDBC");
try (Connection c = DriverManager.getConnection("jdbc:sqlite:WalkerTechCars.db")) {
c.setAutoCommit(false);
System.out.println("Opened database successfully");
String query = "UPDATE CUSTOMERS2 set ADDRESS = ? where PHONE = ? ";
try (PreparedStatement pstmt = c.prepareStatement(query)) {
pstmt.setString(1, "1"); // set input parameter 1
pstmt.setString(2, "DOES THIS WORK"); // set input parameter 2
pstmt.executeUpdate(); // execute update statement
c.commit();
}
} catch (SQLException exp) {
exp.printStackTrace();
}
} catch (ClassNotFoundException exp) {
exp.printStackTrace();
System.out.println("Failed to load driver");
}
This will ensure that regardless of how you leave the try block the resource will be closed.
You might also consider taking a look at the JDBC(TM) Database Access
Your update method will set ADDRESS to 1 if there is any row in table with PHONE = does this work.
Try to put Address in 1st Input parameter and Phone 2nd Input parameter
When a connection is created, it is in auto-commit mode.
We need to use [setAutoCommit] method only when we need to make Auto Commit false and make it manual commit after executing the query.
More details at Oracle site on JDBC Transaction.

Java prepared statement in try-with-resources not working [duplicate]

This question already has answers here:
How should I use try-with-resources with JDBC?
(5 answers)
Closed 8 years ago.
Yesterday multiple people on Stack recommended using try-with-resources. I am doing this for all my database operations now. Today I wanted to change Statement to PreparedStatement to make the queries more secure. But when I try to use a prepared statement in try-with-resources I keep getting errors like 'identifier expected' or ';' or ')'.
What am I doing wrong? Or isnt this possible? This is my code:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()) {
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
A try-with-resource statement is used to declare (Autoclosable) resources. Connection, PreparedStatement and ResultSet are Autoclosable, so that's fine.
But stmt.setInt(1, user) is NOT a resource, but a simple statement. You cannot have simple statements (that are no resource declarations) within a try-with-resource statement!
Solution: Create multiple try-with-resource statements!
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
executeStatement(conn);
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
private void executeStatement(Connection con) throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id=? LIMIT 1")) {
stmt.setInt(1, user);
try (ResultSet rs = stmt.executeQuery()) {
// process result
}
}
}
(Please note that technically it is not required to put the execution of the SQL statement into a separate method as I did. It also works if both, opening the connection and creating the PreparedStatement are within the same try-with-resource statement. I just consider it good practice to separate connection management stuff from the rest of the code).
try this code:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = pstmt.executeQuery())
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
note that here, resource is your Connection and you have to use it in the try block ()
Move
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()
...within the try{ /*HERE*/ }
This is because stmt is the resource being created try (/*HERE*/) {} to be used try{ /*HERE*/ }
Try-with-resources
try (/*Create resources in here such as conn and stmt*/)
{
//Use the resources created above such as stmt
}
The point being that everything created in the resource creation block implements AutoClosable and when the try block is exited, close() is called on them all.
In your code stmt.setInt(1, user); is not an AutoCloseable resource, hence the problem.

How to truncate a Postgresql's table from JDBC

I have a Postgresql database and I want to truncate some tables using JDBC. How do I do that?
This is what I tried, but none worked... without even any error being reported:
Using CallableStatement.
try (Connection connection = getConnection();
CallableStatement statement = connection.prepareCall("TRUNCATE " + tableName)) {
return statement.execute();
}
Using Statement.
try (Connection connection = getConnection();
Statement statement = connection.createStatement()) {
return statement.execute("TRUNCATE " + tableName);
}
Using PreparedStatement.
try (Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement("TRUNCATE " + tableName)) {
return statement.execute();
}
After the truncate, I need to commit:
try (Connection connection = getConnection();
Statement statement = connection.createStatement()) {
int result = statement.executeUpdate("TRUNCATE " + tableName);
connection.commit();
return result;
}
From the documentation:
TRUNCATE is transaction-safe with respect to the data in the tables: the truncation will be safely rolled back if the surrounding transaction does not commit.
You may run into issues if the table has dependencies. If so, truncate the parent tables first, and also use the CASCADE option.
Connection connection = getConnection();
try {
PreparedStatement statement = connection.prepareStatement("TRUNCATE " + parentTable1, parentTable2, ... + " CASCADE");
try {
return statement.execute();
} finally {
statement.close();
}
} finally {
connection.close();
}
First, if you are truncating a table, you probably want to also RESTART IDENTITY (in addition to possibly doing CASCADE, as John Hogan mentioned).
Second, as far as doing a connection.commit(), the assumption is that you have autocommit set to OFF. My Postgres was set up with it set to ON (apparently, that is sometimes the default).
If it is set to ON, then calling the commit is unnecessary, and will result in the error:
"org.postgresql.util.PSQLException: Cannot commit when autoCommit is enabled."
Third, you may not have permission to truncate a table (or restart identity). In that case, you will need to:
DELETE from your_table
SELECT setval('your_table_id', 1)
The following worked for me:
public String truncateTable(String tableName, boolean cascadeFlag) {
String message = "";
try {
connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
String truncation = "TRUNCATE TABLE yourSchema." + tableName + " RESTART IDENTITY" + (cascadeFlag ? " CASCADE" : "");
System.out.println("truncateTable: Executing query '" + truncation + "'.");
int result = statement.executeUpdate(truncation);
// connection.commit(); // If autocommit is enabled (which it is for our DB), then throws exception after truncating the table.
statement.close();
connection.close();
} catch (SQLException sqlex) {
message = "Could not truncate table " + tableName + ". " + sqlex.getMessage();
System.err.println(message);
sqlex.printStackTrace();
}
return message;
}
Also:
public int deleteResetTable(String tableName, String fieldName) {
int affectedRows = 0;
try {
connection = DriverManager.getConnection(url, username, password);
String sql = "DELETE FROM yourSchema." + tableName;
PreparedStatement preparedStatement = connection.prepareStatement(sql);
affectedRows = preparedStatement.executeUpdate();
System.out.println("Deleted " + affectedRows+ " rows from table " + tableName + ".");
sql = "SELECT setval('yourSchema." + fieldName + "', 1)";
preparedStatement = connection.prepareStatement(sql);
affectedRows = preparedStatement.executeUpdate();
System.out.println("Reset " + affectedRows+ " values from table " + tableName + ".");
} catch (SQLException ex) {
System.out.println("Failed to delete rows from " + tableName + " " + ex.getMessage());
}
return affectedRows;
}

Categories

Resources