[#585] Add support for DATE, TIME and INTERVAL arithmetic - Implementation done for HSQLDB, implementation attempts for Ingres, Postgres

This commit is contained in:
Lukas Eder 2012-04-04 20:23:23 +00:00
parent 26c7a3090a
commit a0dacbcc0e
5 changed files with 36 additions and 58 deletions

View File

@ -82,10 +82,12 @@ class DateDiff extends AbstractFunction<Integer> {
getDataType(), field("SQL_TSI_DAY"), date2, date1);
case H2:
case HSQLDB:
return function("datediff", getDataType(), literal("'day'"), date2, date1);
case CUBRID:
case ORACLE:
case POSTGRES:
// TODO [#585] This cast shouldn't be necessary
return date1.sub(date2).cast(Integer.class);

View File

@ -66,6 +66,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.Date;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;
@ -220,6 +221,9 @@ class Expression<T> extends AbstractFunction<T> {
}
}
/**
* Return the expression to be rendered when the RHS is an interval type
*/
private final Field<T> getIntervalExpression(Configuration configuration) {
SQLDialect dialect = configuration.getDialect();
@ -266,8 +270,7 @@ class Expression<T> extends AbstractFunction<T> {
}
}
case DB2:
case HSQLDB: {
case DB2: {
if (rhs.get(0).getType() == YearToMonth.class) {
YearToMonth interval = ((Param<YearToMonth>) rhs.get(0)).getValue();
@ -280,7 +283,6 @@ class Expression<T> extends AbstractFunction<T> {
}
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"));
}
@ -290,7 +292,8 @@ class Expression<T> extends AbstractFunction<T> {
}
}
case DERBY: {
case DERBY:
case HSQLDB: {
if (rhs.get(0).getType() == YearToMonth.class) {
YearToMonth interval = ((Param<YearToMonth>) rhs.get(0)).getValue();
@ -349,11 +352,15 @@ class Expression<T> extends AbstractFunction<T> {
}
}
case ORACLE:
default:
return new DefaultExpression();
}
}
/**
* Return the expression to be rendered when the RHS is a number type
*/
private final Field<T> getNumberExpression(Configuration configuration) {
switch (configuration.getDialect()) {
case ASE: {
@ -396,6 +403,26 @@ class Expression<T> extends AbstractFunction<T> {
}
}
// That implementation seems a bit off...
case INGRES: {
if (operator == ADD) {
return lhs.add(field("date('" + rhsAsNumber() + " days')", Object.class));
}
else {
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) {
return new DefaultExpression();
}
else {
return new Expression(operator, lhs.cast(Date.class), rhsAsNumber());
}
}
// These dialects can add / subtract days using +/- operators
case H2:
case ORACLE:

View File

@ -4637,59 +4637,6 @@ public class Factory implements FactoryOperations {
return new TimestampDiff(timestamp1, timestamp2);
}
/**
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
* type
* <p>
* This translates into any dialect
*
* @see Field#sub(Field)
*/
@Support
public static Field<DayToSecond> timeDiff(Time time1, Time time2) {
return timeDiff(val(time1), val(time2));
}
/**
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
* type
* <p>
* This translates into any dialect
*
* @see Field#sub(Field)
*/
@Support
public static Field<DayToSecond> timeDiff(Field<Time> time1, Time time2) {
return timeDiff(nullSafe(time1), val(time2));
}
/**
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
* type
* <p>
* This translates into any dialect
*
* @see Field#sub(Field)
*/
@Support
public static Field<DayToSecond> timeDiff(Time time1, Field<Time> time2) {
return timeDiff(val(time1), nullSafe(time2));
}
/**
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
* type
* <p>
* This translates into any dialect
*
* @see Field#sub(Field)
*/
@Support
public static Field<DayToSecond> timeDiff(Field<Time> time1, Field<Time> time2) {
// TODO [#585] This cast shouldn't be necessary
return nullSafe(time1).sub(nullSafe(time2)).cast(DayToSecond.class);
}
// -------------------------------------------------------------------------
// XXX other functions
// -------------------------------------------------------------------------

View File

@ -93,6 +93,7 @@ class TimestampDiff extends AbstractFunction<DayToSecond> {
SQLDataType.INTEGER, field("SQL_TSI_SECOND"), timestamp2, timestamp1).div(literal(86400.0));
case H2:
case HSQLDB:
return function("datediff", getDataType(), literal("'ms'"), timestamp2, timestamp1).div(literal(86400000.0));
// MySQL's datetime operations operate on a microsecond level
@ -100,6 +101,7 @@ class TimestampDiff extends AbstractFunction<DayToSecond> {
return function("timestampdiff", getDataType(), literal("microsecond"), timestamp2, timestamp1).div(new DayToSecond(1).getTotalMicro());
case ORACLE:
case POSTGRES:
// TODO [#585] This cast shouldn't be necessary
return timestamp1.sub(timestamp2).cast(DayToSecond.class);

View File

@ -185,7 +185,7 @@ class Val<T> extends AbstractField<T> implements Param<T>, BindingProvider {
// [#566] JDBC doesn't explicitly support interval data types. To be on
// the safe side, always cast these types in those dialects that support
// them
else if (getDataType().isInterval()) {
if (getDataType().isInterval()) {
switch (context.getDialect()) {
case ORACLE:
case POSTGRES: