OPENJPA-2883 fix handling of java.sql.Time on MSSQL

This commit is contained in:
Mark Struberg 2021-03-31 19:09:03 +02:00
parent 9a96e0cd89
commit e9f3f9cdfc
4 changed files with 35 additions and 11 deletions

View File

@ -25,11 +25,13 @@ import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.util.Calendar;
import java.util.Locale;
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
@ -61,13 +63,12 @@ public class SQLServerDictionary extends AbstractSQLServerDictionary {
public boolean uniqueIdentifierAsVarbinary = true;
/**
* Whether to send Time values as DateTime or as Time.
* This affects how the Database actually looks like.
* sendTimeAsDatetime is supported as of SQLServer2008 and
* is only to be used with TIME columns.
* Previous to that a DATETIME column had to be used with a fixed 1970-01-01 date.
* SQLServer doesn't like a java.sql.Time as default.
* So either we send it as String or people configure sendTimeAsDatetime=false on the Connection.
* This is depending how the Database actually is setup.
* To mitigate misconfiguration we can work around by sending the time as String to the JDBC driver.
*/
public Boolean sendTimeAsDatetime = null;
public Boolean sendTimeAsString = null;
public SQLServerDictionary() {
platform = "Microsoft SQL Server";
@ -95,8 +96,8 @@ public class SQLServerDictionary extends AbstractSQLServerDictionary {
// serverMajorVersion of 8==2000, 9==2005, 10==2008, 11==2012
if (meta.getDatabaseMajorVersion() >= 9) {
setSupportsXMLColumn(true);
if (sendTimeAsDatetime == null) {
sendTimeAsDatetime = Boolean.TRUE;
if (sendTimeAsString == null) {
sendTimeAsString = Boolean.FALSE;
}
}
if (meta.getDatabaseMajorVersion() >= 10) {
@ -404,6 +405,16 @@ public class SQLServerDictionary extends AbstractSQLServerDictionary {
return rs.getObject(column, OffsetDateTime.class);
}
@Override
public void setTime(PreparedStatement stmnt, int idx, Time val, Calendar cal, Column col) throws SQLException {
if (sendTimeAsString) {
stmnt.setString(idx, val.toString());
}
else {
// use Time
super.setTime(stmnt, idx, val, cal, col);
}
}
@Override
public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,

View File

@ -133,6 +133,15 @@ public class TestTemporalTypeQueryParameterBinding extends SingleEMFTestCase {
assertEquals(1, q.getResultList().size());
}
public void testNamedTimeParam() {
Date d2 = new Date(T2);
Query q = em.createQuery("SELECT p FROM TimeKeeper p WHERE p.time=:t");
q.setParameter("t", d2, TemporalType.TIME);
assertEquals(1, q.getResultList().size());
}
public void testPositionalParameterConvertedFromDateValue() {
Date d1 = new Date(T1);
Date d2 = new Date(T2);

View File

@ -212,8 +212,8 @@ For running against a h2 based installation:
For running against a hsqldb based installation:
-ea -Dopenjpa.ConnectionDriverName=org.hsqldb.Driver -Dopenjpa.ConnectionURL=jdbc:hsqldb:mem:openjpa20-hsqldb-database -Dopenjpa.ConnectionUserName=sa -Dopenjpa.ConnectionPassword=
For running tests against a SQLServer Docker based installation:
-ea -Dopenjpa.ConnectionDriverName=com.microsoft.sqlserver.jdbc.SQLServerDriver -Dopenjpa.ConnectionURL=jdbc:sqlserver://localhost:1433 -Dopenjpa.ConnectionUserName=SA -Dopenjpa.ConnectionPassword=OpenJP8tst
For running tests against a Microsoft SQLServer Docker based installation:
-ea -Dopenjpa.ConnectionDriverName=com.microsoft.sqlserver.jdbc.SQLServerDriver -Dopenjpa.ConnectionURL=jdbc:sqlserver://localhost:1433;sendTimeAsDatetime=false -Dopenjpa.ConnectionUserName=SA -Dopenjpa.ConnectionPassword=OpenJP8tst
TODO: finish!

View File

@ -947,7 +947,11 @@
<openjpa.mssql.dbname>openjpatst</openjpa.mssql.dbname>
<openjpa.mssql.username>SA</openjpa.mssql.username>
<openjpa.mssql.password>OpenJP8tst</openjpa.mssql.password>
<openjpa.mssql.url>jdbc:sqlserver://localhost:${docker.external.mssql.port}</openjpa.mssql.url>
<!--
* sendTimeAsDatetime=false is important to make SQLServer understand java.sql.Time parameters.
* Alternatively you can set the SQLServerDictionary parameter sendTimeAsString=true
-->
<openjpa.mssql.url>jdbc:sqlserver://localhost:${docker.external.mssql.port};sendTimeAsDatetime=false</openjpa.mssql.url>
<!--<connection.url>jdbc:postgresql://localhost/openjpa</connection.url>-->
<connection.url>${openjpa.mssql.url}</connection.url>