UCAExc 3.0.7 unexpected token Errors - java

I'm working on a project that wants me to integrate a Microsoft Access database into a Java program. I have successfully connected to the database however my SQL statements are not updating the DB. I have defined variables that read user input and use that information as the conditional for the WHERE statement. I have taken parts of the first query out and have gotten positive results but the whole statement refuses to cooperate. What do I need to change about the first query to make it run?
result = statement.executeQuery("SELECT slipNumber FROM Slip WHERE (slipOpen = -1 & slipLength >= " + boatLengthdub + "& slipDepth >= " + boatDepthdub + ")"+ "LIMIT 1" );
statement.executeQuery("INSERT INTO Slip (slipOpen, boatID) VALUES (0," + boatIDdub + ")");
System.out.println("Have a" + result);

You appear to be trying to use the ampersand character (&) where you should be using the SQL keyword AND. You also should be using PreparedStatement objects to perform parameterized queries, e.g.,
String sql =
"SELECT slipNumber FROM Slip " +
"WHERE slipOpen = -1 AND slipLength >= ? AND slipDepth >= ? " +
"LIMIT 1";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setDouble(1, boatLengthdub); // assuming that they are Double values
ps.setDouble(2, boatDepthdub);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
System.out.println(rs.getInt("slipNumber"));
} else {
System.out.println("Not found.");
}

I fully agree. And when you perform an update, I'd suggest to use 'statement.executeUpdate(query)'.

Related

LogIn with SQL and java

i'm try to made a simple log in sistem with java and mysql, the configuration of the db is made up, but i have an error in the SQL sintax:
System.out.println("SISTEM LOGIN");
System.out.println("INSERIRE NOMEUTENTE");
Scanner scan= new Scanner(System.in);
String user= scan.nextLine();
System.out.println("INSERIRE PASSWORD");
String pass= scan.nextLine();
try {
boolean log = true;
while(log) {
//conn db
Connection c = DriverManager.getConnection(url,usr,pswd);
//creaz statement
Statement ss = c.createStatement();
//creaz codice sql
String sql = " SELECT * FROM users WHERE user'" + user + "' && password='" + pass+ "' ";
ResultSet res = ss.executeQuery(sql);
if(res!=null) {
System.out.println("LOGIN");
log = false;
}
else System.out.println("LOGIN FAILE");
}
}
what do you think i haven't see in the sql string?
this is the response :
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 ''ciao' && password='12'' at line 1
The following statement is wrong and should be avoided:
String sql = " SELECT * FROM users WHERE user'" + user + "' && password='" + pass+ "' ";
String concatenation makes it vulnerable to SQL injection attacks. Use preparedstatement. Look here for an example and here as well.
Moreover you are missing an = after user and replace && with AND.
And as suggested by the error, go through the mysql manual once.
Your expanded SQL statement reads
SELECT * FROM users WHERE user 'ciao' && password='12'
That's wrong. To be valid SQL it needs to say
SELECT * FROM users WHERE user = 'ciao' AND password='12'
#PritamBanerjee pointed out it's vulnerable to sql injection. That's dangerous.
And, this is horrendous for another reason. You should never, ever, store unscrambled passwords in your dbms. If you're not sure why, visit https://haveibeenpwned.com.
The php manual has a good explanation of the right way to do it. http://php.net/manual/en/faq.passwords.php You should use a one-way scrambling function like bcrypt for this purpose.
Here's some decent material about doing this in Java. https://www.owasp.org/index.php/Hashing_Java
Your query is not correct
String sql = " SELECT * FROM users WHERE user'" + user + "' && password='" + pass+ "' ";
If you will check you have included "' && password='" + pass+ "' ";
but in forst part of statement user'" + user here missing =
Correct query should be
String sql = " SELECT * FROM users WHERE user='" + user + "' && password='" + pass+ "' ";
Actually there is not any issue with the && operator as mentioned in comments : https://dev.mysql.com/doc/refman/5.7/en/non-typed-operators.html
You just missing the = operator just after the WHERE user statement.
I suggest you to use "prepared statements" when injecting parameters to your sql statement for preventing sql injection (How does a PreparedStatement avoid or prevent SQL injection?).
PreparedStatement stmt = c.prepareStatement("SELECT * FROM users WHERE user=? && password=?");
stmt.setString(1, user);
stmt.setString(2, pass);
ResultSet res = stmt.executeQuery();

Trouble with ResultSet using executeUpdate

I am new to programming and have run into a problem while using executeUpdate with the resultSet next() method.
It iterates once only through the result set then the execute update closes the result set. I get error: ResultSet not open. Operation "next" not permitted. Verify that autocommit is off.
I have added the con.setAutoCommit(false) statement but problem still persists.
I need to run the update multiple times with different variable values.
Here is the code I have:
try {
String eidQuery = "SELECT EID FROM EMPLOYEE_DATA WHERE ACTIVE = TRUE ORDER BY EID";
int nextEID;
Statement st = con.createStatement();
con.setAutoCommit(false);
rs = st.executeQuery(eidQuery);
while (rs.next()){
nextEID = rs.getInt(1);
String getDailyTotals = "SELECT DATE, SUM(TOTAL), MAX(OUT_1) FROM PUNCHES WHERE EID = " + nextEID + " AND DATE >= '" + fd + "' "
+ "AND DATE <= '" + td + "' GROUP BY DATE";
ResultSet rs2 = st.executeQuery(getDailyTotals);
while (rs2.next()){
double dailyTotal = rs2.getDouble(2);
if (dailyTotal > 8){
double dailyOT = dailyTotal-8;
String dailyDate = rs2.getDate(1).toString();
Timestamp maxTime = rs2.getTimestamp(3);
String updateOT = "UPDATE PUNCHES SET OT = " + dailyOT + " WHERE EID = " + nextEID + " AND DATE = '" + dailyDate + "' AND OUT_1 = '" + maxTime + "'";
st.executeUpdate(updateOT);
}
}
}
rs = st.executeQuery("SELECT PUNCHES.EID, EMPLOYEE_DATA.FIRST_NAME, EMPLOYEE_DATA.LAST_NAME, SUM(PUNCHES.OT) FROM PUNCHES "
+ "JOIN EMPLOYEE_DATA ON PUNCHES.EID = EMPLOYEE_DATA.EID WHERE PUNCHES.DATE >= '" + fd + "' AND PUNCHES.DATE <= '" + td + "' GROUP BY EMPLOYEE_DATA.FIRST_NAME, EMPLOYEE_DATA.LAST_NAME, PUNCHES.EID");
Reports.setModel(DbUtils.resultSetToTableModel(rs));
} catch (SQLException ex) {
Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(null, ex);
}
You're new to programming and (obviously) Java. Here are a few recommendations that I can offer you:
Do yourself a favor and learn about PreparedStatement. You should not be creating SQL by concatenating Strings.
You are committing the classic newbie sin of mingling database and UI Swing code into a single, hard to debug lump. Better to decompose your app into layers. Start with a data access interface that encapsulates all the database code. Get that tested and give your UI an instance to work with.
Do not interleave an update query inside the loop over a ResultSet. Better to separate the two completely.
Read about MVC. You'll want your Swing View to be separate from the app Controller. Let the Controller interact with the data access interface, get the results, and give the results to the View for display. Keep them decoupled and separate.
Learn JUnit. It'll help you with testing.
From the java.sql.ResultSet javadoc:
A ResultSet object is automatically closed when the Statement object
that generated it is closed, re-executed, or used to retrieve the next
result from a sequence of multiple results.
After you execute the update, the prior ResultSet is closed. You need to rework your code to account for that.
https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
The easiest way to rework might be to use two Statements, one for the query and one for the update, but as noted in duffymo's answer there's a fair amount more you could do to improve things.
From API's statement documentation "By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects"
You need two different Statements if you want to read two different ResultSet in the same nested loops.

JDBC timeout with ResultSet am I doing it right?

I have a JDBC ResultSet that gives me a TimeOut after only a few thousand rows are processed. I have a few million rows to process, so I'd like to tweak my program to avoid this, just not sure what needs to be tweaked.
Database table is indexed and returns data quickly using selection criteria, so I don't believe it is on the database side. I'm returned 14 columns mixed between address columns and ints. Not a lot of data.
I'm doing a connection.createStatement() and then building the SQL from there. The answer might be I should use a prepared statement.
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
String jobNameFilter = (Cli.getJobName() != null) ? " AND [JobName] = '" + Cli.getJobName() + "'" : "";
String sortOrder = (Cli.isAscending()) ? "ASC" : "DESC";
String orderByClause = Cli.isRandom() ? " ORDER BY [Randomizer] " + sortOrder + ",[RecordID] " + sortOrder : " ORDER BY [RecordID] " + sortOrder;
String startingIdFilter = (Cli.getStartingId() != null) ? " AND [RecordId] > " + Cli.getStartingId() : "";
String driverQuery = "SELECT [RecordID], [Column1] AS [TrackingID], [Address]" + ", [Suite] AS [AptSuiteOther], [City], [Building2Key]"
+ ", [ST] AS [State], [ZIPCode]" + ", [BusinessName], [ContactLastName], [Suite]" + ", [Phone], [EmailAddress]"
+ " FROM [Project].[TestSet] WITH (READUNCOMMITTED)"
+ " INNER JOIN [Project].[State] sttable ON sttable.[ST] = UPPER([Project].[TestSet].[ST]) AND [TerritoryFlag] = 0" + " WHERE [BuildingKey] = 0 " + jobNameFilter
+ startingIdFilter + " AND (([FirstResponse] IS NULL AND ([Building2Key] IS NULL OR [Building2Key] = 0)) OR ([Building2Key] > 0 AND [SecondResponse] IS NULL)) " + orderByClause;
rs = stmt.executeQuery(driverQuery);
} catch (SQLException e1) {
logger.error("SQLException", e1);
}
try {
while (rs.next()) {
int recordId = rs.getInt("RecordID");
// Process data
numberProcessed++;
}
} catch (SQLException sqle) {
logger.error("SQLException", sqle);
}
I'm closing all the ResultSet, Connection and Statement in a finally statement at a different level also.
I'm not sure if I need to set the timeout to something higher, setFetchSize to something greater? Trap timeout and create ResultSet again?
Change logic to only pull one row at a time?
You'd have to profile your app to find out for sure, but I'm guessing that the "// Process data" part is the culprit. You're holding the connection open while process all of the rows.
I'd suggest that you read a batch of rows at a time, close the statement, and then process the batch. Then do a select for the next batch, rinse and repeat.
Selecting one row at a time would introduce a lot of overhead, so I wouldn't suggest doing that.
Also, make sure that you're using a connection pool, so that you don't actually have to build a new Connection each time. The pool will keep it open for you, and recycle it if it goes dead / times out.

Retriving data from different tables in database sending SQL code to be executed, returning data?

I am making a class in Java to connect and otherwise talk to a database, that I have set up elsewhere. I want to use the executeQuery method for a statement, and recieve a ResultSet, from where I will retrieve the information received in the ResultSet.
My issue is with the SQL command, as in; the query I'm sending to the database. Something appears to be wrong, and I get an SQLException at the very point where I send the command, meaning I must have done something wrong.
Maybe I'm writing something wrong? I can't tell, since I've simply tried to follow the example guidance provided for this course the best way I can.
Here is the query I'm trying to send:
"SELECT fr.DepartureLocation, fr.Destination, d.Date, d.Time FROM `FlightRoute` fr,
`Departure` d WHERE d.FlightRouteId = fr.Id AND d.Date > " + dateFrom + " AND
d.Date < " + dateTo + " AND fr.Destination = `" + destination + "`;"
The "dateFrom", "dateTo" and "destination" are all parameters for the method I'm calling, and I'm trying to limit the results I get from this statement, to those within a certain date-span as well as having a specific destination.
I might add that the dates are integers lined up such as this: 20131205
This should make it so that later dates are a higher number.
Is the way that I use the parameters with the SQL code wrong somehow, or did I make generally faulty SQL code here?
Thanks a lot, to anyone who might be able to provide a correct SQL code for me to use, so that I may see what I did wrong (since I'll have to make a few more similarly working SQL statements)!
Thanks in advance! :)
EDIT:
Here is the requested code where I am announcing the query and trying to execute it:
try
{
ArrayList<Departure> departures = new ArrayList<>();
Statement stmt = con.createStatement();
System.out.println("derp0");
String query = "SELECT fr.DepartureLocation, fr.Destination, d.Date, d.Time FROM FlightRoute fr, Departure d WHERE d.FlightRouteId = fr.Id AND d.Date > " + dateFrom + " AND d.Date < " + dateTo + " AND fr.Destination = `" + destination + "`;";
System.out.println("derp0.1");
ResultSet rs = stmt.executeQuery(query);
System.out.println("derp1");
As a short explaination, the souts are to check where the SQLException occured, and I can only say that the exception happens right after "derp0.1".
I suggest the following change:
PreparedStatement ps = connection.prepareStatement(
"SELECT fr.DepartureLocation, fr.Destination, d.Date, d.Time FROM `FlightRoute` fr,"+
"`Departure` d WHERE d.FlightRouteId = fr.Id AND d.Date > ? AND d.Date < ? "+
" AND fr.Destination = ?");
ps.setDate(1, dateFrom);
ps.setDate(2, dateTo);
ps.setString(3, destination); //assuming destination is a String
ResultSet rs = ps.executeQuery();
In JDBC you should always use parametrisation, as above. It might also solve your problem, which could be caused by an invalid date format.

SQL Where Clause with Values Provided

I am trying to use a SQL Select statement for a query in Java. I currently have the following:
ResultSet rs = stmt.executeQuery("SELECT *" +
" FROM " + table +
" WHERE " + selection +
" VALUES " + selectionArgs);
where "selection" is a string and "selectionArgs" is a string array.
String selection = "documentFK=?";
String[] selectionArgs = { ... };
Is it possible to use the VALUES command to replace the ? like in with the INSERT command? Either way, what would be the correct syntax?
Thanks for the help.
I believe what you're looking for is the IN statement. Your query should look like this:
SELECT *
FROM table
WHERE documentFK IN ('doc1', 'doc2', 'doc3')
AND userFK IN ('user1', 'user2', 'user3')
This is (obviously) going to make your code a bit more ugly. You'll have to ensure that the WHERE keyword is used for the first clause, but the AND keyword is used for every other clause. Also, each list will have to be comma-delimited.
no, that is not the way it's done. first you create the statement from the query, using the question marks as place holders for the real values you want to put there. then you bind these values to the statement.
//the query
String sql = "SELECT " + "*" +
" FROM " + table +
" WHERE documetFK = ?";
//create the statement
PreparedStatement stmt = connection.prepareStatement(sql);
//bind the value
stmt.setInt(1, 4); //1 is "the first question mark", 4 is some fk
//execute the query and get the result set back
ResultSet rs = stmt.executeQuery();
now, if you want this thing with selection string and some args, then you're going to have a loop in your java code. not sure what your array looks like (you're not giving me that much to go on), but if it's made up from strings, it would be something like this:
//the query
String sql = "SELECT " + "*" +
" FROM " + table +
" WHERE " + selection;
//create the statement
PreparedStatement stmt = connection.prepareStatement(sql);
//bind the values
for(int i = 0; i < selectionArgs.length; i++) {
stmt.setString(i, selectionArgs[i]); //i is "the nth question mark"
}
//execute the query and get the result set back
ResultSet rs = stmt.executeQuery();
Can you use a PreparedStatement?
First of all SELECT .. WHERE .. VALUES is incorrect SQL syntax. Lose the VALUES part.
Then you're looking for prepared statements.
In your example it's going to look something like this:
String sql = "SELECT * FROM myTable WHERE documentFK=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "myDocumentFK"); // parameters start from 1, not 0. also we're assuming the parameter type is String;
ResultSet rs = pstmt.executeQuery();
Or with multiple parameters:
String sql = "SELECT * FROM myTable WHERE documentFK=? AND indexTerm=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "myDocumentFK"); // parameters start from 1, not 0. also we're assuming the parameter type is String;
pstsm.setInt(2, 100); // assume indexTerm can be 100 and is an integer
ResultSet rs = pstmt.executeQuery();
However, all of this doesn't worth your while since you can simply do the same by concatenating the value into the statement. But be aware of the SQL injections, so don't forget to escape the parameters that you're passing into the database.
PS: I was typing this way too long. You already have the answers :-)
As a side note, you may want to take a look at this to prevent SQL injections:
https://www.owasp.org/index.php/Preventing_SQL_Injection_in_Java
Sormula can select using "IN" operator from a java.util.Collection of arbitrary size. You write no SQL. It builds the SQL SELECT query with correct number of "?" parameters. See example 4.

Categories