[jOOQ/jOOQ#8754] Remove more SQL templating
Removes SQL templating in expression, date, and timestamp related functions as well as in a few other classes.
This commit is contained in:
parent
070bb2cf99
commit
5076b5eeff
@ -15929,7 +15929,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ H2, HSQLDB, POSTGRES })
|
||||
public static Field<Date> toDate(Field<String> value, Field<String> format) {
|
||||
return DSL.field("{to_date}({0}, {1})", SQLDataType.DATE, nullSafe(value), nullSafe(format));
|
||||
return function("to_date", SQLDataType.DATE, nullSafe(value), nullSafe(format));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15973,7 +15973,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ H2, HSQLDB, POSTGRES })
|
||||
public static Field<Timestamp> toTimestamp(Field<String> value, Field<String> format) {
|
||||
return DSL.field("{to_timestamp}({0}, {1})", SQLDataType.TIMESTAMP, nullSafe(value), nullSafe(format));
|
||||
return function("to_timestamp", SQLDataType.TIMESTAMP, nullSafe(value), nullSafe(format));
|
||||
}
|
||||
|
||||
|
||||
@ -17580,7 +17580,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ CUBRID })
|
||||
public static Field<String> sysConnectByPath(Field<?> field, String separator) {
|
||||
return field("{sys_connect_by_path}({0}, {1})", String.class, field, inline(separator));
|
||||
return function("sys_connect_by_path", String.class, field, inline(separator));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -38,18 +38,31 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.DSL.sql;
|
||||
import static org.jooq.impl.Keywords.F_ADD_MONTHS;
|
||||
import static org.jooq.impl.Keywords.F_DATEADD;
|
||||
import static org.jooq.impl.Keywords.F_DATE_ADD;
|
||||
import static org.jooq.impl.Keywords.F_STRFTIME;
|
||||
import static org.jooq.impl.Keywords.F_TIMESTAMPADD;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.Keywords.K_CAST;
|
||||
import static org.jooq.impl.Keywords.K_DAY;
|
||||
import static org.jooq.impl.Keywords.K_HOUR;
|
||||
import static org.jooq.impl.Keywords.K_INTERVAL;
|
||||
import static org.jooq.impl.Keywords.K_MINUTE;
|
||||
import static org.jooq.impl.Keywords.K_MONTH;
|
||||
import static org.jooq.impl.Keywords.K_SECOND;
|
||||
import static org.jooq.impl.Keywords.K_YEAR;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DatePart;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Keyword;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class DateAdd<T> extends AbstractFunction<T> {
|
||||
final class DateAdd<T> extends AbstractField<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -61,7 +74,7 @@ final class DateAdd<T> extends AbstractFunction<T> {
|
||||
private final DatePart datePart;
|
||||
|
||||
DateAdd(Field<T> date, Field<? extends Number> interval, DatePart datePart) {
|
||||
super("dateadd", date.getDataType());
|
||||
super(DSL.name("dateadd"), date.getDataType());
|
||||
|
||||
this.date = date;
|
||||
this.interval = interval;
|
||||
@ -69,10 +82,11 @@ final class DateAdd<T> extends AbstractFunction<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
final QueryPart getFunction0(Configuration configuration) {
|
||||
String keyword = null;
|
||||
public final void accept(Context<?> ctx) {
|
||||
Keyword keyword = null;
|
||||
String string = null;
|
||||
|
||||
switch (configuration.family()) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
@ -81,59 +95,63 @@ final class DateAdd<T> extends AbstractFunction<T> {
|
||||
case MARIADB:
|
||||
case MYSQL: {
|
||||
switch (datePart) {
|
||||
case YEAR: keyword = "year"; break;
|
||||
case MONTH: keyword = "month"; break;
|
||||
case DAY: keyword = "day"; break;
|
||||
case HOUR: keyword = "hour"; break;
|
||||
case MINUTE: keyword = "minute"; break;
|
||||
case SECOND: keyword = "second"; break;
|
||||
case YEAR: keyword = K_YEAR; break;
|
||||
case MONTH: keyword = K_MONTH; break;
|
||||
case DAY: keyword = K_DAY; break;
|
||||
case HOUR: keyword = K_HOUR; break;
|
||||
case MINUTE: keyword = K_MINUTE; break;
|
||||
case SECOND: keyword = K_SECOND; break;
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{date_add}({0}, {interval} {1} {2})", getDataType(), date, interval, keyword(keyword));
|
||||
ctx.visit(F_DATE_ADD).sql('(').visit(date).sql(", ").visit(K_INTERVAL).sql(' ').visit(interval).sql(' ').visit(keyword).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case DERBY:
|
||||
case HSQLDB: {
|
||||
switch (datePart) {
|
||||
case YEAR: keyword = "sql_tsi_year"; break;
|
||||
case MONTH: keyword = "sql_tsi_month"; break;
|
||||
case DAY: keyword = "sql_tsi_day"; break;
|
||||
case HOUR: keyword = "sql_tsi_hour"; break;
|
||||
case MINUTE: keyword = "sql_tsi_minute"; break;
|
||||
case SECOND: keyword = "sql_tsi_second"; break;
|
||||
case YEAR: keyword = DSL.keyword("sql_tsi_year"); break;
|
||||
case MONTH: keyword = DSL.keyword("sql_tsi_month"); break;
|
||||
case DAY: keyword = DSL.keyword("sql_tsi_day"); break;
|
||||
case HOUR: keyword = DSL.keyword("sql_tsi_hour"); break;
|
||||
case MINUTE: keyword = DSL.keyword("sql_tsi_minute"); break;
|
||||
case SECOND: keyword = DSL.keyword("sql_tsi_second"); break;
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{fn {timestampadd}({0}, {1}, {2}) }", getDataType(), keyword(keyword), interval, date);
|
||||
ctx.sql("{fn ").visit(F_TIMESTAMPADD).sql('(').visit(keyword).sql(", ").visit(interval).sql(", ").visit(date).sql(") }");
|
||||
break;
|
||||
}
|
||||
|
||||
case FIREBIRD: {
|
||||
switch (datePart) {
|
||||
case YEAR: keyword = "year"; break;
|
||||
case MONTH: keyword = "month"; break;
|
||||
case DAY: keyword = "day"; break;
|
||||
case HOUR: keyword = "hour"; break;
|
||||
case MINUTE: keyword = "minute"; break;
|
||||
case SECOND: keyword = "second"; break;
|
||||
case YEAR: keyword = K_YEAR; break;
|
||||
case MONTH: keyword = K_MONTH; break;
|
||||
case DAY: keyword = K_DAY; break;
|
||||
case HOUR: keyword = K_HOUR; break;
|
||||
case MINUTE: keyword = K_MINUTE; break;
|
||||
case SECOND: keyword = K_SECOND; break;
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{dateadd}({0}, {1}, {2})", getDataType(), keyword(keyword), interval, date);
|
||||
ctx.visit(F_DATEADD).sql('(').visit(keyword).sql(", ").visit(interval).sql(", ").visit(date).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case H2: {
|
||||
switch (datePart) {
|
||||
case YEAR: keyword = "year"; break;
|
||||
case MONTH: keyword = "month"; break;
|
||||
case DAY: keyword = "day"; break;
|
||||
case HOUR: keyword = "hour"; break;
|
||||
case MINUTE: keyword = "minute"; break;
|
||||
case SECOND: keyword = "second"; break;
|
||||
case YEAR: string = "year"; break;
|
||||
case MONTH: string = "month"; break;
|
||||
case DAY: string = "day"; break;
|
||||
case HOUR: string = "hour"; break;
|
||||
case MINUTE: string = "minute"; break;
|
||||
case SECOND: string = "second"; break;
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{dateadd}({0}, {1}, {2})", getDataType(), inline(keyword), interval, date);
|
||||
ctx.visit(F_DATEADD).sql('(').visit(inline(string)).sql(", ").visit(interval).sql(", ").visit(date).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -146,35 +164,37 @@ final class DateAdd<T> extends AbstractFunction<T> {
|
||||
|
||||
case POSTGRES: {
|
||||
switch (datePart) {
|
||||
case YEAR: keyword = " year"; break;
|
||||
case MONTH: keyword = " month"; break;
|
||||
case DAY: keyword = " day"; break;
|
||||
case HOUR: keyword = " hour"; break;
|
||||
case MINUTE: keyword = " minute"; break;
|
||||
case SECOND: keyword = " second"; break;
|
||||
case YEAR: string = " year"; break;
|
||||
case MONTH: string = " month"; break;
|
||||
case DAY: string = " day"; break;
|
||||
case HOUR: string = " hour"; break;
|
||||
case MINUTE: string = " minute"; break;
|
||||
case SECOND: string = " second"; break;
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
// [#3824] Ensure that the output for DATE arithmetic will also
|
||||
// be of type DATE, not TIMESTAMP
|
||||
if (getDataType().isDate())
|
||||
return DSL.field("({0} + ({1} || {2})::interval)::date", getDataType(), date, interval, inline(keyword));
|
||||
ctx.sql('(').visit(date).sql(" + (").visit(interval).sql(" || ").visit(inline(string)).sql(")::interval)::date");
|
||||
else
|
||||
return DSL.field("({0} + ({1} || {2})::interval)", getDataType(), date, interval, inline(keyword));
|
||||
ctx.sql('(').visit(date).sql(" + (").visit(interval).sql(" || ").visit(inline(string)).sql(")::interval)");
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE: {
|
||||
switch (datePart) {
|
||||
case YEAR: keyword = " year"; break;
|
||||
case MONTH: keyword = " month"; break;
|
||||
case DAY: keyword = " day"; break;
|
||||
case HOUR: keyword = " hour"; break;
|
||||
case MINUTE: keyword = " minute"; break;
|
||||
case SECOND: keyword = " second"; break;
|
||||
case YEAR: string = " year"; break;
|
||||
case MONTH: string = " month"; break;
|
||||
case DAY: string = " day"; break;
|
||||
case HOUR: string = " hour"; break;
|
||||
case MINUTE: string = " minute"; break;
|
||||
case SECOND: string = " second"; break;
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{strftime}('%Y-%m-%d %H:%M:%f', {0}, {1})", getDataType(), date, interval.concat(inline(keyword)));
|
||||
ctx.visit(F_STRFTIME).sql("('%Y-%m-%d %H:%M:%f', ").visit(date).sql(", ").visit(interval.concat(inline(string))).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -285,6 +305,17 @@ final class DateAdd<T> extends AbstractFunction<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -298,8 +329,6 @@ final class DateAdd<T> extends AbstractFunction<T> {
|
||||
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private final void throwUnsupported() {
|
||||
|
||||
@ -38,15 +38,21 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.Keywords.F_DATEDIFF;
|
||||
import static org.jooq.impl.Keywords.F_DAYS_BETWEEN;
|
||||
import static org.jooq.impl.Keywords.F_STRFTIME;
|
||||
import static org.jooq.impl.Keywords.F_TIMESTAMPDIFF;
|
||||
import static org.jooq.impl.Keywords.K_DAY;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class DateDiff<T> extends AbstractFunction<Integer> {
|
||||
final class DateDiff<T> extends AbstractField<Integer> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -57,38 +63,43 @@ final class DateDiff<T> extends AbstractFunction<Integer> {
|
||||
private final Field<T> date2;
|
||||
|
||||
DateDiff(Field<T> date1, Field<T> date2) {
|
||||
super("datediff", SQLDataType.INTEGER, date1, date2);
|
||||
super(DSL.name("datediff"), SQLDataType.INTEGER);
|
||||
|
||||
this.date1 = date1;
|
||||
this.date2 = date2;
|
||||
}
|
||||
|
||||
@Override
|
||||
final Field<Integer> getFunction0(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
public final void accept(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
case MARIADB:
|
||||
case MYSQL:
|
||||
return function("datediff", getDataType(), date1, date2);
|
||||
ctx.visit(F_DATEDIFF).sql('(').visit(date1).sql(", ").visit(date2).sql(')');
|
||||
break;
|
||||
|
||||
case DERBY:
|
||||
return DSL.field("{fn {timestampdiff}({sql_tsi_day}, {0}, {1}) }", getDataType(), date2, date1);
|
||||
ctx.sql("{fn ").visit(F_TIMESTAMPDIFF).sql('(').visit(keyword("sql_tsi_day")).sql(", ").visit(date2).sql(", ").visit(date1).sql(") }");
|
||||
break;
|
||||
|
||||
case FIREBIRD:
|
||||
return DSL.field("{datediff}(day, {0}, {1})", getDataType(), date2, date1);
|
||||
ctx.visit(F_DATEDIFF).sql('(').visit(K_DAY).sql(", ").visit(date2).sql(", ").visit(date1).sql(')');
|
||||
break;
|
||||
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
|
||||
|
||||
|
||||
return DSL.field("{datediff}('day', {0}, {1})", getDataType(), date2, date1);
|
||||
ctx.visit(F_DATEDIFF).sql("('day', ").visit(date2).sql(", ").visit(date1).sql(')');
|
||||
break;
|
||||
|
||||
case SQLITE:
|
||||
return DSL.field("({strftime}('%s', {0}) - {strftime}('%s', {1})) / 86400", getDataType(), date1, date2);
|
||||
ctx.sql('(').visit(F_STRFTIME).sql("('%s', ").visit(date1).sql(") - ").visit(F_STRFTIME).sql("('%s', ").visit(date2).sql(")) / 86400");
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@ -99,7 +110,8 @@ final class DateDiff<T> extends AbstractFunction<Integer> {
|
||||
|
||||
// [#4481] Parentheses are important in case this expression is
|
||||
// placed in the context of other arithmetic
|
||||
return DSL.field("({0} - {1})", getDataType(), date1, date2);
|
||||
ctx.sql('(').visit(date1).sql(" - ").visit(date2).sql(')');
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@ -122,9 +134,13 @@ final class DateDiff<T> extends AbstractFunction<Integer> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
// Default implementation for equals() and hashCode()
|
||||
ctx.visit(castIfNeeded(date1.sub(date2), Integer.class));
|
||||
break;
|
||||
}
|
||||
|
||||
// Default implementation for equals() and hashCode()
|
||||
return castIfNeeded(date1.sub(date2), Integer.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +59,7 @@ import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.DSL.two;
|
||||
import static org.jooq.impl.DSL.val;
|
||||
import static org.jooq.impl.ExpressionOperator.ADD;
|
||||
@ -71,6 +72,21 @@ import static org.jooq.impl.ExpressionOperator.BIT_XOR;
|
||||
import static org.jooq.impl.ExpressionOperator.SHL;
|
||||
import static org.jooq.impl.ExpressionOperator.SHR;
|
||||
import static org.jooq.impl.ExpressionOperator.SUBTRACT;
|
||||
import static org.jooq.impl.Keywords.F_DATEADD;
|
||||
import static org.jooq.impl.Keywords.F_DATE_ADD;
|
||||
import static org.jooq.impl.Keywords.F_STRFTIME;
|
||||
import static org.jooq.impl.Keywords.F_TIMESTAMPADD;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.Keywords.K_CAST;
|
||||
import static org.jooq.impl.Keywords.K_DAY;
|
||||
import static org.jooq.impl.Keywords.K_DAY_MICROSECOND;
|
||||
import static org.jooq.impl.Keywords.K_DAY_MILLISECOND;
|
||||
import static org.jooq.impl.Keywords.K_DAY_TO_SECOND;
|
||||
import static org.jooq.impl.Keywords.K_INTERVAL;
|
||||
import static org.jooq.impl.Keywords.K_MILLISECOND;
|
||||
import static org.jooq.impl.Keywords.K_MONTH;
|
||||
import static org.jooq.impl.Keywords.K_YEAR_MONTH;
|
||||
import static org.jooq.impl.Keywords.K_YEAR_TO_MONTH;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
@ -92,7 +108,7 @@ import org.jooq.types.Interval;
|
||||
import org.jooq.types.YearToMonth;
|
||||
import org.jooq.types.YearToSecond;
|
||||
|
||||
final class Expression<T> extends AbstractFunction<T> {
|
||||
final class Expression<T> extends AbstractField<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -106,14 +122,16 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
private final Field<T> lhs;
|
||||
private final QueryPartList<Field<?>> rhs;
|
||||
private final Field<?>[] arguments;
|
||||
private final ExpressionOperator operator;
|
||||
|
||||
Expression(ExpressionOperator operator, Field<T> lhs, Field<?>... rhs) {
|
||||
super(operator.toSQL(), lhs.getDataType(), Tools.combine(lhs, rhs));
|
||||
super(DSL.name(operator.toSQL()), lhs.getDataType());
|
||||
|
||||
this.operator = operator;
|
||||
this.lhs = lhs;
|
||||
this.rhs = new QueryPartList<Field<?>>(rhs);
|
||||
this.arguments = Tools.combine(lhs, rhs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -138,8 +156,8 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
final Field<T> getFunction0(Configuration configuration) {
|
||||
SQLDialect family = configuration.family();
|
||||
public final void accept(Context<?> ctx) {
|
||||
SQLDialect family = ctx.family();
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// XXX: Bitwise operators
|
||||
@ -147,17 +165,17 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
// DB2, H2 and HSQLDB know functions, instead of operators
|
||||
if (BIT_AND == operator && SUPPORT_BIT_AND.contains(family))
|
||||
return function("bitand", getDataType(), getArguments());
|
||||
ctx.visit(function("bitand", getDataType(), arguments));
|
||||
else if (BIT_AND == operator && FIREBIRD == family)
|
||||
return function("bin_and", getDataType(), getArguments());
|
||||
ctx.visit(function("bin_and", getDataType(), arguments));
|
||||
else if (BIT_XOR == operator && SUPPORT_BIT_OR_XOR.contains(family))
|
||||
return function("bitxor", getDataType(), getArguments());
|
||||
ctx.visit(function("bitxor", getDataType(), arguments));
|
||||
else if (BIT_XOR == operator && FIREBIRD == family)
|
||||
return function("bin_xor", getDataType(), getArguments());
|
||||
ctx.visit(function("bin_xor", getDataType(), arguments));
|
||||
else if (BIT_OR == operator && SUPPORT_BIT_OR_XOR.contains(family))
|
||||
return function("bitor", getDataType(), getArguments());
|
||||
ctx.visit(function("bitor", getDataType(), arguments));
|
||||
else if (BIT_OR == operator && FIREBIRD == family)
|
||||
return function("bin_or", getDataType(), getArguments());
|
||||
ctx.visit(function("bin_or", getDataType(), arguments));
|
||||
|
||||
|
||||
|
||||
@ -167,9 +185,9 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
// ~(a & b) & (a | b)
|
||||
else if (BIT_XOR == operator && EMULATE_BIT_XOR.contains(family))
|
||||
return (Field<T>) DSL.bitAnd(
|
||||
ctx.visit(DSL.bitAnd(
|
||||
DSL.bitNot(DSL.bitAnd(lhsAsNumber(), rhsAsNumber())),
|
||||
DSL.bitOr(lhsAsNumber(), rhsAsNumber()));
|
||||
DSL.bitOr(lhsAsNumber(), rhsAsNumber())));
|
||||
|
||||
|
||||
|
||||
@ -180,26 +198,26 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
// Many dialects don't support shifts. Use multiplication/division instead
|
||||
else if (SHL == operator && EMULATE_SHR_SHL.contains(family))
|
||||
return lhs.mul((Field<? extends Number>) castIfNeeded(DSL.power(two(), rhsAsNumber()), lhs));
|
||||
ctx.visit(lhs.mul((Field<? extends Number>) castIfNeeded(DSL.power(two(), rhsAsNumber()), lhs)));
|
||||
|
||||
// [#3962] This emulation is expensive. If this is emulated, BitCount should
|
||||
// use division instead of SHR directly
|
||||
else if (SHR == operator && EMULATE_SHR_SHL.contains(family))
|
||||
return lhs.div((Field<? extends Number>) castIfNeeded(DSL.power(two(), rhsAsNumber()), lhs));
|
||||
ctx.visit(lhs.div((Field<? extends Number>) castIfNeeded(DSL.power(two(), rhsAsNumber()), lhs)));
|
||||
|
||||
// Some dialects support shifts as functions
|
||||
else if (SHL == operator && FIREBIRD == family)
|
||||
return function("bin_shl", getDataType(), getArguments());
|
||||
ctx.visit(function("bin_shl", getDataType(), arguments));
|
||||
else if (SHR == operator && FIREBIRD == family)
|
||||
return function("bin_shr", getDataType(), getArguments());
|
||||
ctx.visit(function("bin_shr", getDataType(), arguments));
|
||||
|
||||
// These operators are not supported in any dialect
|
||||
else if (BIT_NAND == operator)
|
||||
return (Field<T>) DSL.bitNot(DSL.bitAnd(lhsAsNumber(), rhsAsNumber()));
|
||||
ctx.visit(DSL.bitNot(DSL.bitAnd(lhsAsNumber(), rhsAsNumber())));
|
||||
else if (BIT_NOR == operator)
|
||||
return (Field<T>) DSL.bitNot(DSL.bitOr(lhsAsNumber(), rhsAsNumber()));
|
||||
ctx.visit(DSL.bitNot(DSL.bitOr(lhsAsNumber(), rhsAsNumber())));
|
||||
else if (BIT_XNOR == operator)
|
||||
return (Field<T>) DSL.bitNot(DSL.bitXor(lhsAsNumber(), rhsAsNumber()));
|
||||
ctx.visit(DSL.bitNot(DSL.bitXor(lhsAsNumber(), rhsAsNumber())));
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// XXX: Date time arithmetic operators
|
||||
@ -210,7 +228,7 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
lhs.getDataType().isDateTime() &&
|
||||
(rhs.get(0).getDataType().isNumeric() ||
|
||||
rhs.get(0).getDataType().isInterval()))
|
||||
return new DateExpression<T>(lhs, operator, rhs.get(0));
|
||||
ctx.visit(new DateExpression<T>(lhs, operator, rhs.get(0)));
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// XXX: Other operators
|
||||
@ -218,7 +236,7 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
// Use the default operator expression for all other cases
|
||||
else
|
||||
return new DefaultExpression<T>(lhs, operator, rhs);
|
||||
ctx.visit(new DefaultExpression<T>(lhs, operator, rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,7 +261,7 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
/**
|
||||
* Return the expression to be rendered when the RHS is an interval type
|
||||
*/
|
||||
private static class DateExpression<T> extends AbstractFunction<T> {
|
||||
private static class DateExpression<T> extends AbstractField<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -255,7 +273,7 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
private final Field<?> rhs;
|
||||
|
||||
DateExpression(Field<T> lhs, ExpressionOperator operator, Field<?> rhs) {
|
||||
super(operator.toSQL(), lhs.getDataType());
|
||||
super(DSL.name(operator.toSQL()), lhs.getDataType());
|
||||
|
||||
this.lhs = lhs;
|
||||
this.operator = operator;
|
||||
@ -272,11 +290,11 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
final Field<T> getFunction0(Configuration configuration) {
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (rhs.getDataType().isInterval())
|
||||
return getIntervalExpression(configuration);
|
||||
acceptIntervalExpression(ctx);
|
||||
else
|
||||
return getNumberExpression(configuration);
|
||||
acceptNumberExpression(ctx);
|
||||
}
|
||||
|
||||
private final Field<T> getYTSExpression() {
|
||||
@ -290,9 +308,8 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private final Field<T> getIntervalExpression(Configuration configuration) {
|
||||
SQLDialect dialect = configuration.dialect();
|
||||
SQLDialect family = dialect.family();
|
||||
private final void acceptIntervalExpression(Context<?> ctx) {
|
||||
SQLDialect family = ctx.family();
|
||||
|
||||
int sign = (operator == ADD) ? 1 : -1;
|
||||
switch (family) {
|
||||
@ -303,8 +320,10 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
case CUBRID:
|
||||
case MARIADB:
|
||||
case MYSQL: {
|
||||
if (rhs.getType() == YearToSecond.class)
|
||||
return getYTSExpression();
|
||||
if (rhs.getType() == YearToSecond.class) {
|
||||
ctx.visit(getYTSExpression());
|
||||
break;
|
||||
}
|
||||
|
||||
Interval interval = rhsAsInterval();
|
||||
|
||||
@ -312,62 +331,74 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
interval = interval.neg();
|
||||
|
||||
if (rhs.getType() == YearToMonth.class)
|
||||
return DSL.field("{date_add}({0}, {interval} {1} {year_month})", getDataType(), lhs, Tools.field(interval, SQLDataType.VARCHAR));
|
||||
else if (dialect == CUBRID)
|
||||
return DSL.field("{date_add}({0}, {interval} {1} {day_millisecond})", getDataType(), lhs, Tools.field(interval, SQLDataType.VARCHAR));
|
||||
ctx.visit(F_DATE_ADD).sql('(').visit(lhs).sql(", ").visit(K_INTERVAL).sql(' ')
|
||||
.visit(Tools.field(interval, SQLDataType.VARCHAR)).sql(' ').visit(K_YEAR_MONTH).sql(')');
|
||||
else if (family == CUBRID)
|
||||
ctx.visit(F_DATE_ADD).sql('(').visit(lhs).sql(", ").visit(K_INTERVAL).sql(' ')
|
||||
.visit(Tools.field(interval, SQLDataType.VARCHAR)).sql(' ').visit(K_DAY_MILLISECOND).sql(')');
|
||||
|
||||
// [#6820] Workaround for bugs:
|
||||
// https://bugs.mysql.com/bug.php?id=88573
|
||||
// https://jira.mariadb.org/browse/MDEV-14452
|
||||
else
|
||||
return DSL.field("{date_add}({0}, {interval} {1} {day_microsecond})", getDataType(), lhs,
|
||||
Tools.field(TRUNC_TO_MICROS.matcher("" + interval).replaceAll("$1"), SQLDataType.VARCHAR)
|
||||
);
|
||||
ctx.visit(F_DATE_ADD).sql('(').visit(lhs).sql(", ").visit(K_INTERVAL).sql(' ')
|
||||
.visit(Tools.field(TRUNC_TO_MICROS.matcher("" + interval).replaceAll("$1"), SQLDataType.VARCHAR)).sql(' ').visit(K_DAY_MICROSECOND).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case DERBY:
|
||||
case HSQLDB: {
|
||||
if (rhs.getType() == YearToSecond.class)
|
||||
return getYTSExpression();
|
||||
if (rhs.getType() == YearToSecond.class) {
|
||||
ctx.visit(getYTSExpression());
|
||||
break;
|
||||
}
|
||||
|
||||
Field<T> result;
|
||||
boolean needsCast = getDataType().getType() != Timestamp.class;
|
||||
if (needsCast)
|
||||
ctx.visit(K_CAST).sql('(');
|
||||
|
||||
if (rhs.getType() == YearToMonth.class)
|
||||
result = DSL.field("{fn {timestampadd}({sql_tsi_month}, {0}, {1}) }",
|
||||
getDataType(), p(sign * rhsAsYTM().intValue()), lhs);
|
||||
ctx.sql("{fn ").visit(F_TIMESTAMPADD).sql('(').visit(keyword("sql_tsi_month")).sql(", ")
|
||||
.visit(p(sign * rhsAsYTM().intValue())).sql(", ").visit(lhs).sql(") }");
|
||||
else
|
||||
result = DSL.field("{fn {timestampadd}({sql_tsi_second}, {0}, {fn {timestampadd}({sql_tsi_milli_second}, {1}, {2}) }) }",
|
||||
getDataType(),
|
||||
p(sign * (long) rhsAsDTS().getTotalSeconds()),
|
||||
p(sign * (long) rhsAsDTS().getMilli()),
|
||||
lhs);
|
||||
ctx.sql("{fn ").visit(F_TIMESTAMPADD).sql('(').visit(keyword("sql_tsi_second")).sql(", ")
|
||||
.visit(p(sign * (long) rhsAsDTS().getTotalSeconds())).sql(", {fn ")
|
||||
.visit(F_TIMESTAMPADD).sql('(').visit(keyword("sql_tsi_milli_second")).sql(", ")
|
||||
.visit(p(sign * (long) rhsAsDTS().getMilli())).sql(", ").visit(lhs).sql(") }) }");
|
||||
|
||||
// [#1883] TIMESTAMPADD returns TIMESTAMP columns. If this
|
||||
// is a DATE column, cast it to DATE
|
||||
return castNonTimestamps(configuration, result);
|
||||
if (needsCast)
|
||||
ctx.sql(' ').visit(K_AS).sql(' ').visit(keyword(getDataType().getCastTypeName(ctx.configuration()))).sql(')');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FIREBIRD: {
|
||||
if (rhs.getType() == YearToSecond.class)
|
||||
return getYTSExpression();
|
||||
ctx.visit(getYTSExpression());
|
||||
else if (rhs.getType() == YearToMonth.class)
|
||||
return DSL.field("{dateadd}({month}, {0}, {1})", getDataType(), p(sign * rhsAsYTM().intValue()), lhs);
|
||||
ctx.visit(F_DATEADD).sql('(').visit(K_MONTH).sql(", ").visit(p(sign * rhsAsYTM().intValue())).sql(", ").visit(lhs).sql(')');
|
||||
else
|
||||
return DSL.field("{dateadd}({millisecond}, {0}, {1})", getDataType(), p(sign * (long) rhsAsDTS().getTotalMilli()), lhs);
|
||||
ctx.visit(F_DATEADD).sql('(').visit(K_MILLISECOND).sql(", ").visit(p(sign * (long) rhsAsDTS().getTotalMilli())).sql(", ").visit(lhs).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case H2: {
|
||||
if (rhs.getType() == YearToSecond.class)
|
||||
return getYTSExpression();
|
||||
ctx.visit(getYTSExpression());
|
||||
else if (rhs.getType() == YearToMonth.class)
|
||||
return DSL.field("{dateadd}('month', {0}, {1})", getDataType(), p(sign * rhsAsYTM().intValue()), lhs);
|
||||
ctx.visit(F_DATEADD).sql("('month', ").visit(p(sign * rhsAsYTM().intValue())).sql(", ").visit(lhs).sql(')');
|
||||
else
|
||||
return DSL.field("{dateadd}('ms', {0}, {1})", getDataType(), p(sign * (long) rhsAsDTS().getTotalMilli()), lhs);
|
||||
ctx.visit(F_DATEADD).sql("('ms', ").visit(p(sign * (long) rhsAsDTS().getTotalMilli())).sql(", ").visit(lhs).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE: {
|
||||
if (rhs.getType() == YearToSecond.class)
|
||||
return getYTSExpression();
|
||||
if (rhs.getType() == YearToSecond.class) {
|
||||
ctx.visit(getYTSExpression());
|
||||
break;
|
||||
}
|
||||
|
||||
boolean ytm = rhs.getType() == YearToMonth.class;
|
||||
Field<?> interval = p(ytm ? rhsAsYTM().intValue() : rhsAsDTS().getTotalSeconds());
|
||||
@ -376,7 +407,8 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
interval = interval.neg();
|
||||
|
||||
interval = interval.concat(inline(ytm ? " months" : " seconds"));
|
||||
return DSL.field("{strftime}('%Y-%m-%d %H:%M:%f', {0}, {1})", getDataType(), lhs, interval);
|
||||
ctx.visit(F_STRFTIME).sql("('%Y-%m-%d %H:%M:%f', ").visit(lhs).sql(", ").visit(interval).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -531,11 +563,13 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
default:
|
||||
return new DefaultExpression<T>(lhs, operator, new QueryPartList<Field<?>>(Arrays.asList(rhs)));
|
||||
ctx.visit(new DefaultExpression<T>(lhs, operator, new QueryPartList<Field<?>>(Arrays.asList(rhs))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,8 +588,10 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
* Return the expression to be rendered when the RHS is a number type
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private final Field<T> getNumberExpression(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
private final void acceptNumberExpression(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -578,9 +614,10 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
case FIREBIRD: {
|
||||
if (operator == ADD)
|
||||
return DSL.field("{dateadd}(day, {0}, {1})", getDataType(), rhsAsNumber(), lhs);
|
||||
ctx.visit(F_DATEADD).sql('(').visit(K_DAY).sql(", ").visit(rhsAsNumber()).sql(", ").visit(lhs).sql(')');
|
||||
else
|
||||
return DSL.field("{dateadd}(day, {0}, {1})", getDataType(), rhsAsNumber().neg(), lhs);
|
||||
ctx.visit(F_DATEADD).sql('(').visit(K_DAY).sql(", ").visit(rhsAsNumber().neg()).sql(", ").visit(lhs).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -588,22 +625,28 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
case HSQLDB: {
|
||||
if (operator == ADD)
|
||||
return lhs.add(DSL.field("{0} day", rhsAsNumber()));
|
||||
ctx.visit(lhs.add(DSL.field("{0} day", rhsAsNumber())));
|
||||
else
|
||||
return lhs.sub(DSL.field("{0} day", rhsAsNumber()));
|
||||
ctx.visit(lhs.sub(DSL.field("{0} day", rhsAsNumber())));
|
||||
break;
|
||||
}
|
||||
|
||||
case DERBY: {
|
||||
Field<T> result;
|
||||
boolean needsCast = getDataType().getType() != Timestamp.class;
|
||||
if (needsCast)
|
||||
ctx.visit(K_CAST).sql('(');
|
||||
|
||||
if (operator == ADD)
|
||||
result = DSL.field("{fn {timestampadd}({sql_tsi_day}, {0}, {1}) }", getDataType(), rhsAsNumber(), lhs);
|
||||
ctx.sql("{fn ").visit(F_TIMESTAMPADD).sql('(').visit(keyword("sql_tsi_day")).sql(", ").visit(rhsAsNumber()).sql(", ").visit(lhs).sql(") }");
|
||||
else
|
||||
result = DSL.field("{fn {timestampadd}({sql_tsi_day}, {0}, {1}) }", getDataType(), rhsAsNumber().neg(), lhs);
|
||||
ctx.sql("{fn ").visit(F_TIMESTAMPADD).sql('(').visit(keyword("sql_tsi_day")).sql(", ").visit(rhsAsNumber().neg()).sql(", ").visit(lhs).sql(") }");
|
||||
|
||||
// [#1883] TIMESTAMPADD returns TIMESTAMP columns. If this
|
||||
// is a DATE column, cast it to DATE
|
||||
return castNonTimestamps(configuration, result);
|
||||
if (needsCast)
|
||||
ctx.sql(' ').visit(K_AS).sql(' ').visit(keyword(getDataType().getCastTypeName(ctx.configuration()))).sql(')');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -614,9 +657,10 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
case MARIADB:
|
||||
case MYSQL: {
|
||||
if (operator == ADD)
|
||||
return DSL.field("{date_add}({0}, {interval} {1} {day})", getDataType(), lhs, rhsAsNumber());
|
||||
ctx.visit(F_DATE_ADD).sql('(').visit(lhs).sql(", ").visit(K_INTERVAL).sql(' ').visit(rhsAsNumber()).sql(' ').visit(K_DAY).sql(')');
|
||||
else
|
||||
return DSL.field("{date_add}({0}, {interval} {1} {day})", getDataType(), lhs, rhsAsNumber().neg());
|
||||
ctx.visit(F_DATE_ADD).sql('(').visit(lhs).sql(", ").visit(K_INTERVAL).sql(' ').visit(rhsAsNumber().neg()).sql(' ').visit(K_DAY).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -636,6 +680,8 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case POSTGRES: {
|
||||
@ -644,16 +690,19 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
// with incompatible data types and timezones
|
||||
// ? + CAST (? || ' days' as interval)
|
||||
if (operator == ADD)
|
||||
return new DateAdd(lhs, rhsAsNumber(), DatePart.DAY);
|
||||
ctx.visit(new DateAdd(lhs, rhsAsNumber(), DatePart.DAY));
|
||||
else
|
||||
return new DateAdd(lhs, rhsAsNumber().neg(), DatePart.DAY);
|
||||
ctx.visit(new DateAdd(lhs, rhsAsNumber().neg(), DatePart.DAY));
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE:
|
||||
if (operator == ADD)
|
||||
return DSL.field("{strftime}('%Y-%m-%d %H:%M:%f', {0}, {1})", getDataType(), lhs, rhsAsNumber().concat(inline(" day")));
|
||||
ctx.visit(F_STRFTIME).sql("('%Y-%m-%d %H:%M:%f', ").visit(lhs).sql(", ").visit(rhsAsNumber().concat(inline(" day"))).sql(')');
|
||||
else
|
||||
return DSL.field("{strftime}('%Y-%m-%d %H:%M:%f', {0}, {1})", getDataType(), lhs, rhsAsNumber().neg().concat(inline(" day")));
|
||||
ctx.visit(F_STRFTIME).sql("('%Y-%m-%d %H:%M:%f', ").visit(lhs).sql(", ").visit(rhsAsNumber().neg().concat(inline(" day"))).sql(')');
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -667,7 +716,8 @@ final class Expression<T> extends AbstractFunction<T> {
|
||||
|
||||
case H2:
|
||||
default:
|
||||
return new DefaultExpression<T>(lhs, operator, new QueryPartList<Field<?>>(Arrays.asList(rhs)));
|
||||
ctx.visit(new DefaultExpression<T>(lhs, operator, new QueryPartList<Field<?>>(Arrays.asList(rhs))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -38,24 +38,42 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.Keywords.F_DATEDIFF;
|
||||
import static org.jooq.impl.Keywords.F_DATEPART;
|
||||
import static org.jooq.impl.Keywords.F_DAYOFWEEK;
|
||||
import static org.jooq.impl.Keywords.F_EXTRACT;
|
||||
import static org.jooq.impl.Keywords.F_STRFTIME;
|
||||
import static org.jooq.impl.Keywords.F_TO_CHAR;
|
||||
import static org.jooq.impl.Keywords.F_TO_NUMBER;
|
||||
import static org.jooq.impl.Keywords.F_TRUNC;
|
||||
import static org.jooq.impl.Keywords.K_DATE;
|
||||
import static org.jooq.impl.Keywords.K_DAY;
|
||||
import static org.jooq.impl.Keywords.K_FROM;
|
||||
import static org.jooq.impl.Keywords.K_HOUR;
|
||||
import static org.jooq.impl.Keywords.K_INT;
|
||||
import static org.jooq.impl.Keywords.K_MINUTE;
|
||||
import static org.jooq.impl.Keywords.K_MONTH;
|
||||
import static org.jooq.impl.Keywords.K_SECOND;
|
||||
import static org.jooq.impl.Keywords.K_YEAR;
|
||||
import static org.jooq.impl.SQLDataType.INTEGER;
|
||||
import static org.jooq.impl.SQLDataType.VARCHAR;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DatePart;
|
||||
import org.jooq.Field;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Extract extends AbstractFunction<Integer> {
|
||||
final class Extract extends AbstractField<Integer> {
|
||||
|
||||
private static final long serialVersionUID = 3748640920856031034L;
|
||||
|
||||
@ -63,48 +81,67 @@ final class Extract extends AbstractFunction<Integer> {
|
||||
private final DatePart datePart;
|
||||
|
||||
Extract(Field<?> field, DatePart datePart) {
|
||||
super("extract", INTEGER, field);
|
||||
super(DSL.name("extract"), INTEGER);
|
||||
|
||||
this.field = field;
|
||||
this.datePart = datePart;
|
||||
}
|
||||
|
||||
@Override
|
||||
final Field<Integer> getFunction0(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
public final void accept(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
case SQLITE:
|
||||
switch (datePart) {
|
||||
case QUARTER:
|
||||
case DECADE:
|
||||
case CENTURY:
|
||||
case MILLENNIUM:
|
||||
return getDefaultEmulation();
|
||||
|
||||
case YEAR:
|
||||
return DSL.field("{strftime}('%Y', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%Y', ").visit(field).sql(')');
|
||||
return;
|
||||
case MONTH:
|
||||
return DSL.field("{strftime}('%m', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%m', ").visit(field).sql(')');
|
||||
return;
|
||||
case DAY:
|
||||
return DSL.field("{strftime}('%d', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%d', ").visit(field).sql(')');
|
||||
return;
|
||||
case HOUR:
|
||||
return DSL.field("{strftime}('%H', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%H', ").visit(field).sql(')');
|
||||
return;
|
||||
case MINUTE:
|
||||
return DSL.field("{strftime}('%M', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%M', ").visit(field).sql(')');
|
||||
return;
|
||||
case SECOND:
|
||||
return DSL.field("{strftime}('%S', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%S', ").visit(field).sql(')');
|
||||
return;
|
||||
|
||||
// See: https://www.sqlite.org/lang_datefunc.html
|
||||
case EPOCH:
|
||||
return DSL.field("{strftime}('%s', {0})", INTEGER, field);
|
||||
ctx.visit(F_STRFTIME).sql("('%s', ").visit(field).sql(')');
|
||||
return;
|
||||
case ISO_DAY_OF_WEEK:
|
||||
return dowSun0ToISO(DSL.field("{strftime}('%w', {0})", INTEGER, field));
|
||||
ctx.visit(dowSun0ToISO(function("strftime", INTEGER, inline("%w"), field)));
|
||||
return;
|
||||
case DAY_OF_WEEK:
|
||||
return DSL.field("{strftime}('%w', {0})", INTEGER, field).add(one());
|
||||
ctx.visit(F_STRFTIME).sql("('%w', ").visit(field).sql(") + ").visit(one());
|
||||
return;
|
||||
case DAY_OF_YEAR:
|
||||
return DSL.field("{strftime}('%j', {0})", INTEGER, field);
|
||||
default:
|
||||
return getNativeFunction();
|
||||
ctx.visit(F_STRFTIME).sql("('%j', ").visit(field).sql(')');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -134,48 +171,26 @@ final class Extract extends AbstractFunction<Integer> {
|
||||
|
||||
case DERBY:
|
||||
switch (datePart) {
|
||||
case DECADE:
|
||||
case CENTURY:
|
||||
case MILLENNIUM:
|
||||
return getDefaultEmulation();
|
||||
|
||||
case YEAR:
|
||||
return function("year", INTEGER, field);
|
||||
ctx.visit(K_YEAR).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case MONTH:
|
||||
return function("month", INTEGER, field);
|
||||
ctx.visit(K_MONTH).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case DAY:
|
||||
return function("day", INTEGER, field);
|
||||
ctx.visit(K_DAY).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case HOUR:
|
||||
return function("hour", INTEGER, field);
|
||||
ctx.visit(K_HOUR).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case MINUTE:
|
||||
return function("minute", INTEGER, field);
|
||||
ctx.visit(K_MINUTE).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case SECOND:
|
||||
return function("second", INTEGER, field);
|
||||
ctx.visit(K_SECOND).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return getDefaultEmulation();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@ -277,81 +292,68 @@ final class Extract extends AbstractFunction<Integer> {
|
||||
case MARIADB:
|
||||
case MYSQL:
|
||||
switch (datePart) {
|
||||
case DECADE:
|
||||
case CENTURY:
|
||||
case MILLENNIUM:
|
||||
return getDefaultEmulation();
|
||||
|
||||
case DAY_OF_WEEK:
|
||||
return DSL.field("{dayofweek}({0})", INTEGER, field);
|
||||
ctx.visit(F_DAYOFWEEK).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case DAY_OF_YEAR:
|
||||
return DSL.field("{dayofyear}({0})", INTEGER, field);
|
||||
ctx.visit(keyword("dayofyear")).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case EPOCH:
|
||||
return DSL.field("{unix_timestamp}({0})", INTEGER, field);
|
||||
ctx.visit(keyword("unix_timestamp")).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case ISO_DAY_OF_WEEK:
|
||||
return DSL.field("{weekday}({0})", INTEGER, field).add(one());
|
||||
ctx.visit(keyword("weekday")).sql('(').visit(field).sql(") + 1");
|
||||
return;
|
||||
case QUARTER:
|
||||
return DSL.field("{quarter}({0})", INTEGER, field);
|
||||
|
||||
default:
|
||||
return getNativeFunction();
|
||||
ctx.visit(datePart.toKeyword()).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
switch (datePart) {
|
||||
case DAY_OF_WEEK:
|
||||
return DSL.field("({extract}({dow from} {0}) + 1)", INTEGER, field);
|
||||
ctx.sql('(').visit(F_EXTRACT).sql('(').visit(keyword("dow")).sql(' ').visit(K_FROM).sql(' ').visit(field).sql(") + 1)");
|
||||
return;
|
||||
case DAY_OF_YEAR:
|
||||
return DSL.field("{extract}({doy from} {0})", INTEGER, field);
|
||||
ctx.visit(F_EXTRACT).sql('(').visit(keyword("doy")).sql(' ').visit(K_FROM).sql(' ').visit(field).sql(')');
|
||||
return;
|
||||
case ISO_DAY_OF_WEEK:
|
||||
return DSL.field("{extract}({isodow from} {0})", INTEGER, field);
|
||||
|
||||
default:
|
||||
return getNativeFunction();
|
||||
ctx.visit(F_EXTRACT).sql('(').visit(keyword("isodow")).sql(' ').visit(K_FROM).sql(' ').visit(field).sql(')');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case HSQLDB:
|
||||
switch (datePart) {
|
||||
case DECADE:
|
||||
case CENTURY:
|
||||
case MILLENNIUM:
|
||||
case TIMEZONE:
|
||||
return getDefaultEmulation();
|
||||
|
||||
case EPOCH:
|
||||
return DSL.field("{unix_timestamp}({0})", INTEGER, field);
|
||||
ctx.visit(keyword("unix_timestamp")).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case ISO_DAY_OF_WEEK:
|
||||
return dowSun1ToISO(DSL.field("{extract}({day_of_week from} {0})", INTEGER, field));
|
||||
ctx.visit(dowSun1ToISO(DSL.field("{extract}({day_of_week from} {0})", INTEGER, field)));
|
||||
return;
|
||||
case QUARTER:
|
||||
return DSL.field("{quarter}({0})", INTEGER, field);
|
||||
case WEEK:
|
||||
return DSL.field("{week}({0})", INTEGER, field);
|
||||
|
||||
default:
|
||||
return getNativeFunction();
|
||||
ctx.visit(datePart.toKeyword()).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case H2:
|
||||
switch (datePart) {
|
||||
case DECADE:
|
||||
case CENTURY:
|
||||
case MILLENNIUM:
|
||||
case TIMEZONE:
|
||||
return getDefaultEmulation();
|
||||
|
||||
case QUARTER:
|
||||
return DSL.field("{quarter}({0})", INTEGER, field);
|
||||
ctx.visit(datePart.toKeyword()).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
case WEEK:
|
||||
return DSL.field("{iso_week}({0})", INTEGER, field);
|
||||
|
||||
default:
|
||||
return getNativeFunction();
|
||||
ctx.visit(keyword("iso_week")).sql('(').visit(field).sql(')');
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
return getNativeFunction();
|
||||
break;
|
||||
}
|
||||
|
||||
acceptDefaultEmulation(ctx);
|
||||
}
|
||||
|
||||
private final static Field<Integer> dowISOToSun1(Field<Integer> dow) {
|
||||
@ -366,31 +368,37 @@ final class Extract extends AbstractFunction<Integer> {
|
||||
return dow.add(inline(6)).mod(inline(7)).add(one());
|
||||
}
|
||||
|
||||
private final Field<Integer> getDefaultEmulation() {
|
||||
private final void acceptDefaultEmulation(Context<?> ctx) {
|
||||
switch (datePart) {
|
||||
case DECADE:
|
||||
return castIfNeeded(DSL.year(field).div(inline(10)), INTEGER);
|
||||
ctx.visit(castIfNeeded(DSL.year(field).div(inline(10)), INTEGER));
|
||||
break;
|
||||
case CENTURY:
|
||||
return castIfNeeded(
|
||||
ctx.visit(castIfNeeded(
|
||||
DSL.sign(DSL.year(field))
|
||||
.mul(DSL.abs(DSL.year(field)).add(inline(99)))
|
||||
.div(inline(100)), INTEGER);
|
||||
.div(inline(100)), INTEGER));
|
||||
break;
|
||||
case MILLENNIUM:
|
||||
return castIfNeeded(
|
||||
ctx.visit(castIfNeeded(
|
||||
DSL.sign(DSL.year(field))
|
||||
.mul(DSL.abs(DSL.year(field)).add(inline(999)))
|
||||
.div(inline(1000)), INTEGER);
|
||||
.div(inline(1000)), INTEGER));
|
||||
break;
|
||||
case QUARTER:
|
||||
return DSL.month(field).add(inline(2)).div(inline(3));
|
||||
ctx.visit(DSL.month(field).add(inline(2)).div(inline(3)));
|
||||
break;
|
||||
case TIMEZONE:
|
||||
return DSL.extract(field, DatePart.TIMEZONE_HOUR).mul(inline(3600))
|
||||
.add(DSL.extract(field, DatePart.TIMEZONE_MINUTE).mul(inline(60)));
|
||||
ctx.visit(DSL.extract(field, DatePart.TIMEZONE_HOUR).mul(inline(3600))
|
||||
.add(DSL.extract(field, DatePart.TIMEZONE_MINUTE).mul(inline(60))));
|
||||
break;
|
||||
default:
|
||||
return getNativeFunction();
|
||||
acceptNativeFunction(ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final Field<Integer> getNativeFunction() {
|
||||
return DSL.field("{extract}({0} {from} {1})", INTEGER, datePart.toKeyword(), field);
|
||||
private final void acceptNativeFunction(Context<?> ctx) {
|
||||
ctx.visit(F_EXTRACT).sql('(').visit(datePart.toKeyword()).sql(' ').visit(K_FROM).sql(' ').visit(field).sql(')');
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,14 +37,11 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.condition;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
|
||||
import org.jooq.Clause;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.QueryPartInternal;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -63,16 +60,7 @@ final class FieldCondition extends AbstractCondition {
|
||||
|
||||
@Override
|
||||
public void accept(Context<?> ctx) {
|
||||
ctx.visit(delegate(ctx.configuration()));
|
||||
}
|
||||
|
||||
@Override // Avoid AbstractCondition implementation
|
||||
public final Clause[] clauses(Context<?> ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private final QueryPartInternal delegate(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
// [#2485] These don't work nicely, yet
|
||||
case CUBRID:
|
||||
@ -90,7 +78,8 @@ final class FieldCondition extends AbstractCondition {
|
||||
|
||||
|
||||
|
||||
return (QueryPartInternal) condition("{0} = {1}", field, inline(true));
|
||||
ctx.sql('(').visit(field).sql(" = ").visit(inline(true)).sql(')');
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@ -108,7 +97,14 @@ final class FieldCondition extends AbstractCondition {
|
||||
case POSTGRES:
|
||||
case SQLITE:
|
||||
default:
|
||||
return (QueryPartInternal) field;
|
||||
ctx.visit(field);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Avoid AbstractCondition implementation
|
||||
public final Clause[] clauses(Context<?> ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -105,6 +105,10 @@ final class Keywords {
|
||||
static final Keyword K_DATE = keyword("date");
|
||||
static final Keyword K_DATETIME = keyword("datetime");
|
||||
static final Keyword K_DATETIMEOFFSET = keyword("datetimeoffset");
|
||||
static final Keyword K_DAY = keyword("day");
|
||||
static final Keyword K_DAY_MICROSECOND = keyword("day_microsecond");
|
||||
static final Keyword K_DAY_MILLISECOND = keyword("day_millisecond");
|
||||
static final Keyword K_DAY_TO_SECOND = keyword("day_to_second");
|
||||
static final Keyword K_DECIMAL = keyword("decimal");
|
||||
static final Keyword K_DECLARE = keyword("declare");
|
||||
static final Keyword K_DEFAULT = keyword("default");
|
||||
@ -167,6 +171,7 @@ final class Keywords {
|
||||
static final Keyword K_GRANT_OPTION_FOR = keyword("grant option for");
|
||||
static final Keyword K_GROUP_BY = keyword("group by");
|
||||
static final Keyword K_HAVING = keyword("having");
|
||||
static final Keyword K_HOUR = keyword("hour");
|
||||
static final Keyword K_HOUR_TO_SECOND = keyword("hour to second");
|
||||
static final Keyword K_IDENTITY = keyword("identity");
|
||||
static final Keyword K_IF = keyword("if");
|
||||
@ -182,6 +187,7 @@ final class Keywords {
|
||||
static final Keyword K_INNER_JOIN = keyword("inner join");
|
||||
static final Keyword K_INSERT = keyword("insert");
|
||||
static final Keyword K_INT = keyword("int");
|
||||
static final Keyword K_INTERVAL = keyword("interval");
|
||||
static final Keyword K_INTO = keyword("into");
|
||||
static final Keyword K_IS = keyword("is");
|
||||
static final Keyword K_IS_NOT_NULL = keyword("is not null");
|
||||
@ -202,10 +208,13 @@ final class Keywords {
|
||||
static final Keyword K_MATCHED = keyword("matched");
|
||||
static final Keyword K_MAXVALUE = keyword("maxvalue");
|
||||
static final Keyword K_MERGE_INTO = keyword("merge into");
|
||||
static final Keyword K_MILLISECOND = keyword("millisecond");
|
||||
static final Keyword K_MINUS = keyword("minus");
|
||||
static final Keyword K_MINUTE = keyword("minute");
|
||||
static final Keyword K_MINVALUE = keyword("minvalue");
|
||||
static final Keyword K_MOD = keyword("mod");
|
||||
static final Keyword K_MODIFY = keyword("modify");
|
||||
static final Keyword K_MONTH = keyword("month");
|
||||
static final Keyword K_MULTISET = keyword("multiset");
|
||||
static final Keyword K_NEW_TABLE = keyword("new table");
|
||||
static final Keyword K_NEXT_VALUE_FOR = keyword("next value for");
|
||||
@ -286,6 +295,7 @@ final class Keywords {
|
||||
static final Keyword K_SCHEMA = keyword("schema");
|
||||
static final Keyword K_SCN = keyword("scn");
|
||||
static final Keyword K_SEARCH_PATH = keyword("search_path");
|
||||
static final Keyword K_SECOND = keyword("second");
|
||||
static final Keyword K_SELECT = keyword("select");
|
||||
static final Keyword K_SEPARATOR = keyword("separator");
|
||||
static final Keyword K_SEQUENCE = keyword("sequence");
|
||||
@ -350,10 +360,14 @@ final class Keywords {
|
||||
static final Keyword K_WITH_TIES = keyword("with ties");
|
||||
static final Keyword K_WITHIN_GROUP = keyword("within group");
|
||||
static final Keyword K_XMLTABLE = keyword("xmltable");
|
||||
static final Keyword K_YEAR = keyword("year");
|
||||
static final Keyword K_YEAR_MONTH = keyword("year_month");
|
||||
static final Keyword K_YEAR_TO_DAY = keyword("year to day");
|
||||
static final Keyword K_YEAR_TO_MONTH = keyword("year to month");
|
||||
static final Keyword K_YEAR_TO_FRACTION = keyword("year to fraction");
|
||||
|
||||
static final Keyword F_ACOS = keyword("acos");
|
||||
static final Keyword F_ADD_MONTHS = keyword("add_months");
|
||||
static final Keyword F_ASC = keyword("asc");
|
||||
static final Keyword F_ASCII = keyword("ascii");
|
||||
static final Keyword F_ASCII_VAL = keyword("ascii_val");
|
||||
@ -376,7 +390,16 @@ final class Keywords {
|
||||
static final Keyword F_CURRENT_TIMESTAMP = keyword("current_timestamp");
|
||||
static final Keyword F_CURRENT_USER = keyword("current_user");
|
||||
static final Keyword F_CURRENTUSER = keyword("currentuser");
|
||||
static final Keyword F_DATE_ADD = keyword("date_add");
|
||||
static final Keyword F_DATE_DIFF = keyword("date_diff");
|
||||
static final Keyword F_DATE_TRUNC = keyword("date_trunc");
|
||||
static final Keyword F_DATEADD = keyword("dateadd");
|
||||
static final Keyword F_DATEDIFF = keyword("datediff");
|
||||
static final Keyword F_DATEPART = keyword("datepart");
|
||||
static final Keyword F_DAYOFWEEK = keyword("dayofweek");
|
||||
static final Keyword F_DAYS_BETWEEN = keyword("days_between");
|
||||
static final Keyword F_DEGREES = keyword("degrees");
|
||||
static final Keyword F_EXTRACT = keyword("extract");
|
||||
static final Keyword F_FLOOR = keyword("floor");
|
||||
static final Keyword F_GEN_ID = keyword("gen_id");
|
||||
static final Keyword F_HASHBYTES = keyword("hashbytes");
|
||||
@ -396,12 +419,14 @@ final class Keywords {
|
||||
static final Keyword F_MID = keyword("mid");
|
||||
static final Keyword F_NOW = keyword("now");
|
||||
static final Keyword F_NULLIF = keyword("nullif");
|
||||
static final Keyword F_NUMTODSINTERVAL = keyword("numtodsinterval");
|
||||
static final Keyword F_NVL = keyword("nvl");
|
||||
static final Keyword F_NVL2 = keyword("nvl2");
|
||||
static final Keyword F_POSITION = keyword("position");
|
||||
static final Keyword F_POWER = keyword("power");
|
||||
static final Keyword F_RAND = keyword("rand");
|
||||
static final Keyword F_RANDOM = keyword("random");
|
||||
static final Keyword F_RATIO_TO_REPORT = keyword("ratio_to_report");
|
||||
static final Keyword F_RAWTOHEX = keyword("rawtohex");
|
||||
static final Keyword F_REPEAT = keyword("repeat");
|
||||
static final Keyword F_REPLACE = keyword("replace");
|
||||
@ -409,6 +434,7 @@ final class Keywords {
|
||||
static final Keyword F_REVERSE = keyword("reverse");
|
||||
static final Keyword F_RIGHT = keyword("right");
|
||||
static final Keyword F_RND = keyword("rnd");
|
||||
static final Keyword F_ROLLUP = keyword("rollup");
|
||||
static final Keyword F_ROUND = keyword("round");
|
||||
static final Keyword F_ROUND_DOWN = keyword("round_down");
|
||||
static final Keyword F_RPAD = keyword("rpad");
|
||||
@ -427,9 +453,12 @@ final class Keywords {
|
||||
static final Keyword F_SUBSTRING = keyword("substring");
|
||||
static final Keyword F_SYSDATE = keyword("sysdate");
|
||||
static final Keyword F_TANH = keyword("tanh");
|
||||
static final Keyword F_TIMESTAMPADD = keyword("timestampadd");
|
||||
static final Keyword F_TIMESTAMPDIFF = keyword("timestampdiff");
|
||||
static final Keyword F_TO_CHAR = keyword("to_char");
|
||||
static final Keyword F_TO_CLOB = keyword("to_clob");
|
||||
static final Keyword F_TO_DATE = keyword("to_date");
|
||||
static final Keyword F_TO_NUMBER = keyword("to_number");
|
||||
static final Keyword F_TO_TIMESTAMP = keyword("to_timestamp");
|
||||
static final Keyword F_TRIM = keyword("trim");
|
||||
static final Keyword F_TRUNC = keyword("trunc");
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.Keywords.K_COALESCE;
|
||||
|
||||
import org.jooq.Context;
|
||||
|
||||
@ -41,6 +41,7 @@ import static org.jooq.Clause.CONDITION;
|
||||
import static org.jooq.Clause.CONDITION_NOT;
|
||||
import static org.jooq.impl.DSL.condition;
|
||||
import static org.jooq.impl.DSL.not;
|
||||
import static org.jooq.impl.Keywords.K_NOT;
|
||||
|
||||
import org.jooq.Clause;
|
||||
import org.jooq.Context;
|
||||
@ -95,7 +96,7 @@ final class NotField extends AbstractField<Boolean> {
|
||||
case POSTGRES:
|
||||
case SQLITE:
|
||||
default:
|
||||
ctx.visit(DSL.field("{not}({0})", getDataType(), field));
|
||||
ctx.visit(K_NOT).sql('(').visit(field).sql(')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
import static org.jooq.impl.Keywords.F_RATIO_TO_REPORT;
|
||||
import static org.jooq.impl.SQLDataType.DECIMAL;
|
||||
import static org.jooq.impl.SQLDataType.DOUBLE;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
@ -39,6 +39,7 @@ package org.jooq.impl;
|
||||
|
||||
import static org.jooq.Clause.CONDITION;
|
||||
import static org.jooq.Clause.CONDITION_COMPARISON;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.Keywords.K_LIKE_REGEX;
|
||||
import static org.jooq.impl.Keywords.K_REGEXP;
|
||||
|
||||
@ -92,8 +93,7 @@ final class RegexpLike extends AbstractCondition {
|
||||
// [#620] HSQLDB has its own syntax
|
||||
case HSQLDB: {
|
||||
|
||||
// [#1570] TODO: Replace this by SQL.condition(String, QueryPart...)
|
||||
ctx.visit(DSL.condition("{regexp_matches}({0}, {1})", search, pattern));
|
||||
ctx.visit(keyword("regexp_matches")).sql('(').visit(search).sql(", ").visit(pattern).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
@ -104,8 +104,7 @@ final class RegexpLike extends AbstractCondition {
|
||||
|
||||
case POSTGRES: {
|
||||
|
||||
// [#1570] TODO: Replace this by SQL.condition(String, QueryPart...)
|
||||
ctx.visit(DSL.condition("{0} ~ {1}", search, pattern));
|
||||
ctx.visit(search).sql(" ~ ").visit(pattern);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -119,7 +118,6 @@ final class RegexpLike extends AbstractCondition {
|
||||
|
||||
|
||||
|
||||
|
||||
// Render the SQL standard for those databases that do not support
|
||||
// regular expressions
|
||||
|
||||
|
||||
@ -37,12 +37,11 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Keywords.F_ROLLUP;
|
||||
import static org.jooq.impl.Keywords.K_WITH_ROLLUP;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.FieldOrRow;
|
||||
import org.jooq.QueryPart;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -63,21 +62,19 @@ final class Rollup extends AbstractField<Object> {
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(delegate(ctx.configuration()));
|
||||
}
|
||||
|
||||
private final QueryPart delegate(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
case CUBRID:
|
||||
case MARIADB:
|
||||
case MYSQL:
|
||||
return new MySQLWithRollup();
|
||||
ctx.visit(new MySQLWithRollup());
|
||||
break;
|
||||
|
||||
default:
|
||||
return DSL.field("{rollup}({0})", Object.class, arguments);
|
||||
ctx.visit(F_ROLLUP).sql('(').visit(arguments).sql(')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.row;
|
||||
import static org.jooq.impl.DSL.sql;
|
||||
|
||||
import org.jooq.Clause;
|
||||
import org.jooq.Comparator;
|
||||
@ -72,7 +71,7 @@ final class TableComparison<R extends Record> extends AbstractCondition {
|
||||
|
||||
|
||||
case POSTGRES: {
|
||||
ctx.visit(DSL.condition("{0} {1} {2}", lhs, sql(comparator.toSQL()), rhs));
|
||||
ctx.visit(lhs).sql(' ').sql(comparator.toSQL()).sql(' ').visit(rhs);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Keyword;
|
||||
import org.jooq.Name;
|
||||
// ...
|
||||
import org.jooq.SQLDialect;
|
||||
@ -312,11 +313,13 @@ enum Term {
|
||||
|
||||
;
|
||||
|
||||
private final Name name;
|
||||
private final String translation;
|
||||
private final Name name;
|
||||
private final Keyword keyword;
|
||||
private final String translation;
|
||||
|
||||
private Term() {
|
||||
this.name = DSL.name(name());
|
||||
this.keyword = DSL.keyword(name());
|
||||
this.translation = name().toLowerCase();
|
||||
}
|
||||
|
||||
@ -329,6 +332,10 @@ enum Term {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Keyword toKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the term to its dialect-specific variant.
|
||||
*
|
||||
|
||||
@ -38,17 +38,22 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.Keywords.F_DATEDIFF;
|
||||
import static org.jooq.impl.Keywords.F_STRFTIME;
|
||||
import static org.jooq.impl.Keywords.F_TIMESTAMPDIFF;
|
||||
import static org.jooq.impl.Keywords.K_MILLISECOND;
|
||||
import static org.jooq.impl.SQLDataType.INTEGER;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.types.DayToSecond;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class TimestampDiff extends AbstractFunction<DayToSecond> {
|
||||
final class TimestampDiff extends AbstractField<DayToSecond> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -59,16 +64,19 @@ final class TimestampDiff extends AbstractFunction<DayToSecond> {
|
||||
private final Field<?> timestamp2;
|
||||
|
||||
TimestampDiff(Field<?> timestamp1, Field<?> timestamp2) {
|
||||
super("timestampdiff", SQLDataType.INTERVALDAYTOSECOND, timestamp1, timestamp2);
|
||||
super(DSL.name("timestampdiff"), SQLDataType.INTERVALDAYTOSECOND);
|
||||
|
||||
this.timestamp1 = timestamp1;
|
||||
this.timestamp2 = timestamp2;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
final Field<DayToSecond> getFunction0(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
public final void accept(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -106,25 +114,30 @@ final class TimestampDiff extends AbstractFunction<DayToSecond> {
|
||||
|
||||
// [#4481] Parentheses are important in case this expression is
|
||||
// placed in the context of other arithmetic
|
||||
return DSL.field("({0} - {1})", getDataType(), timestamp1, timestamp2);
|
||||
ctx.sql('(').visit(timestamp1).sql(" - ").visit(timestamp2).sql(')');
|
||||
break;
|
||||
|
||||
// CUBRID's datetime operations operate on a millisecond level
|
||||
case CUBRID:
|
||||
return (Field) timestamp1.sub(timestamp2);
|
||||
ctx.visit(timestamp1.sub(timestamp2));
|
||||
break;
|
||||
|
||||
case DERBY:
|
||||
return (Field) DSL.field("1000 * {fn {timestampdiff}({sql_tsi_second}, {0}, {1}) }", INTEGER, timestamp2, timestamp1);
|
||||
ctx.sql("1000 * {fn ").visit(F_TIMESTAMPDIFF).sql('(').visit(keyword("sql_tsi_second")).sql(", ").visit(timestamp2).sql(", ").visit(timestamp1).sql(") }");
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case FIREBIRD:
|
||||
return DSL.field("{datediff}(millisecond, {0}, {1})", getDataType(), timestamp2, timestamp1);
|
||||
ctx.visit(F_DATEDIFF).sql('(').visit(K_MILLISECOND).sql(", ").visit(timestamp2).sql(", ").visit(timestamp1).sql(')');
|
||||
break;
|
||||
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
return DSL.field("{datediff}('ms', {0}, {1})", getDataType(), timestamp2, timestamp1);
|
||||
ctx.visit(F_DATEDIFF).sql("('ms', ").visit(timestamp2).sql(", ").visit(timestamp1).sql(')');
|
||||
break;
|
||||
|
||||
// MySQL's datetime operations operate on a microsecond level
|
||||
|
||||
@ -134,18 +147,21 @@ final class TimestampDiff extends AbstractFunction<DayToSecond> {
|
||||
|
||||
case MARIADB:
|
||||
case MYSQL:
|
||||
return DSL.field("{timestampdiff}(microsecond, {0}, {1}) / 1000", getDataType(), timestamp2, timestamp1);
|
||||
ctx.visit(F_TIMESTAMPDIFF).sql('(').visit(keyword("microsecond")).sql(", ").visit(timestamp2).sql(", ").visit(timestamp1).sql(") / 1000");
|
||||
break;
|
||||
|
||||
case SQLITE:
|
||||
return DSL.field("({strftime}('%s', {0}) - {strftime}('%s', {1})) * 1000", getDataType(), timestamp1, timestamp2);
|
||||
ctx.sql('(').visit(F_STRFTIME).sql("('%s', ").visit(timestamp1).sql(") - ").visit(F_STRFTIME).sql("('%s', ").visit(timestamp2).sql(")) * 1000");
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
// Default implementation for equals() and hashCode()
|
||||
ctx.visit(castIfNeeded(timestamp1.sub(timestamp2), DayToSecond.class));
|
||||
break;
|
||||
}
|
||||
|
||||
// Default implementation for equals() and hashCode()
|
||||
return castIfNeeded(timestamp1.sub(timestamp2), DayToSecond.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,19 +38,21 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.Keywords.F_DATE_TRUNC;
|
||||
import static org.jooq.impl.Keywords.F_TRUNC;
|
||||
import static org.jooq.impl.Keywords.K_CAST;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DatePart;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.QueryPart;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class TruncDate<T> extends AbstractFunction<T> {
|
||||
final class TruncDate<T> extends AbstractField<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -61,18 +63,18 @@ final class TruncDate<T> extends AbstractFunction<T> {
|
||||
private final DatePart part;
|
||||
|
||||
TruncDate(Field<T> date, DatePart part) {
|
||||
super("trunc", date.getDataType());
|
||||
super(DSL.name("trunc"), date.getDataType());
|
||||
|
||||
this.date = date;
|
||||
this.part = part;
|
||||
}
|
||||
|
||||
@Override
|
||||
final QueryPart getFunction0(Configuration configuration) {
|
||||
public final void accept(Context<?> ctx) {
|
||||
String keyword = null;
|
||||
String format = null;
|
||||
|
||||
switch (configuration.family()) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
// [http://jira.cubrid.org/browse/ENGINE-120] This currently doesn't work for all date parts in CUBRID
|
||||
case CUBRID:
|
||||
@ -87,7 +89,8 @@ final class TruncDate<T> extends AbstractFunction<T> {
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{trunc}({0}, {1})", getDataType(), date, inline(keyword));
|
||||
ctx.visit(F_TRUNC).sql('(').visit(date).sql(", ").visit(inline(keyword)).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
case H2: {
|
||||
@ -101,7 +104,9 @@ final class TruncDate<T> extends AbstractFunction<T> {
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{parsedatetime}({formatdatetime}({0}, {1}), {1})", getDataType(), date, inline(format));
|
||||
ctx.visit(DSL.keyword("parsedatetime")).sql('(')
|
||||
.visit(DSL.keyword("formatdatetime")).sql('(').visit(date).sql(", ").visit(inline(format)).sql("), ").visit(inline(format)).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
// These don't work yet and need better integration-testing:
|
||||
@ -136,7 +141,8 @@ final class TruncDate<T> extends AbstractFunction<T> {
|
||||
default: throwUnsupported();
|
||||
}
|
||||
|
||||
return DSL.field("{date_trunc}({0}, {1})", getDataType(), inline(keyword), date);
|
||||
ctx.visit(F_DATE_TRUNC).sql('(').visit(inline(keyword)).sql(", ").visit(date).sql(')');
|
||||
break;
|
||||
}
|
||||
|
||||
// These don't work yet and need better integration-testing:
|
||||
@ -220,6 +226,12 @@ final class TruncDate<T> extends AbstractFunction<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -228,7 +240,8 @@ final class TruncDate<T> extends AbstractFunction<T> {
|
||||
|
||||
|
||||
default:
|
||||
return DSL.field("{trunc}({0}, {1})", getDataType(), date, inline(part.name()));
|
||||
ctx.visit(F_TRUNC).sql('(').visit(date).sql(", ").visit(inline(keyword)).sql(')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.keyword;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.zero;
|
||||
|
||||
@ -79,7 +80,7 @@ final class WidthBucket<T extends Number> extends AbstractField<T> {
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
ctx.visit(DSL.field("{width_bucket}({0}, {1}, {2}, {3})", getType(), field, low, high, buckets));
|
||||
ctx.visit(keyword("width_bucket")).sql('(').visit(field).sql(", ").visit(low).sql(", ").visit(high).sql(", ").visit(buckets).sql(')');
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user