Oracle Java Stored Procedure Command-line Interaction - java

I have a funny requirement.
We need to have a command-line interaction in a Java Stored Procedure. In spite of granting appropriate permissions using the dbms_java.grant_permission commands, I am encountering java.io.IOException, where I read from System.in using java.io.InputStreamReader.
Where is the problem?
The Java Source is here:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.SQLException;
import oracle.jdbc.driver.OracleDriver;
public class ExecuteInteractiveBatch {
public static void aFunction() {
Connection connection = null;
try {
int rowFetched = 0;
connection = new OracleDriver().defaultConnection();
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT count(1) cnt from sometable where c = 2");
int count = 0;
if (rs.next()) {
count = rs.getInt(1);
}
rs.close();
stmt.close();
rs = null;
stmt = null;
if (count == 1) {
System.out.println("Do you want to continue?");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String response = reader.readLine();
if ("Y".equalsIgnoreCase(response)) {
stmt = connection.createStatement();
int rowsAffected = stmt.executeUpdate("DELETE from sometable where c=2");
System.out.println("" + rowsAffected + " row(s) deleted");
stmt.close();
}
}
} catch (IOException ex) {
ex.printStackTrace();
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
try {
if (connection != null || !connection.isClosed()) {
connection.close();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}

You can't perform I/O to the console from within Oracle... not in java, not in PL/SQL, nowhere. Oracle is running in a separate process from the user, quite likely even a different computer, and java stored procedures are being run in that process. You will need some java code running on the client system to perform console I/O.

Related

Not able to insert million records from csv file to MySql database

So I wanted to read per say 100 lines and print it and it should be happening for every 100 lines and I don't know where to insert that code. The CSV file with one million records isn't getting inserted into the DB as only few thousand are getting inserted.
String csvFilePath = "C:\\Student1.csv";
try {
BufferedReader lineReader = new BufferedReader(new FileReader("C:\\File12\\Student1.csv"));
CSVParser records = CSVParser.parse(lineReader, CSVFormat.EXCEL.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());
System.out.println(records.size);
ArrayList<TestSql> students = new ArrayList<TestSql>();
for (CSVRecord record : records) {
TestSql testsql = new TestSql();
testsql.setDate(record.get(0));
testsql.setName(record.get(1));
testsql.setGender(record.get(2));
students.add(testsql);
}
PreparedStatement statement = null;
Connection con = dbconnection();
String sql = "INSERT INTO test12(DOB, NAME, GENDER) VALUES (?, ?, ?)";
statement = con.prepareStatement(sql);
for (TestSql record : students) {
statement.setString(1, record.getDate());
statement.setString(2, record.getName());
statement.setString(3, record.getGender());
statement.addBatch();
}
statement.executeBatch();
con.commit();
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
public static Connection dbconnection() {
Connection connection = null;
try {
System.out.println( "Hello World!" );
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/newschema1", "root", "12345");
System.out.println("connection sucessfull");
connection.setAutoCommit(false);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
If you want to insert records from the CSV file into the database table in batches of 100, then you need a counter. In the below code I use a variable count. Whenever it reaches 100, the code inserts those 100 rows and resets the count variable.
Note: More explanations after the code.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
public class CsvParse {
private static final int LIMIT = 100;
public static Connection dbConnection() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/newschema1",
"root",
"12345");
connection.setAutoCommit(false);
return connection;
}
public static void main(String[] args) {
try (BufferedReader lineReader = new BufferedReader(new FileReader("C:\\File12\\Student1.csv"))) {
CSVParser records = CSVParser.parse(lineReader,
CSVFormat.EXCEL.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());
String sql = "INSERT INTO test12(DOB, NAME, GENDER) VALUES (?, ?, ?)";
Connection con = dbConnection();
PreparedStatement statement = con.prepareStatement(sql);
int count = 0;
for (CSVRecord record : records) {
count++;
if (count > LIMIT) {
count = 1;
statement.executeBatch();
con.commit();
statement.clearBatch();
}
statement.setString(1, record.get(0));
statement.setString(2, record.get(1));
statement.setString(3, record.get(2));
statement.addBatch();
}
// Insert last batch that may be less than LIMIT.
statement.executeBatch();
con.commit();
con.close();
records.close();
}
catch (IOException | SQLException e) {
e.printStackTrace();
}
}
}
In method dbConnection(), I removed Class.forName() since it is no longer needed. I also changed the exception handling. If the method fails to obtain a database connection then there's not much point in continuing since you won't be able to insert anything into the database and that's the whole point of the program. So catching the SQLException in method dbConnection() and printing the stack trace means that when you try to create a PreparedStatement, you will get a NullPointerExcetion since con will be null.
In method main I use try-with-resources when creating lineReader.
I don't see the reason for class TestSql. You can simply set the PreparedStatement parameters directly from the CSV record.
Since Java 7 there is multi-catch so no need for a separate catch block for each exception when each catch block simply prints the stack trace.

Getting java.sql.SQLException: - ORA-01000: maximum open cursors exceeded for DML (Update Statement)

I am reading an excel file that contains 30000 rows and trying to update an Oracle dB table field based on some logic. My Java application error out "java.sql.SQLException: - ORA-01000: maximum open cursors exceeded" when it writes approximately 700th record in the table. Need help in optimising the code so as to avoid this error.
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.ResourceBundle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import oracle.jdbc.driver.OracleDriver;
public class UpdateTest {
private static Connection conn = null;
static ResourceBundle bundle = ResourceBundle.getBundle("PropertiesFile");
public static void main(String[] args) {
String filename = bundle.getString("FILEPATH") + bundle.getString("FILENAME");
FileInputStream fileInputStream = null;
String input = null;
PreparedStatement preparedStatement = null;
Integer result = null;
int counter = 0;
try {
DriverManager.registerDriver(new OracleDriver());
conn = DriverManager.getConnection(
bundle.getString("DATABASE_URL"),
bundle.getString("DATABASE_USERNAME"),
bundle.getString("DATABASE_PASSWORD"));
conn.setAutoCommit(false);
fileInputStream = new FileInputStream(filename);
XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
XSSFSheet sheet = workbook.getSheetAt(0);
System.out.println("Number of records to be updated: " + (sheet.getPhysicalNumberOfRows() - 1));
Iterator i = sheet.iterator();
while (i.hasNext()) {
XSSFRow row = (XSSFRow) i.next();
input = row.getCell(0).toString();
preparedStatement = conn.prepareStatement("update table1 set column1='value' where input=?");
preparedStatement.setString(1, input);
result = preparedStatement.executeUpdate();
}
if (preparedStatement != null) {
preparedStatement.close();
}
conn.commit();
conn.close();
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
} finally {
try {
if (conn != null && !conn.isClosed()) {
if (!conn.getAutoCommit()) {
conn.commit();
conn.setAutoCommit(true);
}
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Each call to prepareStatement() creates a new cursor in the Oracle server which is not closed in your loop.
The correct solution to avoid the "too many open cursors" is to only create one cursor by preparing the statement only once before the loop.
preparedStatement = conn.prepareStatement("update table1 set column1='value' where input=?");
Iterator i = sheet.iterator();
while (i.hasNext()) {
XSSFRow row = (XSSFRow) i.next();
input = row.getCell(0).toString();
preparedStatement.setString(1, input);
result = preparedStatement.executeUpdate();
}
Then close it after the loop in a finally block.
Calling prepareStatement() in a loop defeats the purpose and intention of a PreparedStatement.
Move your preparedStatement.close() inside of while:
preparedStatement = conn.prepareStatement("update table1 set column1='value' where input=?");
while (i.hasNext()) {
XSSFRow row = (XSSFRow) i.next();
input = row.getCell(0).toString();
preparedStatement.clearParameters();
preparedStatement.setString(1, input);
result = preparedStatement.executeUpdate();
}
if (preparedStatement != null) {
preparedStatement.close();
}
When assings a new preparedStatement you are losing the reference and only it is closing the last preparedStatement.
If you use ResultSet on other part of your code, remember close it too if you are doing a loop.
EDIT: Reusing the prepared statement, you can close it outside of loop. More details here

Why different issues are found when using different versions of SonarQube?

I'm testing sonar in order to ensure the closing database connections and I'm having extrange results I don't understand.
I'm trying two versions of the code executing the maven goal "sonar:sonar" from eclipse with the embeded maven version 3.3.9.
I've tried with three versions of sonarqube server: 5.6.6, 6.2 and 6.4.
With this code
package db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class TestClosingResources {
public static void main(String[] args) {
Connection con = null;
ResultSet rsGet = null;
PreparedStatement psGet = null;
try {
DriverManager.registerDriver (new com.mysql.jdbc.Driver());
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "test", "test");
psGet = con.prepareStatement("SELECT * FROM TEST");
rsGet = psGet.executeQuery();
int counter = 0;
while (rsGet.next()) {
counter++;
System.err.println(counter);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rsGet != null) {
rsGet.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
rsGet = null;
try {
if (psGet != null) {
psGet.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
psGet = null;
}
}
}
I have these issues about closing resources:
sonarqube 5.6.6:
Close this "Connection"
Close this "PreparedStatement"
sonarqube 6.2:
Close this "Connection"
Close this "PreparedStatement"
sonarqube 6.4:
Close this "Connection"
My question with this code is:
Why does 5.6.6 and 6.2 complain about PreparedStatement when it's
closed exactly the same than the ResultSet?
And whith this code (only changes the way I retrieve the connection, it doesn't matter if it would work or not)
package db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class TestClosingResources {
public static void main(String[] args) {
Connection con = null;
ResultSet rsGet = null;
PreparedStatement psGet = null;
try {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/testci");
con = ds.getConnection();
psGet = con.prepareStatement("SELECT * FROM TEST");
rsGet = psGet.executeQuery();
int counter = 0;
while (rsGet.next()) {
counter++;
System.err.println(counter);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rsGet != null) {
rsGet.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
rsGet = null;
try {
if (psGet != null) {
psGet.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
psGet = null;
}
}
}
sonarqube 5.6.6:
Close this "PreparedStatement"
sonarqube 6.2:
Close this "PreparedStatement"
sonarqube 6.4:
no issues about closing resources
My questions with this code are:
Why does 5.6.6 and 6.2 complain about PreparedStatement when it's
closed exactly the same than the ResultSet?
Why doesn't any version complain about not closing the connection?
Thanks
The reason why some issues are not detected in more recent versions is due to the fact that static analyzer doing the analysis was improved.
Plugin used for Java source code analysis is called SonarJava, and it has independent release cycle than SonarQube. You should always use the latest release to obtain best results. Use update center on your SonarQube server to update to the latest available release.

How to get a String from a field

I've got a mysql question within java. I've got a mysql database with different tables. I currently got a database called 'litebans' and a table called 'litebans_mutes'.
Within that table there is a row called reason and under that reason (let's say what's within reason) there's a string called 'This is a test' and 'sorry'; how would I get the string 'This is a test' and 'sorry' associated with the same 'uuid' row in java? Here is a picture explaining more:
Here is an image explaining the sql format
Additionally, i've currently initialized all variables and such in java, i currently have this code:
http://hastebin.com/odumaqazok.java (Main class; using it for a minecraft plugin)
The below code is the MySQL class; api used to connect and execute stuff.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import net.octopusmc.punish.Core;
public class MySQL {
public static Connection openConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e1) {
System.err.println(e1);
e1.printStackTrace();
}
try {
Connection conn = DriverManager.getConnection("jdbc:mysql://" + Core.host + ":" + Core.port + "/" + Core.database, Core.user, Core.pass);
System.out.println("Currently connected to the database.");
return conn;
} catch (SQLException e) {
System.out.println("An error has occured while connecting to the database");
System.err.println(e);
e.printStackTrace();
}
return null;
}
public static void Update(String qry) {
try {
Statement stmt = Core.SQLConn.createStatement();
stmt.executeUpdate(qry);
stmt.close();
} catch (Exception ex) {
openConnection();
System.err.println(ex);
}
}
public static Connection getConnection() {
return Core.SQLConn;
}
public static ResultSet Query(String qry) {
ResultSet rs = null;
try {
Statement stmt = Core.SQLConn.createStatement();
rs = stmt.executeQuery(qry);
} catch (Exception ex) {
openConnection();
System.err.println(ex);
}
return rs;
}
}
An example using that api above is shown below:
try {
ResultSet rs = MySQL.Query("QUERY GOES HERE");
while (rs.next()) {
//do stuff
}
} catch (Exception err) {
System.err.println(err);
err.printStackTrace();
}
tl;dr: I want to get the two fields called 'reason' with the give 'uuid' string field.
First , make sure that your using the jdbc mysql driver to connect to the database
Defile a class where you could write the required connection and create statement code.
For example
class ConnectorAndSQLStatement {
ResultSet rs = null;
public Statement st = null;
public Connection conn = null;
public connect() {
try {
final String driver = "com.mysql.jdbc.Driver";
final String db_url = "jdbc:mysql://localhost:3306/your_db_name";
Class.forName(driver);//Loading jdbc Driver
conn = DriverManager.getConnection(db_url, "username", "password");
st = conn.createStatement();
rs = st.executeQuery("Select what_you_want from your_table_name");
while (rs.next()) {
String whatever = rs.getInt("whatever ");
System.out.print(whatever);
}
} catch (SQLException se) {
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Just call this function and the magic :D
Hope it is helpful

Run MySql from Java failed

I'm trying to run MySql command from Java process using Process exec
the code:
String s = "mysql -h192.168.0.1 -u USER -PASSWORD DB_NAME-e \"select * from table\"
System.out.println(s);
Process p = r.exec(s);
p.waitFor();
When I'm running the sql query from command line its works great, but from the Java process I get '
Usage: mysql [OPTIONS] [database]... with all the MySql options.
Without the -e parameter its seems to work, no error but of course nothing happens.
In Win& machine its also works great, not on the deploy Linux machine.
Any ideas what I'm doing wrong?
Example of Java using MySQL:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
// assume that conn is an already created JDBC connection (see previous examples)
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT foo FROM bar");
// or alternatively, if you don't know ahead of time that
// the query will be a SELECT...
if (stmt.execute("SELECT foo FROM bar")) {
rs = stmt.getResultSet();
}
// Now do something with the ResultSet ....
}
catch (SQLException ex){
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
finally {
// it is a good idea to release
// resources in a finally{} block
// in reverse-order of their creation
// if they are no-longer needed
if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) { } // ignore
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) { } // ignore
stmt = null;
}
}
Taken from here.
Try this, see if it aids your efforts
http://pastebin.com/XpRyGQBq
Usage:
DBConnectionHandler | new DBConnectionHandler(connectionURL, username*, password*) ResultSet | +query(String sqlStatementGoesHere)
void | +update(String sqlStatementGoesHere)
ResultSet | +getTables()
*means optional

Categories