I m writing a small utility that captures and logs SQL statements, but will have to remove sensitive data from the Query text and replace with with some dummy text (i.e:XXXXX).
What is a good way to parse the SQL query in java and replace parameters value?
for example:
replace
SELECT NAME, ADDRESS, .... FROM USER WHERE SSN IN ('11111111111111', '22222222222222');
with
SELECT NAME, ADDRESS, .... FROM USER WHERE SSN IN (?, ?);
Using JSQLParser (V0.8.9) this is a solution for your problem:
String sql ="SELECT NAME, ADDRESS, COL1 FROM USER WHERE SSN IN ('11111111111111', '22222222222222');";
Select select = (Select) CCJSqlParserUtil.parse(sql);
//Start of value modification
StringBuilder buffer = new StringBuilder();
ExpressionDeParser expressionDeParser = new ExpressionDeParser() {
#Override
public void visit(StringValue stringValue) {
this.getBuffer().append("XXXX");
}
};
SelectDeParser deparser = new SelectDeParser(expressionDeParser,buffer );
expressionDeParser.setSelectVisitor(deparser);
expressionDeParser.setBuffer(buffer);
select.getSelectBody().accept(deparser);
//End of value modification
System.out.println(buffer.toString());
//Result is: SELECT NAME, ADDRESS, COL1 FROM USER WHERE SSN IN (XXXX, XXXX)
This replaces all found String values within your SQL. To replace other types of data e.g. Long values, override the corresponding visit method in ExpressionDeParser.
Don't use regexp in this case. It turns out quickly to be hard maintainable.
The correct answer depends on how much you want to replace. Something like:
[0-9]{3}-?[0-9]{2}-?[0-9]{4}
will replace social security numbers pretty well. I always take regex code to
regexpal.com
to tweak it and work out bugs.
If you need to replace tons of sensitive information though, and if there are a lot of cases, definitely start looking into using a parser to parse the SQL query string. (such as jsqlparser, as Anirudh recommended.)
String sqlDebit = select * from table where and billing_cycle_start_date between :startDate and :endDate
java:
sqlDebit= sqlDebit.replaceAll(":startDate ", ""+startDate).replaceAll(":endDate", ""+endDate);
With prepare statement you can replace "?" in your query string with your value. Use number to specify which "?" you are referring too. They go by order from right to left.
For example: "SELECT LastName, FirstName FROM Person.Contact WHERE LastName = ? and FirstName = ?"
pstmt.setString(1, "LastNameValue");
pstmt.setString(2, "FirstNameValue");
see full example below:
public static void executeStatement(Connection con) {
try(PreparedStatement pstmt = con.prepareStatement("SELECT LastName, FirstName FROM Person.Contact WHERE LastName = ?");) {
pstmt.setString(1, "Smith");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
Related
What I'm trying to do seems simple but I get this error SQLITE_ERROR] SQL error or missing database (no such column: user1)
public String getIdUser(String name) {
try {
this.stat = conn.createStatement();
String sql = "SELECT id_user FROM User WHERE name = " + name;
ResultSet user = stat.executeQuery(sql);
return user.toString();
} catch (SQLException e) {
return null;
}
}
Replace
String sql = "SELECT FROM User WHERE name = " + name;
with
String sql = "SELECT * FROM User WHERE name = " + name; // you can also specify a column/columns instead of *
I see many problems in your code :
First
Your query should return something it should be :
SELECT col_name1, col_name2, ... FROM User ...
Or if you want to select every thing :
SELECT * FROM User ...
Second
String or Varchar should be between two quotes, your query for example should look like :
SELECT col_name1 FROM User WHERE name = 'name'
Third
I don't advice to use concatenation of query instead use Prepared Statement it is more secure and more helpful (I will provide an example)
Forth
To get a result you have to move the cursor you have to call result.next()
Fifth
Name of variable should be significant for example ResultSet should be ResultSet rs not ResultSet user
Your final code can be :
PrepareStatement prst = conn.prepareStatement("SELECT colName FROM User WHERE name = ?");
prst.setString(1, name);
ResultSet rs = prst.executeQuery();
if(rs.next()){
reuturn rs.getString("colName");
}
Without quoting the name string it's interpreted as column name, and thus the error you see. You could surround it with single quotes, but that's still generally a bad practice, and will leave the code vulnerable to SQL injection attacks.
Additionally, you're missing the select list (specifically, the id_user column), and missing getting it from the result set.
And finally, you forgot to close the statement and the result set.
If you put all of these corrections together, you should use something like this:
public String getIdUser(String name) {
try (PreparedStatmet ps =
conn.prepareStatement("SELECT id_user FROM User WHERE name = ?")) {
ps.setString(1, name);
try (ResultSet rs = stat.executeQuery()) {
if (rs.next()) {
return rs.getString(1);
}
}
} catch (SQLException ignore) {
}
return null;
}
I've encountered an error and I'm not able to figure out my mistake. I've done my research and haven't found an appropriate answer for my question.
This is my code:
private void jButton6ActionPerformed(java.awt.event.ActionEvent evt) {
String CN, CNo, MN, NT, SNo, VIP, T, D;
CN = TF1.getText();
CNo = TF2.getText();
MN = TF3.getText();
NT = TF4.getText();
SNo = TF5.getText();
VIP = TF6.getText();
T = TF7.getText();
D = TF8.getText();
try
{
Class.forName("java.sql.DriverManager");
Connection con = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/devika", "root", "rockgirl12");
Statement stmt = (Statement) con.createStatement();
String query = "INSERT INTO Maintenance VALUES ('"+CN+"',"+CNo+",'"+MN+"',"+NT+",'"+SNo+"','"+VIP+"','"+T+"','"+D+"');";
stmt.executeUpdate(query);
JOptionPane.showMessageDialog(this, "Record added succesfully!");
}
catch(Exception e)
{
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
What I'm trying to do here is I'm adding data to my SQL database through a form I designed in Java Netbeans. I've attached the form I've created here.
My Form
Help would be greatly appreciated :)
Exactly what the error says. The number of columns and the fields in valules do not match. This sort of insert without specifing the column names isn't the best practice by any stretch. You should do
String query = "INSERT INTO Maintenance(col1, col2, col3, col4,..) VALUES ('"+CN+"',"+CNo+",'"+MN+"',"+NT+",'"+SNo+"','"+VIP+"','"+T+"','"+D+"');";
In fact, you shouldn't be doing this sort of string concatenation either. It's far better to use prepared statements. The current approach does not ensure that the data is properly escaped before being saved.
I'm creating a program to put on my resume seeing as I am a college student with no work experience yet. For this particular part of the program I want to allow the user to search the sqlite database for an employee by either id number, first name or last name. It is working properly, however, it will only show the employee with the name that is spelled exactly and caps sensitive. I want it so that the user can type in a single letter or more and it will show everything in the database that contains that letter or couple letters and so on.
This is what I have:
try {
String field = (String)fieldCombo.getSelectedItem();//gets jcombobox selection
//jcombobox fields are slightly different than the column names in sql table so i did this
if(field.equals("First Name")) {
newField = "firstName";
}
else if(field.equals("Last Name")) {
newField = "lastName";
}
else if(field.equals("ID Num")) {
newField = "idNum";
}
String sql = "select idNum as 'ID Number', firstName as 'First Name', lastName as 'Last Name' from tableEMPLOYEE where " + newField + " = ?";
pst = connect.prepareStatement(sql);
pst.setString(1, searchField.getText());
rs = pst.executeQuery();
empTable.setModel(DbUtils.resultSetToTableModel(rs));
}
catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
as Tim mentioned in comment section. SQL LIKE is what you might need.
But it will not be fast if the database is big and the user types fast, it wont feel responsive enough.
For making a query in SQLITE case insensitive you can use:
SELECT * FROM ... WHERE name = 'enterName' COLLATE NOCASE
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
public class StudentDAO extends ConnectorDAO {
private List<StudentBean> studentList = new LinkedList<>();
private StudentBean studentBean;
public List<StudentBean> retrieveStudents() {
Connection connection;
try {
String myQuery = "SELECT ?, ?, ? FROM Students";
connection = getConnection() // getConnection() comes from superclass
PreparedStatement preparedstatement = connection.prepareStatement(myQuery);
preparedStatement.setString(1, "firstname");
preparedStatement.setString(2, "lastname");
preparedStatement.setString(3, "studentID");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
studentBean = new StudentBean();
studentBean.setFirstName(resultSet.getString("firstname"));
studentBean.setLastName(resultSet.getString("lastname"));
studentBean.setID(resultSet.getInt("studentID"));
studentList.add(studentBean);
}
} catch (Exception e) {
// Error handling stuff
} finally {
// close connection, resultset and preparedstatement
}
}
}
An error shows in my eclipse. On the line where I set the studentBean's ID. The data type of the studentID in my database is of Int. I'm not sure how to retrieve it though. Can anyone help me? It works when I use a Statement object when I query with the parameters used in the prepared statement.
Your code for building the query is incorrect:
String myQuery = "SELECT ?, ?, ? FROM Students";
connection = getConnection() // getConnection() comes from superclass
PreparedStatement preparedstatement = connection.prepareStatement(myQuery);
preparedStatement.setString(1, "firstname");
preparedStatement.setString(2, "lastname");
preparedStatement.setString(3, "studentID");
Is not possible:
A query string is formatted like this (example):
String myQuery = "SELECT firstname, lastname, studentID FROM Students WHERE studentID=?";
The parameters are only to be used on variables not on column names, table names etc.
So once you have code like that you could query on a studentID (not your goal but just for the example):
preparedStatement.setInt(1, someStudentID);
Which would be send with the preparedStatement to the DBMS in which then the DBMS replaces the ? with the value of someStudentID.
The meaning of setString (or setInt or any other setXXX in PreparedStatement), is "replace the corresponding question mark with the given value, appropriately typed". So this code:
String myQuery = "SELECT ?, ?, ? FROM Students";
connection = getConnection() // getConnection() comes from superclass
PreparedStatement preparedstatement = connection.prepareStatement(myQuery);
preparedStatement.setString(1, "firstname");
preparedStatement.setString(2, "lastname");
preparedStatement.setString(3, "studentID");
Effectively creates the following query:
SELECT 'firstname', 'lastname', 'studentID' FROM Students
Now, this tells it to select three literal strings from the table. If you ran this query in an SQL command line utility or something similar, you'd find that the result is
firstname | lastname | studentID
firstname | lastname | studentID
firstname | lastname | studentID
firstname | lastname | studentID
...
Instead of what you expected. Anything set by setString is interpreted as a literal string - as if it includes single quotes.
So question marks are used for setting values in the statement, that would be literal values if you were typing the statement in a command line utility.
So what your result set has is rows upon rows containing the three strings firstname, lastname and studentID.
Now, in the next bit of code:
while (resultSet.next()) {
studentBean = new StudentBean();
studentBean.setFirstName(resultSet.getString("firstname"));
studentBean.setLastName(resultSet.getString("lastname"));
studentBean.setID(resultSet.getInt("studentID"));
studentList.add(studentBean);
}
in many database systems, you wouldn't even be able to use getString("firstname") because the returned column name from a query for literals is arbitrary. But I suppose your database system actually gives the return column the same name as the literal value. So you are able to retrieve firstname and lastname (But their content is not the student name! It's the literal strings "firstname" and "lastname"), because you are using getString.
But you run out of luck when you try to use getInt. Since you queried for literal strings, you are getting back three strings. The third column is not an integer but the literal string "studentID". This is where you hit the error.
So you should change your query to
"SELECT firstname, lastname, studentID FROM Students"
Which means you don't necessarily need a prepared statement in this case, but it doesn't hurt either.
Where can you use the question marks, then?
Anywhere you need a literal value in your query. For example, if you want to know the difference between a person's year of birth and a given year, you could write:
SELECT year_of_birth - ? FROM people
And then use setInt(1,1969) or setInt(1,2001) to make the query become:
SELECT year_of_birth - 1969 FROM people
and
SELECT year_of_birth - 2001 FROM people
Respectively. In prepared statements, the actual names of database objects such as columns and tables, which are not literals, cannot be replaced with a question mark. They are part of the query plan itself.
I have 3 comboboxes in Java which are ;
'departurecities={city1,city2,city3}
destinationcities={city1,city2,city3}
date={1,2,3,4,5,6...}
I want to define a variable for the date because I don't know, what user will bus date, so I need a variable for SQL query.
I want to query like that:
sql=select busid from buses where dep='city1'and des='city2' and
datebus=(????variable????);
how can I define it ???
Please help me ..
Thanks in advance
PreparedStatement
In case you want to pass a variable to your SQL statement, I would recommend a PreparedStatement. See Oracle Tutorial.
You can use setInt in order to pass an integer, setString to pass a String etc.
Here is the API.
Here is an example:
String result = null;
String query = "select busid from buses where dep='city1'and des='city2' and datebus=?";
try {
PreparedStatement preps = con.prepareStatement(query);
preps.setInt(1, Integer.parseInt((String) date.getSelectedItem()));
preps.execute();
rs = preps.getResultSet();
if (rs.next()) {
result = rs.getString(...);
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
I assume that datebus is declared as an integer in your database table.
You can use a String type for a constant like '2012-12-31 12:00 am', or, Date or GregorianCalendar if you want to manipulate days/date differences in Java.
In SQL, you can convert string or character values into SQL's internal date format with the to_date() function:
SQL examples:
to_date('29-Oct-09', 'DD-Mon-YY')
to_date('10/29/09', 'MM/DD/YY')
to_date('120109', 'MMDDYY')
So, if you wanted to create a SQL command from Java:
String date = "12/31/2012";
String dep = "city1";
String des = "city2";
String SQL = "INSERT INTO buses VALUES(" + dep + "," + des + ",to_date(" + date + ",'MM/DD/YYYY'));";