HHH-16131 - Added workaround and test for date calculcation errors on Oracle
Temporarily excluded TiDB from that test (until they fix https://github.com/pingcap/tidb/issues/41052) Added tidb to the docker_db script Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
b918909359
commit
989a127b17
29
docker_db.sh
29
docker_db.sh
|
@ -769,6 +769,33 @@ EOF
|
|||
|
||||
}
|
||||
|
||||
tidb() {
|
||||
tidb_5_1
|
||||
}
|
||||
|
||||
tidb_5_1() {
|
||||
$CONTAINER_CLI rm -f tidb || true
|
||||
$CONTAINER_CLI run --name tidb -p4000:4000 -d docker.io/pingcap/tidb:v5.1.4
|
||||
# Give the container some time to start
|
||||
OUTPUT=
|
||||
n=0
|
||||
until [ "$n" -ge 5 ]
|
||||
do
|
||||
OUTPUT=$($CONTAINER_CLI logs tidb 2>&1)
|
||||
if [[ $OUTPUT == *"server is running"* ]]; then
|
||||
break;
|
||||
fi
|
||||
n=$((n+1))
|
||||
echo "Waiting for TiDB to start..."
|
||||
sleep 3
|
||||
done
|
||||
if [ "$n" -ge 5 ]; then
|
||||
echo "TiDB failed to start and configure after 15 seconds"
|
||||
else
|
||||
echo "TiDB successfully started"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z ${1} ]; then
|
||||
echo "No db name provided"
|
||||
echo "Provide one of:"
|
||||
|
@ -804,6 +831,8 @@ if [ -z ${1} ]; then
|
|||
echo -e "\tpostgresql_10"
|
||||
echo -e "\tpostgresql_9_5"
|
||||
echo -e "\tsybase"
|
||||
echo -e "\ttidb"
|
||||
echo -e "\ttidb_5_1"
|
||||
else
|
||||
${1}
|
||||
fi
|
||||
|
|
|
@ -150,6 +150,14 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw";
|
||||
|
||||
private static final String yqmSelect =
|
||||
"( SELECT b_.bd + ( LEAST( EXTRACT( DAY FROM b_.od ), EXTRACT( DAY FROM LAST_DAY( b_.bd ) ) ) - 1 )\n" +
|
||||
"FROM (SELECT a_.od, TRUNC(a_.od, 'MONTH') + NUMTOYMINTERVAL(%1$s, 'MONTH') bd FROM ( SELECT %2$s od FROM dual ) a_) b_ ) ";
|
||||
|
||||
private static final String ADD_YEAR_EXPRESSION = String.format( yqmSelect, "?2*12", "?3" );
|
||||
private static final String ADD_QUARTER_EXPRESSION = String.format( yqmSelect, "?2*3", "?3" );
|
||||
private static final String ADD_MONTH_EXPRESSION = String.format( yqmSelect, "?2", "?3" );
|
||||
|
||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 11, 2 );
|
||||
|
||||
private final LimitHandler limitHandler = supportsFetchClause( FetchClauseType.ROWS_ONLY )
|
||||
|
@ -480,63 +488,36 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
|
||||
|
||||
StringBuilder pattern = new StringBuilder();
|
||||
pattern.append("(?3+");
|
||||
switch ( unit ) {
|
||||
case YEAR:
|
||||
pattern.append( ADD_YEAR_EXPRESSION );
|
||||
break;
|
||||
case QUARTER:
|
||||
pattern.append( ADD_QUARTER_EXPRESSION );
|
||||
break;
|
||||
case MONTH:
|
||||
pattern.append("numtoyminterval");
|
||||
pattern.append( ADD_MONTH_EXPRESSION );
|
||||
break;
|
||||
case WEEK:
|
||||
pattern.append("(?3+numtodsinterval((?2)*7,'day'))");
|
||||
break;
|
||||
case DAY:
|
||||
case HOUR:
|
||||
case MINUTE:
|
||||
case SECOND:
|
||||
pattern.append("(?3+numtodsinterval(?2,'?1'))");
|
||||
break;
|
||||
case NANOSECOND:
|
||||
pattern.append("(?3+numtodsinterval((?2)/1e9,'second'))");
|
||||
break;
|
||||
case NATIVE:
|
||||
pattern.append("numtodsinterval");
|
||||
pattern.append("(?3+numtodsinterval(?2,'second'))");
|
||||
break;
|
||||
default:
|
||||
throw new SemanticException(unit + " is not a legal field");
|
||||
}
|
||||
pattern.append("(");
|
||||
switch ( unit ) {
|
||||
case NANOSECOND:
|
||||
case QUARTER:
|
||||
case WEEK:
|
||||
pattern.append("(");
|
||||
break;
|
||||
}
|
||||
pattern.append("?2");
|
||||
switch ( unit ) {
|
||||
case QUARTER:
|
||||
pattern.append(")*3");
|
||||
break;
|
||||
case WEEK:
|
||||
pattern.append(")*7");
|
||||
break;
|
||||
case NANOSECOND:
|
||||
pattern.append(")/1e9");
|
||||
break;
|
||||
}
|
||||
pattern.append(",'");
|
||||
switch ( unit ) {
|
||||
case QUARTER:
|
||||
pattern.append("month");
|
||||
break;
|
||||
case WEEK:
|
||||
pattern.append("day");
|
||||
break;
|
||||
case NANOSECOND:
|
||||
case NATIVE:
|
||||
pattern.append("second");
|
||||
break;
|
||||
default:
|
||||
pattern.append("?1");
|
||||
}
|
||||
pattern.append("')");
|
||||
pattern.append(")");
|
||||
return pattern.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,14 +10,12 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.dialect.CockroachDialect;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.MariaDBDialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
import org.hibernate.dialect.TiDBDialect;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||
|
@ -28,10 +26,10 @@ import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
|||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -51,6 +49,7 @@ import org.hamcrest.Matchers;
|
|||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
@ -58,7 +57,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
@ServiceRegistry
|
||||
@DomainModel( standardModels = StandardDomainModel.GAMBIT )
|
||||
@SessionFactory
|
||||
public class FunctionTests {
|
||||
|
@ -1314,20 +1312,44 @@ public class FunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect( dialectClass = TiDBDialect.class, reason = "Bug in the TiDB timestampadd function (https://github.com/pingcap/tidb/issues/41052)")
|
||||
public void testDurationArithmetic(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertEquals( LocalDate.now().minus(2, ChronoUnit.DAYS),
|
||||
session.createQuery("select local date - 2 day")
|
||||
session.createQuery("select local date - 2 day", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.now().plus(1, ChronoUnit.MONTHS),
|
||||
session.createQuery("select local date + 1 month")
|
||||
.getSingleResult() );
|
||||
session.createQuery("select e.theTimestamp - 21 second from EntityOfBasics e")
|
||||
session.createQuery("select local date + 1 month", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.now().plus(1, ChronoUnit.YEARS),
|
||||
session.createQuery("select local date + 1 year", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.now().plus(3, ChronoUnit.MONTHS),
|
||||
session.createQuery("select local date + 1 quarter", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
// Some explicit 'special' cases:
|
||||
assertEquals( LocalDate.of(2024, 02, 29),
|
||||
session.createQuery("select {2024-01-31} + 1 month", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.of(2025, 02, 28),
|
||||
session.createQuery("select {2024-02-29} + 1 year", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.of(2028, 02, 29),
|
||||
session.createQuery("select {2024-02-29} + 4 year", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.of(2025, 03, 29),
|
||||
session.createQuery("select {2024-02-29} + 13 month", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
assertEquals( LocalDate.of(2024, 02, 29),
|
||||
session.createQuery("select {2023-11-30} + 1 quarter", LocalDate.class)
|
||||
.getSingleResult() );
|
||||
|
||||
session.createQuery("select e.theTimestamp - 21 second from EntityOfBasics e", java.util.Date.class)
|
||||
.getSingleResult();
|
||||
session.createQuery("select e.theTimestamp + 2 day from EntityOfBasics e")
|
||||
session.createQuery("select e.theTimestamp + 2 day from EntityOfBasics e", java.util.Date.class)
|
||||
.getSingleResult();
|
||||
session.createQuery("select e.theTimestamp - 21 second + 2 day from EntityOfBasics e")
|
||||
session.createQuery("select e.theTimestamp - 21 second + 2 day from EntityOfBasics e", java.util.Date.class)
|
||||
.getSingleResult();
|
||||
//TODO: FIX!!
|
||||
// session.createQuery("select e.theTimestamp + 2 * e.theDuration from EntityOfBasics e")
|
||||
|
@ -1786,4 +1808,4 @@ public class FunctionTests {
|
|||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue