diff --git a/jOOQ/src/main/java/org/jooq/Data.java b/jOOQ/src/main/java/org/jooq/Data.java new file mode 100644 index 0000000000..ab8a2e66f3 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/Data.java @@ -0,0 +1,79 @@ +/* + * 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 + * + * https://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 + * Apache-2.0 license and offer limited warranties, support, maintenance, and + * commercial database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq; + +import java.io.Serializable; +import java.sql.SQLXML; + +import org.jetbrains.annotations.NotNull; + +/** + * A type holding {@link #data()}, which is a {@link String} based + * representation of a SQL data type with no reasonable representation in the + * JDK or in JDBC. + *
+ * JDBC maps most types to JDK types, but some vendor specific types lack an + * equivalent in the JDK, or the relevant type is unsatisfactory (such as + * {@link SQLXML}, which is a resource). To work around such limitations, jOOQ + * establishes the set of {@link Data} types, with these properties: + *
+ *
CAST(NULL AS …) value is represented by a
+ * null reference of type {@link Data}, not as
+ * data() == null. This is consistent with jOOQ's general way of
+ * returning NULL from {@link Result} and {@link Record}
+ * methods.DECFLOAT data types.
+ *
+ * The wrapper represents DECFLOAT {@link #data()} in serialised string form. A
+ * CAST(NULL AS DECFLOAT) value is represented by a
+ * null reference of type {@link Decfloat}, not as
+ * data() == null. This is consistent with jOOQ's general way of
+ * returning NULL from {@link Result} and {@link Record} methods.
+ */
+public class Decfloat implements Data {
+
+ private final String data;
+ private transient BigDecimal coefficient;
+ private transient int exponent;
+ private transient Special special;
+
+ private Decfloat(String data) {
+ this.data = String.valueOf(data);
+ }
+
+ @Override
+ @NotNull
+ public final String data() {
+ return data;
+ }
+
+ /**
+ * Create a new {@link Decfloat} instance from string data input.
+ */
+ @NotNull
+ public static final Decfloat valueOf(String data) {
+ return new Decfloat(data);
+ }
+
+ /**
+ * Create a new {@link Decfloat} instance from string data input.
+ *
+ * This is the same as {@link #valueOf(String)}, but it can be static
+ * imported.
+ */
+ @NotNull
+ public static final Decfloat decfloat(String data) {
+ return new Decfloat(data);
+ }
+
+ /**
+ * Create a new {@link Decfloat} instance from string data input, or
+ * null if the input is null.
+ */
+ @Nullable
+ public static final Decfloat decfloatOrNull(String data) {
+ return data == null ? null : decfloat(data);
+ }
+
+ @Override
+ public int hashCode() {
+ parse();
+
+ if (special != null) {
+ return special.hashCode();
+ }
+ else if (coefficient != null) {
+ final int prime = 31;
+ int result = 1;
+
+ result = prime * result + ((coefficient == null) ? 0 : coefficient.hashCode());
+ result = prime * result + exponent;
+
+ return result;
+ }
+ else
+ return data.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj instanceof Decfloat x) {
+ parse();
+ x.parse();
+
+ if (special != null && x.special != null)
+ return special == x.special;
+ else if (coefficient != null && x.coefficient != null)
+ return Objects.equals(coefficient, x.coefficient) && exponent == x.exponent;
+ else
+ return Objects.equals(data, x.data);
+ }
+ return false;
+
+ }
+
+ @Override
+ public String toString() {
+ parse();
+
+ if (special != null) {
+ switch (special) {
+ case NAN:
+ return "NaN";
+ case POSITIVE_INFINITY:
+ return "Infinity";
+ case NEGATIVE_INFINITY:
+ return "-Infinity";
+ }
+ }
+ else if (coefficient != null)
+ return coefficient + "E" + exponent;
+
+ return String.valueOf(data);
+ }
+
+ private void parse() {
+ if (coefficient != null || special != null)
+ return;
+
+ switch (data) {
+ case "+NaN":
+ case "NaN":
+ special = Special.NAN;
+ break;
+
+ case "+Infinity":
+ case "Infinity":
+ case "+Inf":
+ case "Inf":
+ special = Special.POSITIVE_INFINITY;
+ break;
+
+ case "-Infinity":
+ case "-Inf":
+ special = Special.NEGATIVE_INFINITY;
+ break;
+
+ default: {
+ int i = data.indexOf("E");
+ if (i == -1)
+ i = data.indexOf("e");
+
+ try {
+ coefficient = new BigDecimal(data.substring(0, i)).stripTrailingZeros();
+ exponent = Integer.parseInt(data.substring(i + 1));
+ }
+
+ // [#10880] If we cannot represent the value internally, then we'll just work with data
+ catch (NumberFormatException ignore) {}
+ break;
+ }
+ }
+ }
+
+ private enum Special {
+ NAN, POSITIVE_INFINITY, NEGATIVE_INFINITY
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/JSON.java b/jOOQ/src/main/java/org/jooq/JSON.java
index 3ae4bca40c..621fd6adcd 100644
--- a/jOOQ/src/main/java/org/jooq/JSON.java
+++ b/jOOQ/src/main/java/org/jooq/JSON.java
@@ -37,8 +37,6 @@
*/
package org.jooq;
-import java.io.Serializable;
-
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -68,7 +66,7 @@ import org.jetbrains.annotations.Nullable;
*
* The {@link #data()} content, however, is not normalised. */ -public final class JSONB implements Serializable { +public final class JSONB implements Data { private final String data; private transient Object parsed; @@ -84,6 +83,7 @@ public final class JSONB implements Serializable { this.data = String.valueOf(data); } + @Override @NotNull public final String data() { return data; diff --git a/jOOQ/src/main/java/org/jooq/Spatial.java b/jOOQ/src/main/java/org/jooq/Spatial.java index 62c4d45694..0936137972 100644 --- a/jOOQ/src/main/java/org/jooq/Spatial.java +++ b/jOOQ/src/main/java/org/jooq/Spatial.java @@ -37,10 +37,6 @@ */ package org.jooq; -import java.io.Serializable; - -import org.jetbrains.annotations.NotNull; - /** * A wrapper type for spatial data obtained from the database. *
@@ -54,9 +50,7 @@ import org.jetbrains.annotations.NotNull; *
* This data type is supported only by the commercial editions of jOOQ.
*/
-public interface Spatial extends Serializable {
+public interface Spatial extends Data {
- @NotNull
- String data();
}
diff --git a/jOOQ/src/main/java/org/jooq/XML.java b/jOOQ/src/main/java/org/jooq/XML.java
index 8fae2e32ac..a550274caf 100644
--- a/jOOQ/src/main/java/org/jooq/XML.java
+++ b/jOOQ/src/main/java/org/jooq/XML.java
@@ -37,8 +37,6 @@
*/
package org.jooq;
-import java.io.Serializable;
-
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,7 +49,7 @@ import org.jetbrains.annotations.Nullable;
* consistent with jOOQ's general way of returning
+ * This is not a JDBC standard. This type handles DECFLOAT types where they
+ * are supported.
+ *
+ * If you want to opt out of code generation support for this type, you can
+ * specify
+ * This is not a JDBC standard. This type handles DECFLOAT types where they
+ * are supported.
+ *
+ * If you want to opt out of code generation support for this type, you can
+ * specify NULL from
* {@link Result} and {@link Record} methods.
*/
-public final class XML implements Serializable {
+public final class XML implements Data {
private final String data;
@@ -59,6 +57,7 @@ public final class XML implements Serializable {
this.data = String.valueOf(data);
}
+ @Override
@NotNull
public final String data() {
return data;
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
index 05ce79f059..878f9f6eb9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
@@ -50,6 +50,8 @@ import static java.util.Arrays.asList;
import static java.util.function.Function.identity;
import static java.util.regex.Matcher.quoteReplacement;
import static org.jooq.ContextConverter.scoped;
+import static org.jooq.Decfloat.decfloat;
+import static org.jooq.Decfloat.decfloatOrNull;
import static org.jooq.Geography.geography;
import static org.jooq.Geometry.geometry;
// ...
@@ -257,6 +259,7 @@ import org.jooq.Converter;
import org.jooq.ConverterContext;
import org.jooq.Converters;
import org.jooq.DataType;
+import org.jooq.Decfloat;
import org.jooq.EnumType;
import org.jooq.ExecuteScope;
import org.jooq.Field;
@@ -376,6 +379,8 @@ public class DefaultBinding/configuration/generator/generate/decfloatTypes to
+ * false.
+ */
+ public static final DataType/configuration/generator/generate/decfloatTypes to
+ * false.
+ */
+ public static final DataType