diff --git a/jOOQ/src/main/java/org/jooq/QueryPartInternal.java b/jOOQ/src/main/java/org/jooq/QueryPartInternal.java
index 8ff5facf2a..291f76608a 100644
--- a/jOOQ/src/main/java/org/jooq/QueryPartInternal.java
+++ b/jOOQ/src/main/java/org/jooq/QueryPartInternal.java
@@ -50,6 +50,15 @@ import org.jooq.exception.DataAccessException;
@Internal
public interface QueryPartInternal extends QueryPart {
+ /**
+ * Whether a call to {@link #accept(Context)} would render content.
+ *
+ * @deprecated - Calling {@link #rendersContent(Context)} directly on a
+ * {@link QueryPart} is almost always a mistake.
+ */
+ @Deprecated
+ boolean rendersContent(Context> ctx);
+
/**
* This {@link QueryPart} can accept a {@link Context} object
* in order to render a SQL string or to bind its variables.
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPart.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPart.java
index b52aecd083..2935463fff 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPart.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPart.java
@@ -102,6 +102,14 @@ abstract class AbstractQueryPart implements QueryPartInternal {
// The QueryPart and QueryPart internal API
// -------------------------------------------------------------------------
+ /**
+ * Subclasses may override this
+ */
+ @Override
+ public boolean rendersContent(Context> ctx) {
+ return true;
+ }
+
/**
* Subclasses may override this
*/
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java b/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java
index e5fd06ea5b..980a4c7f7d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldProxy.java
@@ -187,6 +187,11 @@ final class FieldProxy implements TableField, QueryPartInternal {
return delegate.generatesCast();
}
+ @Override
+ public final boolean rendersContent(Context> ctx) {
+ return delegate.rendersContent(ctx);
+ }
+
@Override
public final void accept(Context> ctx) {
delegate.accept(ctx);
diff --git a/jOOQ/src/main/java/org/jooq/impl/JSONArray.java b/jOOQ/src/main/java/org/jooq/impl/JSONArray.java
index 4fee3617a2..061642aa6d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/JSONArray.java
+++ b/jOOQ/src/main/java/org/jooq/impl/JSONArray.java
@@ -43,12 +43,9 @@ import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.DSL.unquotedName;
import static org.jooq.impl.DSL.values;
-import static org.jooq.impl.JSONNullClause.ABSENT_ON_NULL;
-import static org.jooq.impl.JSONNullClause.NULL_ON_NULL;
-import static org.jooq.impl.JSONObject.acceptJSONNullClause;
+import static org.jooq.impl.JSONNull.JSONNullType.ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.NULL_ON_NULL;
import static org.jooq.impl.Keywords.K_JSON_ARRAY;
-import static org.jooq.impl.Keywords.K_NULL;
-import static org.jooq.impl.Keywords.K_ON;
import static org.jooq.impl.Names.N_JSON_ARRAY;
import java.util.Collection;
@@ -59,6 +56,7 @@ import org.jooq.Field;
import org.jooq.JSONArrayNullStep;
import org.jooq.Row1;
import org.jooq.Table;
+import org.jooq.impl.JSONNull.JSONNullType;
/**
@@ -73,17 +71,17 @@ final class JSONArray extends AbstractField implements JSONArrayNullStep> args;
- private final JSONNullClause nullClause;
+ private final JSONNullType nullType;
JSONArray(DataType type, Collection extends Field>> args) {
this(type, args, null);
}
- JSONArray(DataType type, Collection extends Field>> args, JSONNullClause nullClause) {
+ JSONArray(DataType type, Collection extends Field>> args, JSONNullType nullType) {
super(N_JSON_ARRAY, type);
this.args = new QueryPartList<>(args);
- this.nullClause = nullClause;
+ this.nullType = nullType;
}
// -------------------------------------------------------------------------
@@ -114,7 +112,7 @@ final class JSONArray extends AbstractField implements JSONArrayNullStep extends AbstractField implements JSONArrayNullStep(args, jsonNull).separator("")).sql(')');
break;
+ }
}
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/JSONArrayAgg.java b/jOOQ/src/main/java/org/jooq/impl/JSONArrayAgg.java
index 6b11d420ad..8a1aa3c0ee 100644
--- a/jOOQ/src/main/java/org/jooq/impl/JSONArrayAgg.java
+++ b/jOOQ/src/main/java/org/jooq/impl/JSONArrayAgg.java
@@ -42,9 +42,8 @@ import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.impl.DSL.groupConcat;
import static org.jooq.impl.DSL.inline;
-import static org.jooq.impl.JSONNullClause.ABSENT_ON_NULL;
-import static org.jooq.impl.JSONNullClause.NULL_ON_NULL;
-import static org.jooq.impl.JSONObject.acceptJSONNullClause;
+import static org.jooq.impl.JSONNull.JSONNullType.ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.NULL_ON_NULL;
import static org.jooq.impl.Names.N_JSONB_AGG;
import static org.jooq.impl.Names.N_JSON_AGG;
import static org.jooq.impl.Names.N_JSON_ARRAYAGG;
@@ -61,6 +60,7 @@ import org.jooq.Field;
import org.jooq.JSONArrayAggOrderByStep;
import org.jooq.OrderField;
import org.jooq.SQLDialect;
+import org.jooq.impl.JSONNull.JSONNullType;
/**
@@ -78,7 +78,7 @@ implements JSONArrayAggOrderByStep {
private static final long serialVersionUID = 1772007627336725780L;
static final Set EMULATE_WITH_GROUP_CONCAT = SQLDialect.supportedBy(MARIADB, MYSQL);
- private JSONNullClause nullClause;
+ private JSONNullType nullType;
JSONArrayAgg(DataType type, Field> arg) {
super(false, N_JSON_ARRAYAGG, type, arg);
@@ -114,7 +114,7 @@ implements JSONArrayAggOrderByStep {
ctx.sql(')');
// TODO: What about a user-defined filter clause?
- if (nullClause == ABSENT_ON_NULL)
+ if (nullType == ABSENT_ON_NULL)
acceptFilterClause(ctx, arguments.get(0).isNotNull());
break;
@@ -139,19 +139,23 @@ implements JSONArrayAggOrderByStep {
ctx.visit(N_JSON_ARRAYAGG).sql('(');
ctx.visit(arguments.get(0));
acceptOrderBy(ctx);
- acceptJSONNullClause(ctx, nullClause);
+
+ JSONNull jsonNull = new JSONNull(nullType);
+ if (jsonNull.rendersContent(ctx))
+ ctx.sql(' ').visit(jsonNull);
+
ctx.sql(')');
}
@Override
public final JSONArrayAgg nullOnNull() {
- nullClause = NULL_ON_NULL;
+ nullType = NULL_ON_NULL;
return this;
}
@Override
public final JSONArrayAgg absentOnNull() {
- nullClause = ABSENT_ON_NULL;
+ nullType = ABSENT_ON_NULL;
return this;
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/JSONNull.java b/jOOQ/src/main/java/org/jooq/impl/JSONNull.java
new file mode 100644
index 0000000000..cacb2ec986
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/JSONNull.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import static org.jooq.SQLDialect.MARIADB;
+import static org.jooq.SQLDialect.MYSQL;
+import static org.jooq.impl.JSONNull.JSONNullType.ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.NULL_ON_NULL;
+import static org.jooq.impl.Keywords.K_ABSENT;
+import static org.jooq.impl.Keywords.K_NULL;
+import static org.jooq.impl.Keywords.K_ON;
+
+import java.util.Set;
+
+import org.jooq.Context;
+import org.jooq.SQLDialect;
+
+/**
+ * @author Lukas Eder
+ */
+final class JSONNull extends AbstractQueryPart {
+
+ /**
+ * Generated UID
+ */
+ private static final long serialVersionUID = 3121287280045911346L;
+ static final Set NO_SUPPORT_ABSENT_ON_NULL = SQLDialect.supportedBy(MARIADB, MYSQL);
+
+ final JSONNullType type;
+
+ JSONNull(JSONNullType type) {
+ this.type = type;
+ }
+
+ @Override
+ public final boolean rendersContent(Context> ctx) {
+ return !NO_SUPPORT_ABSENT_ON_NULL.contains(ctx.dialect()) && type != null;
+ }
+
+ @Override
+ public final void accept(Context> ctx) {
+ if (!NO_SUPPORT_ABSENT_ON_NULL.contains(ctx.dialect()))
+ if (type == NULL_ON_NULL)
+ ctx.visit(K_NULL).sql(' ').visit(K_ON).sql(' ').visit(K_NULL);
+ else if (type == ABSENT_ON_NULL)
+ ctx.visit(K_ABSENT).sql(' ').visit(K_ON).sql(' ').visit(K_NULL);
+ }
+
+ enum JSONNullType {
+ NULL_ON_NULL, ABSENT_ON_NULL
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/JSONNullClause.java b/jOOQ/src/main/java/org/jooq/impl/JSONNullClause.java
deleted file mode 100644
index 8587e05241..0000000000
--- a/jOOQ/src/main/java/org/jooq/impl/JSONNullClause.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Other licenses:
- * -----------------------------------------------------------------------------
- * Commercial licenses for this work are available. These replace the above
- * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
- * database integrations.
- *
- * For more information, please visit: http://www.jooq.org/licenses
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-package org.jooq.impl;
-
-/**
- * @author Lukas Eder
- */
-enum JSONNullClause {
- NULL_ON_NULL, ABSENT_ON_NULL
-}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/JSONObject.java b/jOOQ/src/main/java/org/jooq/impl/JSONObject.java
index ad770ddd91..f74ecf8de8 100644
--- a/jOOQ/src/main/java/org/jooq/impl/JSONObject.java
+++ b/jOOQ/src/main/java/org/jooq/impl/JSONObject.java
@@ -38,8 +38,6 @@
package org.jooq.impl;
import static org.jooq.SQLDialect.H2;
-import static org.jooq.SQLDialect.MARIADB;
-import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.impl.DSL.asterisk;
import static org.jooq.impl.DSL.inline;
@@ -48,18 +46,14 @@ import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.DSL.unquotedName;
import static org.jooq.impl.DSL.values;
-import static org.jooq.impl.JSONNullClause.ABSENT_ON_NULL;
-import static org.jooq.impl.JSONNullClause.NULL_ON_NULL;
-import static org.jooq.impl.Keywords.K_ABSENT;
+import static org.jooq.impl.JSONNull.JSONNullType.ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.NULL_ON_NULL;
import static org.jooq.impl.Keywords.K_JSON_OBJECT;
-import static org.jooq.impl.Keywords.K_NULL;
-import static org.jooq.impl.Keywords.K_ON;
import static org.jooq.impl.Names.N_JSON_MERGE;
import static org.jooq.impl.Names.N_JSON_OBJECT;
import static org.jooq.impl.Names.N_T;
import java.util.Collection;
-import java.util.Set;
import org.jooq.Context;
import org.jooq.DataType;
@@ -68,8 +62,8 @@ import org.jooq.JSONB;
import org.jooq.JSONEntry;
import org.jooq.JSONObjectNullStep;
import org.jooq.Name;
-import org.jooq.SQLDialect;
// ...
+import org.jooq.impl.JSONNull.JSONNullType;
/**
@@ -83,20 +77,19 @@ final class JSONObject extends AbstractField implements JSONObjectNullStep
* Generated UID
*/
private static final long serialVersionUID = 1772007627336725780L;
- static final Set NO_SUPPORT_ABSENT_ON_NULL = SQLDialect.supportedBy(MARIADB, MYSQL);
private final QueryPartList> args;
- private final JSONNullClause nullClause;
+ private final JSONNullType nullType;
JSONObject(DataType type, Collection extends JSONEntry>> args) {
this(type, args, null);
}
- JSONObject(DataType type, Collection extends JSONEntry>> args, JSONNullClause nullClause) {
+ JSONObject(DataType type, Collection extends JSONEntry>> args, JSONNullType nullType) {
super(N_JSON_OBJECT, type);
this.args = new QueryPartList<>(args);
- this.nullClause = nullClause;
+ this.nullType = nullType;
}
// -------------------------------------------------------------------------
@@ -126,12 +119,12 @@ final class JSONObject extends AbstractField implements JSONObjectNullStep
case POSTGRES:
- if (nullClause == ABSENT_ON_NULL)
+ if (nullType == ABSENT_ON_NULL)
ctx.visit(unquotedName(getDataType().getType() == JSONB.class ? "jsonb_strip_nulls" : "json_strip_nulls")).sql('(');
ctx.visit(unquotedName(getDataType().getType() == JSONB.class ? "jsonb_build_object" : "json_build_object")).sql('(').visit(args).sql(')');
- if (nullClause == ABSENT_ON_NULL)
+ if (nullType == ABSENT_ON_NULL)
ctx.sql(')');
break;
@@ -202,27 +195,19 @@ final class JSONObject extends AbstractField implements JSONObjectNullStep
}
private final void acceptStandard(Context> ctx) {
- ctx.visit(K_JSON_OBJECT).sql('(').visit(args);
+ JSONNull jsonNull;
// Workaround for https://github.com/h2database/h2database/issues/2496
if (args.isEmpty() && ctx.family() == H2)
- ctx.visit(K_NULL).sql(' ').visit(K_ON).sql(' ').visit(K_NULL);
+ jsonNull = new JSONNull(NULL_ON_NULL);
else
- acceptJSONNullClause(ctx, nullClause);
+ jsonNull = new JSONNull(nullType);
- ctx.sql(')');
- }
-
- static final void acceptJSONNullClause(Context> ctx, JSONNullClause nullClause) {
- if (!NO_SUPPORT_ABSENT_ON_NULL.contains(ctx.dialect()))
- if (nullClause == NULL_ON_NULL)
- ctx.sql(' ').visit(K_NULL).sql(' ').visit(K_ON).sql(' ').visit(K_NULL);
- else if (nullClause == ABSENT_ON_NULL)
- ctx.sql(' ').visit(K_ABSENT).sql(' ').visit(K_ON).sql(' ').visit(K_NULL);
+ ctx.visit(K_JSON_OBJECT).sql('(').visit(new QueryPartList<>(args, jsonNull).separator("")).sql(')');
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/JSONObjectAgg.java b/jOOQ/src/main/java/org/jooq/impl/JSONObjectAgg.java
index 0c3ffb0444..be415e561d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/JSONObjectAgg.java
+++ b/jOOQ/src/main/java/org/jooq/impl/JSONObjectAgg.java
@@ -43,9 +43,8 @@ import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.jsonObject;
import static org.jooq.impl.DSL.jsonValue;
import static org.jooq.impl.DSL.when;
-import static org.jooq.impl.JSONNullClause.ABSENT_ON_NULL;
-import static org.jooq.impl.JSONNullClause.NULL_ON_NULL;
-import static org.jooq.impl.JSONObject.acceptJSONNullClause;
+import static org.jooq.impl.JSONNull.JSONNullType.ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.NULL_ON_NULL;
import static org.jooq.impl.Names.N_JSONB_OBJECT_AGG;
import static org.jooq.impl.Names.N_JSON_OBJECTAGG;
import static org.jooq.impl.Names.N_JSON_OBJECT_AGG;
@@ -57,6 +56,7 @@ import org.jooq.Field;
import org.jooq.JSON;
import org.jooq.JSONEntry;
import org.jooq.JSONObjectAggNullStep;
+import org.jooq.impl.JSONNull.JSONNullType;
/**
@@ -74,7 +74,7 @@ implements JSONObjectAggNullStep {
private static final long serialVersionUID = 1772007627336725780L;
private final JSONEntry> entry;
- private JSONNullClause nullClause;
+ private JSONNullType nullType;
JSONObjectAgg(DataType type, JSONEntry> entry) {
super(false, N_JSON_OBJECTAGG, type, entry.key(), entry.value());
@@ -101,7 +101,7 @@ implements JSONObjectAggNullStep {
// [#10089] These dialects support non-standard JSON_OBJECTAGG without ABSENT ON NULL support
case MARIADB:
case MYSQL:
- if (nullClause == ABSENT_ON_NULL)
+ if (nullType == ABSENT_ON_NULL)
acceptGroupConcat(ctx);
@@ -124,7 +124,7 @@ implements JSONObjectAggNullStep {
ctx.sql(')');
// TODO: What about a user-defined filter clause?
- if (nullClause == ABSENT_ON_NULL)
+ if (nullType == ABSENT_ON_NULL)
acceptFilterClause(ctx, entry.value().isNotNull());
acceptOverClause(ctx);
@@ -152,7 +152,7 @@ implements JSONObjectAggNullStep {
break;
}
- if (nullClause == ABSENT_ON_NULL)
+ if (nullType == ABSENT_ON_NULL)
value = when(entry.value().isNull(), inline((String) null)).else_((Field) value);
}
@@ -164,7 +164,7 @@ implements JSONObjectAggNullStep {
inline('"'),
DSL.replace(entry.key(), inline('"'), inline("\\\"")),
inline("\":"),
- nullClause == ABSENT_ON_NULL ? value1 : DSL.coalesce(value1, inline("null"))
+ nullType == ABSENT_ON_NULL ? value1 : DSL.coalesce(value1, inline("null"))
)));
acceptOverClause(c);
}
@@ -174,23 +174,25 @@ implements JSONObjectAggNullStep {
}
private final void acceptStandard(Context> ctx) {
- ctx.visit(N_JSON_OBJECTAGG).sql('(');
- ctx.visit(entry);
- acceptJSONNullClause(ctx, nullClause);
- ctx.sql(')');
+ ctx.visit(N_JSON_OBJECTAGG).sql('(').visit(entry);
+ JSONNull jsonNull = new JSONNull(nullType);
+ if (jsonNull.rendersContent(ctx))
+ ctx.sql(' ').visit(jsonNull);
+
+ ctx.sql(')');
acceptOverClause(ctx);
}
@Override
public final JSONObjectAgg nullOnNull() {
- nullClause = NULL_ON_NULL;
+ nullType = NULL_ON_NULL;
return this;
}
@Override
public final JSONObjectAgg absentOnNull() {
- nullClause = ABSENT_ON_NULL;
+ nullType = ABSENT_ON_NULL;
return this;
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
index 2945791da0..ee73a3f7b7 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
@@ -309,8 +309,8 @@ import static org.jooq.impl.DSL.xmlquery;
import static org.jooq.impl.DSL.xmltable;
import static org.jooq.impl.DSL.year;
import static org.jooq.impl.DSL.zero;
-import static org.jooq.impl.JSONNullClause.ABSENT_ON_NULL;
-import static org.jooq.impl.JSONNullClause.NULL_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.JSONNullType.NULL_ON_NULL;
import static org.jooq.impl.Keywords.K_DELETE;
import static org.jooq.impl.Keywords.K_INSERT;
import static org.jooq.impl.Keywords.K_SELECT;
@@ -540,6 +540,7 @@ import org.jooq.conf.RenderNameCase;
import org.jooq.conf.RenderQuotedNames;
import org.jooq.conf.Settings;
import org.jooq.conf.SettingsTools;
+import org.jooq.impl.JSONNull.JSONNullType;
import org.jooq.impl.XMLParse.DocumentOrContent;
import org.jooq.tools.StringUtils;
import org.jooq.tools.reflect.Reflect;
@@ -7196,19 +7197,19 @@ final class ParserImpl implements Parser {
return DSL.jsonArray();
List> result = null;
- JSONNullClause nullClause = parseJSONObjectNullClauseIf(ctx);
+ JSONNullType nullType = parseJSONNullTypeIf(ctx);
- if (nullClause == null) {
+ if (nullType == null) {
result = parseFields(ctx);
- nullClause = parseJSONObjectNullClauseIf(ctx);
+ nullType = parseJSONNullTypeIf(ctx);
}
parse(ctx, ')');
JSONArrayNullStep a = result == null ? DSL.jsonArray() : DSL.jsonArray(result);
- return nullClause == NULL_ON_NULL
+ return nullType == NULL_ON_NULL
? a.nullOnNull()
- : nullClause == ABSENT_ON_NULL
+ : nullType == ABSENT_ON_NULL
? a.absentOnNull()
: a;
}
@@ -7221,7 +7222,7 @@ final class ParserImpl implements Parser {
Field> result;
JSONArrayAggOrderByStep s1;
JSONArrayAggNullStep s2;
- JSONNullClause nullClause;
+ JSONNullType nullType;
parse(ctx, '(');
result = s2 = s1 = DSL.jsonArrayAgg(parseField(ctx));
@@ -7229,8 +7230,8 @@ final class ParserImpl implements Parser {
if (parseKeywordIf(ctx, "ORDER BY"))
result = s2 = s1.orderBy(parseSortSpecification(ctx));
- if ((nullClause = parseJSONObjectNullClauseIf(ctx)) != null)
- result = nullClause == ABSENT_ON_NULL ? s2.absentOnNull() : s2.nullOnNull();
+ if ((nullType = parseJSONNullTypeIf(ctx)) != null)
+ result = nullType == ABSENT_ON_NULL ? s2.absentOnNull() : s2.nullOnNull();
parse(ctx, ')');
return result;
@@ -7246,22 +7247,22 @@ final class ParserImpl implements Parser {
return DSL.jsonObject();
List> result = new ArrayList<>();
- JSONNullClause nullClause = parseJSONObjectNullClauseIf(ctx);
+ JSONNullType nullType = parseJSONNullTypeIf(ctx);
- if (nullClause == null) {
+ if (nullType == null) {
do {
result.add(parseJSONEntry(ctx));
}
while (parseIf(ctx, ','));
- nullClause = parseJSONObjectNullClauseIf(ctx);
+ nullType = parseJSONNullTypeIf(ctx);
}
parse(ctx, ')');
JSONObjectNullStep o = DSL.jsonObject(result);
- return nullClause == NULL_ON_NULL
+ return nullType == NULL_ON_NULL
? o.nullOnNull()
- : nullClause == ABSENT_ON_NULL
+ : nullType == ABSENT_ON_NULL
? o.absentOnNull()
: o;
}
@@ -7273,13 +7274,13 @@ final class ParserImpl implements Parser {
if (parseFunctionNameIf(ctx, "JSON_OBJECTAGG")) {
Field> result;
JSONObjectAggNullStep s1;
- JSONNullClause nullClause;
+ JSONNullType nullType;
parse(ctx, '(');
result = s1 = DSL.jsonObjectAgg(parseJSONEntry(ctx));
- if ((nullClause = parseJSONObjectNullClauseIf(ctx)) != null)
- result = nullClause == ABSENT_ON_NULL ? s1.absentOnNull() : s1.nullOnNull();
+ if ((nullType = parseJSONNullTypeIf(ctx)) != null)
+ result = nullType == ABSENT_ON_NULL ? s1.absentOnNull() : s1.nullOnNull();
parse(ctx, ')');
return result;
@@ -7288,7 +7289,7 @@ final class ParserImpl implements Parser {
return null;
}
- private static final JSONNullClause parseJSONObjectNullClauseIf(ParserContext ctx) {
+ private static final JSONNullType parseJSONNullTypeIf(ParserContext ctx) {
if (parseKeywordIf(ctx, "NULL ON NULL"))
return NULL_ON_NULL;
else if (parseKeywordIf(ctx, "ABSENT ON NULL"))
diff --git a/jOOQ/src/main/java/org/jooq/impl/QueryPartCollectionView.java b/jOOQ/src/main/java/org/jooq/impl/QueryPartCollectionView.java
index 2f3d8a27f2..c8bf501e71 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QueryPartCollectionView.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QueryPartCollectionView.java
@@ -42,12 +42,14 @@ import static java.lang.Boolean.TRUE;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.jooq.Context;
import org.jooq.QueryPart;
+import org.jooq.QueryPartInternal;
import org.jooq.Statement;
/**
@@ -62,6 +64,7 @@ class QueryPartCollectionView extends AbstractQueryPart imp
final Collection wrapped;
int indentSize;
Boolean qualify;
+ String separator;
static QueryPartCollectionView wrap(Collection wrapped) {
return new QueryPartCollectionView<>(wrapped);
@@ -70,6 +73,7 @@ class QueryPartCollectionView extends AbstractQueryPart imp
QueryPartCollectionView(Collection wrapped) {
this.wrapped = wrapped;
this.indentSize = 2;
+ this.separator = ",";
}
/**
@@ -85,13 +89,29 @@ class QueryPartCollectionView extends AbstractQueryPart imp
return this;
}
+ QueryPartCollectionView separator(String newSeparator) {
+ this.separator = newSeparator;
+ return this;
+ }
+
Collection wrapped() {
return wrapped;
}
+ @Override
+ public boolean rendersContent(Context> ctx) {
+ return !isEmpty();
+ }
+
@Override
public /* non-final */ void accept(Context> ctx) {
- int size = size();
+ BitSet rendersContent = new BitSet(size());
+ int i = 0;
+
+ for (T e : this)
+ rendersContent.set(i++, ((QueryPartInternal) e).rendersContent(ctx));
+
+ int size = rendersContent.cardinality();
boolean format = size >= indentSize;
boolean previousQualify = ctx.qualify();
@@ -110,18 +130,23 @@ class QueryPartCollectionView extends AbstractQueryPart imp
}
else {
- boolean indent = format && !TRUE.equals(ctx.data(DATA_LIST_ALREADY_INDENTED));
+ Object previousIndented = ctx.data(DATA_LIST_ALREADY_INDENTED);
+ boolean indent = format && !TRUE.equals(previousIndented);
if (indent)
ctx.formatIndentStart();
- int i = 0;
+ int j = 0;
+ int k = 0;
for (T part : this) {
- if (i++ > 0) {
+ if (!rendersContent.get(j++))
+ continue;
+
+ if (k++ > 0) {
// [#3607] Procedures and functions are not separated by comma
if (!(part instanceof Statement))
- ctx.sql(',');
+ ctx.sql(separator);
if (format)
ctx.formatSeparator();
@@ -131,7 +156,13 @@ class QueryPartCollectionView extends AbstractQueryPart imp
else if (indent)
ctx.formatNewLine();
- ctx.visit(part);
+ if (indent) {
+ ctx.data(DATA_LIST_ALREADY_INDENTED, part instanceof QueryPartCollectionView);
+ ctx.visit(part);
+ ctx.data(DATA_LIST_ALREADY_INDENTED, previousIndented);
+ }
+ else
+ ctx.visit(part);
}
if (indent)
diff --git a/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java b/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java
index c46fb5002b..7fad47b509 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java
@@ -56,7 +56,8 @@ class QueryPartList extends QueryPartListView {
this((Collection) null);
}
- QueryPartList(T[] wrappedList) {
+ @SafeVarargs
+ QueryPartList(T... wrappedList) {
this(asList(wrappedList));
}
@@ -77,4 +78,9 @@ class QueryPartList extends QueryPartListView {
QueryPartList qualify(boolean newQualify) {
return (QueryPartList) super.qualify(newQualify);
}
+
+ @Override
+ QueryPartList separator(String newSeparator) {
+ return (QueryPartList) super.separator(newSeparator);
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/QueryPartListView.java b/jOOQ/src/main/java/org/jooq/impl/QueryPartListView.java
index 709b13c6e9..d68a30c841 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QueryPartListView.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QueryPartListView.java
@@ -83,6 +83,11 @@ class QueryPartListView extends QueryPartCollectionView
return (QueryPartListView) super.qualify(newQualify);
}
+ @Override
+ QueryPartListView separator(String newSeparator) {
+ return (QueryPartListView) super.separator(newSeparator);
+ }
+
@Override
List wrapped() {
return (List) super.wrapped();
diff --git a/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java b/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java
index 82325d37c2..8bd278bc2f 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ScopeMarkers.java
@@ -51,6 +51,11 @@ enum ScopeMarkers implements QueryPartInternal {
BEFORE_FIRST_TOP_LEVEL_CTE,
AFTER_LAST_TOP_LEVEL_CTE;
+ @Override
+ public boolean rendersContent(Context> ctx) {
+ return false;
+ }
+
@Override
public final void accept(Context> ctx) {}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java b/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java
index 941e4fd459..468d893fc6 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java
@@ -63,7 +63,12 @@ final class SelectFieldList extends QueryPartLi
}
@Override
- protected void toSQLEmptyList(Context> ctx) {
+ public final boolean rendersContent(Context> ctx) {
+ return true;
+ }
+
+ @Override
+ protected final void toSQLEmptyList(Context> ctx) {
ctx.visit(AsteriskImpl.INSTANCE);
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java
index f7f3786db9..dab460a466 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java
@@ -115,7 +115,7 @@ import static org.jooq.impl.DSL.xmlagg;
import static org.jooq.impl.DSL.xmlattributes;
import static org.jooq.impl.DSL.xmlelement;
import static org.jooq.impl.JSONArrayAgg.EMULATE_WITH_GROUP_CONCAT;
-import static org.jooq.impl.JSONObject.NO_SUPPORT_ABSENT_ON_NULL;
+import static org.jooq.impl.JSONNull.NO_SUPPORT_ABSENT_ON_NULL;
import static org.jooq.impl.Keywords.K_AND;
import static org.jooq.impl.Keywords.K_BY;
import static org.jooq.impl.Keywords.K_CONNECT_BY;
diff --git a/jOOQ/src/main/java/org/jooq/impl/TableList.java b/jOOQ/src/main/java/org/jooq/impl/TableList.java
index be7b60d056..f6ff2d10ed 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TableList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TableList.java
@@ -69,6 +69,11 @@ final class TableList extends QueryPartList> {
super(wrappedList);
}
+ @Override
+ public final boolean rendersContent(Context> ctx) {
+ return true;
+ }
+
@Override
protected void toSQLEmptyList(Context> ctx) {
ctx.visit(new Dual());
diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java
index b69dc6e2be..29e3b143bd 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Tools.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java
@@ -5125,12 +5125,17 @@ final class Tools {
static final QueryPartList qualify(final Table> table, SelectFieldList fields) {
QueryPartList result = new QueryPartList() {
@Override
- protected void toSQLEmptyList(Context> context) {
+ public final boolean rendersContent(Context> ctx) {
+ return super.rendersContent(ctx);
+ }
+
+ @Override
+ protected final void toSQLEmptyList(Context> context) {
table.asterisk();
}
@Override
- public boolean declaresFields() {
+ public final boolean declaresFields() {
return true;
}
};