I have a statement that could retrieve last month's transaction records from Oracle:
select
c.CustomerID as id,
c.Order_ID as txID,
c.Transaction_Date as date1
from
Members a, Verify_Detail b, Verify_Request c
where
a.CustomerID = b.CustomerID AND
b.CustomerID = c.CustomerID AND
b.Order_ID = c.Order_ID AND
c.Transaction_Date between add_months(trunc(sysdate,'mm'),-1) and last_day(add_months(trunc(sysdate,'mm'),-1))
order by
c.CustomerID, c.Transaction_Date desc
This statement works fine on SQL Developer. But when I use JDBC and Prepared statement to try to fetch my data, it shows me exception 17006: Invalid Column Name, Cause: null all the time.
I'd like to know what is wrong with my statement that made me unable to execute it on JDBC? Isn't it support to be executed if I could use it on Oracle SQL Developer?
Update:
The code that I use is simple:
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/myDBSrc");
Connection con = ds.getConnection();
String sql = "select " +
"c.CustomerID as id, c.Order_ID as txID, c.Transaction_Date as date1 " +
"from Members a, Verify_Detail b, Verify_Request c " +
"where a.CustomerID = b.CustomerID AND b.CustomerID = c.CustomerID AND " +
"b.Order_ID = c.Order_ID AND " +
"c.Transaction_Date between add_months(trunc(sysdate,'mm'),-1) and last_day(add_months(trunc(sysdate,'mm'),-1)) " +
"order by c.CustomerID, c.Transaction_Date desc";
PreparedStatement pstmt = con.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
out.println("ID: " + rs.getLong("id") + ", txID: " + rs.getString("txID") + ", Date: " + rs.getString("date1"));
}
}
catch(SQLException e){
out.println("SQL state: " + e.getSQLState() + ", Code: " + e.getErrorCode() + ", Msg: " + e.getMessage() + ", Cause: " + e.getCause());
}
This is only a guess, but too large for the comments section...
Maybe you connected the lines in a way that two consecutive lines get merged (in my example, the AND from one line merges with b.CustomerID from the next):
PreparedStatement stmt = conn.prepareStatement("select "+
"c.CustomerID as id, "+
"c.Order_ID as txID, "+
"c.Transaction_Date as date1 "+
"from "+
"Members a, Verify_Detail b, Verify_Request c "+
"where "+
"a.CustomerID = b.CustomerID AND" // <=====
"b.CustomerID = c.CustomerID AND "+
"b.Order_ID = c.Order_ID AND "+
"c.Transaction_Date between add_months(trunc(sysdate,'mm'),-1) "+
"and last_day(add_months(trunc(sysdate,'mm'),-1)) "+
"order by "+
"c.CustomerID, c.Transaction_Date desc");
EDIT: I think the reason is much simpler... it's Oracle turning all Identifiers to uppercase, so try this:
String sql = "select " +
"c.CustomerID as \"id\", c.Order_ID as \"txID\", c.Transaction_Date as \"date1\" " +
"from Members a, Verify_Detail b, Verify_Request c " +
"where a.CustomerID = b.CustomerID AND b.CustomerID = c.CustomerID AND " +
"b.Order_ID = c.Order_ID AND " +
"c.Transaction_Date between add_months(trunc(sysdate,'mm'),-1) and last_day(add_months(trunc(sysdate,'mm'),-1)) " +
"order by c.CustomerID, c.Transaction_Date desc";
17006: Invalid Column Name Is raised if you are trying to get not existing column from result set.
1) Option Add external select and try again select * from (your_select)
2) Try to get data with column names.
"ID: " + rs.getLong("CustomerID") + ", txID: " + rs.getString("Order_ID") + ", Date: " + rs.getString("Transaction_Date")
I know there is connection propertie GET_COLUMN_LABEL_FOR_NAME. And if is set to false. ResultSet only knows real column_name. But i'm not sure if ojdbc supports it.
Related
I use this code to make SQL request to find DB record:
public Optional<Subscription> findSubscriptionsByUserEmail(String email) {
String hql = "SELECT s " +
"FROM " + Subscription.class.getName() + " s " +
"INNER JOIN " + Orders.class.getName() + " o ON s.orderId = o.id " +
"INNER JOIN " + Users.class.getName() + " u ON u.id = o.userId " +
"WHERE u.email = :email " +
"ORDER BY s.createdAt DESC ";
TypedQuery<Subscription> query = entityManager.createQuery(hql, Subscription.class).setMaxResults(1).setParameter("email", email);
Optional<Subscription> subscription = Optional.of(query.getSingleResult());
return subscription;
}
But when I don't have a record I get exception: No entity found for query
Do you know how I can skip this exception and continue code execution?
The simplest way to do it is either to try/catch the optional object to see there has been a data sent back or make simple check to see if the optional has an object in it.
Eg:
!subscription.isPresent()? null:subscription;
If i insert a quote symbol " in the codContract parameter I receive the following error.
Error querying database. Cause: java.sql.SQLSyntaxErrorException:
ORA-00972: identifier too long
The error may exist in mappers/existence.xml The error may involve
com.iv.queryinterface.AssistenzaMapper.getTitlesFromCodContratct-Inline
The error occurred while setting parameters
SQL:
SELECT t.id_title,
c.des_lastname,
c.des_firstname,
to_char(t.dta_raw, 'DD/MM/YYYY') AS DTA_RAW,
DECODE(t.cod_statustitle, '1', 'Raw', '2', 'Stated') AS STATUS_TITLE
FROM Ivf_Policy p,
Ivf_Title t,
Ivg_Client c,
Ivf_Price pr
WHERE Cod_Contract = TEST
AND p.id_policy = t.id_policy
AND t.cod_type_title IN(2, 3, 13)
AND t.cod_statustitle IN(1, 2)
AND t.cod_client = c.cod_client
AND t.id_price = pr.id_price;
Cause: java.sql.SQLSyntaxErrorException: ORA-00972: identifier too
long
In this example, i set " TEST as value for the codContract parameter. My questions are:
Is this an exploitable SQL injection or a false positive that just prints an sql error into the stack trace?
The code is susceptible to SQL injection, and does no escaping. All that is avoidable by the use of PreparedStatement. Where the query string is not composed dynamically.
Now "TEST is the first part of an SQL identifier till a closing double quote.
I do not want to instruct readers on hacking, but think what something like
"'' OR 1=1 "
+ "UNION SELECT u.login, u.password, '', '', '', '' "
+ "FROM users"
+ "\u0000-- ";
might reveal on data.
Use java.sql.PreparedStatement for avoiding SQL injection.
String query =
"SELECT " +
" t.id_title , " +
" c.des_lastname , " +
" c.des_firstname , " +
" TO_CHAR(t.dta_raw, 'DD/MM/YYYY') AS DTA_RAW, " +
" DECODE(t.cod_statustitle, '1', 'Raw', '2', 'Stated') AS STATUS_TITLE " +
"FROM " +
" Ivf_Policy p, " +
" Ivf_Title t, " +
" Ivg_Client c, " +
" Ivf_Price pr " +
"WHERE " +
"1 = 1 AND " +
" Cod_Contract = ? " +
"AND p.id_policy = t.id_policy " +
"AND t.cod_type_title IN(2, " +
" 3, " +
" 13) " +
"AND t.cod_statustitle IN(1, " +
" 2) " +
"AND t.cod_client = c.cod_client " +
"AND t.id_price = pr.id_price;";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setString(1, 'TEST');
ResultSet rs = stmt.executeQuery();
To avoid SQL injection, do not append parameter values directly to SQL queries.
Use bind variables instead.
Thanks.
I wanted to execute this query, but it gave me an error without using variables but it gave me an error ORA-00905: missing keyword.
I tested the query in SQL Developer and it ran with no errors. I'm probably think it's a driver issue or a syntax issue with JDBC. But I have no idea here's the code:
public List<ReimbBean> getAllReimb() {
String sql = "select reim.reimb_id, reim.reimb_amount,"
+ "reim.reimb_submitted, reim.reimb_resolved, "
+ "CONCAT(CONCAT(u.user_first_name,' '),"
+ " u.user_last_name) AS \"REIMB_AUTHOR\", "
+ "reim.REIMB_RESCRIPTION, rst.REIMB_STATUS, "
+ "rtype.REIMB_TYPE, CONCAT(CONCAT(urs.user_first_name,' '), "
+ "urs.user_last_name) AS \"REIMB_RESOLVER\""
+ "FROM ERS_REIMBURSTMENT reim"
+ "LEFT JOIN ERS_USERS u"
+ "ON u.ERS_USERS_ID = reim.REIMB_AUTHOR"
+ "LEFT JOIN ERS_REIMBURSTMENT_STATUS rst"
+ "ON rst.REIMB_STATUS_ID = reim.REIMB_STATUS_ID"
+ "LEFT JOIN ERS_REIMBURSTMENT_TYPE rtype"
+ "ON rtype.reimb_type_id = reim.REIMB_TYPE_ID"
+ "LEFT JOIN ERS_USERS urs"
+ "ON urs.ERS_USERS_ID = reim.REIMB_RESOLVER"
+ "ORDER BY reim.reimb_id";
List<ReimbBean> reimbAllList = new ArrayList<>();
ReimbBean reimb = new ReimbBean();
try {
PreparedStatement preparedStatement = conn6.prepareStatement(sql);
ResultSet rs = preparedStatement.executeQuery();
while(rs.next()){
reimb.setReimbAmount(rs.getDouble("reimb_Amount"));
reimb.setReimbDescript(rs.getString("reimb_Description"));
reimb.setReimbSubmitted(rs.getTimestamp("reimb_Submitted"));
reimb.setReimbAuthor(rs.getInt("reimb_Author"));
reimb.setReimbResolved(rs.getTimestamp("reimb_Resolved"));
reimb.setReimbResolver(rs.getInt("reimb_Resolver"));
reimb.setReimbStatusID(rs.getInt("reimb_Status_ID"));
reimb.setReimbTypeID(rs.getInt("reimb_Type_ID"));
reimbAllList.add(reimb);
}
I read online that the preapareStatement is unable to bind objects only variables, so the alternative was to define them explicitly, so I created a part for declarations and substituted the fields with String variables, but the error continues to persist.
You are missing whitespaces at the end of a lot of those strings:
String sql = "select reim.reimb_id, reim.reimb_amount,"
+ "reim.reimb_submitted, reim.reimb_resolved, "
+ "CONCAT(CONCAT(u.user_first_name,' '),"
+ " u.user_last_name) AS \"REIMB_AUTHOR\", "
+ "reim.REIMB_RESCRIPTION, rst.REIMB_STATUS, "
+ "rtype.REIMB_TYPE, CONCAT(CONCAT(urs.user_first_name,' '), "
+ "urs.user_last_name) AS \"REIMB_RESOLVER\" " // Here
+ "FROM ERS_REIMBURSTMENT reim " // and here
+ "LEFT JOIN ERS_USERS u " // and here
+ "ON u.ERS_USERS_ID = reim.REIMB_AUTHOR " // and here
+ "LEFT JOIN ERS_REIMBURSTMENT_STATUS rst " // and here
+ "ON rst.REIMB_STATUS_ID = reim.REIMB_STATUS_ID " // and here
+ "LEFT JOIN ERS_REIMBURSTMENT_TYPE rtype " // and here
+ "ON rtype.reimb_type_id = reim.REIMB_TYPE_ID " // and here
+ "LEFT JOIN ERS_USERS urs " // and here
+ "ON urs.ERS_USERS_ID = reim.REIMB_RESOLVER " // and here
+ "ORDER BY reim.reimb_id";
The SQL statement below works in mySQL Workbench, but when I execute it in Eclipse, there is an mySQL exeception error. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 'by schedule.id' at line 1
String sqlStr = "select movie_db.movie , schedule.date , schedule.timeslot "
+ ", schedule.seats as NoSeats,"
+ " a.bookingsMade, if ( (schedule.seats-a.bookingsMade) is null, schedule.seats,(schedule.seats-a.bookingsMade) ) as availSeats"
+ " ,schedule.movie_id, schedule.id as scID"
+ " from schedule"
+ " left outer join movie_db on ( movie_db.id=schedule.movie_id )"
+ " left outer join ("
+ " select count(*) as bookingsMade, tickets.movie_id as aid from tickets"
+ " group by schedule_id"
+ " ) as a on (schedule.id=a.aid)"
+ " where schedule.movie_id=?"
+ "group by schedule.id";
PreparedStatement pstmt = sqlConnect.getPreparedStatement(sqlStr);
pstmt.setInt(1, Integer.parseInt(movieId));
ResultSet rs = pstmt.executeQuery();
that cannot work:
where schedule.movie_id=?"
+ "group by schedule.id";
change it to
where schedule.movie_id=?"
+ " group by schedule.id";
I have a problem with an empty result set, which are throwing some errors. But it is working fine as long as it is not empty.
String sql = "SELECT M2.fromProfileId, profiles.profileMiniature, profiles.firstName, profiles.lastName, profiles.timeFormat, lastMessages.message, lastMessages.timeStamp " +
"FROM (" +
" SELECT M1.fromProfileId, " +
" max(M1.timeStamp) AS lastMessageTime " +
" FROM messages AS M1 " +
" WHERE M1.toProfileId = ? " +
" GROUP BY M1.fromProfileId " +
" ORDER BY max(M1.timeStamp) DESC " +
" LIMIT 10 " +//line 60
" ) AS M2 " +
"INNER JOIN messages AS lastMessages " +
"ON (" +
" lastMessages.timeStamp = M2.lastMessageTime " +
"AND lastMessages.fromProfileId = M2.fromProfileId" +
" )" +
"INNER JOIN profiles " +
"ON M2.fromProfileId = profiles.profileId ";
PreparedStatement statement = con.prepareStatement(sql);
statement.setString(1, profileId);
ResultSet result = statement.executeQuery();
JSONArray messages = new JSONArray();
while(result.next()){
JSONObject message = new JSONObject();
message.put("fromProfileId", result.getString("fromProfileId"));
message.put("profileMiniature", result.getString("profileMiniature"));
message.put("firstName", result.getString("firstName"));
message.put("lastName", result.getString("lastName"));
message.put("lastMessage", result.getString("message"));
message.put("lastMessageTime", result.getString("timeStamp"));
message.put("timeFormat", result.getString("timeFormat"));
messages.put(message);
}
and the error is Illegal operation on empty result set. How shall I fix this?
StackTrace:
Illegal operation on empty result set.
at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at
com.mysql.jdbc.ResultSetImpl.checkRowPos(ResultSetImpl.java:841)
at
com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5656)
at
com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5576)
at
com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5616)
at
messages.GetMessages.doGet(GetMessages.java:60)
at
javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at
javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at
org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:534)
etc..
I found many bugs in MySQL JDBC driver which seem to cause this exception.