public ArrayList<Message> searchMessages(String word) throws DaoException{
ArrayList<Message> messages = new ArrayList<>();
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = getConnection();
//String query = "SELECT * FROM messages WHERE text LIKE %?% order by date";
String query = "SELECT * FROM messages WHERE text LIKE '%?%'";
ps = con.prepareStatement(query);
ps.setString(1,word);
rs = ps.executeQuery();
while (rs.next()) {
int messageId = rs.getInt("messageId");
String text = rs.getString("text");
String date = rs.getString("date");
int memberId2 = rs.getInt("memberId");
Message m = new Message(messageId,text,date,memberId2);
messages.add(m);
//Company c = new Company(companyId, symbol, companyName, sharePrice, high, low);
//companies.add(c);
}
} catch (SQLException e) {
throw new DaoException("searchMessages(): " + e.getMessage());
} finally {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (con != null) {
freeConnection(con);
}
} catch (SQLException e) {
throw new DaoException("searchMessages(): " + e.getMessage());
}
}
return messages;
}
Just explain the code a little first.It simply just searches the messages table and its field of text for whatever is supplied.I use a prepared statement to insert it into the query and run it.No matter what string i supply it gives this error
oow_package.DaoException: searchMessages(): Parameter index out of range (1 > number of parameters, which is 0).
No idea why it isn't working in the slightest. Would appreciate any help.
You can't use such a parameter in a prepared statement. The query should be
SELECT * FROM messages WHERE text LIKE ?
And you should use
ps.setString(1, "%" + word + "%");
I'm no expert, but i'd say your prepared statement is recognized with no parameters, and you still insert one (word)... maybe the trouble comes from the % sign?
EDIT: agree with the guy above... seems legit.
Related
I have a complex directory system with millions of xml files which i need to retrieve to an XMLType column in Oracle 18c. I'm working with a java method that is executed by a procedure to re-load this files on this particular table. Since a lot of the of the java libraries were deprecated i'm out of options to solve this issue. The way I had finded to workaround was a tempory table with a CLOB column where I can insert the content from the files and than inside oracle I insert those in the original table using a XMLType(clobVariable). BUT, it doesnt work on files larger then 20k characters.
If anyone can help me I'm more than glad to give more information.
(I'm from Brazil and maybe I didn't made myself clear on the explanation btw)
public static void inserirXml() throws Exception{
try {
int num_id_nfe;
String dirArquivo = "";
String query;
String queryUpdate;
String reCheck, insert;
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:default:connection:");
conn.setAutoCommit(false);
query = "SELECT ID_NFE, DSC_CAMINHO_XML FROM DFE_NFE_CAMINHO_XML WHERE FLG_CARREGADO = 0 AND ROWNUM <= 1000";
Statement stmt = conn.createStatement();
Statement stmt2 = conn.createStatement();
Statement stmt3 = conn.createStatement();
Statement stmt4 = conn.createStatement();
stmt.executeQuery(query);
ResultSet rset = stmt.getResultSet();
while(rset.next() == true) {
try {
num_id_nfe = rset.getInt(1);
dirArquivo = rset.getString(2);
byte[] bytes = Files.readAllBytes(Paths.get(dirArquivo));
String xmlString = new String(bytes, "utf-8");
String insertQuery = "INSERT INTO DFE_NFE_REP_XML_TMP (ID_NFE, XMLCLOB) VALUES(?,?)";
PreparedStatement pstmt = conn.prepareStatement(insertQuery);
xmlString = xmlString.substring(1);
pstmt.setInt(1, num_id_nfe);
pstmt.setNString(2, xmlString);
pstmt.execute();
pstmt.close();
queryUpdate = "UPDATE DFE_NFE_CAMINHO_XML SET FLG_CARREGADO = 1 WHERE ID_NFE = " + num_id_nfe + " \n";
stmt2.executeQuery(queryUpdate);
}catch(SQLException e) {
System.err.println(e.getMessage()+" loop");
stmt2.close();
throw e;
}
}
insert = "INSERT INTO DFE_NFE_REP_XML (ID_NFE, CONTEUDO) SELECT ID_NFE, XMLType(XMLCLOB) FROM DFE_NFE_REP_XML_TMP";
stmt4.executeUpdate(insert);
reCheck = "UPDATE DFE_NFE_CAMINHO_XML SET FLG_CARREGADO = 0 WHERE id_nfe not in (select id_nfe from dfe_nfe_rep_xml) and flg_carregado = 1";
stmt3.executeQuery(reCheck);
conn.commit();
rset.close();
stmt.close();
stmt2.close();
stmt3.close();
stmt4.close();
conn.close();
} catch (SQLException x) {
System.err.println(x.getMessage()+" geral");
}catch (ClassNotFoundException y) {
throw y;
}catch(Exception z) {
throw z;
}
}
I have following program which insert emoji and any text to my MySql AWS Database. I was unable to add Emojis in my MySql database, but then i fixed this problem by changing collation and adding this-> SET NAMES utf8mb4; query before my previous insert query but now i am unable to get last inserted id from it. what should i do in order to insert emoji as well as to get last inserted id from it.
Here is my code.
public static JSONObject emoji(String comment) {
JSONObject json = new JSONObject();
Connection con = null;
PreparedStatement stmt = null;
String newInsertId = "";
try {
BasicDataSource bds = DBConnection.getInstance().getBds();
con = bds.getConnection();
String query = "SET NAMES utf8mb4; insert into emojis set message = '" + comment + "';";
stmt = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
if (stmt.executeUpdate() > 0) {
json.put("success", 1);
}
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
newInsertId = rs.getString(1); //giving empty values cause of that SET NAMES utf8mb4; query
}
System.out.println(newInsertId); //empty
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
DbUtils.close(con);
DbUtils.close(stmt);
} catch (Exception e) {
e.printStackTrace();
}
}
return json;
}
static int create() throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
String sql = "insert into user(name,birthday, money) values ('name2 gk', '1987-01-01', 400) ";
ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);//参数2最好写上,虽然Mysql不写也能获取但是不代表别的数据库可以做到
ps.executeUpdate();
rs = ps.getGeneratedKeys();
int id = 0;
if (rs.next())
id = rs.getInt(1);
return id;
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
——————————————————————————————————————————————————————
Focus on this 'Statement.RETURN_GENERATED_KEYS'
I am trying to use the setString(index, parameter) method for Prepared Statements in order to create a ResultSet but it doesn't seem to be inserting properly. I know the query is correct because I use the same one (minus the need for the setString) in a later else. Here is the code I currently have:
**From what I understand, the ps.setString(1, "'%" + committeeCode + "%'"); is supposed to replace the ? in the query but my output says otherwise. Any help is appreciated.
public String getUpcomingEvents(String committeeCode) throws SQLException{
Context ctx = null;
DataSource ds = null;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
StringBuilder htmlBuilder = new StringBuilder();
String html = "";
try {
ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:ConnectDaily");
conn = ds.getConnection();
if(committeeCode != null){
//get all events
String queryStatement = "SELECT " +
.......
"WHERE c.calendar_id = ci.calendar_id AND c.short_name LIKE ? " +
"AND ci.style_id = 0 " +
"AND ci.starting_date > to_char(sysdate-1, 'J') " +
"AND ci.item_type_id = cit.item_type_id " +
"ORDER BY to_date(to_char(ci.starting_date), 'J')";
ps = conn.prepareStatement(queryStatement);
ps.setString(1, "'%" + committeeCode + "%'");
System.out.println(queryStatement);
rs = ps.executeQuery();
if (rs != null){
while(rs.next()){
String com = rs.getString("name");
String comID = rs.getString("short_name");
String startTime = rs.getString("starting_time");
String endTime = rs.getString("ending_time");
String name = rs.getString("contact_name");
String desc = rs.getString("description");
String info = rs.getString("contact_info");
String date = rs.getString("directory");
htmlBuilder.append("<li><a href='?com="+committeeCode+"&directory=2014-09-10'>"+com+" - "+ date +" - "+startTime+" - "+endTime+"</a> <!-- Link/title/date/start-end time --><br>");
htmlBuilder.append("<strong>Location: </strong>"+comID+"<br>");
htmlBuilder.append("<strong>Dial-In:</strong>"+com+"<br>");
htmlBuilder.append("<strong>Part. Code:</strong>"+info+"<br>");
htmlBuilder.append("<a href='http://nyiso.webex.com'>Take me to WebEx</a>");
htmlBuilder.append("</li>");
}
}
html = htmlBuilder.toString();
.
.
.
}catch (NamingException e) {
e.printStackTrace();
//log error and send error email
} catch (SQLException e) {
e.printStackTrace();
//log error and send error email
}finally{
//close all resources here
ps.close();
rs.close();
conn.close();
}
return html;
}
}
Output
14:18:22,979 INFO [STDOUT] SELECT to_char(to_date(to_char(ci.starting_date), 'J'),'mm/dd/yyyy') as start_date, to_char(to_date(to_char(ci.ending_date), 'J'),'mm/dd/yyyy') as end_date, to_char(to_date(to_char(ci.starting_date), 'J'),'yyyy-mm-dd') as directory, ci.starting_time, ci.ending_time, ci.description, cit.description as location, c.name, c.short_name, ci.add_info_url, ci.contact_name, ci.contact_info FROM calitem ci, calendar c, calitemtypes cit WHERE c.calendar_id = ci.calendar_id AND c.short_name LIKE ? AND ci.style_id = 0 AND ci.starting_date > to_char(sysdate-1, 'J') AND ci.item_type_id = cit.item_type_id ORDER BY to_date(to_char(ci.starting_date), 'J')
There is no need for the quotes in setString:
ps.setString(1, "%" + committeeCode + "%");
This method will bind the specified String to the first parameter. It will not change the original query String saved in queryStatement.
The placeholder remains as part of the SQL text.
The bind value is passed when the statement is executed; the actual SQL text is not modified. (This is one of the big advantages of prepared statements: the same exact SQL text is reused, and we avoid the overhead of a hard parse.
Also note that you are including single quotes within the value, which is a bit odd.
If the bind placeholder were to be replaced in the SQL text, assuming committeeCode contains foo, the equivalent SQL text would be:
AND c.short_name LIKE '''%foo%'''
which will match only c.short_name values that begin and end with a single quote, and contain the string foo.
(This looks more like Oracle SQL syntax than it does MySQL.)
As we know that in setString we can pass string value only, So even if we write the code like this:
String param="'%"+committeeCode+"%'";
And if you print the value of param it will throw error, Hence you cannot use it as well in prepared statement.
You need to modify modify it little bit as:
String param="%"+committeeCode+"%";(Simpler one, other way can be used)
ps.setString(1,param);
I have this method to load the objects, however when I am running the sql code it is giving me a Syntax error.
public void loadObjects() {
Statement s = setConnection();
// Add Administrators
try {
ResultSet r = s.executeQuery("SELECT * FROM Administrator;");
while (r.next()) {
Administrator getUser = new Administrator();
getUser.ID = r.getString(2);
ResultSet r2 = s.executeQuery("SELECT * FROM Userx WHERE ID= {" + getUser.ID + "};");
getUser.name = r2.getString(2);
getUser.surname = r2.getString(3);
getUser.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(getUser);
}
} catch (Exception e) {
System.out.println(e);
}
}
I have tried inserting the curly braces as stated in other questions, but I am either doing it wrong or it doesn't work.
This method should be able to load all administrators but I believe it is only inserting half of the ID.
The ID that it gets, consists of numbers and char; example "26315G"
the Error -
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '26315'.
Edit -
private java.sql.Connection setConnection(){
java.sql.Connection con = null;
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://" + host + ";DatabaseName=" + database + ";integratedSecurity=true;";
con = DriverManager.getConnection(url, username, password);
} catch(Exception e) {
System.out.println(e);
}
return con;
}
public void loadObjects() {
java.sql.Connection con = setConnection();
// Add Administrators
try {
PreparedStatement sql = con.prepareStatement("SELECT * FROM Administrator");
ResultSet rs = sql.executeQuery();
while (rs.next()) {
Administrator getUser = new Administrator();
getUser.ID = rs.getString(2);
PreparedStatement sql2 = con.prepareStatement("SELECT * FROM Userx WHERE ID=?");
sql2.setString(1, getUser.ID);
ResultSet r2 = sql2.executeQuery();
getUser.name = r2.getString(2);
getUser.surname = r2.getString(3);
getUser.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(getUser);
}
} catch (Exception e) {
System.out.println(e);
}
}
Actually it is not the way to do that in JDBC. That way, even if you sort your syntax error, your code is prone to sql injection attacks.
The right way would be:
// Let's say your user id is an integer
PreparedStatement stmt = connection.prepareStatement("select * from userx where id=?");
stmt.setInt(1, getUser.ID);
ResultSet rs = stmt.executeQuery();
This way you are guarded against any attempt to inject SQL in your application request parameters
First of all: if you use concurrently result-sets, you must use separate statements for each one of them (you can not share Statement s between two r and r2). And more, you lack r2.next() before reading from it.
On the other hand: it would be much more effective to use PreparedStatement in the loop that to rewrite the query all the time.
So I'd go for something like this:
public void loadObjects() {
try (
Statement st = getConnection().createStatement();
//- As you read (later) only id, then why to use '*' in this query? It only takes up resources.
ResultSet rs = st.executeQuery("SELECT id FROM Administrator");
PreparedStatement ps = getConnection().prepareStatement("SELECT * FROM Userx WHERE ID = ?");
ResultSet r2 = null;
) {
while (rs.next()) {
Administrator user = new Administrator();
user.ID = rs.getString("id");
ps.setInt(1, user.ID);
r2 = ps.executeQuery();
if (r2.next()) {
user.name = r2.getString(2);
user.surname = r2.getString(3);
user.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(user);
}
else {
System.out.println("User with ID=" + user.ID + " was not found.");
}
}
}
catch (Exception x) {
x.printStacktrace();
}
}
Please note use of Java7 auto-close feature (you didn't close resources in you code). And last note: until you are not separating statements in your queries, as to JDBC documentation, you should not place ';' at the end of statements (in all cases you shouldn't place ';' as the last character in you query string).
You should not use {} and you should not append parameters into a SQL query like this.
Remove the curly braces and use PreparedStatement instead.
see http://www.unixwiz.net/techtips/sql-injection.html
I want to create Java method which can count the rows in Oracle table. So far I made this:
public int CheckDataDB(String DBtablename, String DBArgument) throws SQLException {
System.out.println("SessionHandle CheckUserDB:"+DBArgument);
int count;
String SQLStatement = null;
if (ds == null) {
throw new SQLException();
}
Connection conn = ds.getConnection();
if (conn == null) {
throw new SQLException();
}
PreparedStatement ps = null;
try {
conn.setAutoCommit(false);
boolean committed = false;
try {
SQLStatement = "SELECT count(*) FROM ? WHERE USERSTATUS = ?";
ps = conn.prepareStatement(SQLStatement);
ps.setString(1, DBtablename);
ps.setString(2, DBArgument);
ResultSet result = ps.executeQuery();
if (result.next()) {
count = result.getString("Passwd");
}
conn.commit();
committed = true;
} finally {
if (!committed) {
conn.rollback();
}
}
} finally {
/* Release the resources */
ps.close();
conn.close();
}
return count;
}
I want to use for different tables. This is the problem that I cannot solve:
count = result.getString("row");
Can you help me to solve the problem?
count = result.getInt(1);
This is needed, because count is int. And you can specify the index of the row returned by the query, you don't need to access it by name.
But you could also do:
count = result.getInt("count(*)");
This should do it:
count = result.getInt("count(*)");
You need to use the same name as you specified in your query to get the value. You could also make your
count = result.getString("row");
work by changing your query to
SQLStatement = "SELECT count(*) as row FROM ? WHERE USERSTATUS = ?";
You cannot use bind variable in place of a database object in an SQL query, can you? It can only be used for parameter binding.
Try this instead,
"SELECT count(*) as row_count FROM " + DBtablename + " WHERE USERSTATUS = ?";
This could be vulnerable to SQL Injection so you might want to check that DBtablename parameter is a valid database object name (i.e. at most 30 bytes long without spaces, and contains only valid chars for database object identifiers).
count = result.getInt("row_count");