multiple sql command - java

I'm trying to execute multiple sql commands, but it gives me "error in your SQL syntax;"
Db_Connection dbconn = new Db_Connection();
Connection myconnection = dbconn.Connection();
String sqlString = "SELECT DISTINCT std_id FROM std_crs WHERE crs_id ='222123'; "
+ "SELECT * FROM cplus_grades ;";
Statement myStatement = myconnection.createStatement();
boolean results = myStatement.execute(sqlString);
do {
if (results) {
ResultSet rs = myStatement.getResultSet();
while (rs.next()) {
}
rs.close();
}
results = myStatement.getMoreResults();
} while(results);
myStatement.close();

I did a small test with three JDBC drivers:
MS SQL: works, returns two result sets
MySQL: fails with a syntax error - that is what you are seeing
HSQLDB: runs, but returns only one result set.
So I guess it simply depends on the JDBC driver if this technique works. Maybe it works only in MS SQL JDBC.
UPDATE:
It also works with Postgres.

please
1. String dbUrl = "jdbc:mysql://yourDatabase?allowMultiQueries=true";
this should be your jdbc connection url

Related

Working on this Java project where I need to be able to delete data from the database on user's request

The query inside MySQL is working:
DELETE FROM f9.yoo
WHERE account_tags = '#8GGGJPUR9'
I can delete data inside MySQL, but the problem is whenever I try to remove the account_tags from my Java application, it throws an error:
java.sql.SQLSyntaxErrorException: 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 'DELETE FROM f9.yoo
WHERE account_tags = '#8GGGJPUR9'' at line 2
Here's my Java SQL query:
Statement statement = dbConnection.createStatement();
String sql = "SELECT * FROM "+databaseName+"."+tableName+";\n" +
"DELETE FROM "+databaseName+"."+tableName+"\n" +
"WHERE account_tags = '"+AccountTag+"';";
statement.executeQuery(sql);
The error isn't giving me much to work with, so I really have no idea what is wrong with the program.
Did you add the allowMultiQueries=true
If not then you can add that while you sending the connecting request to your database. So you need to append the allowMultiQueries=true in your to database URL.
Like this:
String dbUrl = "jdbc:mysql:///test?allowMultiQueries=true";
String sql = "DELETE FROM "+databaseName+"."+tableName+"\n" +
"WHERE account_tags = ?";
try (PreparedStatement statement = dbConnection.prepareStatement(sq)) {
statement.setString(1, AccountTag);
int updateCount = statement.executeUpdate();
System.out.printf("%s: %d records deleted.%n", tableName, updateCount);
}
The only thing used is the DELETE, for which one should use executeUpdate.
One definitely should use a PreparedStatement as many code checkers will give alarms otherwise. It escapes things like ', handles types of the arguments, and possible conversions, and especially is a security feature against SQL injection.
The System.out usage is bad style, better would be using a logger.
try-with-resources automatically closes the PreparedStatement even with a raised exception or break/return.
When doing both database operations, it seems better to use two (prepared) statements, as the first returns a ResultSet.
So:
String sql = SELECT * FROM "+databaseName+"."+tableName + "\n" +
"WHERE account_tags = ?";
try (PreparedStatement statement = dbConnection.prepareStatement(sq)) {
statement.setString(1, AccountTag);
try (ResultSet rs = statement.executeQuery()) {
...
}
}
Better to separate statements with an If condition :
String sql1="SELECT * FROM "+databaseName+"."+tableName;
String sql2="DELETE FROM "+databaseName+"."+tableName+" "+
"WHERE account_tags = '"+AccountTag+"';
statement.executeQuery(sql1);
statement.executeUpdate(sql2);

Are ResultSet update{ColumnType} methods vulnerable to SQL injection?

A security scan made by AppScan source flags that the input has to be validated (Validation.Required) on the line uprs.updateString in the code below:
PreparedStatement statement =
conn.prepareStatement (query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
...
ResultSet uprs = statement.executeQuery ();
...
// Update DB ColumnA with input coming from client
uprs.updateString ('ColumnA', unvalidatedUserInput);
...
// Updates the underlying database
uprs.updateRow();
I assume that the intention behind this is to avoid SQL injection attacks, but I'm not sure whether that is possible in that scenario.
Questions: Are SQL Injection attacks possible through these JDBC methods? How does JDBC implements this under the scenes? Would this be another false positive reported by AppScan?
I'm not sure about bluemix-app-scan, but I'm providing my explanation here. (This is my assumption based on the below tests and code pasted)
I ran a test code to check this (in H2 DB)
value of testName String : (select 'sqlInjection' from dual)
Using createStatement (Not-Safe):
String query = "update TEST_TABLE set TEST_CHAR = " + testName + " where ID = 1";
Statement statement = connection.createStatement();
statement.executeUpdate(query);
Output: TEST_CHAR in DB was sqlInjection.
Using ResultSet of createStatement (Safe in H2 DB):
String query = "select * from TEST_TABLE where ID = 1";
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet executeQuery = statement.executeQuery(query);
executeQuery.next();
executeQuery.updateString("TEST_CHAR", testName);
executeQuery.updateRow();
Output: Surprisingly TEST_CHAR in DB was (select 'sqlInjection' from dual).
Using PreparedStatement (Safe):
String query = "update TEST_TABLE set TEST_CHAR = ? where ID = 1";
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, testName);
statement.executeUpdate();
Output: Expected - TEST_CHAR in DB was (select 'sqlInjection' from dual).
Using ResultSet of prepareStatement (Safe in H2 DB):
String query = "select * from TEST_TABLE where ID = 1";
PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet uprs = statement.executeQuery();
uprs.next();
uprs.updateString("TEST_CHAR", testName);
uprs.updateRow();
Output: Expected - TEST_CHAR in DB was (select 'sqlInjection' from dual).
Back to Questions:
Are SQL Injection attacks possible through these JDBC methods?
Maybe. It depends on the database driver that you're using.
How? :
The reason SQL Injection failed in my result set update was because H2 database internally uses PreparedStatement to update the row when ResultSet.updateRow() is invoked.
public void updateRow(Value[] current, Value[] updateRow) throws SQLException {
StatementBuilder buff = new StatementBuilder("UPDATE ");
...
buff.append(" SET ");
appendColumnList(buff, true);
...
appendKeyCondition(buff);
PreparedStatement prep = conn.prepareStatement(buff.toString());
...
for (int i = 0; i < columnCount; i++) {
...
v.set(prep, j++);
}
setKey(prep, j, current);
int count = prep.executeUpdate();
...
}
I'm not sure if all DB drivers in java implemented updateRow() method using preparedStatement or not. However it's clear that this is left to the driver and if bluemix is suggesting you to add a validation here, I suggest you follow that :)
How does JDBC implements this under the scenes?
Well, as shown above this is driver specific. However there is a good explanation on how PreparedStatement handles it over here.
Would this be another false positive reported by AppScan?
I don't think this is false positive (but in cases like H2 DB it is) but you'll never know if all database drivers implemented this securely.
Edit -
Even PostgreSQL and MySQL use PreparedStatement to handle this.
public synchronized void updateRow() throws SQLException
{
...
updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
...
updateStatement.executeUpdate();
...
}

postgres how to get data from multiple databases

i have 2 PostgreSQL databases on different port: DB1 on port 5432 and DB2 on port 5431
and i have code to get data from DB1 like this :
try {
Class.forName("org.postgresql.Driver");
String conString = "jdbc:postgresql://127.0.0.1:5432/DB1?user=MyUser&pass=MyPass" ;
c = DriverManager.getConnection(conString);
st = c.createStatement();
ResultSet rs = st.executeQuery(query);
while (rs.next()){
vaArrL.add(rs.getDouble("va"));
vbArrL.add(rs.getDouble("vb"));
vcArrL.add(rs.getDouble("vc"));
}
and work good when i send singe query to DB1 only.
but now, i have query to both databases together like :
select va, vb from DB1.public.t1 where datatime >= 1417384860 and datatime <= 1417381199
union
select va, vb from dblink('hostaddr=127.0.0.1 port=5431 dbname=DB2 user=MyUser password =MyPass '::text,
'select va, vb
from Db2.public.t2 order by datatime ')
datos(va integer,vb integer);
when i run query from pgAdmin i get result
but when i sent query to gunction i get : connection not available
Now. How can i send my query to function and i get values?
Can you try using JDBC's setCatalog method?
setCatalog's javadoc states that:
Calling setCatalog has no effect on previously created or prepared
Statement objects. It is implementation defined whether a DBMS prepare
operation takes place immediately when the Connection method
prepareStatement or prepareCall is invoked. For maximum portability,
setCatalog should be called before a Statement is created or prepared.
try {
Class.forName("org.postgresql.Driver");
// Connect to DB1 (specified in connection string/URL).
String conString = "jdbc:postgresql://127.0.0.1:5432/DB1?user=MyUser&pass=MyPass" ;
c = DriverManager.getConnection(conString);
st = c.createStatement();
// Execute query on DB1.
ResultSet rs = st.executeQuery(query);
while (rs.next()){
vaArrL.add(rs.getDouble("va"));
vbArrL.add(rs.getDouble("vb"));
vcArrL.add(rs.getDouble("vc"));
}
// Switch to DB2 and execute query.
c.setCatalog("DB2");
Statement st2 = c.createStatement();
ResultSet rs2 = st2.executeQuery(...);
}
If the JDBC driver doesn't support setCatalog, then you can execute the SQL query USE DB2 explicitly but this might affect already open statements (I'm not sure about this).
Edit: OP wants all results from both databases in the same ResultSet.
Assuming that DB1 and DB2 are on same server, I'd recommend creating a view in database DB1 which can access tables in database DB2 and return combined results. Then you can just SELECT * from the view via JDBC and get the results.
You can use a query like this for your view (assuming that the view is created in DB1):
SELECT all.va, all.vb FROM
(SELECT va, vb, datatime FROM t2
UNION
SELECT va, vb, datatime FROM DB2.public.t2) all
ORDER BY all.datatime
Note: To access a table in another database, you need to specify [db-name].[schema].[tablename].
If your query needs dynamic arguments, then you can create a stored procedure instead of a view.
i am find 1 solution
i am use 2 connection and send to query from client to xmlrpc server, here :
String conString = "jdbc:postgresql://" + host + ":" + port + "/" + DBName +
"?user=" + user + "&pass=" + pass;
String conString1 = "jdbc:postgresql://" + host + ":" + port2 + "/" + DBName2 +
"?user=" + user + "&pass=" + pass;
c = DriverManager.getConnection(conString);
c2 = DriverManager.getConnection(conString1);
st = c.createStatement();
st2 = c2.createStatement();
List<ResultSet> resultSets = new ArrayList<>();
resultSets.add(st.executeQuery(query));
resultSets.add(st2.executeQuery(query2));
ResultSets rs = new ResultSets(resultSets);
while (rs.next()){
unbArrL.add(rs.getUnbalance("unbalance"));
}
and resultSets class to get values from DB is :
class ResultSets {
private java.util.List<java.sql.ResultSet> resultSets;
private java.sql.ResultSet current;
public ResultSets(java.util.List<java.sql.ResultSet> resultSets) {
this.resultSets = new java.util.ArrayList<>(resultSets);
current = resultSets.remove(0);
}
public boolean next() throws SQLException {
if (current.next()) {
return true;
}else if (!resultSets.isEmpty()) {
current = resultSets.remove(0);
return next();
}
return false;
}
public Double getUnbalance(String unbalance) throws SQLException{
return current.getDouble("unbalance");
}
}

Execute multiple SQL statements in java

I want to execute a query in Java.
I create a connection. Then I want to execute an INSERT statement, when done, the connection is closed but I want to execute some insert statement by a connection and when the loop is finished then closing connection.
What can I do ?
My sample code is :
public NewClass() throws SQLException {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
System.out.println("Where is your Oracle JDBC Driver?");
return;
}
System.out.println("Oracle JDBC Driver Registered!");
Connection connection = null;
try {
connection = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:orcl1", "test",
"oracle");
} catch (SQLException e) {
System.out.println("Connection Failed! Check output console");
return;
}
if (connection != null) {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * from test.special_columns");
while (rs.next()) {
this.ColName = rs.getNString("column_name");
this.script = "insert into test.alldata (colname) ( select " + ColName + " from test.alldata2 ) " ;
stmt.executeUpdate("" + script);
}
}
else {
System.out.println("Failed to make connection!");
}
}
When the select statement ("SELECT * from test.special_columns") is executed, the loop must be twice, but when (stmt.executeUpdate("" + script)) is executed and done, then closing the connection and return from the class.
Following example uses addBatch & executeBatch commands to execute multiple SQL commands simultaneously.
import java.sql.*;
public class jdbcConn {
public static void main(String[] args) throws Exception{
Class.forName("org.apache.derby.jdbc.ClientDriver");
Connection con = DriverManager.getConnection
("jdbc:derby://localhost:1527/testDb","name","pass");
Statement stmt = con.createStatement
(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
String insertEmp1 = "insert into emp values
(10,'jay','trainee')";
String insertEmp2 = "insert into emp values
(11,'jayes','trainee')";
String insertEmp3 = "insert into emp values
(12,'shail','trainee')";
con.setAutoCommit(false);
stmt.addBatch(insertEmp1);
stmt.addBatch(insertEmp2);
stmt.addBatch(insertEmp3);
ResultSet rs = stmt.executeQuery("select * from emp");
rs.last();
System.out.println("rows before batch execution= "
+ rs.getRow());
stmt.executeBatch();
con.commit();
System.out.println("Batch executed");
rs = stmt.executeQuery("select * from emp");
rs.last();
System.out.println("rows after batch execution= "
+ rs.getRow());
}
}
Result:
The above code sample will produce the following result.The result may vary.
rows before batch execution= 6
Batch executed
rows after batch execution= = 9
Source: Execute multiple SQL statements
In the abscence of the schema or the data contained in each table I'm going to make the following assumptions:
The table special_columns could look like this:
column_name
-----------
column_1
column_2
column_3
The table alldata2 could look like this:
column_1 | column_2 | column_3
---------------------------------
value_1_1 | value_2_1 | value_3_1
value_1_2 | value_2_2 | value_3_2
The table alldata should, after inserts have, happened look like this:
colname
---------
value_1_1
value_1_2
value_2_1
value_2_2
value_3_1
value_3_2
Given these assumptions you can copy the data like this:
try (
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:orcl1", "test", "oracle")
)
{
StringBuilder columnNames = new StringBuilder();
try (
Statement select = connection.createStatement();
ResultSet specialColumns = select.executeQuery("SELECT column_name FROM special_columns");
Statement insert = connection.createStatement()
)
{
while (specialColumns.next())
{
int batchSize = 0;
insert.addBatch("INSERT INTO alldata(colname) SELECT " + specialColumns.getString(1) + " FROM alldata2");
if (batchSize >= MAX_BATCH_SIZE)
{
insert.executeBatch();
batchSize = 0;
}
}
insert.executeBatch();
}
A couple of things to note:
MAX_BATCH_SIZE should be set to a value based on your database configuration and the data being inserted.
this code is using the Java 7 try-with-resources feature to ensure the database resources are released when they're finished with.
you haven't needed to do a Class.forName since the service provider mechanism was introduced as detailed in the JavaDoc for DriverManager.
There are two problems in your code. First you use the same Statement object (stmt) to execute the select query, and the insert. In JDBC, executing a statement will close the ResultSet of the previous execute on the same object.
In your code, you loop over the ResultSet and execute an insert for each row. However executing that statement will close the ResultSet and therefor on the next iteration the call to next() will throw an SQLException as the ResultSet is closed.
The solution is to use two Statement objects: one for the select and one for the insert. This will however not always work by default, as you are working in autoCommit (this is the default), and with auto commit, the execution of any statement will commit any previous transactions (which usually also closes the ResultSet, although this may differ between databases and JDBC drivers). You either need to disable auto commit, or create the result set as holdable over commit (unless that already is the default of your JDBC driver).

No Database selected when retrieving from mysql website

I have a mysql database that I am trying to retrieve from our website host (godaddy). I followed a format that seems to be right but it tells me that:
java.sql.SQLException: No database selected
Code:
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
// STEP 2: Register JDBC driver
Class.forName(JDBC_DRIVER);
// STEP 3: Open a connection
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// STEP 4: Execute a query
System.out.println("Creating statement...");
stmt = conn.createStatement();
String sql;
sql = "SELECT * FROM item_master";
ResultSet rs = stmt.executeQuery(sql); //<-- This is where the error is.
// STEP 5: Extract data from result set
while (rs.next()) {
// Retrieve by column name
int id = rs.getInt("id");
// Display values
System.out.print("ID: " + id);
}
...
}
I did a print statement of the conn to maybe think the connection could of been null and was shown this:
com.mysql.jdbc.JDBC4Connection#2a6*****
Anyone have any ideas what could cause something like this?
Your URL for your database should include your database name. This is normally your URL followed by a "/DBNAME".
String URL = "jdbc:mysql://localhost:3306/mydb";
Where "mydb" is your database name.
What is the value of DB_URL? As far as I am aware, the URL needs to be of the form:
"WEBURL/DATABASENAME:PORT"
Are you just trying to connect to the WEBURL, without specifying a DATABASE?
I had the same problem.
Just run one more query (before your 'SELECT' statement) to connect to your database.
First:
sql = "USE <yourdatabase>";
ResultSet rs = stmt.executeQuery(sql);
And after:
sql = "SELECT * FROM item_master";
rs = stmt.executeQuery(sql);

Categories

Resources