PreparedStatement SetString doesn't work (case Oracle) - sql

I don't have an idea why this method gets an error
public TdPegawai getTdPegawai(String nip) throws Exception {
PreparedStatement ps = null;
try {
TdPegawai tp = new TdPegawai();
sql = "select * "
"from TD_PEGAWAI " +
"where NIP=? ";
ps = connection.prepareStatement(sql);
ps.setString(1, nip);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
// tp.setblablabla();
}
rs.close();
return tp;
} finally {
ConnectionUtil.closePreparedStatement(ps);
}
}
My SQL variable just returns SELECT * FROM TD_PEGAWAI WHERE NIP=?
My nip variable can return a value.
Is there any something wrong with my preparestatement or setstring ?

Related

SQL injection error in Dynamic SQL with prepared statement

I my application we are collection some user inputs from UI and based on those values we are generating dynamic SQLs with different 'Where' conditions to query data.
It is found that that piece of code has some SQL injection flaw.
public void filter(String strSerialNumberLogic, String strSerialNumber1,
String strSerialNumber2, String strCreationDateLogic,
long lngCreationDate1, long lngCreationDate2,
String strTypeNumbers, String strTitles, long lngLoc)
throws SQLException, ClassNotFoundException {
StringBuffer strWhere = new StringBuffer();
List paramList = new ArrayList();
String arrTypeNumbers[];
String arrTitles[];
int i;
boolean bolHit;
if (!strTypeNumbers.equals("") || !strTitles.equals("")) {
arrTypeNumbers = strTypeNumbers.split(",");
arrTitles = strTitles.split(",");
bolHit = false;
strWhere.append("(");
for (i = 0; i < arrTypeNumbers.length; i++) {
if (arrTypeNumbers[i].length() > 0) {
if (bolHit) {
strWhere.append(" OR ");
} else {
bolHit = true;
}
strWhere.append(" REPORT_NUMBER = ?");
paramList.add(arrTypeNumbers[i]);
}
}
for (i = 0; i < arrTitles.length; i++) {
if (arrTitles[i].length() > 0) {
if (bolHit) {
strWhere.append(" OR ");
} else {
bolHit = true;
}
strWhere.append(" REPORT_NAME = ?");
paramList.add(arrTitles[i]);
}
}
strWhere.append(") ");
}
if (!strSerialNumber1.equals("")) {
if (!strWhere.equals("")) {
strWhere.append(" AND ");
}
strWhere.append(" REPORT_FILE_NO " + strSerialNumberLogic + " ? ");
paramList.add(strSerialNumber1);
if (strSerialNumberLogic.equals("between")) {
strWhere.append(" AND ? ");
paramList.add(strSerialNumber2);
}
}
if (lngCreationDate1 != 0) {
if (!strWhere.equals("")) {
strWhere.append(" AND ");
}
strWhere.append(" REPORT_CREATION_DATE " + strCreationDateLogic + " ? ");
paramList.add(Long.toString(lngCreationDate1));
if (strCreationDateLogic.equals("between")) {
strWhere.append(" AND ? ");
paramList.add(Long.toString(lngCreationDate2));
}
}
if (lngLoc != 0) {
if (!strWhere.equals("")) {
strWhere.append(" AND ");
}
strWhere.append(" REPORT_FILE_LOCATION = ? ");
paramList.add(Long.toString(lngLoc));
}
String finalQuery = "";
if (!strWhere.equals("")) {
finalQuery = "WHERE " + strWhere.toString();
}
String strSQL = "SELECT * " + "FROM D990800 "
+ "LEFT JOIN D990400 ON REPORT_SYSTEM_ID ||" + " REPORT_NO = REPORT_NUMBER " + finalQuery
+ "ORDER BY REPORT_FILE_NO ASC";
System.out.println("strSQL:" + strSQL );
System.out.println("paramList:" + paramList );
Connection conn = ConnectionFactory.instance().getConnection();
PreparedStatement preparedStatement = null;
preparedStatement = conn.prepareStatement(strSQL);
for (int index = 0; index < paramList.size(); index++) {
String param = (String) paramList.get(index);
if (isParsableInt(param)) {
preparedStatement.setInt(index+1, Integer.parseInt(param));
} else {
preparedStatement.setString(index+1, param);
}
}
ResultSet rsReports = preparedStatement.executeQuery();
buildCollection(rsReports);
rsReports.close();
preparedStatement.close();
conn.close();
}
How did you come to the conclusion that you have SQL injection in this code? That would help clearing that up.
Anyway, looking at your code it seems that both strSerialNumberLogic and strCreationDateLogic are variables that comes from an external source, and are concatinated in a way that allows SQL to be injected. If this external source is the user, SQL injection can be executed. If not, than this is probably a false positive. I would improve the code anyway by chaning the logic variables turning them into Enums.

Unable to set data to textField from tableView - on Mouseclick and Up and Down Arrow keys (H2 Database)

I am a recent user of the h2 database, I need some assistance with the SQL syntax.
I'm able to retrieve data from the h2 dB and set it into JavaFX tableView, On performing the mouseclick or buttonpress action (Up & Down arrows) the intended behaviour is to display the current row of data from the tableView into the textfields, below is the code.
I'm getting the following exception:
Invalid value "1" for parameter "parameterIndex" [90008-193]
I'm certain this exception is due to SQL grammar unique to the H2 database, as the placeholder (' "+slnoField.getText()+" ' ") works fine in other databases. Please could you suggest the correct syntax or a solution. Many thanks.
#FXML
public void UpdateTable(){
data.clear();
try
{
conn = lrconn.getDatabaseConnection();
String sql = "SELECT * from APP_TABLE ;
pst = conn.prepareStatement(sql);
rs = pst.executeQuery();
while(rs.next())
{
data.add(new TestPOJO(
rs.getString("SLNO"),
rs.getString("NAME")
));
Table.setItems(data);
}
pst.close();
rs.close();
}
catch(Exception e1)
{
e1.printStackTrace();
}
Table.setOnMouseClicked((MouseEvent me) ->{
try{
conn = lrconn.getDatabaseConnection();
TestPOJO user = (TestPOJO)Table.getSelectionModel().getSelectedItem();
String sql = "SELECT * from APP_TABLE where SLNO =' "+slnoField.getText()+" ' ";
pst = conn.prepareStatement(sql);
pst.setString(1, user.getSLNO());
rs = pst.executeQuery();
while(rs.next()){
slnoField.setText(rs.getString("SLNO"));
nameField.setText(rs.getString("NAME"));
}
rs.close();
pst.close();
}catch(SQLException ex){
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
);
Table.setOnKeyReleased((KeyEvent e) ->{
if(e.getCode() == KeyCode.UP || e.getCode() == KeyCode.DOWN){
try{
TestPOJO user = (TestPOJO)Table.getSelectionModel().getSelectedItem();
String sql = "SELECT * from APP_TABLE where SLNO =' "+slnoField.getText()+" ' ";
pst = conn.prepareStatement(sql);
pst.setString(1, user.getSLNO());
rs = pst.executeQuery();
while(rs.next()){
slnoField.setText(rs.getString("SLNO"));
nameField.setText(rs.getString("NAME"));
catch(IOException | SQLException ex){
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
);
}
You're not using the PreparedStatement correctly. Place ? at locations where you want to insert parameters in the query string. You don't seem to add one of those:
String sql = "SELECT * from APP_TABLE where SLNO = ?";
pst = conn.prepareStatement(sql);
pst.setString(1, user.getSLNO());
rs = pst.executeQuery();

using clearParameter() even thought PreparedStatement is being closed

private PreparedStatement InsertPS = null;
public boolean InsertInDB(String username, String password, double balance, String secret) {
boolean ans = false;
try {
InsertPS = con.prepareStatement("Insert into BankDB values(?,?,?,?)");
String data[] = AMC.SendtoDB(password, secret);
InsertPS.setString(1, data[0]);
InsertPS.setString(2, username);
InsertPS.setString(3, data[1]);
InsertPS.setDouble(4, balance);
int rows = InsertPS.executeUpdate();
if (rows != 0) {
ans = true;
}
InsertPS.clearParameters();
} catch (SQLException sqlInite) {
System.out.println("SQL Error in InsertInDB method: " + sqlInite);
} finally {
try {
InsertPS.close();
} catch (SQLException sqle) {
System.out.println("SQL Exception in InsertInDB method finally clause : " + sqle);
}
}
return ans;
}
Above is the InsertInDB() method given,
It has a InsertPS PreparedStatement Object.
Here is it necessary to use clearParameters() method even though i am closing the InsertPS object at the end of the method.
(I have provided a separate method to close the connection object)
also another question: Is it a good idea to create PreparedStatement Object's outside any method within a class,initializing using Constructor and Say for example Once all Object's (each in different method) are used, close all PreparedStatement Objects using a separate method.
public class JavatoDB {
Driver DM = null;
Connection con = null;
PreparedStatement InsertPS = null;
PreparedStatement BalancePS = null;
PreparedStatement DeletePS = null;
PreparedStatement UpdatePS = null;
PreparedStatement SearchDB = null;
ResultSet RS = null;
ResultSetMetaData RSMD = null;
AdminControl AMC = null;
public JavatoDB() {
AMC = new AdminControl();
try {
DM = new com.mysql.jdbc.Driver();
con = DriverManager.getConnection("jdbc:mysql://localhost/javadb", "java", "javaaccess");
InsertPS = con.prepareStatement("Insert into BankDB values(?,?,?,?)");
BalancePS = con.prepareStatement("Select BALANCE from BankDB where ACCNAME=? AND ACCPIN = ?");
DeletePS = con.prepareStatement("Delete from BankDB where ACCNAME = ? AND ACCPIN = ? ");
UpdatePS = con.prepareStatement("Update BankDB set BALANCE = (BALANCE + ?) where ACCNAME = ? AND ACCPIN = ?");
SearchDB = con.prepareStatement("Select ID AND ACCPIN from BankDB where ACCNAME = ? ");
} catch (SQLException JavatoDBContrsuctor) {
System.out.println("SQL Error in JavatoDBConstructor: " + JavatoDBContrsuctor);
}
}
public boolean InsertInDB(String username, String password, double balance, String secret) {
boolean ans = false;
try {
String data[] = AMC.SendtoDB(password, secret);
InsertPS.setString(1, data[0]);
InsertPS.setString(2, username);
InsertPS.setString(3, data[1]);
InsertPS.setDouble(4, balance);
int rows = InsertPS.executeUpdate();
if (rows != 0) {
ans = true;
}
InsertPS.clearParameters();
} catch (SQLException sqlInite) {
System.out.println("SQL Error in InsertInDB method: " + sqlInite);
}
return ans;
}
Suggestion's or Criticism on other aspects of code are also welcome.
For the first question, when you call:
con.prepareStatement()
a new preparedStatement is created, then parameters dont survive, i mean you dont need to clear then.
About the second question, in your implementation i cant see where you close your preparedStatement, and if you only add close, next time method will fail. Then, it is usual to create the preparedStatement and close it in the same method.

How to auto Increment a primarykey in JDBC sql

can you please guys help me, i'm having trouble on making my primary key into auto-increment, My table name is books and the column that i want to be auto-increment is serial_no which is a primary key.
public class donate extends javax.swing.JFrame {
Connection con;
Statement stmt;
ResultSet rs;
PreparedStatement pst;
DefaultTableModel loginModel = new DefaultTableModel();
int curRow = 0;
/**
* Creates new form donate
*/
public donate() {
initComponents();
DoConnect();
showAll();
}
void showAll(){
try{
rs = stmt.executeQuery("SELECT * FROM books");
while(rs.next())
{
String book = rs.getString("book_title");
String categorie = rs.getString("category");
String status = rs.getString("book_status");
String donators = rs.getString("donator");
int serial_nos = rs.getInt("serial_no");
loginModel.addRow(new Object[]{book, categorie, status, donators, serial_nos});
}
}catch(SQLException err){
System.out.println(err);
}
}
void DoConnect( ) {
try{
//CONNECT TO THE DATABASE
String host = "jdbc:derby://localhost:1527/Dafuq7";
String uName ="Dafuq7";
String uPass ="Dafuq7";
con = DriverManager.getConnection(host, uName, uPass);
//EXECUTE SOME SQL AND LOAD THE RECORDS INTO THE RESULTSET
stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
String sql = "SELECT * FROM books";
rs = stmt.executeQuery(sql);
}
catch(SQLException err){
JOptionPane.showMessageDialog(donate.this, err.getMessage());
}
}
and here is for may button, which when i input all the data will be submitted to my table books
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String bookttl = bookt.getText();
String yourn = yn.getText();
String categ = cat.getSelectedItem().toString();
String bstat = bs.getSelectedItem().toString();
try {
rs.moveToInsertRow();
rs.updateString( "book_title", bookttl );
rs.updateString( "category", yourn );
rs.updateString( "book_status", categ );
rs.updateString( "donator", bstat );
loginModel.addRow(new Object[]{bookttl, yourn, categ, bstat});
rs.insertRow( );
stmt.close();
rs.close();
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql = "SELECT * FROM books";
rs = stmt.executeQuery(sql);
}
catch (SQLException err) {
System.out.println(err.getMessage() );
}// TODO add your handling code here:
}
BTW i found another way around by doing this, grabbing my table and reconstructing it and put this code in the create table script
SERIAL_NO INTEGER default AUTOINCREMENT: start 1 increment 1 not null primary key
Simply define your serial_no column as int primary key generated always as identity and then Derby will automatically assign the numbers for you. Here is some example code:
public static void main(String[] args) {
try (Connection conn = DriverManager.getConnection(
"jdbc:derby:C:/__tmp/derbytest;create=true")) {
String sql;
sql = "DROP TABLE books";
try (Statement s = conn.createStatement()) {
s.executeUpdate(sql);
} catch (Exception e) {
// assume table did not previously exist
}
sql = "CREATE TABLE books (" +
"serial_no int primary key " +
"generated always as identity, " +
"title varchar(100))";
try (Statement s = conn.createStatement()) {
s.executeUpdate(sql);
}
sql = "INSERT INTO books (title) VALUES (?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "The Book of Foo");
ps.executeUpdate();
ps.setString(1, "The Book of Bar");
ps.executeUpdate();
ps.setString(1, "The Book of Baz");
ps.executeUpdate();
}
sql = "SELECT * FROM books";
try (Statement s = conn.createStatement()) {
try (ResultSet rs = s.executeQuery(sql)) {
while (rs.next()) {
System.out.println(String.format(
"%d: %s",
rs.getInt("serial_no"),
rs.getString("title")));
}
}
}
} catch (SQLException se) {
se.printStackTrace(System.out);
System.exit(0);
}
}
which produces
1: The Book of Foo
2: The Book of Bar
3: The Book of Baz

JDBC if a string exist in a database

I am trying to find where a specific string exist in a database (all tables). I have the following code:
DatabaseMetaData md = con.getMetaData();
ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
stm = con.createStatement();
String sql;
sql = "SELECT * FROM "+rs.getString(3)+"WHERE F01 = '0000000000998'";
rs2 = stm.executeQuery(sql);
while(rs2.next()){
System.out.println(rs.getString(3));
}
}
The problem is in some of the tables F01 doesn't exist, so it throws an exception. Is there any way that even without specifying the column I can search through the whole table?
which database you are using.
Look over this discussion post. you may get good ideas about how to make sure column exists before you call your check
http://www.coderanch.com/t/299298/JDBC/databases/Oracle-describe-table-jdbc
For oracle
you can check these queries
select COLUMN_NAME, DATA_LENGTH, DATA_TYPE from user_tab_columns where Lower(table_name) = 'product'
select table_name, COLUMN_NAME, DATA_LENGTH, DATA_TYPE from user_tab_columns where upper(column_name) = 'PRODUCTID'
therefore your call should be something like this
select table_name from user_tab_columns where upper(column_name) = 'F01'
and then
SELECT * FROM "+rs.getString(1)+"WHERE F01 = '0000000000998'
as you see I am using LOWER and UPPER, you need to make sure you include them, reason as you can understand even though SQL is not case sensitive in its statements, but the value for which conditional check is happening is case sensitive.
The following Java code loops through each VARCHAR/NVARCHAR column in each table and performs a SELECT TOP 1 on that column to see if it gets a hit:
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class JDBCQuery {
public static void main(String args[]) {
String textToSearchFor = "Gord"; // test data
System.out.println(String.format("The value '%s' was found in the following locations:", textToSearchFor));
Connection conn = null;
PreparedStatement ps = null;
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String connectionString =
"jdbc:odbc:Driver={SQL Server};" +
"Server=.\\SQLEXPRESS;" +
"Trusted_Connection=yes;" +
"Database=myDb";
conn = DriverManager.getConnection(connectionString);
DatabaseMetaData md = conn.getMetaData();
ResultSet mdrs = md.getTables(null, null, "%", new String[] { "TABLE" });
List<String> tableList = new ArrayList<String>();
while (mdrs.next()) {
tableList.add(String.format("[%s].[%s].[%s]", mdrs.getString(1), mdrs.getString(2), mdrs.getString(3)));
// i.e., [catalogName].[schemaName].[tableName]
}
mdrs.close();
for (String tableName : tableList) {
Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM " + tableName + " WHERE 0=1");
ResultSet rs0 = stmt.getResultSet();
ResultSetMetaData rsmd = rs0.getMetaData();
List<String> columnList = new ArrayList<String>();
for (int colIndex = 1; colIndex <= rsmd.getColumnCount(); colIndex++) {
switch (rsmd.getColumnType(colIndex)) {
case java.sql.Types.VARCHAR:
case java.sql.Types.NVARCHAR:
columnList.add("[" + rsmd.getColumnName(colIndex) + "]");
break;
}
}
rs0.close();
stmt.close();
for (String columnName : columnList) {
String psSql = String.format("SELECT TOP 1 * FROM %s WHERE %s = ?", tableName, columnName);
ps = conn.prepareStatement(psSql);
ps.setString(1, textToSearchFor);
ResultSet rs1 = ps.executeQuery();
if (rs1.next()) {
System.out.println(String.format("column %s in %s", columnName, tableName));
}
rs1.close();
ps.close();
}
}
} catch( Exception e ) {
e.printStackTrace();
} finally {
try {
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
} catch( Exception e ) {
e.printStackTrace();
}
}
}
}
The results look like this;
The value 'Gord' was found in the following locations:
column [textCol] in [myDb].[dbo].[linkedTable]
column [FirstName] in [myDb].[dbo].[myContacts]