diff --git a/jOOQ/src/main/java/org/jooq/JoinType.java b/jOOQ/src/main/java/org/jooq/JoinType.java index 83c6da6b16..d8ce734a51 100644 --- a/jOOQ/src/main/java/org/jooq/JoinType.java +++ b/jOOQ/src/main/java/org/jooq/JoinType.java @@ -76,7 +76,7 @@ public enum JoinType { * INNER JOIN two tables. */ @Support - JOIN("join", true), + JOIN("join", "inner join", "join", true), /** * CROSS JOIN two tables. @@ -88,43 +88,43 @@ public enum JoinType { * LEFT OUTER JOIN two tables. */ @Support - LEFT_OUTER_JOIN("left outer join", true), + LEFT_OUTER_JOIN("left outer join", "left outer join", "left join", true), /** * RIGHT OUTER JOIN two tables. */ @Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES }) - RIGHT_OUTER_JOIN("right outer join", true), + RIGHT_OUTER_JOIN("right outer join", "right outer join", "right join", true), /** * FULL OUTER JOIN two tables. */ @Support({ FIREBIRD, HSQLDB, POSTGRES }) - FULL_OUTER_JOIN("full outer join", true), + FULL_OUTER_JOIN("full outer join", "full outer join", "full join", true), /** * NATURAL INNER JOIN two tables. */ @Support - NATURAL_JOIN("natural join", false), + NATURAL_JOIN("natural join", "natural inner join", "natural join", false), /** * NATURAL LEFT OUTER JOIN two tables. */ @Support - NATURAL_LEFT_OUTER_JOIN("natural left outer join", false), + NATURAL_LEFT_OUTER_JOIN("natural left outer join", "natural left outer join", "natural left join", false), /** * NATURAL RIGHT OUTER JOIN two tables. */ @Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES }) - NATURAL_RIGHT_OUTER_JOIN("natural right outer join", false), + NATURAL_RIGHT_OUTER_JOIN("natural right outer join", "natural right outer join", "natural right join", false), /** * NATURAL FULL OUTER JOIN two tables. */ @Support({ FIREBIRD, HSQLDB, POSTGRES }) - NATURAL_FULL_OUTER_JOIN("natural full outer join", false), + NATURAL_FULL_OUTER_JOIN("natural full outer join", "natural full outer join", "natural full join", false), /** * CROSS APPLY two tables. @@ -158,22 +158,34 @@ public enum JoinType { ; - private final String sql; - private final Keyword keyword; + private final String defaultSql; + private final Keyword defaultKeyword; + private final Keyword includingOptionalKeywords; + private final Keyword excludingOptionalKeywords; private final boolean qualified; private JoinType(String sql, boolean qualified) { - this.sql = sql; - this.keyword = DSL.keyword(sql); + this(sql, sql, sql, qualified); + } + + private JoinType(String defaultSql, String includingOptionalKeywords, String excludingOptionalKeywords, boolean qualified) { + this.defaultSql = defaultSql; + this.includingOptionalKeywords = DSL.keyword(includingOptionalKeywords); + this.excludingOptionalKeywords = DSL.keyword(excludingOptionalKeywords); + this.defaultKeyword = DSL.keyword(defaultSql); this.qualified = qualified; } public final String toSQL() { - return sql; + return defaultSql; } public final Keyword toKeyword() { - return keyword; + return defaultKeyword; + } + + public final Keyword toKeyword(boolean includeOptionalKeywords) { + return includeOptionalKeywords ? includingOptionalKeywords : excludingOptionalKeywords; } /** diff --git a/jOOQ/src/main/java/org/jooq/conf/RenderOptionalKeyword.java b/jOOQ/src/main/java/org/jooq/conf/RenderOptionalKeyword.java new file mode 100644 index 0000000000..19e9d2867a --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/conf/RenderOptionalKeyword.java @@ -0,0 +1,40 @@ + +package org.jooq.conf; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for RenderOptionalKeyword. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="RenderOptionalKeyword">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="OFF"/>
+ *     <enumeration value="ON"/>
+ *     <enumeration value="DEFAULT"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "RenderOptionalKeyword") +@XmlEnum +public enum RenderOptionalKeyword { + + OFF, + ON, + DEFAULT; + + public String value() { + return name(); + } + + public static RenderOptionalKeyword fromValue(String v) { + return valueOf(v); + } + +} diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 0858df2b63..4bc6103a24 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -65,6 +65,12 @@ public class Settings @XmlElement(defaultValue = "false") protected Boolean renderFormatted = false; protected RenderFormatting renderFormatting; + @XmlElement(defaultValue = "DEFAULT") + @XmlSchemaType(name = "string") + protected RenderOptionalKeyword renderOptionalInnerKeyword = RenderOptionalKeyword.DEFAULT; + @XmlElement(defaultValue = "DEFAULT") + @XmlSchemaType(name = "string") + protected RenderOptionalKeyword renderOptionalOuterKeyword = RenderOptionalKeyword.DEFAULT; @XmlElement(defaultValue = "false") protected Boolean renderScalarSubqueriesForStoredFunctions = false; @XmlElement(defaultValue = "true") @@ -473,6 +479,38 @@ public class Settings this.renderFormatting = value; } + /** + * Whether to render the optional INNER keyword in INNER JOIN, if it is optional in the output dialect. + * + */ + public RenderOptionalKeyword getRenderOptionalInnerKeyword() { + return renderOptionalInnerKeyword; + } + + /** + * Whether to render the optional INNER keyword in INNER JOIN, if it is optional in the output dialect. + * + */ + public void setRenderOptionalInnerKeyword(RenderOptionalKeyword value) { + this.renderOptionalInnerKeyword = value; + } + + /** + * Whether to render the optional OUTER keyword in OUTER JOIN, if it is optional in the output dialect. + * + */ + public RenderOptionalKeyword getRenderOptionalOuterKeyword() { + return renderOptionalOuterKeyword; + } + + /** + * Whether to render the optional OUTER keyword in OUTER JOIN, if it is optional in the output dialect. + * + */ + public void setRenderOptionalOuterKeyword(RenderOptionalKeyword value) { + this.renderOptionalOuterKeyword = value; + } + /** * Whether stored function calls should be wrapped in scalar subqueries. *

@@ -1765,6 +1803,24 @@ public class Settings return this; } + /** + * Whether to render the optional INNER keyword in INNER JOIN, if it is optional in the output dialect. + * + */ + public Settings withRenderOptionalInnerKeyword(RenderOptionalKeyword value) { + setRenderOptionalInnerKeyword(value); + return this; + } + + /** + * Whether to render the optional OUTER keyword in OUTER JOIN, if it is optional in the output dialect. + * + */ + public Settings withRenderOptionalOuterKeyword(RenderOptionalKeyword value) { + setRenderOptionalOuterKeyword(value); + return this; + } + public Settings withRenderScalarSubqueriesForStoredFunctions(Boolean value) { setRenderScalarSubqueriesForStoredFunctions(value); return this; @@ -2208,6 +2264,8 @@ public class Settings builder.append("renderLocale", renderLocale); builder.append("renderFormatted", renderFormatted); builder.append("renderFormatting", renderFormatting); + builder.append("renderOptionalInnerKeyword", renderOptionalInnerKeyword); + builder.append("renderOptionalOuterKeyword", renderOptionalOuterKeyword); builder.append("renderScalarSubqueriesForStoredFunctions", renderScalarSubqueriesForStoredFunctions); builder.append("renderOrderByRownumberForEmulatedPagination", renderOrderByRownumberForEmulatedPagination); builder.append("renderOutputForSQLServerReturningClause", renderOutputForSQLServerReturningClause); @@ -2392,6 +2450,24 @@ public class Settings return false; } } + if (renderOptionalInnerKeyword == null) { + if (other.renderOptionalInnerKeyword!= null) { + return false; + } + } else { + if (!renderOptionalInnerKeyword.equals(other.renderOptionalInnerKeyword)) { + return false; + } + } + if (renderOptionalOuterKeyword == null) { + if (other.renderOptionalOuterKeyword!= null) { + return false; + } + } else { + if (!renderOptionalOuterKeyword.equals(other.renderOptionalOuterKeyword)) { + return false; + } + } if (renderScalarSubqueriesForStoredFunctions == null) { if (other.renderScalarSubqueriesForStoredFunctions!= null) { return false; @@ -2906,6 +2982,8 @@ public class Settings result = ((prime*result)+((renderLocale == null)? 0 :renderLocale.hashCode())); result = ((prime*result)+((renderFormatted == null)? 0 :renderFormatted.hashCode())); result = ((prime*result)+((renderFormatting == null)? 0 :renderFormatting.hashCode())); + result = ((prime*result)+((renderOptionalInnerKeyword == null)? 0 :renderOptionalInnerKeyword.hashCode())); + result = ((prime*result)+((renderOptionalOuterKeyword == null)? 0 :renderOptionalOuterKeyword.hashCode())); result = ((prime*result)+((renderScalarSubqueriesForStoredFunctions == null)? 0 :renderScalarSubqueriesForStoredFunctions.hashCode())); result = ((prime*result)+((renderOrderByRownumberForEmulatedPagination == null)? 0 :renderOrderByRownumberForEmulatedPagination.hashCode())); result = ((prime*result)+((renderOutputForSQLServerReturningClause == null)? 0 :renderOutputForSQLServerReturningClause.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java index c2b220dc4b..386c4947fe 100755 --- a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java +++ b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java @@ -90,7 +90,7 @@ import static org.jooq.impl.DSL.exists; import static org.jooq.impl.DSL.notExists; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.Keywords.K_CROSS_JOIN_LATERAL; -import static org.jooq.impl.Keywords.K_INNER_JOIN; +import static org.jooq.impl.Keywords.K_LEFT_JOIN_LATERAL; import static org.jooq.impl.Keywords.K_LEFT_OUTER_JOIN_LATERAL; import static org.jooq.impl.Keywords.K_ON; import static org.jooq.impl.Keywords.K_PARTITION_BY; @@ -126,6 +126,7 @@ import org.jooq.TableOnConditionStep; import org.jooq.TableOptionalOnStep; import org.jooq.TableOuterJoinStep; import org.jooq.TablePartitionByStep; +import org.jooq.conf.RenderOptionalKeyword; import org.jooq.exception.DataAccessException; /** @@ -205,19 +206,7 @@ implements public final void accept(Context ctx) { JoinType translatedType = translateType(ctx); Clause translatedClause = translateClause(translatedType); - - Keyword keyword = translatedType.toKeyword(); - - if (translatedType == CROSS_APPLY && EMULATE_APPLY.contains(ctx.family())) - keyword = K_CROSS_JOIN_LATERAL; - else if (translatedType == OUTER_APPLY && EMULATE_APPLY.contains(ctx.family())) - keyword = K_LEFT_OUTER_JOIN_LATERAL; - - - - - - + Keyword keyword = translateKeyword(ctx, translatedType); toSQLTable(ctx, lhs); @@ -308,6 +297,63 @@ implements .formatIndentEnd(); } + private final Keyword translateKeyword(Context ctx, JoinType translatedType) { + Keyword keyword; + + switch (translatedType) { + case JOIN: + case NATURAL_JOIN: + if (ctx.settings().getRenderOptionalInnerKeyword() == RenderOptionalKeyword.ON) + keyword = translatedType.toKeyword(true); + + + + + + + + else + keyword = translatedType.toKeyword(); + + break; + + case LEFT_OUTER_JOIN: + case NATURAL_LEFT_OUTER_JOIN: + case RIGHT_OUTER_JOIN: + case NATURAL_RIGHT_OUTER_JOIN: + case FULL_OUTER_JOIN: + case NATURAL_FULL_OUTER_JOIN: + if (ctx.settings().getRenderOptionalOuterKeyword() == RenderOptionalKeyword.OFF) + keyword = translatedType.toKeyword(false); + + + + + + + + else + keyword = translatedType.toKeyword(); + + break; + + default: + keyword = translatedType.toKeyword(); + break; + } + + if (translatedType == CROSS_APPLY && EMULATE_APPLY.contains(ctx.family())) + keyword = K_CROSS_JOIN_LATERAL; + else if (translatedType == OUTER_APPLY && EMULATE_APPLY.contains(ctx.family())) + if (ctx.settings().getRenderOptionalOuterKeyword() == RenderOptionalKeyword.OFF) + keyword = K_LEFT_JOIN_LATERAL; + else + keyword = K_LEFT_OUTER_JOIN_LATERAL; + + + return keyword; + } + private void toSQLTable(Context ctx, Table table) { // [#671] Some databases formally require nested JOINS on the right hand diff --git a/jOOQ/src/main/java/org/jooq/impl/Keywords.java b/jOOQ/src/main/java/org/jooq/impl/Keywords.java index d9fb76d736..bf1e260b13 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Keywords.java +++ b/jOOQ/src/main/java/org/jooq/impl/Keywords.java @@ -205,6 +205,7 @@ final class Keywords { static final Keyword K_LATERAL = keyword("lateral"); static final Keyword K_LEADING = keyword("leading"); static final Keyword K_LEAVE = keyword("leave"); + static final Keyword K_LEFT_JOIN_LATERAL = keyword("left join lateral"); static final Keyword K_LEFT_OUTER_JOIN_LATERAL = keyword("left outer join lateral"); static final Keyword K_LIKE = keyword("like"); static final Keyword K_LIKE_REGEX = keyword("like_regex"); diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd index 14d906308a..482af7b32d 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd @@ -110,6 +110,14 @@ providing a name to parameters, resulting in :1 or @1 + + INNER keyword in INNER JOIN, if it is optional in the output dialect.]]> + + + + OUTER keyword in OUTER JOIN, if it is optional in the output dialect.]]> + + @@ -765,6 +773,20 @@ Either <input/> or <inputExpression/> must be provided]]> + + + + + + + + + + + + + +