Frequently Asked Questions about i-net JDBC drivers for MS SQL Server
For General JDBC FAQ see the Sun Site.
This subprotocol implements the communication protocol for the SQL Server 6.5. If you want to be compatible with SQL Server 6.5 then you need to use this protocol. SQL Server 2000 is very slow with this protocol (approx 10-100 times slower than inetdae7). This is an ASCII protocol (1 byte per character) and it supports only features of SQL Server 6.5 like
This is a unicode communication protocol. Every character has 2 bytes. It is not compatible with SQL Server 6.5. You need SQL Server 7.0 or higher. This subprotocol has a very good support for the nXXX data types. Because JDBC API does not make a difference between ASCII and UNICODE data types and the SQL Server cannot convert NTEXT to TEXT you cannot use the TEXT data type with this subprotocol.
If you have an ASCII column (varchar or char) then some SQL Server versions (without service pack) will have performance problems because they cannot use indexes.
If you save data to an ASCII column then SQL Server will convert the unicode from the driver with the codepage of the SQL Server to ASCII.
If you read ASCII data then the driver convert the ASCII data to UNICODE. The driver uses the codepage that you set with the option charset for converting. If you do not set the charset then the driver will detect the codepage from the SQL Server.
If you want to save include values as UNICODE then the include values will need to be marked with the N prefix.
The “a” stand for ASCII. This protocol equals inetdae7 except string parameter of PreparedStatements. These parameters are sent as ASCII. But all SQL expressions are sent as UNICODE. This means if you have parameters included in your SQL expression then these will also be sent as UNICODE. If you want to save it as UNICODE then the include values will need to be marked with the N prefix.
If you use ASCII data types this is the recommended subprotocol. This protocol might be a little slower than inetdea7 if the SQL Server has no index problems. This is the case because the character converting of Java is slower than the converting of the SQL Server (Java byte code versus native code).
jdbc:inetdae6:LocalHost?charset=KSC5601
” If you do not set a charset then only the low part of the characters is save.… N'YourUnicode' …
ByteToCharXXXX.class
and CharToByteXXXX.class
. You can test your JVM with: “TestString”.getBytes( “MS936” );
You need to use the option language in JDBC URL. The available languages can be requested with:
SELECT * FROM syslanguages;
No, you cannot get a java timestamp from a timestamp column of the SQL server. The timestamp column in the SQL server is not a column that contains a time or date. It contains a binary number (8 byte) that is unique in the database. You can get bytes from a timestamp field that can be read with the methods getBytes, getString or getBinaryStream.
To get a java timestamp from a SQL Server column you need to use a date/time column in the SQL Server database.
If you call getObject on a column that is a timestamp column in the SQL Server then you get a binary object. If you call toString
on that binary object then you get something like “[B”
.
The SQL Server versions 6.5 and 7.0 do not behave equivalently with spaces and null values in strings.
You can make the following test:
UPDATE TABLE SET textfield= ? SELECT textfield FROM TABLE
and here is the result of this test:
Update Value | Return Value from SQL Server 6.5 | Return Value from SQL Server 7.0 | Return Value from SQL Server 7.0** with sql7=true |
---|---|---|---|
null | null | null | null |
0 space | 1 space | 1 space | 0 space |
1 space | 1 space | 1 space | 1 space |
2 space | 1 space | 2 space | 2 space |
3 space | 1 space | 3 space | 3 space |
This conversion comes from the SQL Server and not from the driver.
** The database needs to employ a CompatibilityLevel of 70 or higher. You can set and request the CompatibilityLevel with the stored procedure sp_dbcmptlevel.
sql7=true
is equal to the JDBC subprotocol inetdae7. i-net software's MS SQL JDBC drivers can be used through a firewall. The firewall must let pass the TCP/IP port of the SQL Server. The default TCP/IP port is 1433. Proxies are not supported.
Connection con = null; try{ con = DriverManager.getConnection("jdbc:inetdae:webserver:1433", user, password ); }catch(Throwable e){e.printStackTrace();} if (con == null) try{ con = DriverManager.getConnection("jdbc:inetdae:webserver:119", user, password ); }catch(Throwable e){e.printStackTrace();} if (con == null) try{ con = DriverManager.getConnection("jdbc:inetdae:webserver:443", user, password ); }catch(Throwable e){e.printStackTrace();} if (con ==null) // message to the user
The driver supports Unicode in sql7 mode.
To save 2 bytes per character (Unicode) you need to set the option “sql7=true
” in the JDBC url and you need to use nXXX columns (e.g. nvarchar, nchar ).
If you use the SQL Server 6.5 compatible mode then you can use the option charset (e.g. charset=Cp1250
) in the JDBC url to convert the characters. In this mode the SQL Server saves only 1 byte per character.
Please empty the cache of your application to make sure that there is no limited trial-version sitting somewhere anymore. Check the class path for old versions.
If you use the command DriverManager.setLogStream(System.out) you will see the license text of the employed driver for setting up the connection. You can find the same text in the file TdsConnection.class
(Or if not available in the largest class file). You can check the texts and make sure you employ the correct driver version.
i-net UNA (a JDBC 1.22 driver) and i-net SPRINTA (a JDBC 2.0 driver) are type 4 drivers. A JDBC type 4 driver is a native-protocol fully Java technology-enable driver that converts JDBC technology calls into the network protocol used by DBMSs directly. This allows a direct call from the client machine to the DBMS server and is a practical solution for Intranet access. Type 4 drivers work on all operating systems with a JVM. The JDBC 2.0 driver i-net SPRINTA requires a JVM 1.2 or higher.
The JDBC 1.22 driver i-net UNA requires a JVM 1.1 or higher.
Yes, both drivers, i-net UNA and i-net SPRINTA, do support these new datatypes. You need to use the flag sql7=true in the JDBC URL.
You use the SQL Server 6.5 compatible mode. The SQL Server 6.5 supports only strings with a size up to 255 characters. You use this mode because you use the JDBC subprotocol inetdae or inetdea6. You need to use the JDBC subprotocol inetdae7 or inetdae7a. For older versions you will have to set the JDBC URL option sql7=true
. More information can be found in the file Manual.
jdbc:inetdae7:localhost
jdbc:inetdae:localhost?sql7=true
There are no absolute read locks for the SQL Server. The reading connection needs to support the read lock (transaction isolation level).
The writing connection started a transaction with:
setAutoCommit ( false );
After the first update of data there is a read lock if the reading connection has an isolation level of TRANSACTION_READ_COMMITTED
, TRANSACTION_REPEATABLE_READ
or TRANSACTION_SERIALIZABLE
. The read lock ends with the end of the transaction ( setAutoCommit (true), commit(), rollback() ).
The writing connection has not started a transaction ( setAutoCommit(true) ) and create a JDBC 2.0 statement with:
createStatement(ResultSet.TYPE_SCROLL_SENSITIVE ,ResultSet.CONCUR_UPDATABLE+1);
After the first update of data there is a read lock if the reading connection has an isolation level of TRANSACTION_SERIALIZABLE
. The read lock ends if the ResultSet scrolls to the next fetch block ( setFetchSize()
).
The best solution for the JDBC 1.22 driver i-net UNA is to call two statements in one. For example:
st.execute( "INSERT INTO YourTable(..) Values(..) SELECT @@IDENTITY" ); if (st.getUpdateCount() == 1) { st.getMoreResults(); rs = st.getResultSet(); rs.next(); Object identity = rs.getObject(); }
With the JDBC 2.0 drivers i-net SPRINTA and i-net OPTA you can use an updateable ResultSet.
After calling the insertRow method you can do a moveLast(xxx) and then getObject(xxx) to get the values of the inserted row if you use a different cursor type than the Scrolling Cursor Type: TYPE_SCROLL_SENSITIVE+1 (Dynamic cursor).
If you use the Scrolling Cursor Type: TYPE_SCROLL_SENSITIVE+1 (Dynamic cursor) then the inserted row does not need to be at the end of the ResultSet.
If you have problems with the driver then you can enable the logging of the driver with:
DriverManager.setLogStream( System.out ); // or DriverManager.setLogStream( System.err );
The driver prints the messages in the default print streams (e.g. java console of the JDK or Browser). You can also use any other PrintStream (e.g. an log file) to make this output. This can be used if you can not see the default PrintStreams. If you use the driver in an servlet, .jsp script or in an Application Server then you need to set an PrintStream on an log file:
PrintStream ps = new PrintStream( new FileOutputStream( "c:\\driver.log" ) ); DriverManager.setLogStream( ps );
Now the driver prints the messages in the file that you have specified.
In some Application Server you can enable the JDBC logging with the visual managment console or enviroment.
Please note: Please enable the logging only when you need it to find a problem because the driver have a better performance without the logging.
If you use the driver in an java application then add the file “DriverName.jar” to your classpath or extract the jar file in the directory of your application.
If you use the driver in an applet then add the file “DriverName.jar” to the Archive attribute of the applet tag, e.g.:
<APPLET CODE="..." Codebase="..." ARCHIVE="DriverName.jar" WIDTH="100%" HEIGHT="100%"> ... </APPLET>
or extract the jar file in the directory of the applet.
For more informations see the readMe.txt of the driver and the JavaSoft documentation at: http://java.sun.com/docs/books/tutorial/java/package/managingfiles.html.
The SQL Server sends the XML data in one or more rows in the first column of the ResultSet. The size of each row is variant. With the following loop you can concatenate the pieces of the XML data:
... StringBuffer sb = new StringBuffer(); while (rs.next()) { sb.append(rs.getString(1)); } System.out.println("XML data: " + sb.toString()); ...
Why is it that the i-net SQL Server driver seems to be slower than other drivers in my tests?
cast(? as char(xx))
…”decimal(38,36)
”, the column type is “numeric (7,0)
”. It seems that the index for the numeric column won't used with SP4. With SQL Server 2005 or earlier SQL Server version such a behavior was not seen. A workaround for that problem is to cast to column type.E.g. SELECT * FROM testnumeric WHERE a = CAST(? AS NUMERIC(7,0));
The driver OPTA and MERLIA support SSL (protected by U.S. Patent) since version 6.00. View the Manual and the current Release Changes. for the SSL system requirements.
Another solution for encryption between client and server is to use the driver in conjunction with i-net KONNEKTER, a Java middleware on the Server.
The encryption of i-net KONNEKTER is a dynamic encryption (not SSL). Using i-net KONNEKTER has security advantages over SSL. For example you do not need to code the real SQL Expression in your client Java classes.
The method ResultSetMetaData.getTableName() requires a server cursor or the “for browse” statement. This is a limitation of the MS SQL Server.
It is a limitation or a feature of the MS SQL Server that temporary tables that are created in a stored procedure (prepared statement) are only valid in this stored procedure (prepared statement). That means that a temporary table that was created with a PreparedStatement is only valid within the PreparedStatement with that it was created.
The possible solution are:
con.createStatement().execute(“CREATE TABLE #temp”);
The ODBC-JDBC-Bridge returns the type value Types.OTHER for this data types. This is not helpful. That's why our driver returns the original SQL99 that the SQL Server sends.
In general the risk of a deadlock increases with the performance of the driver. Since our drivers are known to be among the very fastest they might be more vulnerable to the deadlock problem.
You can find many general guidelines in the SQL Server online manual to solve deadlocks. If you use a query timeout then the driver will not hang rather it will throw a timeout exception in such cases; with a rollback you can solve the deadlock.
To solve a deadlock you need to verify which SQL expression produces the deadlock in the first place. You can find out about this:
When you have found the critical transaction you need to verify the order of your SQL expression whether it can produce a deadlock. Please note that a row lock is like a table lock if the SQL Server can't use an index. If the SQL Server can't use an index then it needs to read every row to verify the WHERE clause. If a row is locked then the SQL expression will wait on this row.
Deadlocks can occur if the SQL Server can't use indexes. The SQL Server can only use an index if the parameter data type and the index data type are compatible. If the data types are different then the data type precedence is used.
With PreparedStatements the driver uses NVARCHAR for string parameters in Unicode mode and VARCHAR in ASCII mode.
If the index data type is lower then the SQL Server will convert the data from the table and not the parameter data. For example, if you use the CHAR data type then the SQL Server can't use the index or if you use the VARCHAR data type and you work in unicode mode.
Solutions:
… cast( ? as CHAR(xx) ) …
”Deadlocks can occur if you do not commit a transaction. This can happen when a transaction has been started without your knowledge. This may occur when you (or your environment) change the isolation level. You can disable this JDBC ODBC default behavior with impltran=false in the JDBC URL.
This error message means that for the requested url no driver was registered. There are 3 causes:
Class.forName(“com.inet.tds.TdsDriver”);
with Class.forName(“com.inet.tds.TdsDriver”).newInstance();
If you receive this SQLException on the call of DriverManager.getConnection(..) then your SQL Server does not listen on the selected TCP/IP port. Please read the chapter “Check Host Name and Port Number of Your Server” in the readme.txt.
If there are already connections established to the SQL Server then the problem could occur, that too many threads request a connection at the same time; the socket connection request queue of the SQL Server is full. A solution to this problem is the use of the connection pool with an initial size.
You downloaded a test-version from our site. The test-version is limited to two connections. Currently you try to get a third connection. Causes:
DriverManager.setLogStream( System.out );
the driver print the license text of the running instance. If you look in the file TdsConnection.class (or the largest class file) you can see the license text of the purchased driver. Please remove all old drivers from your classpath until you receive a ClassNotFoundException. After this exception add the new driver. Generally, this error message means that the driver is waiting for an answer from the SQL Server of its own request. If you like to execute a command (SELECT, UPDATE, INSERT…) that need more time to finish then you can increment the query timeout of your statement to resolve the problem.
The default query timeout is that value of the driver login timeout that was valid at this time at the connection was created. You can read or change the login timeout of the Driver Manager with set/getLoginTimeout.
In contrast to older versions of the driver the version 4.xx is checking the status of the ResultSet before using it. The JDBC 1.22 and JDBC 2.0 standard allows only one open ResultSet per statement.
A Resultset can be closed with the following methods:
You tried to execute one of the following SQL statements:
SELECT * FROM table1 WHERE textColumn = "xyz"; UPDATE table1 SET textColumn="xyz";
In standard configuration (ANSI) strings in double quotes are interpreted as identifiers. Use the following SQL statements instead with single quotation:
SELECT * FROM table1 WHERE textColumn = 'xyz'; UPDATE table1 SET textColumn='xyz';
or execute the SQL statement “set quoted_identifier off” once per connection.
The classes are not in your classpath. See the question "How to add the driver to the classpath?".
By default our MS SQL Server JDBC drivers uses a Forward Only ResultSet (client cursor) and reads all rows into memory. This is very fast for small ResultSets. This can produce an OutOfMemoryError, though.
You can use the following methods to use a server cursor with a fetch size of 128 for executeQuery(). This doesn't work for execute() or executeUpdate().
The default fetch size is 0. This means a unlimited fetch size. This value will change when:
This problem can occur in one of the following causes:
localhost
” or “127.0.0.1
” but with the name or the IP-address of your computer.getCodeBase().getHost()
.http://MyWebServer/myApplet.html | jdbc:inetdae:100.100.100.100 | invalid |
http://100.100.100.100/myApplet.html | jdbc:inetdae:MyWebServer | invalid |
http://MyWebServer/myApplet.html | jdbc:inetdae:MyWebServer | valid |
http://100.100.100.100/myApplet.html | jdbc:inetdae:100.100.100.100 | valid |
http://MyWebServer/myApplet.html | “jdbc:inetdae:” + getCodeBase().getHost() | valid |
http://100.100.100.100/myApplet.html | “jdbc:inetdae:” + getCodeBase().getHost() | valid |
This message means that the socket to the SQL server was closed. This can occur when
In general if you use a database connection over a long time you should check it before you use it. Example for connection check:
try{ if (con.isClosed()) con = DriverManager.getConnection( ..... ); }catch(Exception e){ e.printStackTrace(); con = DriverManager.getConnection( ..... ); }
I am trying to execute the following SQL statement against our SQL Server database:
INSERT INTO Notice (Id, DateApproved, DateTimeReceived) VALUES (1,{d'2002-1-1'},'edyke',{ts'2001-1-12 10:20:54.27'})
and receive the following error: Syntax error converting datetime from character string.
What could be causing this? You need to use two digits for the months and day. The correct syntax:
{d 'yyyy-mm-dd'}
{ts 'yyyy-mm-dd hh:mi:ss'}
or {ts 'yyyy-mm-dd hh:mi:ss.mmm'}
.
You have called a Connection.rollback()
in a Distributed Transaction. You need to call Transaction.rollback()
.
This exception will occur if you call a method from a higher JDBC API level than the driver implements. For every JDBC API level and every driver a minimum JDK version is needed. I-net software offers drivers for 3 different JDBC API level.
For example:
The SQL server 7.0 supports new datatypes, i.e. nchar, ntext, nvarchar, varchar larger than 255 character. If you like to use these new datatypes you need to use the subprotocol inetdae7 or set the property sql7=true
in the url of the JDBC connection. If you use the subprotocol inetdae7 or set the property sql7=true
you will not be able to connect to the SQL Server 6.5.
You can find more information about this topic in the file View the Manual and the current Release Changes..
The default data type mapping of the driver is equivalent to the JDBC specification:
You generated a statement with the property ResultSet. CONCUR_UPDATABLE and receive this error message when updating data. The following might cause the error:
You can obtain further information on this topic in the Books Online of MS SQL Server looking for “Implicit Cursor Conversions”.
The driver checks the required JDBC 2.0 interface. The JVM that you use does not have not this interface. If you use the driver in a browser you need to use a JVM plugin because no browser supports a JVM 1.2.x currently. You can check the version of your JVM with:
System.out.println( System.getProperty( "java.version" ) ); System.out.println( System.getProperty( "java.vendor" ) );
If you use connection pooling, DataSource or the driver “com.inet.pool.PoolDriver” you will have to download:
The JDBC 3.0 driver i-net MERLIA is a driver for the JDK 1.4.x. If you need a driver for an older JDK then you can use one of our other drivers for MS SQL Server.
The message text can vary with different Java VM's
com.inet.tds.SQLException: Address in use: no further information java.net.BindException: Address in use: no further information java.net.PlainSocketImpl.socketConnect(Native Method) java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305) java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:125) java.net.PlainSocketImpl.connect(PlainSocketImpl.java:112) java.net.Socket.<init>(Socket.java:269) java.net.Socket.<init>(Socket.java:98) com.inet.tds.TdsDriver.connect(Unknown Source)
This is a problem of the used sockets with Windows NT. You can request the active sockets with the command netstat. The problem is a function of:
MaxUserPort (default 5000) KeepAliveTime (default 120)
The exception “com.inet.tds.SQLException: java.net.BindException: Address in use
” occurs if you want to create a new socket and all sockets between 1024 and MaxUserPort are in use.
With the formula: (MaxUserPort - 1024 - UsedSocket) / KeepAliveTime
you can calculate the count of sockets that can be created per second. With the default values you can create a maximum of 33 sockets per second.
Workaround: