[#566] Add support for INTERVAL data types - some fixes
[#585] Add support for DATE, TIME and INTERVAL arithmetic - some fixes
This commit is contained in:
parent
d1285173f7
commit
d0d0198cbc
@ -37,7 +37,6 @@ package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.field;
|
||||
import static org.jooq.impl.Factory.function;
|
||||
import static org.jooq.impl.Factory.literal;
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
@ -70,7 +69,7 @@ class DateDiff extends AbstractFunction<Integer> {
|
||||
case ASE:
|
||||
case SQLSERVER:
|
||||
case SYBASE:
|
||||
return function("datediff", getDataType(), literal("day"), date2, date1);
|
||||
return field("{datediff}(day, {0}, {1})", getDataType(), date2, date1);
|
||||
|
||||
case MYSQL:
|
||||
return function("datediff", getDataType(), date1, date2);
|
||||
@ -84,14 +83,17 @@ class DateDiff extends AbstractFunction<Integer> {
|
||||
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
return function("datediff", getDataType(), literal("'day'"), date2, date1);
|
||||
return field("{datediff}('day', {0}, {1})", getDataType(), date2, date1);
|
||||
|
||||
case SQLITE:
|
||||
return field("({strftime}('%s', {0}) - {strftime}('%s', {1})) / 86400", getDataType(), date1, date2);
|
||||
|
||||
case CUBRID:
|
||||
case ORACLE:
|
||||
case POSTGRES:
|
||||
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return date1.sub(date2).cast(Integer.class);
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return date1.sub(date2).cast(Integer.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -195,9 +195,6 @@ class DefaultBindContext extends AbstractBindContext {
|
||||
else if (type == Clob.class) {
|
||||
stmt.setClob(nextIndex(), (Clob) value);
|
||||
}
|
||||
else if (type == Date.class) {
|
||||
stmt.setDate(nextIndex(), (Date) value);
|
||||
}
|
||||
else if (type == Double.class) {
|
||||
stmt.setDouble(nextIndex(), (Double) value);
|
||||
}
|
||||
@ -216,11 +213,32 @@ class DefaultBindContext extends AbstractBindContext {
|
||||
else if (type == String.class) {
|
||||
stmt.setString(nextIndex(), (String) value);
|
||||
}
|
||||
|
||||
// There is potential for trouble when binding date time as such
|
||||
// -------------------------------------------------------------
|
||||
else if (type == Date.class) {
|
||||
if (dialect == SQLITE) {
|
||||
stmt.setString(nextIndex(), ((Date) value).toString());
|
||||
}
|
||||
else {
|
||||
stmt.setDate(nextIndex(), (Date) value);
|
||||
}
|
||||
}
|
||||
else if (type == Time.class) {
|
||||
stmt.setTime(nextIndex(), (Time) value);
|
||||
if (dialect == SQLITE) {
|
||||
stmt.setString(nextIndex(), ((Time) value).toString());
|
||||
}
|
||||
else {
|
||||
stmt.setTime(nextIndex(), (Time) value);
|
||||
}
|
||||
}
|
||||
else if (type == Timestamp.class) {
|
||||
stmt.setTimestamp(nextIndex(), (Timestamp) value);
|
||||
if (dialect == SQLITE) {
|
||||
stmt.setString(nextIndex(), ((Timestamp) value).toString());
|
||||
}
|
||||
else {
|
||||
stmt.setTimestamp(nextIndex(), (Timestamp) value);
|
||||
}
|
||||
}
|
||||
|
||||
// [#566] Interval data types are best bound as Strings
|
||||
|
||||
@ -63,7 +63,7 @@ import static org.jooq.impl.Factory.bitOr;
|
||||
import static org.jooq.impl.Factory.bitXor;
|
||||
import static org.jooq.impl.Factory.field;
|
||||
import static org.jooq.impl.Factory.function;
|
||||
import static org.jooq.impl.Factory.literal;
|
||||
import static org.jooq.impl.Factory.two;
|
||||
import static org.jooq.impl.Factory.val;
|
||||
|
||||
import java.sql.Date;
|
||||
@ -74,12 +74,15 @@ import java.util.List;
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.types.DayToSecond;
|
||||
import org.jooq.types.Interval;
|
||||
import org.jooq.types.YearToMonth;
|
||||
|
||||
class Expression<T> extends AbstractFunction<T> {
|
||||
@ -152,10 +155,10 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
// Many dialects don't support shifts. Use multiplication/division instead
|
||||
else if (SHL == operator && asList(ASE, DB2, H2, HSQLDB, INGRES, ORACLE, SQLSERVER, SYBASE).contains(dialect)) {
|
||||
return lhs.mul(Factory.power(literal(2), rhsAsNumber()));
|
||||
return lhs.mul(Factory.power(two(), rhsAsNumber()));
|
||||
}
|
||||
else if (SHR == operator && asList(ASE, DB2, H2, HSQLDB, INGRES, ORACLE, SQLSERVER, SYBASE).contains(dialect)) {
|
||||
return lhs.div(Factory.power(literal(2), rhsAsNumber()));
|
||||
return lhs.div(Factory.power(two(), rhsAsNumber()));
|
||||
}
|
||||
|
||||
// These operators are not supported in any dialect
|
||||
@ -200,6 +203,36 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
return (Field<Number>) rhs.get(0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final YearToMonth rhsAsYTM() {
|
||||
try {
|
||||
return ((Param<YearToMonth>) rhs.get(0)).getValue();
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
throw new DataTypeException("Cannot perform datetime arithmetic with a non-numeric, non-interval data type on the right hand side of the expression: " + rhs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final DayToSecond rhsAsDTS() {
|
||||
try {
|
||||
return ((Param<DayToSecond>) rhs.get(0)).getValue();
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
throw new DataTypeException("Cannot perform datetime arithmetic with a non-numeric, non-interval data type on the right hand side of the expression: " + rhs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final Interval rhsAsInterval() {
|
||||
try {
|
||||
return ((Param<Interval>) rhs.get(0)).getValue();
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
throw new DataTypeException("Cannot perform datetime arithmetic with a non-numeric, non-interval data type on the right hand side of the expression: " + rhs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
private class DateExpression extends AbstractFunction<T> {
|
||||
|
||||
/**
|
||||
@ -226,71 +259,56 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
*/
|
||||
private final Field<T> getIntervalExpression(Configuration configuration) {
|
||||
SQLDialect dialect = configuration.getDialect();
|
||||
int sign = (operator == ADD) ? 1 : -1;
|
||||
|
||||
switch (dialect) {
|
||||
case ASE:
|
||||
case SYBASE:
|
||||
case SQLSERVER: {
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
YearToMonth interval = ((Param<YearToMonth>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == ADD) {
|
||||
return function("dateadd", getDataType(), literal("mm"), val(interval.intValue()), lhs);
|
||||
}
|
||||
else {
|
||||
return function("dateadd", getDataType(), literal("mm"), val(-interval.intValue()), lhs);
|
||||
}
|
||||
return field("{dateadd}(mm, {0}, {1})", getDataType(), val(sign * rhsAsYTM().intValue()), lhs);
|
||||
}
|
||||
else {
|
||||
// SQL Server needs this cast.
|
||||
Field<?> result = lhs.cast(Timestamp.class);
|
||||
DayToSecond interval = ((Param<DayToSecond>) rhs.get(0)).getValue();
|
||||
Field<Timestamp> lhsAsTS = lhs.cast(Timestamp.class);
|
||||
DayToSecond interval = rhsAsDTS();
|
||||
|
||||
if (operator == ADD) {
|
||||
if (interval.getNano() != 0) {
|
||||
int micro = interval.getNano() / 1000;
|
||||
|
||||
result = function("dateadd", getDataType(), literal("us"), val(micro), result);
|
||||
result = function("dateadd", getDataType(), literal("ss"), val((long) interval.getTotalSeconds()), result);
|
||||
}
|
||||
else {
|
||||
result = function("dateadd", getDataType(), literal("ss"), val((long) interval.getTotalSeconds()), result);
|
||||
}
|
||||
// Be careful with 32-bit INT arithmetic. Sybase ASE
|
||||
// may fatally overflow when using micro-second precision
|
||||
if (interval.getNano() != 0) {
|
||||
return field("{dateadd}(ss, {0}, {dateadd}(us, {1}, {2}))", getDataType(),
|
||||
val(sign * (long) interval.getTotalSeconds()),
|
||||
val(sign * interval.getMicro()),
|
||||
lhsAsTS);
|
||||
}
|
||||
else {
|
||||
if (interval.getNano() != 0) {
|
||||
int micro = interval.getNano() / 1000;
|
||||
|
||||
result = function("dateadd", getDataType(), literal("us"), val(-micro), result);
|
||||
result = function("dateadd", getDataType(), literal("ss"), val(-(long) interval.getTotalSeconds()), result);
|
||||
}
|
||||
else {
|
||||
result = function("dateadd", getDataType(), literal("ss"), val(-(long) interval.getTotalSeconds()), result);
|
||||
}
|
||||
return field("{dateadd}(ss, {0}, {1})", getDataType(), val(sign * (long) interval.getTotalSeconds()), lhsAsTS);
|
||||
}
|
||||
|
||||
return (Field) result;
|
||||
}
|
||||
}
|
||||
|
||||
case DB2: {
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
YearToMonth interval = ((Param<YearToMonth>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == ADD) {
|
||||
return lhs.add(field("{0} month", val(interval.intValue())));
|
||||
return lhs.add(field("{0} month", val(rhsAsYTM().intValue())));
|
||||
}
|
||||
else {
|
||||
return lhs.sub(field("{0} month", val(interval.intValue())));
|
||||
return lhs.sub(field("{0} month", val(rhsAsYTM().intValue())));
|
||||
}
|
||||
}
|
||||
else {
|
||||
DayToSecond interval = ((Param<DayToSecond>) rhs.get(0)).getValue();
|
||||
// DB2 needs this cast if lhs is of type DATE.
|
||||
DataType<T> type = lhs.getDataType();
|
||||
|
||||
if (operator == ADD) {
|
||||
return (Field) lhs.cast(Timestamp.class).add(field("{0} microseconds", val(interval.getTotalMicro())));
|
||||
return lhs.cast(Timestamp.class)
|
||||
.add(field("{0} microseconds", val(rhsAsDTS().getTotalMicro())))
|
||||
.cast(type);
|
||||
}
|
||||
else {
|
||||
return (Field) lhs.cast(Timestamp.class).sub(field("{0} microseconds", val(interval.getTotalMicro())));
|
||||
return lhs.cast(Timestamp.class)
|
||||
.sub(field("{0} microseconds", val(rhsAsDTS().getTotalMicro())))
|
||||
.cast(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -298,60 +316,53 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
case DERBY:
|
||||
case HSQLDB: {
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
YearToMonth interval = ((Param<YearToMonth>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == ADD) {
|
||||
return field("{fn {timestampadd}({sql_tsi_month}, {0}, {1}) }", getDataType(), val(interval.intValue()), lhs);
|
||||
}
|
||||
else {
|
||||
return field("{fn {timestampadd}({sql_tsi_month}, {0}, {1}) }", getDataType(), val(-interval.intValue()), lhs);
|
||||
}
|
||||
return field("{fn {timestampadd}({sql_tsi_month}, {0}, {1}) }",
|
||||
getDataType(), val(sign * rhsAsYTM().intValue()), lhs);
|
||||
}
|
||||
else {
|
||||
DayToSecond interval = ((Param<DayToSecond>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == ADD) {
|
||||
return field("{fn {timestampadd}({sql_tsi_second}, {0}, {1}) }", getDataType(), val((long) interval.getTotalSeconds()), lhs);
|
||||
}
|
||||
else {
|
||||
return field("{fn {timestampadd}({sql_tsi_second}, {0}, {1}) }", getDataType(), val((long) -interval.getTotalSeconds()), lhs);
|
||||
}
|
||||
return field("{fn {timestampadd}({sql_tsi_second}, {0}, {1}) }",
|
||||
getDataType(), val(sign * (long) rhsAsDTS().getTotalSeconds()), lhs);
|
||||
}
|
||||
}
|
||||
|
||||
case CUBRID:
|
||||
case MYSQL: {
|
||||
org.jooq.types.Interval<?> interval = ((Param<org.jooq.types.Interval<?>>) rhs.get(0)).getValue();
|
||||
Interval interval = rhsAsInterval();
|
||||
|
||||
if (operator == SUBTRACT) {
|
||||
interval = interval.neg();
|
||||
}
|
||||
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
return field("{date_add}({0}, {interval} {1} {year_month})", getDataType(), lhs, val(interval));
|
||||
return field("{date_add}({0}, {interval} {1} {year_month})", getDataType(), lhs, val(interval, String.class));
|
||||
}
|
||||
else {
|
||||
if (dialect == MYSQL) {
|
||||
return field("{date_add}({0}, {interval} {1} {day_microsecond})", getDataType(), lhs, val(interval));
|
||||
return field("{date_add}({0}, {interval} {1} {day_microsecond})", getDataType(), lhs, val(interval, String.class));
|
||||
}
|
||||
else {
|
||||
return field("{date_add}({0}, {interval} {1} {day_millisecond})", getDataType(), lhs, val(interval));
|
||||
return field("{date_add}({0}, {interval} {1} {day_millisecond})", getDataType(), lhs, val(interval, String.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case H2: {
|
||||
org.jooq.types.Interval<?> interval = ((Param<org.jooq.types.Interval<?>>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == SUBTRACT) {
|
||||
interval = interval.neg();
|
||||
}
|
||||
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
return function("dateadd", getDataType(), literal("'month'"), val(interval.intValue()), lhs);
|
||||
return field("{dateadd}('month', {0}, {1})", getDataType(), val(sign * rhsAsYTM().intValue()), lhs);
|
||||
}
|
||||
else {
|
||||
return function("dateadd", getDataType(), literal("'ms'"), val((long) ((DayToSecond) interval).getTotalMilli()), lhs);
|
||||
return field("{dateadd}('ms', {0}, {1})", getDataType(), val(sign * (long) rhsAsDTS().getTotalMilli()), lhs);
|
||||
}
|
||||
}
|
||||
|
||||
case SQLITE: {
|
||||
String prefix = (sign > 0) ? "+" : "-";
|
||||
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
return field("{datetime}({0}, '" + prefix + rhsAsYTM().intValue() + " months')", getDataType(), lhs);
|
||||
}
|
||||
else {
|
||||
return field("{datetime}({0}, '" + prefix + rhsAsDTS().getTotalSeconds() + " seconds')", getDataType(), lhs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,10 +381,10 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
case SQLSERVER:
|
||||
case SYBASE: {
|
||||
if (operator == ADD) {
|
||||
return function("dateadd", getDataType(), literal("day"), rhsAsNumber(), lhs);
|
||||
return field("{dateadd}(day, {0}, {1})", getDataType(), rhsAsNumber(), lhs);
|
||||
}
|
||||
else {
|
||||
return function("dateadd", getDataType(), literal("day"), rhsAsNumber().neg(), lhs);
|
||||
return field("{dateadd}(day, {0}, {1})", getDataType(), rhsAsNumber().neg(), lhs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,29 +420,31 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
// Ingres is not working yet
|
||||
case INGRES: {
|
||||
if (operator == ADD) {
|
||||
return lhs.add(field("date('" + rhsAsNumber() + " days')", Object.class));
|
||||
return lhs.add(field("{date}('" + rhsAsNumber() + " days')", Object.class));
|
||||
}
|
||||
else {
|
||||
return lhs.sub(field("date('" + rhsAsNumber() + " days')", Object.class));
|
||||
return lhs.sub(field("{date}('" + rhsAsNumber() + " days')", Object.class));
|
||||
}
|
||||
}
|
||||
|
||||
// Postgres can add / subtract days using +/- operators only to DATE
|
||||
case POSTGRES: {
|
||||
if (getType() == Date.class) {
|
||||
// Postgres can add / subtract days using +/- operators only to DATE
|
||||
DataType<T> type = lhs.getDataType();
|
||||
|
||||
if (type.getType() == Date.class) {
|
||||
return new DefaultExpression();
|
||||
}
|
||||
else {
|
||||
return new Expression(operator, lhs.cast(Date.class), rhsAsNumber());
|
||||
return new Expression<Date>(operator, lhs.cast(Date.class), rhsAsNumber()).cast(type);
|
||||
}
|
||||
}
|
||||
|
||||
case SQLITE:
|
||||
if (operator == ADD) {
|
||||
return function("datetime", getDataType(), lhs, literal("+" + rhsAsNumber() + " day"));
|
||||
return field("{datetime}({0}, '+" + rhsAsNumber() + " day')", getDataType(), lhs);
|
||||
}
|
||||
else {
|
||||
return function("datetime", getDataType(), lhs, literal("-" + rhsAsNumber() + " day"));
|
||||
return field("{datetime}({0}, '-" + rhsAsNumber() + " day')", getDataType(), lhs);
|
||||
}
|
||||
|
||||
// These dialects can add / subtract days using +/- operators
|
||||
|
||||
@ -36,10 +36,8 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.field;
|
||||
import static org.jooq.impl.Factory.field;
|
||||
import static org.jooq.impl.Factory.function;
|
||||
import static org.jooq.impl.Factory.literal;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.DatePart;
|
||||
@ -69,17 +67,17 @@ class Extract extends AbstractFunction<Integer> {
|
||||
case SQLITE:
|
||||
switch (datePart) {
|
||||
case YEAR:
|
||||
return function("strftime", SQLDataType.INTEGER, literal("'%Y'"), field);
|
||||
return field("{strftime}('%Y', {0})", SQLDataType.INTEGER, field);
|
||||
case MONTH:
|
||||
return function("strftime", SQLDataType.INTEGER, literal("'%m'"), field);
|
||||
return field("{strftime}('%m', {0})", SQLDataType.INTEGER, field);
|
||||
case DAY:
|
||||
return function("strftime", SQLDataType.INTEGER, literal("'%d'"), field);
|
||||
return field("{strftime}('%d', {0})", SQLDataType.INTEGER, field);
|
||||
case HOUR:
|
||||
return function("strftime", SQLDataType.INTEGER, literal("'%H'"), field);
|
||||
return field("{strftime}('%H', {0})", SQLDataType.INTEGER, field);
|
||||
case MINUTE:
|
||||
return function("strftime", SQLDataType.INTEGER, literal("'%M'"), field);
|
||||
return field("{strftime}('%M', {0})", SQLDataType.INTEGER, field);
|
||||
case SECOND:
|
||||
return function("strftime", SQLDataType.INTEGER, literal("'%S'"), field);
|
||||
return field("{strftime}('%S', {0})", SQLDataType.INTEGER, field);
|
||||
default:
|
||||
throw new SQLDialectNotSupportedException("DatePart not supported: " + datePart);
|
||||
}
|
||||
@ -106,17 +104,17 @@ class Extract extends AbstractFunction<Integer> {
|
||||
case ORACLE:
|
||||
switch (datePart) {
|
||||
case YEAR:
|
||||
return function("to_char", SQLDataType.INTEGER, field, literal("'YYYY'"));
|
||||
return field("{to_char}({0}, 'YYYY')", SQLDataType.INTEGER, field);
|
||||
case MONTH:
|
||||
return function("to_char", SQLDataType.INTEGER, field, literal("'MM'"));
|
||||
return field("{to_char}({0}, 'MM')", SQLDataType.INTEGER, field);
|
||||
case DAY:
|
||||
return function("to_char", SQLDataType.INTEGER, field, literal("'DD'"));
|
||||
return field("{to_char}({0}, 'DD')", SQLDataType.INTEGER, field);
|
||||
case HOUR:
|
||||
return function("to_char", SQLDataType.INTEGER, field, literal("'HH24'"));
|
||||
return field("{to_char}({0}, 'HH24')", SQLDataType.INTEGER, field);
|
||||
case MINUTE:
|
||||
return function("to_char", SQLDataType.INTEGER, field, literal("'MI'"));
|
||||
return field("{to_char}({0}, 'MI')", SQLDataType.INTEGER, field);
|
||||
case SECOND:
|
||||
return function("to_char", SQLDataType.INTEGER, field, literal("'SS'"));
|
||||
return field("{to_char}({0}, 'SS')", SQLDataType.INTEGER, field);
|
||||
default:
|
||||
throw new SQLDialectNotSupportedException("DatePart not supported: " + datePart);
|
||||
}
|
||||
@ -126,17 +124,17 @@ class Extract extends AbstractFunction<Integer> {
|
||||
case SYBASE:
|
||||
switch (datePart) {
|
||||
case YEAR:
|
||||
return function("datepart", SQLDataType.INTEGER, field("yy"), field);
|
||||
return field("{datepart}(yy, {0})", SQLDataType.INTEGER, field);
|
||||
case MONTH:
|
||||
return function("datepart", SQLDataType.INTEGER, field("mm"), field);
|
||||
return field("{datepart}(mm, {0})", SQLDataType.INTEGER, field);
|
||||
case DAY:
|
||||
return function("datepart", SQLDataType.INTEGER, field("dd"), field);
|
||||
return field("{datepart}(dd, {0})", SQLDataType.INTEGER, field);
|
||||
case HOUR:
|
||||
return function("datepart", SQLDataType.INTEGER, field("hh"), field);
|
||||
return field("{datepart}(hh, {0})", SQLDataType.INTEGER, field);
|
||||
case MINUTE:
|
||||
return function("datepart", SQLDataType.INTEGER, field("mi"), field);
|
||||
return field("{datepart}(mi, {0})", SQLDataType.INTEGER, field);
|
||||
case SECOND:
|
||||
return function("datepart", SQLDataType.INTEGER, field("ss"), field);
|
||||
return field("{datepart}(ss, {0})", SQLDataType.INTEGER, field);
|
||||
default:
|
||||
throw new SQLDialectNotSupportedException("DatePart not supported: " + datePart);
|
||||
}
|
||||
|
||||
@ -2718,6 +2718,7 @@ public class Factory implements FactoryOperations {
|
||||
* <p>
|
||||
* This has been observed to work with the following databases:
|
||||
* <ul>
|
||||
* <li>CUBRID (simulated using the GROUP BY .. WITH ROLLUP clause)</li>
|
||||
* <li>DB2</li>
|
||||
* <li>MySQL (simulated using the GROUP BY .. WITH ROLLUP clause)</li>
|
||||
* <li>Oracle</li>
|
||||
@ -4258,6 +4259,7 @@ public class Factory implements FactoryOperations {
|
||||
* <li> {@link SQLDialect#H2}: Using <code>GROUP_CONCAT()</code></li>
|
||||
* <li> {@link SQLDialect#HSQLDB}: Using <code>GROUP_CONCAT()</code></li>
|
||||
* <li> {@link SQLDialect#MYSQL}: Using <code>GROUP_CONCAT()</code></li>
|
||||
* <li> {@link SQLDialect#POSTGRES}: Using <code>STRING_AGG()</code></li>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
@ -4279,6 +4281,7 @@ public class Factory implements FactoryOperations {
|
||||
* <li> {@link SQLDialect#H2}: Using <code>GROUP_CONCAT</code></li>
|
||||
* <li> {@link SQLDialect#HSQLDB}: Using <code>GROUP_CONCAT</code></li>
|
||||
* <li> {@link SQLDialect#MYSQL}: Using <code>GROUP_CONCAT</code></li>
|
||||
* <li> {@link SQLDialect#POSTGRES}: Using <code>STRING_AGG()</code></li>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
@ -4305,6 +4308,7 @@ public class Factory implements FactoryOperations {
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#DB2}: Using <code>XMLAGG()</code></li>
|
||||
* <li> {@link SQLDialect#ORACLE}: Using <code>LISTAGG()</code></li>
|
||||
* <li> {@link SQLDialect#POSTGRES}: Using <code>STRING_AGG()</code></li>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
@ -4329,6 +4333,7 @@ public class Factory implements FactoryOperations {
|
||||
* It is simulated by the following dialects:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* <li> {@link SQLDialect#POSTGRES}: Using <code>STRING_AGG()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #listAgg(Field)
|
||||
|
||||
@ -37,7 +37,7 @@ package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.field;
|
||||
import static org.jooq.impl.Factory.function;
|
||||
import static org.jooq.impl.Factory.literal;
|
||||
import static org.jooq.impl.SQLDataType.INTEGER;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@ -67,47 +67,56 @@ class TimestampDiff extends AbstractFunction<DayToSecond> {
|
||||
|
||||
@Override
|
||||
final Field<DayToSecond> getFunction0(Configuration configuration) {
|
||||
double milliInDay = new DayToSecond(1).getTotalMilli();
|
||||
|
||||
switch (configuration.getDialect()) {
|
||||
|
||||
// Sybase ASE's datediff incredibly overflows on 3 days' worth of
|
||||
// microseconds. That's why the days have to be leveled at first
|
||||
case ASE:
|
||||
Field<Double> days = function("datediff", SQLDataType.DOUBLE, literal("day"), timestamp2, timestamp1);
|
||||
Field<Double> milli = function("datediff", SQLDataType.DOUBLE, literal("ms"), timestamp2.add(days), timestamp1);
|
||||
return (Field) days.add(milli.div(literal(new DayToSecond(1).getTotalMilli())));
|
||||
|
||||
// The difference in number of days
|
||||
Field<Integer> days = field("{datediff}(day, {0}, {1})", INTEGER, timestamp2, timestamp1);
|
||||
|
||||
// The intra-day difference in number of milliseconds
|
||||
Field<Integer> milli = field("{datediff}(ms, {0}, {1})", INTEGER, timestamp2.add(days), timestamp1);
|
||||
return (Field) days.mul(86400000).add(milli);
|
||||
|
||||
// CUBRID's datetime operations operate on a millisecond level
|
||||
case CUBRID:
|
||||
return (Field) timestamp1.sub(timestamp2).div(literal(new DayToSecond(1).getTotalMilli()));
|
||||
return (Field) timestamp1.sub(timestamp2);
|
||||
|
||||
// Fun with DB2 dates. Find some info here:
|
||||
// http://www.ibm.com/developerworks/data/library/techarticle/0211yip/0211yip3.html
|
||||
case DB2:
|
||||
return (Field) function("days", SQLDataType.INTEGER, timestamp1).sub(
|
||||
function("days", SQLDataType.INTEGER, timestamp2)).add(
|
||||
function("midnight_seconds", SQLDataType.INTEGER, timestamp1).sub(
|
||||
function("midnight_seconds", SQLDataType.INTEGER, timestamp2)).div(literal(new DayToSecond(1).getTotalSeconds())));
|
||||
return (Field) function("days", INTEGER, timestamp1).sub(
|
||||
function("days", INTEGER, timestamp2)).mul(86400000).add(
|
||||
function("midnight_seconds", INTEGER, timestamp1).sub(
|
||||
function("midnight_seconds", INTEGER, timestamp2)).mul(1000));
|
||||
|
||||
case DERBY:
|
||||
return (Field) field("{fn {timestampdiff}({sql_tsi_second}, {0}, {1}) }", SQLDataType.INTEGER, timestamp2, timestamp1).div(literal(new DayToSecond(1).getTotalSeconds()));
|
||||
return (Field) field("1000 * {fn {timestampdiff}({sql_tsi_second}, {0}, {1}) }", INTEGER, timestamp2, timestamp1);
|
||||
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
return function("datediff", getDataType(), literal("'ms'"), timestamp2, timestamp1).div(literal(new DayToSecond(1).getTotalMilli()));
|
||||
return field("{datediff}('ms', {0}, {1})", getDataType(), timestamp2, timestamp1);
|
||||
|
||||
// MySQL's datetime operations operate on a microsecond level
|
||||
case MYSQL:
|
||||
return function("timestampdiff", getDataType(), literal("microsecond"), timestamp2, timestamp1).div(literal(new DayToSecond(1).getTotalMicro()));
|
||||
return field("{timestampdiff}(microsecond, {0}, {1}) / 1000", getDataType(), timestamp2, timestamp1);
|
||||
|
||||
case SQLSERVER:
|
||||
case SYBASE:
|
||||
return function("datediff", getDataType(), literal("ms"), timestamp2, timestamp1).div(literal(new DayToSecond(1).getTotalMilli()));
|
||||
return field("{datediff}(ms, {0}, {1})", getDataType(), timestamp2, timestamp1);
|
||||
|
||||
case SQLITE:
|
||||
return field("({strftime}('%s', {0}) - {strftime}('%s', {1})) * 1000", getDataType(), timestamp1, timestamp2);
|
||||
|
||||
case ORACLE:
|
||||
case POSTGRES:
|
||||
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return timestamp1.sub(timestamp2).cast(DayToSecond.class);
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return timestamp1.sub(timestamp2).cast(DayToSecond.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -38,22 +38,44 @@ package org.jooq.types;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jooq.Field;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.tools.Convert;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
/**
|
||||
* An implementation for the SQL standard <code>INTERVAL YEAR TO MONTH</code>
|
||||
* An implementation for the SQL standard <code>INTERVAL DAY TO SECOND</code>
|
||||
* data type.
|
||||
* <p>
|
||||
* <code>DayToSecond</code> is a {@link Number} whose {@link Number#intValue()}
|
||||
* represents the (truncated) number of days of the interval,
|
||||
* {@link Number#doubleValue()} represents the approximative number of days
|
||||
* (including hours, minutes, seconds, nanoseconds) of the interval.
|
||||
* represents the (truncated) number of milliseconds of the interval,
|
||||
* {@link Number#doubleValue()} represents the approximative number of
|
||||
* milliseconds (including hours, minutes, seconds, nanoseconds) of the
|
||||
* interval.
|
||||
* <p>
|
||||
* Note: only a few databases actually support this data type on its own. You
|
||||
* can still use it for date time arithmetic in other databases, though, through
|
||||
* {@link Field#add(Field)} and {@link Field#sub(Field)} Databases that have
|
||||
* been observed to natively support <code>INTERVAL</code> data types are:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#HSQLDB}</li>
|
||||
* <li> {@link SQLDialect#INGRES}</li>
|
||||
* <li> {@link SQLDialect#ORACLE}</li>
|
||||
* <li> {@link SQLDialect#POSTGRES}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* These dialects have been observed to partially support <code>INTERVAL</code>
|
||||
* data types in date time arithmetic functions, such as
|
||||
* <code>TIMESTAMPADD</code>, and <code>TIMESTAMPDIFF</code>:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#CUBRID}</li>
|
||||
* <li> {@link SQLDialect#MYSQL}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @see Interval
|
||||
*/
|
||||
public final class DayToSecond extends Number implements Interval<DayToSecond> {
|
||||
public final class DayToSecond extends Number implements Interval, Comparable<DayToSecond> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -169,21 +191,21 @@ public final class DayToSecond extends Number implements Interval<DayToSecond> {
|
||||
/**
|
||||
* Load a {@link Double} representation of a <code>INTERVAL DAY TO SECOND</code>
|
||||
*
|
||||
* @param days The number of days as a fractional number
|
||||
* @param milli The number of milliseconds as a fractional number
|
||||
* @return The loaded <code>INTERVAL DAY TO SECOND</code> object
|
||||
*/
|
||||
public static DayToSecond valueOf(double days) {
|
||||
double abs = Math.abs(days);
|
||||
public static DayToSecond valueOf(double milli) {
|
||||
double abs = Math.abs(milli);
|
||||
|
||||
int d = (int) abs; abs = (abs - d) * 24.0;
|
||||
int h = (int) abs; abs = (abs - h) * 60.0;
|
||||
int m = (int) abs; abs = (abs - m) * 60.0;
|
||||
int s = (int) abs; abs = (abs - s) * 1000000000.0;
|
||||
int n = (int) abs;
|
||||
int n = (int) ((abs % 1000) * 1000000.0); abs = Math.floor(abs / 1000);
|
||||
int s = (int) (abs % 60); abs = Math.floor(abs / 60);
|
||||
int m = (int) (abs % 60); abs = Math.floor(abs / 60);
|
||||
int h = (int) (abs % 24); abs = Math.floor(abs / 24);
|
||||
int d = (int) abs;
|
||||
|
||||
DayToSecond result = new DayToSecond(d, h, m, s, n);
|
||||
|
||||
if (days < 0) {
|
||||
if (milli < 0) {
|
||||
result = result.neg();
|
||||
}
|
||||
|
||||
@ -211,11 +233,7 @@ public final class DayToSecond extends Number implements Interval<DayToSecond> {
|
||||
|
||||
@Override
|
||||
public final double doubleValue() {
|
||||
return getTotalDays();
|
||||
}
|
||||
|
||||
private final int negativeFactor() {
|
||||
return negative ? -1 : 1;
|
||||
return getTotalMilli();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -260,6 +278,20 @@ public final class DayToSecond extends Number implements Interval<DayToSecond> {
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (truncated) milli-part of this interval
|
||||
*/
|
||||
public final int getMilli() {
|
||||
return nano / 1000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (truncated) micro-part of this interval
|
||||
*/
|
||||
public final int getMicro() {
|
||||
return nano / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nano-part of this interval
|
||||
*/
|
||||
@ -271,55 +303,91 @@ public final class DayToSecond extends Number implements Interval<DayToSecond> {
|
||||
* Get the whole interval in days
|
||||
*/
|
||||
public final double getTotalDays() {
|
||||
return getTotalNano() / 1000000000.0 / 3600.0 / 24.0;
|
||||
return getSign() * (
|
||||
nano / (24.0 * 3600.0 * 1000000000.0) +
|
||||
seconds / (24.0 * 3600.0) +
|
||||
minutes / (24.0 * 60.0) +
|
||||
hours / 24.0 +
|
||||
days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole interval in hours
|
||||
*/
|
||||
public final double getTotalHours() {
|
||||
return getTotalNano() / 1000000000.0 / 3600.0;
|
||||
return getSign() * (
|
||||
nano / (3600.0 * 1000000000.0) +
|
||||
seconds / 3600.0 +
|
||||
minutes / 60.0 +
|
||||
hours +
|
||||
24.0 * days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole interval in minutes
|
||||
*/
|
||||
public final double getTotalMinutes() {
|
||||
return getTotalNano() / 1000000000.0 / 60.0;
|
||||
return getSign() * (
|
||||
nano / (60.0 * 1000000000.0) +
|
||||
seconds / 60.0 +
|
||||
minutes +
|
||||
60.0 * hours +
|
||||
60.0 * 24.0 * days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole interval in seconds
|
||||
*/
|
||||
public final double getTotalSeconds() {
|
||||
return getTotalNano() / 1000000000.0;
|
||||
}
|
||||
return getSign() * (
|
||||
nano / 1000000000.0 +
|
||||
seconds +
|
||||
60.0 * minutes +
|
||||
3600.0 * hours +
|
||||
3600.0 * 24.0 * days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole interval in milli-seconds
|
||||
*/
|
||||
public final double getTotalMilli() {
|
||||
return getTotalNano() / 1000000.0;
|
||||
return getSign() * (
|
||||
nano / 1000000.0 +
|
||||
1000.0 * seconds +
|
||||
1000.0 * 60.0 * minutes +
|
||||
1000.0 * 3600.0 * hours +
|
||||
1000.0 * 3600.0 * 24.0 * days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole interval in micro-seconds
|
||||
*/
|
||||
public final double getTotalMicro() {
|
||||
return getTotalNano() / 1000.0;
|
||||
return getSign() * (
|
||||
nano / 1000.0 +
|
||||
1000000.0 * seconds +
|
||||
1000000.0 * 60.0 * minutes +
|
||||
1000000.0 * 3600.0 * hours +
|
||||
1000000.0 * 3600.0 * 24.0 * days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whole interval in nano-seconds
|
||||
*/
|
||||
public final double getTotalNano() {
|
||||
return negativeFactor() * (nano +
|
||||
return getSign() * (
|
||||
nano +
|
||||
1000000000.0 * seconds +
|
||||
1000000000.0 * 60.0 * minutes +
|
||||
1000000000.0 * 3600.0 * hours +
|
||||
1000000000.0 * 3600.0 * 24.0 * days);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getSign() {
|
||||
return negative ? -1 : 1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Comparable and Object API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -101,30 +101,46 @@ import org.jooq.SQLDialect;
|
||||
* </table>
|
||||
* <p>
|
||||
* Interval implementations can be expected to also also extend {@link Number}.
|
||||
* True SQL standard INTERVAL data types have been observed to be supported by
|
||||
* any of these dialects:
|
||||
* <p>
|
||||
* Note: only a few databases actually support this data type on its own. You
|
||||
* can still use it for date time arithmetic in other databases, though, through
|
||||
* {@link Field#add(Field)} and {@link Field#sub(Field)} Databases that have
|
||||
* been observed to natively support <code>INTERVAL</code> data types are:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#HSQLDB}</li>
|
||||
* <li> {@link SQLDialect#INGRES}</li>
|
||||
* <li> {@link SQLDialect#ORACLE}</li>
|
||||
* <li> {@link SQLDialect#POSTGRES}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* In other dialects, jOOQ allows for using them for date time arithmetic. See
|
||||
* {@link Field#add(Field)}, {@link Field#sub(Field)}
|
||||
* These dialects have been observed to partially support <code>INTERVAL</code>
|
||||
* data types in date time arithmetic functions, such as
|
||||
* <code>TIMESTAMPADD</code>, and <code>TIMESTAMPDIFF</code>:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#CUBRID}</li>
|
||||
* <li> {@link SQLDialect#MYSQL}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface Interval<T extends Interval<T>> extends Serializable, Comparable<T> {
|
||||
public interface Interval extends Serializable {
|
||||
|
||||
/**
|
||||
* Negate the interval (change its sign)
|
||||
*/
|
||||
T neg();
|
||||
Interval neg();
|
||||
|
||||
/**
|
||||
* Get the absolute value of the interval (set its sign to positive)
|
||||
*/
|
||||
T abs();
|
||||
Interval abs();
|
||||
|
||||
/**
|
||||
* The sign of the interval
|
||||
*
|
||||
* @return <code>1</code> for positive or zero, <code>-1</code> for negative
|
||||
*/
|
||||
int getSign();
|
||||
|
||||
/**
|
||||
* @see Number#doubleValue()
|
||||
|
||||
@ -38,17 +38,39 @@ package org.jooq.types;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jooq.Field;
|
||||
import org.jooq.SQLDialect;
|
||||
|
||||
/**
|
||||
* An implementation for the SQL standard <code>INTERVAL YEAR TO MONTH</code>
|
||||
* data type.
|
||||
* <p>
|
||||
* <code>YearToMonth</code> is a {@link Number} whose {@link Number#intValue()}
|
||||
* represents the number of months of the interval.
|
||||
* <p>
|
||||
* Note: only a few databases actually support this data type on its own. You
|
||||
* can still use it for date time arithmetic in other databases, though, through
|
||||
* {@link Field#add(Field)} and {@link Field#sub(Field)} Databases that have
|
||||
* been observed to natively support <code>INTERVAL</code> data types are:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#HSQLDB}</li>
|
||||
* <li> {@link SQLDialect#INGRES}</li>
|
||||
* <li> {@link SQLDialect#ORACLE}</li>
|
||||
* <li> {@link SQLDialect#POSTGRES}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* These dialects have been observed to partially support <code>INTERVAL</code>
|
||||
* data types in date time arithmetic functions, such as
|
||||
* <code>TIMESTAMPADD</code>, and <code>TIMESTAMPDIFF</code>:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#CUBRID}</li>
|
||||
* <li> {@link SQLDialect#MYSQL}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @see Interval
|
||||
*/
|
||||
public final class YearToMonth extends Number implements Interval<YearToMonth> {
|
||||
public final class YearToMonth extends Number implements Interval, Comparable<YearToMonth> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -134,6 +156,11 @@ public final class YearToMonth extends Number implements Interval<YearToMonth> {
|
||||
return months;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getSign() {
|
||||
return negative ? -1 : 1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Number API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
package org.jooq.test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.jooq.JoinType.LEFT_OUTER_JOIN;
|
||||
import static org.jooq.impl.Factory.avg;
|
||||
import static org.jooq.impl.Factory.condition;
|
||||
@ -2288,21 +2289,24 @@ public class jOOQTest {
|
||||
|
||||
@Test
|
||||
public void testDayToSecond() {
|
||||
for (double i = -1394892834972.0; i <= 23487289374987.0; i += 283749827.3839293) {
|
||||
intervalChecks(i, DayToSecond.valueOf(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
intervalChecks(i / 2.0, DayToSecond.valueOf(i / 2.0));
|
||||
intervalChecks(i, new DayToSecond(i));
|
||||
intervalChecks(i / 24.0, new DayToSecond(0, i));
|
||||
intervalChecks(i / 24.0 / 60.0, new DayToSecond(0, 0, i));
|
||||
intervalChecks(i / 24.0 / 3600.0, new DayToSecond(0, 0, 0, i));
|
||||
intervalChecks(i / 24.0 / 3600.0 / 1000000000.0, new DayToSecond(0, 0, 0, 0, i));
|
||||
intervalChecks(i * 1000 * 86400.0, new DayToSecond(i));
|
||||
intervalChecks(i * 1000 * 3600.0, new DayToSecond(0, i));
|
||||
intervalChecks(i * 1000 * 60.0, new DayToSecond(0, 0, i));
|
||||
intervalChecks(i * 1000, new DayToSecond(0, 0, 0, i));
|
||||
intervalChecks(i / 1000000.0, new DayToSecond(0, 0, 0, 0, i));
|
||||
}
|
||||
}
|
||||
|
||||
private <I extends Number & Interval<I>> void intervalChecks(Number expected, I interval) {
|
||||
if (expected.doubleValue() > 1 / 24.0) {
|
||||
assertEquals(expected.doubleValue(), interval.doubleValue());
|
||||
assertEquals(expected.floatValue(), interval.floatValue());
|
||||
}
|
||||
private <I extends Number & Interval> void intervalChecks(Number expected, I interval) {
|
||||
// Allow some floating point arithmetic inaccuracy
|
||||
assertTrue(Math.abs(Double.doubleToLongBits(expected.doubleValue()) - Double.doubleToLongBits(interval.doubleValue())) < 50);
|
||||
assertTrue(Math.abs(Float.floatToIntBits(expected.floatValue()) - Float.floatToIntBits(interval.floatValue())) < 5);
|
||||
|
||||
assertEquals(expected.byteValue(), interval.byteValue());
|
||||
assertEquals(expected.shortValue(), interval.shortValue());
|
||||
assertEquals(expected.intValue(), interval.intValue());
|
||||
@ -2316,11 +2320,11 @@ public class jOOQTest {
|
||||
DayToSecond m = DayToSecond.valueOf(interval.toString());
|
||||
assertEquals(interval, m);
|
||||
assertEquals(m.getDays(),
|
||||
(int) m.getTotalDays());
|
||||
m.getSign() * (int) m.getTotalDays());
|
||||
assertEquals(m.getDays() * 24 + m.getHours(),
|
||||
(int) m.getTotalHours());
|
||||
m.getSign() * (int) m.getTotalHours());
|
||||
assertEquals(m.getDays() * 24 * 60 + m.getHours() * 60 + m.getMinutes(),
|
||||
(int) m.getTotalMinutes());
|
||||
m.getSign() * (int) m.getTotalMinutes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user