[#585] Add support for DATE, TIME and INTERVAL arithmetic - Implementation done for DB2
This commit is contained in:
parent
82737aa437
commit
299a4bb3ba
@ -43,6 +43,7 @@ import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.jooq.SQLDialect.ASE;
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
import static org.jooq.SQLDialect.DB2;
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
import static org.jooq.impl.Factory.cast;
|
||||
@ -1215,6 +1216,7 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
// Interval tests
|
||||
// --------------
|
||||
if (getDialect() == ASE ||
|
||||
getDialect() == DB2 ||
|
||||
getDialect() == CUBRID ||
|
||||
getDialect() == MYSQL) {
|
||||
|
||||
|
||||
@ -72,6 +72,10 @@ class DateDiff extends AbstractFunction<Integer> {
|
||||
case MYSQL:
|
||||
return function("datediff", getDataType(), date1, date2);
|
||||
|
||||
case DB2:
|
||||
return function("days", getDataType(), date1).sub(
|
||||
function("days", getDataType(), date2));
|
||||
|
||||
case CUBRID:
|
||||
case ORACLE:
|
||||
|
||||
|
||||
@ -65,6 +65,7 @@ import static org.jooq.impl.Factory.function;
|
||||
import static org.jooq.impl.Factory.literal;
|
||||
import static org.jooq.impl.Factory.val;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -169,7 +170,8 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
// [#585] Date time arithmetic for numeric or interval RHS
|
||||
else if (asList(ADD, SUBTRACT).contains(operator) &&
|
||||
lhs.getDataType().isDateTime() &&
|
||||
!rhs.get(0).getDataType().isDateTime()) {
|
||||
(rhs.get(0).getDataType().isNumeric() ||
|
||||
rhs.get(0).getDataType().isInterval())) {
|
||||
|
||||
return new DateExpression();
|
||||
}
|
||||
@ -263,6 +265,30 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
}
|
||||
}
|
||||
|
||||
case DB2:
|
||||
case HSQLDB: {
|
||||
if (rhs.get(0).getType() == YearToMonth.class) {
|
||||
YearToMonth interval = ((Param<YearToMonth>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == ADD) {
|
||||
return lhs.add(new IntervalLiteral(val(interval.intValue()), "month"));
|
||||
}
|
||||
else {
|
||||
return lhs.sub(new IntervalLiteral(val(interval.intValue()), "month"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
DayToSecond interval = ((Param<DayToSecond>) rhs.get(0)).getValue();
|
||||
|
||||
if (operator == ADD) {
|
||||
return (Field) lhs.cast(Timestamp.class).add(new IntervalLiteral(val(interval.getTotalMicro()), "microseconds"));
|
||||
}
|
||||
else {
|
||||
return (Field) lhs.cast(Timestamp.class).sub(new IntervalLiteral(val(interval.getTotalMicro()), "microseconds"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case CUBRID:
|
||||
case MYSQL: {
|
||||
org.jooq.types.Interval<?> interval = ((Param<org.jooq.types.Interval<?>>) rhs.get(0)).getValue();
|
||||
@ -287,13 +313,24 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
private final Field<T> getNumberExpression(Configuration configuration) {
|
||||
switch (configuration.getDialect()) {
|
||||
case ASE:
|
||||
case ASE: {
|
||||
if (operator == ADD) {
|
||||
return function("dateadd", getDataType(), literal("day"), rhsAsNumber(), lhs);
|
||||
}
|
||||
else {
|
||||
return function("dateadd", getDataType(), literal("day"), rhsAsNumber().neg(), lhs);
|
||||
}
|
||||
}
|
||||
|
||||
case DB2:
|
||||
case HSQLDB: {
|
||||
if (operator == ADD) {
|
||||
return lhs.add(new IntervalLiteral(rhsAsNumber(), "day"));
|
||||
}
|
||||
else {
|
||||
return lhs.sub(new IntervalLiteral(rhsAsNumber(), "day"));
|
||||
}
|
||||
}
|
||||
|
||||
case CUBRID:
|
||||
case MYSQL: {
|
||||
|
||||
@ -44,18 +44,18 @@ import org.jooq.RenderContext;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class IntervalLiteral<T> extends CustomField<T> {
|
||||
class IntervalLiteral extends CustomField<Object> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -530284767039331529L;
|
||||
|
||||
private final Field<T> field;
|
||||
private final Field<?> field;
|
||||
private final String intervalType;
|
||||
|
||||
IntervalLiteral(Field<T> field, String intervalType) {
|
||||
super("interval", field.getDataType());
|
||||
IntervalLiteral(Field<?> field, String intervalType) {
|
||||
super("interval", SQLDataType.OTHER);
|
||||
|
||||
this.field = field;
|
||||
this.intervalType = intervalType;
|
||||
@ -63,23 +63,39 @@ class IntervalLiteral<T> extends CustomField<T> {
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
if (context.getDialect() == CUBRID) {
|
||||
boolean inline = context.inline();
|
||||
switch (context.getDialect()) {
|
||||
case CUBRID: {
|
||||
boolean inline = context.inline();
|
||||
|
||||
context.keyword("interval ")
|
||||
.inline(true)
|
||||
.sql(field.getDataType().isNumeric() ? "" : "'")
|
||||
.sql(field)
|
||||
.sql(field.getDataType().isNumeric() ? "" : "'")
|
||||
.inline(inline)
|
||||
.sql(" ")
|
||||
.keyword(intervalType);
|
||||
}
|
||||
else {
|
||||
context.keyword("interval ")
|
||||
.sql(field)
|
||||
.sql(" ")
|
||||
.keyword(intervalType);
|
||||
context.keyword("interval ")
|
||||
.inline(true)
|
||||
.sql(field.getDataType().isNumeric() ? "" : "'")
|
||||
.sql(field)
|
||||
.sql(field.getDataType().isNumeric() ? "" : "'")
|
||||
.inline(inline)
|
||||
.sql(" ")
|
||||
.keyword(intervalType);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DB2:
|
||||
case HSQLDB: {
|
||||
context.sql(field)
|
||||
.sql(" ")
|
||||
.keyword(intervalType);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
context.keyword("interval ")
|
||||
.sql(field)
|
||||
.sql(" ")
|
||||
.keyword(intervalType);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -73,11 +73,19 @@ class TimestampDiff extends AbstractFunction<DayToSecond> {
|
||||
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(new DayToSecond(1).getTotalMilli()));
|
||||
return (Field) days.add(milli.div(literal(new DayToSecond(1).getTotalMilli())));
|
||||
|
||||
// CUBRID's datetime operations operate on a millisecond level
|
||||
case CUBRID:
|
||||
return (Field) timestamp1.sub(timestamp2).div(new DayToSecond(1).getTotalMilli());
|
||||
return (Field) timestamp1.sub(timestamp2).div(literal(new DayToSecond(1).getTotalMilli()));
|
||||
|
||||
// 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(86400.0)));
|
||||
|
||||
// MySQL's datetime operations operate on a microsecond level
|
||||
case MYSQL:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user