[jOOQ/jOOQ#8807] Add setting to specify whether INNER and OUTER keywords should be generated in joins
This commit is contained in:
parent
182c18c737
commit
582ee276c5
@ -76,7 +76,7 @@ public enum JoinType {
|
||||
* <code>INNER JOIN</code> two tables.
|
||||
*/
|
||||
@Support
|
||||
JOIN("join", true),
|
||||
JOIN("join", "inner join", "join", true),
|
||||
|
||||
/**
|
||||
* <code>CROSS JOIN</code> two tables.
|
||||
@ -88,43 +88,43 @@ public enum JoinType {
|
||||
* <code>LEFT OUTER JOIN</code> two tables.
|
||||
*/
|
||||
@Support
|
||||
LEFT_OUTER_JOIN("left outer join", true),
|
||||
LEFT_OUTER_JOIN("left outer join", "left outer join", "left join", true),
|
||||
|
||||
/**
|
||||
* <code>RIGHT OUTER JOIN</code> 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),
|
||||
|
||||
/**
|
||||
* <code>FULL OUTER JOIN</code> 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),
|
||||
|
||||
/**
|
||||
* <code>NATURAL INNER JOIN</code> two tables.
|
||||
*/
|
||||
@Support
|
||||
NATURAL_JOIN("natural join", false),
|
||||
NATURAL_JOIN("natural join", "natural inner join", "natural join", false),
|
||||
|
||||
/**
|
||||
* <code>NATURAL LEFT OUTER JOIN</code> 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),
|
||||
|
||||
/**
|
||||
* <code>NATURAL RIGHT OUTER JOIN</code> 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),
|
||||
|
||||
/**
|
||||
* <code>NATURAL FULL OUTER JOIN</code> 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),
|
||||
|
||||
/**
|
||||
* <code>CROSS APPLY</code> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
40
jOOQ/src/main/java/org/jooq/conf/RenderOptionalKeyword.java
Normal file
40
jOOQ/src/main/java/org/jooq/conf/RenderOptionalKeyword.java
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
package org.jooq.conf;
|
||||
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for RenderOptionalKeyword.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
* <p>
|
||||
* <pre>
|
||||
* <simpleType name="RenderOptionalKeyword">
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}string">
|
||||
* <enumeration value="OFF"/>
|
||||
* <enumeration value="ON"/>
|
||||
* <enumeration value="DEFAULT"/>
|
||||
* </restriction>
|
||||
* </simpleType>
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@XmlType(name = "RenderOptionalKeyword")
|
||||
@XmlEnum
|
||||
public enum RenderOptionalKeyword {
|
||||
|
||||
OFF,
|
||||
ON,
|
||||
DEFAULT;
|
||||
|
||||
public String value() {
|
||||
return name();
|
||||
}
|
||||
|
||||
public static RenderOptionalKeyword fromValue(String v) {
|
||||
return valueOf(v);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 <code>INNER</code> keyword in <code>INNER JOIN</code>, if it is optional in the output dialect.
|
||||
*
|
||||
*/
|
||||
public RenderOptionalKeyword getRenderOptionalInnerKeyword() {
|
||||
return renderOptionalInnerKeyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to render the optional <code>INNER</code> keyword in <code>INNER JOIN</code>, if it is optional in the output dialect.
|
||||
*
|
||||
*/
|
||||
public void setRenderOptionalInnerKeyword(RenderOptionalKeyword value) {
|
||||
this.renderOptionalInnerKeyword = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to render the optional <code>OUTER</code> keyword in <code>OUTER JOIN</code>, if it is optional in the output dialect.
|
||||
*
|
||||
*/
|
||||
public RenderOptionalKeyword getRenderOptionalOuterKeyword() {
|
||||
return renderOptionalOuterKeyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to render the optional <code>OUTER</code> keyword in <code>OUTER JOIN</code>, 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.
|
||||
* <p>
|
||||
@ -1765,6 +1803,24 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to render the optional <code>INNER</code> keyword in <code>INNER JOIN</code>, if it is optional in the output dialect.
|
||||
*
|
||||
*/
|
||||
public Settings withRenderOptionalInnerKeyword(RenderOptionalKeyword value) {
|
||||
setRenderOptionalInnerKeyword(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to render the optional <code>OUTER</code> keyword in <code>OUTER JOIN</code>, 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()));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -110,6 +110,14 @@ providing a name to parameters, resulting in <code>:1</code> or <code>@1</code>
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[All sorts of formatting flags / settings.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="renderOptionalInnerKeyword" type="jooq-runtime:RenderOptionalKeyword" minOccurs="0" maxOccurs="1" default="DEFAULT">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether to render the optional <code>INNER</code> keyword in <code>INNER JOIN</code>, if it is optional in the output dialect.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="renderOptionalOuterKeyword" type="jooq-runtime:RenderOptionalKeyword" minOccurs="0" maxOccurs="1" default="DEFAULT">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether to render the optional <code>OUTER</code> keyword in <code>OUTER JOIN</code>, if it is optional in the output dialect.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="renderScalarSubqueriesForStoredFunctions" type="boolean" minOccurs="0" maxOccurs="1" default="false">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether stored function calls should be wrapped in scalar subqueries.
|
||||
<p>
|
||||
@ -765,6 +773,20 @@ Either <input/> or <inputExpression/> must be provided]]></jxb:javad
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<simpleType name="RenderOptionalKeyword">
|
||||
<restriction base="string">
|
||||
|
||||
<!-- Optional keywords will never be generated (does not affect mandatory keywords). -->
|
||||
<enumeration value="OFF"/>
|
||||
|
||||
<!-- Optional keywords will always be generated (does not affect mandatory keywords). -->
|
||||
<enumeration value="ON"/>
|
||||
|
||||
<!-- The default applies for optional keywords. -->
|
||||
<enumeration value="DEFAULT"/>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<simpleType name="ParseWithMetaLookups">
|
||||
<restriction base="string">
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user