I have a problem with the output parameter of a stored procedure when it contains more than 4000 characters. The response seems to be truncated by the JDBC driver? How can I get the full result?
The stored procedure answers with the complete response (> 4000 characters) but I can not open it from Java. I have tried both jTDS and Microsoft's JDBC driver 6.0. Here is my code:
CallableStatement pstmt = con.prepareCall("{call sp_horus_get_consultorios_stv(?)}");
pstmt.registerOutParameter(1, -1);
pstmt.setString(1, "");
pstmt.execute();
String sp_horus_get_consultorios_stv = pstmt.getString(1);
This works with stored procedures in sybase.
I was able to recreate your issue using Microsoft JDBC Driver 6.x. I found that I could avoid the problem by commenting out the setString call:
try (CallableStatement pstmt = conn.prepareCall("{call usp_horus_get_consultorios_stv(?)}")) {
pstmt.registerOutParameter(1, Types.LONGNVARCHAR);
//pstmt.setString(1, ""); // disabled
pstmt.execute();
String sp_horus_get_consultorios_stv = pstmt.getString(1);
System.out.println(sp_horus_get_consultorios_stv.length()); // > 4000 characters
}
Unfortunately, that fix did not solve the problem under jTDS 1.3.1. It appears that jTDS still suffers from the limitation described here. So, for jTDS it appears that we have to do something like this:
String sql =
"DECLARE #out NVARCHAR(MAX);" +
"EXEC usp_horus_get_consultorios_stv #out OUTPUT;" +
"SELECT #out;";
try (
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql)) {
rs.next();
String sp_horus_get_consultorios_stv = rs.getString(1);
System.out.println(sp_horus_get_consultorios_stv.length()); // > 4000 characters
}
From what I understand, your output parameter is of type NVARCHAR(8000), which is the maximum explicit number allowed, and outputs a 4000 character Unicode string lenght (2 bytes per char).
However, and lucky you, there another possibility : NVARCHAR(MAX), that basically allows an infinite string lenght (well, not infinite, but almost :
What is the maximum number of characters that nvarchar(MAX) will hold?
You should change your output paramater type to NVARCHAR(MAX).
Happy coding ;)
Related
Let's say there is a sequence created on SQL Server:
CREATE SEQUENCE dbo.my_seq
START WITH 1
INCREMENT BY 1
NO CYCLE;
GO
And the following Java code to fetch the next sequence value:
Connection conn = ...;
String sql = "SELECT NEXT VALUE FOR my_seq;";
try (Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql)) {
while (resultSet.next()) {
long seq = resultSet.getLong(1);
System.out.println(seq);
}
}
Why are sequences jumping by two when this code is executed repeatedly?
2
4
6
I've tried with the CACHE option on and off. It makes no difference.
Sequences are incremented by one if I execute the same query multiple times on Azure Data Studio.
I'm running Microsoft SQL Server 2019 (RTM-CU15) (KB5008996) - 15.0.4198.2 (X64). I tried the same code with com.microsoft.sqlserver:mssql-jdbc:10.2.0.jre8 and com.microsoft.sqlserver:mssql-jdbc:11.1.1.jre8-preview drivers and got the same behavior.
I analyzed the SQL Server query history, and the Java code made only one query to fetch the next sequence value per execution.
According to Gary's answer to a similar question, this is a known behavior when using the selectMethod=cursor option. Just remove this option from the connection URL, and sequence numbers won't skip anymore.
What if you must use selectMethod=cursor for some reason? Then try the sys.sp_sequence_get_range stored procedure instead as demonstrated below.
Connection conn = ...;
String sequenceName = "my_seq";
try (CallableStatement statement = conn.prepareCall("{call sys.sp_sequence_get_range(?, ?, ?)}")) {
statement.setString("sequence_name", sequenceName);
statement.setLong("range_size", 1);
statement.registerOutParameter("range_first_value", microsoft.sql.Types.SQL_VARIANT);
statement.execute();
long seq = statement.getLong("range_first_value");
System.out.println(seq);
}
It doesn't skip sequence numbers even if the selectMethod=cursor option is enabled.
I am connected to IBM DB2 database with java but data is stored as binary format in database so when I fetch any value it comes as binary or hexdecimal format. How can I convert this in binary data in utf-8 at query level.
Sample code to fetch data -
String sql = "SELECT poMast.ORDNO from AMFLIBL.POMAST AS poMast ";
Class.forName("com.ddtek.jdbc.db2.DB2Driver");
String url = "jdbc:datadirect:db2://hostname:port;DatabaseName=dbName;";
Connection con = DriverManager.getConnection(url, "username","password");
PreparedStatement preparedStatement = con.prepareStatement(sql);
ResultSet rs = preparedStatement.executeQuery();
System.out.println("ResultSet : \n");
System.out.println(" VNDNO");
while (rs.next())
{
System.out.println(rs.getString("ORDNO"));
}
You probably need to use the CAST expression:
SELECT CAST(poMast.ORDNO as VARCHAR(50)) from AMFLIBL.POMAST AS poMast
Adjust the VARCHAR length to your needs. The string is in the database codepage (often UTF-8 these days) and converted to the client/application codepage when fetched.
you can "cast" the result from your select to utf8 like below.
String sql = "SELECT poMast.ORDNO, CAST(poMast.ORDNO AS VARCHAR(255) CCSID UNICODE) FROM AMFLIBL.POMAST AS poMast ";
src: cast db2
In my case, somehow bad UTF-8 data had gotten into varchars in a 1208/UTF-8 DB. Prior to conversion, when querying such data via the JDBC driver, the DB returned -4220 via the JDBC driver. This is fixable at the JDBC driver level by adding this property:
java -Ddb2.jcc.charsetDecoderEncoder=3 MyApp
see:
https://www.ibm.com/support/pages/sqlexception-message-caught-javaiocharconversionexception-and-errorcode-4220
The Db2 LUW Command Line Processor fixed it long ago as an APAR, so this error is only seen via the JDBC driver when the above property is not set.
But, if you want to fix the data in the db, this works:
update <table_name> set <bad_data_col> = cast(cast( <bad_data_col> as vargraphic) as varchar);
1st db2 treats (casts) the bad data as a binary where "anything goes" and then converts (casts) it back to valid UTF-8. After the casts, the JDBC driver shows the same result with or without the special property set and returns no errors.
I'm trying to find a explanation why Oracle driver, by default, escapes end-line character "\n" to a escaped string "\\n", that makes the "\n" to show up when I print it. I'd also like to get some suggestions on how to deal with it in a elegante way besides simply replacing "\\n" to "\n" before printing it.
extra info:
- Oracle driver: ojdbc6.jar
- Java 1.6.0_18 and 1.7.0_45
Example:
- DB "column1" data = line1\nline2\nline3
java.sql.PreparedStatement stmt = conn.prepareStatement("SELECT column1 FROM TABLE1");
java.sql.ResultSet rs = stmt.executeQuery();
while (rs.next()) {
rs.getString(1); // it returns line1\\nline2\\nline3
}
Appreciate any help,
Cheers
If the output from SQL*Plus shows \n and not actually starts a new line, then you have stored the two characters "\n" in your database and not an actual newline.
See http://www.unix.com/unix-advanced-expert-users/56212-sqlplus-output-new-line-character.html where the asker wants to get rid of actual line feeds in his database.
I am using a JDBC connection to fetch data from an Access database.
The database design is not my control. In the database there are columns that have "?" included in their names, for example: Open?, Paid?, and lots more.
When I try to fetch data with a PreparedStatement it gives me an error. The query is:
SELECT Open? FROM tblJobList WHERE WeekEnding=?
I also tried to use brackets like [Open?], but the result is the same.
The error I receive is "Too few parameters ..." as I am pushing only one parameter into the PreparedStatement.
I can not use normal statement because of WeekEnding=? as this value is a Timestamp and I could not manage to work it with Statement. Only prepared statement works here.
Can anyone tell me how to use these kind of column names in a PreparedStatement?
use the " character
"SELECT \"Open?\" FROM tblJobList WHERE WeekEnding=?"
tested this against oracle and appears to work with mssqlserver
How to select a column in SQL Server with a special character in the column name?
Just to update this for current technologies:
While the JDBC-ODBC Bridge and Access ODBC were unable to handle a PreparedStatement with a column name containing a question mark, the UCanAccess JDBC driver handles it just fine, as can be confirmed with the following code:
String connectionUrl = "jdbc:ucanaccess://C:/Users/Public/UCanAccessTest.accdb";
Connection conn = DriverManager.getConnection(connectionUrl);
String sql = "SELECT ID, [Open?] FROM tblJobList WHERE WeekEnding=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setDate(1, java.sql.Date.valueOf("2016-01-01"));
ResultSet rs = ps.executeQuery();
while (rs.next()) {
System.out.printf("%d: %s%n", rs.getInt("ID"), rs.getBoolean("Open?"));
}
conn.close();
For more information on UCanAccess, see
Manipulating an Access database from Java without ODBC
I am not sure but you can try // to escape the special meaning of ? and to use it as a normal character. Like:
"SELECT Open//? FROM tblJobList WHERE WeekEnding=?"
You can get something similar to your problem here:
Round bracket in string with JDBC prepared statement
Escaping quotes in MSSQL is done by a double quote, so a '' or a "" will produce one escaped ' and ", respectively.
This question already has answers here:
How can I get the SQL of a PreparedStatement?
(14 answers)
Closed 5 years ago.
I'm working with PreparedStatement with MySQL Server.
example:
String myQuery = "select id from user where name = ?";
PreparedStatement stmt = sqlConnection.prepareStatement(myQuery);
stmt.setString(1, "test");
stmt.executeQUery();
ResultSet rs = stmt.getResultSet();
How can I receive the full SQL query that is about to be executed on the MySQL Server?
It's not mandated by the JDBC spec, but several JDBC drivers let the toString of a PreparedStatement return sort-of the query that will be run, and MySQL's Connector/J happens to have this behavior (or at least it did a few years ago).
String myQuery = "select id from user where name = ?";
PreparedStatement stmt = sqlConnection.prepareStatement(myQuery);
stmt.setString(1, "test");
System.out.println(stmt); // May do what you want!
You cannot really get out the query that will be executed but there are logging APIs that will log database calls for you such as log4jdbc and p6spy.
You can't, as Java isn't responsible for constructing it. Prepared statements are supported within MySQL, so Java sends the actual parameterized SQL ("select id from user where name = ?") straight to MySQL along with the parameters
I can tell you what it is. If you're using MySQL 4.1 or newer with Connector/J 3.1 or newer, it will be something like:
PREPARE stmt FROM 'select id from user where name = ?'
SET #a = 'test'
EXECUTE stmt USING #a
This is because MySQL supports server-side prepared statements.
(More likely it uses the binary protocol, but this code is just to make a point)
Hi I implement the following code which fetch SQL from PreparedStatement . No need to use any jar and Driver .
public void printSqlStatement(PreparedStatement preparedStatement, String sql) throws SQLException{
String[] sqlArrya= new String[preparedStatement.getParameterMetaData().getParameterCount()];
try {
Pattern pattern = Pattern.compile("\\?");
Matcher matcher = pattern.matcher(sql);
StringBuffer sb = new StringBuffer();
int indx = 1; // Parameter begin with index 1
while (matcher.find()) {
matcher.appendReplacement(sb,String.valueOf(sqlArrya[indx]));
}
matcher.appendTail(sb);
System.err.println("Executing Query [" + sb.toString() + "] with Database[" + "] ...");
} catch (Exception ex) {
System.err.println("Executing Query [" + sql + "] with Database[" + "] ...");
}
}
Slightly different approach from all answers here,
If you are familiar with Debugging options in Eclipse. You may try the following:
Set a Breakpoint at stmt.executeQUery();
Right click your application, say Debug As select Java Application (or Whatever applicable in your case i.e. may be SpringBoot App etc.
Perform step that gets you to code mentioned in the Question.
If you check Variables tab in Debug Perspective of Eclipse, you will find variables like myQuery , stmt (according to your code)
Whatever you see as value of stmt would be the full SQL query you need.
Also, if you don't want to keep looking at this variable always you may try Java Logging and Print your Full SQL query in Logs.