diff --git a/jOOQ/src/main/java/org/jooq/SelectLimitPercentAfterOffsetStep.java b/jOOQ/src/main/java/org/jooq/SelectLimitPercentAfterOffsetStep.java
index 013e58f80c..4106c241f9 100644
--- a/jOOQ/src/main/java/org/jooq/SelectLimitPercentAfterOffsetStep.java
+++ b/jOOQ/src/main/java/org/jooq/SelectLimitPercentAfterOffsetStep.java
@@ -43,6 +43,7 @@ import org.jetbrains.annotations.*;
import static org.jooq.SQLDialect.H2;
// ...
// ...
+// ...
/**
* This type is used for the {@link Select}'s DSL API when selecting generic
diff --git a/jOOQ/src/main/java/org/jooq/SelectLimitPercentStep.java b/jOOQ/src/main/java/org/jooq/SelectLimitPercentStep.java
index 4f17dc608c..8642cc4340 100644
--- a/jOOQ/src/main/java/org/jooq/SelectLimitPercentStep.java
+++ b/jOOQ/src/main/java/org/jooq/SelectLimitPercentStep.java
@@ -43,6 +43,7 @@ import org.jetbrains.annotations.*;
import static org.jooq.SQLDialect.H2;
// ...
// ...
+// ...
/**
* This type is used for the {@link Select}'s DSL API when selecting generic
diff --git a/jOOQ/src/main/java/org/jooq/conf/RenderImplicitWindowRange.java b/jOOQ/src/main/java/org/jooq/conf/RenderImplicitWindowRange.java
new file mode 100644
index 0000000000..350b94d14d
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/conf/RenderImplicitWindowRange.java
@@ -0,0 +1,43 @@
+
+package org.jooq.conf;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ *
Java class for RenderImplicitWindowRange.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ * <simpleType name="RenderImplicitWindowRange">
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ * <enumeration value="OFF"/>
+ * <enumeration value="ROWS_UNBOUNDED_PRECEDING"/>
+ * <enumeration value="ROWS_ALL"/>
+ * <enumeration value="RANGE_UNBOUNDED_PRECEDING"/>
+ * <enumeration value="RANGE_ALL"/>
+ * </restriction>
+ * </simpleType>
+ *
+ *
+ */
+@XmlType(name = "RenderImplicitWindowRange")
+@XmlEnum
+public enum RenderImplicitWindowRange {
+
+ OFF,
+ ROWS_UNBOUNDED_PRECEDING,
+ ROWS_ALL,
+ RANGE_UNBOUNDED_PRECEDING,
+ RANGE_ALL;
+
+ public String value() {
+ return name();
+ }
+
+ public static RenderImplicitWindowRange 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 fad547693f..f08180dd25 100644
--- a/jOOQ/src/main/java/org/jooq/conf/Settings.java
+++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java
@@ -79,6 +79,9 @@ public class Settings
@XmlElement(defaultValue = "DEFAULT")
@XmlSchemaType(name = "string")
protected RenderOptionalKeyword renderOptionalOuterKeyword = RenderOptionalKeyword.DEFAULT;
+ @XmlElement(defaultValue = "OFF")
+ @XmlSchemaType(name = "string")
+ protected RenderImplicitWindowRange renderImplicitWindowRange = RenderImplicitWindowRange.OFF;
@XmlElement(defaultValue = "false")
protected Boolean renderScalarSubqueriesForStoredFunctions = false;
@XmlElement(defaultValue = "DEFAULT")
@@ -288,6 +291,9 @@ public class Settings
@XmlElement(defaultValue = "OFF")
@XmlSchemaType(name = "string")
protected ParseWithMetaLookups parseWithMetaLookups = ParseWithMetaLookups.OFF;
+ @XmlElement(defaultValue = "WHEN_NEEDED")
+ @XmlSchemaType(name = "string")
+ protected Transformation parseAppendMissingTableReferences = Transformation.WHEN_NEEDED;
@XmlElement(defaultValue = "false")
protected Boolean parseSetCommands = false;
@XmlElement(defaultValue = "IGNORE")
@@ -680,6 +686,22 @@ public class Settings
this.renderOptionalOuterKeyword = value;
}
+ /**
+ * Whether to render an explicit window RANGE clause when an implicit clause is applied.
+ *
+ */
+ public RenderImplicitWindowRange getRenderImplicitWindowRange() {
+ return renderImplicitWindowRange;
+ }
+
+ /**
+ * Whether to render an explicit window RANGE clause when an implicit clause is applied.
+ *
+ */
+ public void setRenderImplicitWindowRange(RenderImplicitWindowRange value) {
+ this.renderImplicitWindowRange = value;
+ }
+
/**
* Whether stored function calls should be wrapped in scalar subqueries.
*
@@ -2628,6 +2650,36 @@ public class Settings
this.parseWithMetaLookups = value;
}
+ /**
+ * Transform the parsed SQL to append missing table references to the query's FROM or USING clause, if applicable.
+ *
+ * Teradata (and possibly others) allow for referencing tables that are not listed in the FROM
+ * clause, such as SELECT t.* FROM t WHERE t.i = u.i. This transformation is executed in the
+ * parser, to produce SELECT t.* FROM t, u WHERE t.i = u.i, instead. By default, it is active
+ * when the input dialect supports this syntax.
+ *
+ * This feature is available in the commercial distribution only.
+ *
+ */
+ public Transformation getParseAppendMissingTableReferences() {
+ return parseAppendMissingTableReferences;
+ }
+
+ /**
+ * Transform the parsed SQL to append missing table references to the query's FROM or USING clause, if applicable.
+ *
+ * Teradata (and possibly others) allow for referencing tables that are not listed in the FROM
+ * clause, such as SELECT t.* FROM t WHERE t.i = u.i. This transformation is executed in the
+ * parser, to produce SELECT t.* FROM t, u WHERE t.i = u.i, instead. By default, it is active
+ * when the input dialect supports this syntax.
+ *
+ * This feature is available in the commercial distribution only.
+ *
+ */
+ public void setParseAppendMissingTableReferences(Transformation value) {
+ this.parseAppendMissingTableReferences = value;
+ }
+
/**
* [#9780] Whether commands of the type SET key = value should be parsed rather than ignored.
*
@@ -2984,6 +3036,15 @@ public class Settings
return this;
}
+ /**
+ * Whether to render an explicit window RANGE clause when an implicit clause is applied.
+ *
+ */
+ public Settings withRenderImplicitWindowRange(RenderImplicitWindowRange value) {
+ setRenderImplicitWindowRange(value);
+ return this;
+ }
+
public Settings withRenderScalarSubqueriesForStoredFunctions(Boolean value) {
setRenderScalarSubqueriesForStoredFunctions(value);
return this;
@@ -3667,6 +3728,22 @@ public class Settings
return this;
}
+ /**
+ * Transform the parsed SQL to append missing table references to the query's FROM or USING clause, if applicable.
+ *
+ * Teradata (and possibly others) allow for referencing tables that are not listed in the FROM
+ * clause, such as SELECT t.* FROM t WHERE t.i = u.i. This transformation is executed in the
+ * parser, to produce SELECT t.* FROM t, u WHERE t.i = u.i, instead. By default, it is active
+ * when the input dialect supports this syntax.
+ *
+ * This feature is available in the commercial distribution only.
+ *
+ */
+ public Settings withParseAppendMissingTableReferences(Transformation value) {
+ setParseAppendMissingTableReferences(value);
+ return this;
+ }
+
public Settings withParseSetCommands(Boolean value) {
setParseSetCommands(value);
return this;
@@ -3805,6 +3882,7 @@ public class Settings
builder.append("renderOptionalAsKeywordForFieldAliases", renderOptionalAsKeywordForFieldAliases);
builder.append("renderOptionalInnerKeyword", renderOptionalInnerKeyword);
builder.append("renderOptionalOuterKeyword", renderOptionalOuterKeyword);
+ builder.append("renderImplicitWindowRange", renderImplicitWindowRange);
builder.append("renderScalarSubqueriesForStoredFunctions", renderScalarSubqueriesForStoredFunctions);
builder.append("renderImplicitJoinType", renderImplicitJoinType);
builder.append("renderDefaultNullability", renderDefaultNullability);
@@ -3893,6 +3971,7 @@ public class Settings
builder.append("parseNamedParamPrefix", parseNamedParamPrefix);
builder.append("parseNameCase", parseNameCase);
builder.append("parseWithMetaLookups", parseWithMetaLookups);
+ builder.append("parseAppendMissingTableReferences", parseAppendMissingTableReferences);
builder.append("parseSetCommands", parseSetCommands);
builder.append("parseUnsupportedSyntax", parseUnsupportedSyntax);
builder.append("parseUnknownFunctions", parseUnknownFunctions);
@@ -4078,6 +4157,15 @@ public class Settings
return false;
}
}
+ if (renderImplicitWindowRange == null) {
+ if (other.renderImplicitWindowRange!= null) {
+ return false;
+ }
+ } else {
+ if (!renderImplicitWindowRange.equals(other.renderImplicitWindowRange)) {
+ return false;
+ }
+ }
if (renderScalarSubqueriesForStoredFunctions == null) {
if (other.renderScalarSubqueriesForStoredFunctions!= null) {
return false;
@@ -4870,6 +4958,15 @@ public class Settings
return false;
}
}
+ if (parseAppendMissingTableReferences == null) {
+ if (other.parseAppendMissingTableReferences!= null) {
+ return false;
+ }
+ } else {
+ if (!parseAppendMissingTableReferences.equals(other.parseAppendMissingTableReferences)) {
+ return false;
+ }
+ }
if (parseSetCommands == null) {
if (other.parseSetCommands!= null) {
return false;
@@ -4993,6 +5090,7 @@ public class Settings
result = ((prime*result)+((renderOptionalAsKeywordForFieldAliases == null)? 0 :renderOptionalAsKeywordForFieldAliases.hashCode()));
result = ((prime*result)+((renderOptionalInnerKeyword == null)? 0 :renderOptionalInnerKeyword.hashCode()));
result = ((prime*result)+((renderOptionalOuterKeyword == null)? 0 :renderOptionalOuterKeyword.hashCode()));
+ result = ((prime*result)+((renderImplicitWindowRange == null)? 0 :renderImplicitWindowRange.hashCode()));
result = ((prime*result)+((renderScalarSubqueriesForStoredFunctions == null)? 0 :renderScalarSubqueriesForStoredFunctions.hashCode()));
result = ((prime*result)+((renderImplicitJoinType == null)? 0 :renderImplicitJoinType.hashCode()));
result = ((prime*result)+((renderDefaultNullability == null)? 0 :renderDefaultNullability.hashCode()));
@@ -5081,6 +5179,7 @@ public class Settings
result = ((prime*result)+((parseNamedParamPrefix == null)? 0 :parseNamedParamPrefix.hashCode()));
result = ((prime*result)+((parseNameCase == null)? 0 :parseNameCase.hashCode()));
result = ((prime*result)+((parseWithMetaLookups == null)? 0 :parseWithMetaLookups.hashCode()));
+ result = ((prime*result)+((parseAppendMissingTableReferences == null)? 0 :parseAppendMissingTableReferences.hashCode()));
result = ((prime*result)+((parseSetCommands == null)? 0 :parseSetCommands.hashCode()));
result = ((prime*result)+((parseUnsupportedSyntax == null)? 0 :parseUnsupportedSyntax.hashCode()));
result = ((prime*result)+((parseUnknownFunctions == null)? 0 :parseUnknownFunctions.hashCode()));
diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java
index fab4ade663..ee650b1c7d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java
@@ -143,6 +143,10 @@ final class DeleteQueryImpl extends AbstractDMLQuery implem
return condition.hasWhere();
}
+ final TableList getUsing() {
+ return using;
+ }
+
@Override
public final void addUsing(Collection extends TableLike>> f) {
for (TableLike> provider : f)
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java b/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java
index 2336359dfe..d4e9910ffe 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java
@@ -41,6 +41,7 @@ import org.jooq.Clause;
import org.jooq.Context;
import org.jooq.Field;
import org.jooq.Name;
+import org.jooq.Query;
import org.jooq.Record;
import org.jooq.Table;
import org.jooq.TableField;
@@ -54,8 +55,26 @@ import org.jooq.TableField;
@SuppressWarnings("unchecked")
final class FieldProxy extends AbstractField implements TableField {
- private AbstractField delegate;
- private int position;
+ /**
+ * The resolved field after a successful meta lookup.
+ */
+ private AbstractField delegate;
+
+ /**
+ * The position in the parsed SQL string where this field proxy was
+ * encountered.
+ */
+ private int position;
+
+ /**
+ * The scope owner that produced this field proxy.
+ */
+ Query scopeOwner;
+
+ /**
+ * Whether this FieldProxy could be resolved at some scope level.
+ */
+ boolean resolved;
FieldProxy(AbstractField delegate, int position) {
super(
@@ -69,16 +88,29 @@ final class FieldProxy extends AbstractField implements TableField newDelegate) {
+ final void delegate(AbstractField newDelegate) {
+ resolve();
this.delegate = newDelegate;
((DataTypeProxy) getDataType()).type((AbstractDataType) newDelegate.getDataType());
}
+ final FieldProxy resolve() {
+ this.resolved = true;
+ this.scopeOwner = null;
+
+ return this;
+ }
+
+ final void scopeOwner(Query query) {
+ if (!resolved && scopeOwner == null)
+ scopeOwner = query;
+ }
+
@Override
public final Name getQualifiedName() {
return delegate.getQualifiedName();
diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
index afcf9a2cd3..8130de60b7 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
@@ -81,8 +81,12 @@ import static org.jooq.impl.Tools.EMPTY_SORTFIELD;
import static org.jooq.impl.Tools.EMPTY_TABLE;
import static org.jooq.impl.Tools.aliased;
import static org.jooq.impl.Tools.anyMatch;
+import static org.jooq.impl.Tools.deleteQueryImpl;
import static org.jooq.impl.Tools.findAny;
import static org.jooq.impl.Tools.normaliseNameCase;
+import static org.jooq.impl.Tools.selectQueryImpl;
+import static org.jooq.impl.Tools.updateQueryImpl;
+import static org.jooq.impl.Transformations.transformAppendMissingTableReferences;
import static org.jooq.impl.XMLPassingMechanism.BY_REF;
import static org.jooq.impl.XMLPassingMechanism.BY_VALUE;
import static org.jooq.tools.StringUtils.defaultIfNull;
@@ -666,25 +670,26 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
scopeStart();
boolean previousMetaLookupsForceIgnore = metaLookupsForceIgnore();
+ Query result = null;
try {
switch (characterUpper()) {
case 'A':
if (!parseResultQuery && peekKeyword("ALTER"))
- return metaLookupsForceIgnore(true).parseAlter();
+ return result = metaLookupsForceIgnore(true).parseAlter();
break;
case 'B':
if (!parseResultQuery && peekKeyword("BEGIN"))
- return parseBlock(false);
+ return result = parseBlock(false);
break;
case 'C':
if (!parseResultQuery && peekKeyword("CREATE"))
- return metaLookupsForceIgnore(true).parseCreate();
+ return result = metaLookupsForceIgnore(true).parseCreate();
else if (!parseResultQuery && peekKeyword("COMMENT ON"))
- return metaLookupsForceIgnore(true).parseCommentOn();
+ return result = metaLookupsForceIgnore(true).parseCommentOn();
else if (peekKeyword("CALL") && requireProEdition())
@@ -699,21 +704,21 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
case 'D':
if (!parseResultQuery && peekKeyword("DECLARE") && requireProEdition())
- return parseBlock(true);
+ return result = parseBlock(true);
else if (!parseResultQuery && (peekKeyword("DELETE") || peekKeyword("DEL")))
- return parseDelete(null);
+ return result = parseDelete(null);
else if (!parseResultQuery && peekKeyword("DROP"))
- return metaLookupsForceIgnore(true).parseDrop();
+ return result = metaLookupsForceIgnore(true).parseDrop();
else if (!parseResultQuery && peekKeyword("DO"))
- return parseDo();
+ return result = parseDo();
break;
case 'E':
if (!parseResultQuery && peekKeyword("EXECUTE BLOCK AS"))
- return parseBlock(true);
+ return result = parseBlock(true);
else if (!parseResultQuery && peekKeyword("EXEC"))
- return parseExec();
+ return result = parseExec();
else if (peekKeyword("EXECUTE PROCEDURE") && requireProEdition())
@@ -724,13 +729,13 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
case 'G':
if (!parseResultQuery && peekKeyword("GRANT"))
- return metaLookupsForceIgnore(true).parseGrant();
+ return result = metaLookupsForceIgnore(true).parseGrant();
break;
case 'I':
if (!parseResultQuery && (peekKeyword("INSERT") || peekKeyword("INS")))
- return parseInsert(null);
+ return result = parseInsert(null);
break;
@@ -742,21 +747,21 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
case 'M':
if (!parseResultQuery && peekKeyword("MERGE"))
- return parseMerge(null);
+ return result = parseMerge(null);
break;
case 'O':
if (!parseResultQuery && peekKeyword("OPEN"))
- return parseOpen();
+ return result = parseOpen();
break;
case 'R':
if (!parseResultQuery && peekKeyword("RENAME"))
- return metaLookupsForceIgnore(true).parseRename();
+ return result = metaLookupsForceIgnore(true).parseRename();
else if (!parseResultQuery && peekKeyword("REVOKE"))
- return metaLookupsForceIgnore(true).parseRevoke();
+ return result = metaLookupsForceIgnore(true).parseRevoke();
else if (parseKeywordIf("REPLACE"))
throw notImplemented("REPLACE");
else if (parseKeywordIf("ROLLBACK"))
@@ -766,9 +771,9 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
case 'S':
if (peekSelect(false))
- return parseSelect();
+ return result = parseSelect();
else if (!parseResultQuery && peekKeyword("SET"))
- return parseSet();
+ return result = parseSet();
else if (parseKeywordIf("SAVEPOINT"))
throw notImplemented("SAVEPOINT");
@@ -776,17 +781,17 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
case 'T':
if (!parseSelect && peekKeyword("TABLE"))
- return parseSelect();
+ return result = parseSelect();
else if (!parseResultQuery && peekKeyword("TRUNCATE"))
- return parseTruncate();
+ return result = parseTruncate();
break;
case 'U':
if (!parseResultQuery && (peekKeyword("UPDATE") || peekKeyword("UPD")))
- return parseUpdate(null);
+ return result = parseUpdate(null);
else if (!parseResultQuery && peekKeyword("USE"))
- return parseUse();
+ return result = parseUse();
else if (parseKeywordIf("UPSERT"))
throw notImplemented("UPSERT");
@@ -794,11 +799,11 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
case 'V':
if (!parseSelect && peekKeyword("VALUES"))
- return parseSelect();
+ return result = parseSelect();
case 'W':
if (peekKeyword("WITH"))
- return parseWith(parseSelect);
+ return result = parseWith(parseSelect);
break;
@@ -806,9 +811,9 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
// TODO are there other possible statement types?
if (peekKeyword("WITH", false, true, false))
- return parseWith(true);
+ return result = parseWith(true);
else
- return parseSelect();
+ return result = parseSelect();
case '{':
if (peekKeyword("{ CALL") && requireProEdition())
@@ -832,7 +837,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
throw e;
}
finally {
- scopeEnd();
+ scopeEnd(result);
scopeResolve();
metaLookupsForceIgnore(previousMetaLookupsForceIgnore);
}
@@ -1065,7 +1070,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
result.setForUpdateSkipLocked();
}
- scopeEnd();
+ scopeEnd(result);
return result;
}
@@ -1150,16 +1155,17 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
private final SelectQueryImpl parseQueryExpressionBody(Integer degree, WithImpl with, SelectQueryImpl prefix) {
SelectQueryImpl lhs = parseQueryTerm(degree, with, prefix);
+ SelectQueryImpl local = lhs;
CombineOperator combine;
while ((combine = parseCombineOperatorIf(false)) != null) {
- scopeEnd();
+ scopeEnd(local);
scopeStart();
if (degree == null)
degree = Tools.degree(lhs);
- SelectQueryImpl rhs = degreeCheck(degree, parseQueryTerm(degree, null, null));
+ SelectQueryImpl rhs = local = degreeCheck(degree, parseQueryTerm(degree, null, null));
switch (combine) {
case UNION:
lhs = lhs.union(rhs);
@@ -1183,16 +1189,17 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
private final SelectQueryImpl parseQueryTerm(Integer degree, WithImpl with, SelectQueryImpl prefix) {
SelectQueryImpl lhs = prefix != null ? prefix : parseQueryPrimary(degree, with);
+ SelectQueryImpl local = lhs;
CombineOperator combine;
while ((combine = parseCombineOperatorIf(true)) != null) {
- scopeEnd();
+ scopeEnd(local);
scopeStart();
if (degree == null)
degree = Tools.degree(lhs);
- SelectQueryImpl rhs = degreeCheck(degree, parseQueryPrimary(degree, null));
+ SelectQueryImpl rhs = local = degreeCheck(degree, parseQueryPrimary(degree, null));
switch (combine) {
case INTERSECT:
lhs = lhs.intersect(rhs);
@@ -1833,7 +1840,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
// [#10954] These are moved into the INSERT .. SELECT clause handling. They should not be necessary here
// either, but it seems we currently don't correctly implement nesting scopes?
- scopeEnd();
+ scopeEnd(null);
scopeStart();
Select> select = parseWithOrSelect();
@@ -1908,7 +1915,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
return returning;
}
finally {
- scopeEnd();
+ scopeEnd(((InsertImpl) s1).getDelegate());
}
}
@@ -13155,6 +13162,19 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
return parseDialect().family();
}
+ private final ParseWithMetaLookups metaLookups() {
+ if (metaLookupsForceIgnore())
+ return ParseWithMetaLookups.OFF;
+
+
+
+
+
+
+ else
+ return this.metaLookups;
+ }
+
private final boolean metaLookupsForceIgnore() {
return this.metaLookupsForceIgnore;
}
@@ -13436,7 +13456,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
lookupFields.setAll(null);
}
- private final void scopeEnd() {
+ private final void scopeEnd(Query scopeOwner) {
List> retain = new ArrayList<>();
for (FieldProxy> lookup : lookupFields) {
@@ -13455,10 +13475,14 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
}
found = resolveInTableScope(tableScope.valueIterable(), lookup.getQualifiedName(), lookup, found);
- if (found != null)
+
+ if (found != null && !(found.value() instanceof FieldProxy)) {
lookup.delegate((AbstractField) found.value());
- else
+ }
+ else {
+ lookup.scopeOwner(scopeOwner);
retain.add(lookup);
+ }
}
lookupFields.scopeEnd();
@@ -13499,6 +13523,14 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
if (x && q.equals(t.value().getQualifiedName()) || !x && q.last().equals(t.value().getName()))
if ((found = Value.of(t.scopeLevel(), t.value().field(lookup.getName()))) != null)
break tableScopeLoop;
+
+
+
+
+
+
+
+
}
else if ((f = Value.of(t.scopeLevel(), t.value().field(lookup.getName()))) != null) {
if (found == null || found.scopeLevel() < f.scopeLevel()) {
@@ -13524,9 +13556,41 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
}
private final void unknownField(FieldProxy> field) {
- if (!scopeClear && !metaLookupsForceIgnore && metaLookups == THROW_ON_FAILURE) {
- position(field.position());
- throw exception("Unknown field identifier");
+ if (!scopeClear) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if (metaLookups() == THROW_ON_FAILURE) {
+ position(field.position());
+ throw exception("Unknown field identifier");
+ }
}
}
@@ -13548,14 +13612,14 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
return tables.get(0);
}
- if (!metaLookupsForceIgnore && metaLookups == THROW_ON_FAILURE)
+ if (metaLookups() == THROW_ON_FAILURE)
throw exception("Unknown table identifier");
return table(name);
}
private final Field> lookupField(Name name) {
- if (metaLookups == ParseWithMetaLookups.OFF)
+ if (metaLookups() == ParseWithMetaLookups.OFF || lookupFields.scopeLevel() < 0)
return field(name);
FieldProxy> field = lookupFields.get(name);
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowCondition.java
index 0daaa73bef..e33e25f8b0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowCondition.java
@@ -63,6 +63,7 @@ import static org.jooq.SQLDialect.FIREBIRD;
// ...
// ...
// ...
+import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Keywords.K_NOT;
import static org.jooq.impl.Tools.map;
@@ -76,6 +77,7 @@ import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.Field;
+// ...
import org.jooq.QueryPartInternal;
import org.jooq.Row;
import org.jooq.SQLDialect;
@@ -85,9 +87,14 @@ import org.jooq.SQLDialect;
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
final class RowCondition extends AbstractCondition {
- private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
- private static final Set EMULATE_EQ_AND_NE = SQLDialect.supportedBy(DERBY, FIREBIRD);
- private static final Set EMULATE_RANGES = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD);
+ private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
+
+
+
+
+
+ private static final Set EMULATE_EQ_AND_NE = SQLDialect.supportedBy(DERBY, FIREBIRD);
+ private static final Set EMULATE_RANGES = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD);
private final Row left;
private final Row right;
@@ -116,6 +123,12 @@ final class RowCondition extends AbstractCondition {
}
private final QueryPartInternal delegate(Configuration configuration) {
+
+
+
+
+
+
// Regular comparison predicate emulation
if ((comparator == EQUALS || comparator == NOT_EQUALS) &&
(forceEmulation || EMULATE_EQ_AND_NE.contains(configuration.dialect()))) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowIsDistinctFrom.java b/jOOQ/src/main/java/org/jooq/impl/RowIsDistinctFrom.java
index 9801e8a5fa..2d60ba7322 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowIsDistinctFrom.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowIsDistinctFrom.java
@@ -61,6 +61,7 @@ import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
+// ...
import static org.jooq.impl.DSL.exists;
import static org.jooq.impl.DSL.notExists;
import static org.jooq.impl.DSL.select;
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java b/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java
index 8555175dbb..dae7cfd501 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java
@@ -64,6 +64,7 @@ import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
+// ...
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.selectCount;
import static org.jooq.impl.Keywords.K_IS_NOT_NULL;
@@ -71,8 +72,6 @@ import static org.jooq.impl.Keywords.K_IS_NULL;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.visitSubquery;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
import org.jooq.Clause;
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java
index 7a851e6886..0f0baa9450 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java
@@ -68,6 +68,7 @@ import static org.jooq.SQLDialect.POSTGRES;
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
+// ...
import static org.jooq.impl.DSL.asterisk;
import static org.jooq.impl.DSL.exists;
import static org.jooq.impl.DSL.name;
diff --git a/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java b/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java
index 3b748f457d..0aedf85783 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ScopeMarker.java
@@ -41,15 +41,14 @@ package org.jooq.impl;
// ...
// ...
import static org.jooq.impl.Keywords.K_DECLARE;
-import static org.jooq.impl.Keywords.K_WITH;
import static org.jooq.impl.Tools.increment;
import static org.jooq.impl.Tools.DataKey.DATA_TOP_LEVEL_CTE;
+import static org.jooq.impl.WithImpl.acceptWithRecursive;
import org.jooq.Clause;
import org.jooq.Context;
// ...
import org.jooq.QueryPartInternal;
-import org.jooq.SQLDialect;
import org.jooq.Statement;
import org.jooq.impl.AbstractContext.ScopeStackElement;
import org.jooq.impl.Tools.DataExtendedKey;
@@ -124,7 +123,7 @@ enum ScopeMarker {
boolean noWith = afterLast != null && beforeFirst.positions[0] == afterLast.positions[0];
if (noWith) {
- ctx.visit(K_WITH);
+ acceptWithRecursive(ctx, cte.recursive);
if (single)
ctx.formatIndentStart()
diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java
index cc984022c3..cbf27a91e9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Tools.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java
@@ -3211,12 +3211,12 @@ final class Tools {
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
static final SelectQueryImpl selectQueryImpl(QueryPart part) {
if (part instanceof SelectQueryImpl)
return (SelectQueryImpl) part;
- else if (part instanceof AbstractDelegatingQuery)
- return ((AbstractDelegatingQuery>) part).getDelegate();
+ else if (part instanceof SelectImpl)
+ return (SelectQueryImpl) ((SelectImpl) part).getDelegate();
else if (part instanceof ScalarSubquery)
return selectQueryImpl(((ScalarSubquery>) part).query);
else if (part instanceof QuantifiedSelectImpl)
@@ -3234,11 +3234,29 @@ final class Tools {
return null;
}
+ static final UpdateQueryImpl> updateQueryImpl(Query query) {
+ AbstractDMLQuery> result = abstractDMLQuery(query);
+
+ if (result instanceof UpdateQueryImpl)
+ return (UpdateQueryImpl>) result;
+ else
+ return null;
+ }
+
+ static final DeleteQueryImpl> deleteQueryImpl(Query query) {
+ AbstractDMLQuery> result = abstractDMLQuery(query);
+
+ if (result instanceof DeleteQueryImpl)
+ return (DeleteQueryImpl>) result;
+ else
+ return null;
+ }
+
static final AbstractDMLQuery> abstractDMLQuery(Query query) {
if (query instanceof AbstractDMLQuery)
return (AbstractDMLQuery>) query;
- else if (query instanceof AbstractDelegatingQuery)
- return abstractDMLQuery(((AbstractDelegatingQuery, ?>) query).getDelegate());
+ else if (query instanceof AbstractDelegatingDMLQuery)
+ return abstractDMLQuery(((AbstractDelegatingDMLQuery, ?>) query).getDelegate());
else if (query instanceof DMLQueryAsResultQuery)
return ((DMLQueryAsResultQuery, ?>) query).getDelegate();
else
diff --git a/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java b/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java
index 4bdb270cc5..6e23a7b216 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TopLevelCte.java
@@ -48,6 +48,8 @@ import org.jooq.impl.ScopeMarker.ScopeContent;
*/
final class TopLevelCte extends QueryPartList implements ScopeContent {
+ boolean recursive;
+
@Override
public void accept(Context> ctx) {
markTopLevelCteAndAccept(ctx, c -> super.accept(c));
diff --git a/jOOQ/src/main/java/org/jooq/impl/Transformations.java b/jOOQ/src/main/java/org/jooq/impl/Transformations.java
index e40b8bf5f5..e5506b22c4 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Transformations.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Transformations.java
@@ -48,6 +48,7 @@ import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DERBY;
// ...
import static org.jooq.SQLDialect.FIREBIRD;
+import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.IGNITE;
@@ -74,10 +75,8 @@ import java.util.Set;
import java.util.function.Predicate;
import org.jooq.Configuration;
-import org.jooq.Context;
import org.jooq.QueryPart;
import org.jooq.SQLDialect;
-import org.jooq.Scope;
import org.jooq.conf.Transformation;
/**
@@ -87,9 +86,10 @@ import org.jooq.conf.Transformation;
*/
final class Transformations {
- private static final Set NO_SUPPORT_IN_LIMIT = SQLDialect.supportedBy(MARIADB, MYSQL);
- private static final Set EMULATE_QUALIFY = SQLDialect.supportedBy(CUBRID, FIREBIRD, MARIADB, MYSQL, POSTGRES, SQLITE);
- private static final Set EMULATE_ROWNUM = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE);
+ private static final Set NO_SUPPORT_IN_LIMIT = SQLDialect.supportedBy(MARIADB, MYSQL);
+ private static final Set SUPPORT_MISSING_TABLE_REFERENCES = SQLDialect.supportedBy();
+ private static final Set EMULATE_QUALIFY = SQLDialect.supportedBy(CUBRID, FIREBIRD, MARIADB, MYSQL, POSTGRES, SQLITE);
+ private static final Set EMULATE_ROWNUM = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE);
static final SelectQueryImpl> subqueryWithLimit(QueryPart source) {
SelectQueryImpl> s;
@@ -123,6 +123,15 @@ final class Transformations {
);
}
+ static final boolean transformAppendMissingTableReferences(Configuration configuration) {
+ return transform(
+ configuration,
+ "Settings.transformAppendMissingTableReferences",
+ configuration.settings().getParseAppendMissingTableReferences(),
+ c -> SUPPORT_MISSING_TABLE_REFERENCES.contains(c.settings().getParseDialect())
+ );
+ }
+
/**
* Check whether a given SQL transformation needs to be applied.
*/
diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java
index ef3bc2c250..c963c5dcc9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java
@@ -521,6 +521,10 @@ final class UpdateQueryImpl extends AbstractStoreQuery impl
return condition.hasWhere();
}
+ final TableList getFrom() {
+ return from;
+ }
+
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
final void accept0(Context> ctx) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java b/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java
index b2549aee85..f1ed7579af 100644
--- a/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java
@@ -66,6 +66,7 @@ import static org.jooq.impl.WindowSpecificationImpl.Exclude.TIES;
import static org.jooq.impl.WindowSpecificationImpl.FrameUnits.GROUPS;
import static org.jooq.impl.WindowSpecificationImpl.FrameUnits.RANGE;
import static org.jooq.impl.WindowSpecificationImpl.FrameUnits.ROWS;
+import static org.jooq.tools.StringUtils.defaultIfNull;
import java.util.Arrays;
import java.util.Collection;
@@ -81,6 +82,7 @@ import org.jooq.WindowSpecificationFinalStep;
import org.jooq.WindowSpecificationOrderByStep;
import org.jooq.WindowSpecificationPartitionByStep;
import org.jooq.WindowSpecificationRowsAndStep;
+import org.jooq.conf.RenderImplicitWindowRange;
import org.jooq.impl.Tools.BooleanDataKey;
/**
@@ -149,7 +151,11 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements
boolean hasWindowDefinitions = windowDefinition != null;
boolean hasPartitionBy = !partitionBy.isEmpty();
boolean hasOrderBy = !o.isEmpty();
- boolean hasFrame = frameStart != null;
+ boolean hasFrame = frameStart != null
+
+
+
+ ;
int clauses = 0;
@@ -199,17 +205,53 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements
if (hasWindowDefinitions || hasPartitionBy || hasOrderBy)
ctx.formatSeparator();
- ctx.visit(frameUnits.keyword).sql(' ');
+ FrameUnits u = frameUnits;
+ Integer s = frameStart;
+ Integer e = frameEnd;
- if (frameEnd != null) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ctx.visit(u.keyword).sql(' ');
+
+ if (e != null) {
ctx.visit(K_BETWEEN).sql(' ');
- toSQLRows(ctx, frameStart);
+ toSQLRows(ctx, s);
ctx.sql(' ').visit(K_AND).sql(' ');
- toSQLRows(ctx, frameEnd);
+ toSQLRows(ctx, e);
}
else {
- toSQLRows(ctx, frameStart);
+ toSQLRows(ctx, s);
}
if (exclude != null)
diff --git a/jOOQ/src/main/java/org/jooq/impl/WithImpl.java b/jOOQ/src/main/java/org/jooq/impl/WithImpl.java
index a0129e701d..65d7c2e6ab 100644
--- a/jOOQ/src/main/java/org/jooq/impl/WithImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/WithImpl.java
@@ -43,6 +43,7 @@ import static org.jooq.Clause.WITH;
// ...
// ...
// ...
+// ...
import static org.jooq.impl.DSL.count;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.one;
@@ -125,7 +126,6 @@ import org.jooq.WithAsStep7;
import org.jooq.WithAsStep8;
import org.jooq.WithAsStep9;
import org.jooq.WithStep;
-import org.jooq.impl.Tools.BooleanDataKey;
/**
* This type models an intermediary DSL construction step, which leads towards
@@ -219,14 +219,8 @@ implements
- ctx.visit(K_WITH);
- if (recursive
-
-
-
- )
- ctx.sql(' ').visit(K_RECURSIVE);
+ acceptWithRecursive(ctx, recursive);
ctx.data(DATA_LIST_ALREADY_INDENTED, true, c1 ->
c1.formatIndentStart()
@@ -238,6 +232,17 @@ implements
}
}
+ static final void acceptWithRecursive(Context> ctx, boolean recursive) {
+ ctx.visit(K_WITH);
+
+ if (recursive
+
+
+
+ )
+ ctx.sql(' ').visit(K_RECURSIVE);
+ }
+
@Override
public final Clause[] clauses(Context> ctx) {
return CLAUSES;
diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd
index ab7b273fed..40bc2ed1a7 100644
--- a/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd
+++ b/jOOQ/src/main/resources/xsd/jooq-runtime-3.15.0.xsd
@@ -129,6 +129,10 @@ providing a name to parameters, resulting in :1 or @1
OUTER keyword in OUTER JOIN, if it is optional in the output dialect.]]>
+
+
+ RANGE clause when an implicit clause is applied.]]>
+
:1 or @1
+
+ FROM or USING clause, if applicable.
+
+Teradata (and possibly others) allow for referencing tables that are not listed in the FROM
+clause, such as SELECT t.* FROM t WHERE t.i = u.i. This transformation is executed in the
+parser, to produce SELECT t.* FROM t, u WHERE t.i = u.i, instead. By default, it is active
+when the input dialect supports this syntax.
+
+This feature is available in the commercial distribution only.]]>
+
+
@@ -1171,6 +1186,26 @@ Either <input/> or <inputExpression/> must be provided]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+