From fb2c870bcf0998abbf932871f0d242763cec0321 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 15 Dec 2021 11:50:31 +0100 Subject: [PATCH] [jOOQ/jOOQ#982] Fix spatial bind values in MySQL MySQL produces an almost WKB style representation from ResultSet, which we can patch to produce the same hex encoded WKB as PostgreSQL. At the same time, we must be able to accept both WKB and WKT content in Spatial::data as bind values, where this makes sense. --- jOOQ/src/main/java/org/jooq/Geometry.java | 1 + jOOQ/src/main/java/org/jooq/Spatial.java | 1 + jOOQ/src/main/java/org/jooq/impl/DSL.java | 98 +++++++++ .../java/org/jooq/impl/DefaultBinding.java | 95 ++++++++ jOOQ/src/main/java/org/jooq/impl/Names.java | 2 + jOOQ/src/main/java/org/jooq/impl/QOM.java | 34 +++ .../main/java/org/jooq/impl/StAsBinary.java | 177 +++++++++++++++ .../java/org/jooq/impl/StGeomFromWKB.java | 207 ++++++++++++++++++ jOOQ/src/main/java/org/jooq/impl/Tools.java | 58 ++++- 9 files changed, 668 insertions(+), 5 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/StAsBinary.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/StGeomFromWKB.java diff --git a/jOOQ/src/main/java/org/jooq/Geometry.java b/jOOQ/src/main/java/org/jooq/Geometry.java index 033db91638..a7fa51f8dd 100644 --- a/jOOQ/src/main/java/org/jooq/Geometry.java +++ b/jOOQ/src/main/java/org/jooq/Geometry.java @@ -116,5 +116,6 @@ package org.jooq; + diff --git a/jOOQ/src/main/java/org/jooq/Spatial.java b/jOOQ/src/main/java/org/jooq/Spatial.java index bf959f1ef2..6bea00dab3 100644 --- a/jOOQ/src/main/java/org/jooq/Spatial.java +++ b/jOOQ/src/main/java/org/jooq/Spatial.java @@ -60,5 +60,6 @@ package org.jooq; + diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 0ccab36cac..1ca7cf9eaf 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -21729,6 +21729,104 @@ public class DSL { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java index 0e6424ffa1..c809636e2a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java @@ -122,6 +122,7 @@ import static org.jooq.impl.Keywords.K_TRUE; import static org.jooq.impl.Keywords.K_YEAR_TO_DAY; import static org.jooq.impl.Keywords.K_YEAR_TO_FRACTION; import static org.jooq.impl.Names.N_ST_GEOMFROMTEXT; +import static org.jooq.impl.Names.N_ST_GEOMFROMWKB; import static org.jooq.impl.R2DBC.isR2dbc; import static org.jooq.impl.SQLDataType.BIGINT; import static org.jooq.impl.SQLDataType.BLOB; @@ -138,11 +139,13 @@ import static org.jooq.impl.SQLDataType.ROWID; import static org.jooq.impl.SQLDataType.SMALLINT; import static org.jooq.impl.SQLDataType.TIME; import static org.jooq.impl.SQLDataType.TIMESTAMP; +import static org.jooq.impl.SQLDataType.VARBINARY; import static org.jooq.impl.SQLDataType.VARCHAR; import static org.jooq.impl.Tools.apply; import static org.jooq.impl.Tools.asInt; import static org.jooq.impl.Tools.attachRecords; import static org.jooq.impl.Tools.convertBytesToHex; +import static org.jooq.impl.Tools.convertHexToBytes; import static org.jooq.impl.Tools.emulateMultiset; import static org.jooq.impl.Tools.enums; // ... @@ -165,6 +168,7 @@ import java.io.StringReader; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.charset.Charset; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; @@ -199,6 +203,7 @@ import java.util.Set; import java.util.UUID; import java.util.function.Function; import java.util.function.Supplier; +import java.util.regex.Pattern; // ... import org.jooq.Attachable; @@ -234,6 +239,7 @@ import org.jooq.RowId; import org.jooq.SQLDialect; import org.jooq.Schema; import org.jooq.Scope; +// ... import org.jooq.TableRecord; import org.jooq.UDT; import org.jooq.UDTField; @@ -5025,6 +5031,95 @@ public class DefaultBinding implements Binding { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Names.java b/jOOQ/src/main/java/org/jooq/impl/Names.java index 495c3e3a63..a651d9c6f6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Names.java +++ b/jOOQ/src/main/java/org/jooq/impl/Names.java @@ -428,6 +428,7 @@ final class Names { static final Name N_STDDEV_POP = unquotedName("stddev_pop"); static final Name N_STDDEV_SAMP = unquotedName("stddev_samp"); static final Name N_ST_AREA = unquotedName("st_area"); + static final Name N_ST_ASBINARY = unquotedName("st_asbinary"); static final Name N_ST_ASTEXT = unquotedName("st_astext"); static final Name N_ST_CENTROID = unquotedName("st_centroid"); static final Name N_ST_CONTAINS = unquotedName("st_contains"); @@ -441,6 +442,7 @@ final class Names { static final Name N_ST_GEOMETRYN = unquotedName("st_geometryn"); static final Name N_ST_GEOMETRYTYPE = unquotedName("st_geometrytype"); static final Name N_ST_GEOMFROMTEXT = unquotedName("st_geomfromtext"); + static final Name N_ST_GEOMFROMWKB = unquotedName("st_geomfromwkb"); static final Name N_ST_INTERIORRINGN = unquotedName("st_interiorringn"); static final Name N_ST_INTERSECTION = unquotedName("st_intersection"); static final Name N_ST_INTERSECTS = unquotedName("st_intersects"); diff --git a/jOOQ/src/main/java/org/jooq/impl/QOM.java b/jOOQ/src/main/java/org/jooq/impl/QOM.java index 4302c2554d..9c051238fe 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QOM.java +++ b/jOOQ/src/main/java/org/jooq/impl/QOM.java @@ -5534,6 +5534,40 @@ public final class QOM { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/StAsBinary.java b/jOOQ/src/main/java/org/jooq/impl/StAsBinary.java new file mode 100644 index 0000000000..723d3df8d4 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/StAsBinary.java @@ -0,0 +1,177 @@ +/* + * 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; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/StGeomFromWKB.java b/jOOQ/src/main/java/org/jooq/impl/StGeomFromWKB.java new file mode 100644 index 0000000000..1d634d40ee --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/StGeomFromWKB.java @@ -0,0 +1,207 @@ +/* + * 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; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index c80f650ad4..9555a503b6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -938,7 +938,16 @@ final class Tools { * All hexadecimal digits accessible through array index, e.g. * HEX_DIGITS[15] == 'f'. */ - private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); + private static final byte[] HEX_LOOKUP = { + /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + /* 0x40 */ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 */ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; static final Set REQUIRES_BACKSLASH_ESCAPING = SQLDialect.supportedBy(MARIADB, MYSQL); static final Set NO_SUPPORT_NULL = SQLDialect.supportedBy(DERBY, FIREBIRD, HSQLDB); @@ -5858,14 +5867,17 @@ final class Tools { * @param len the number of bytes to encode * @return the hex encoded string */ - static final String convertBytesToHex(byte[] value, int len) { - char[] buff = new char[len + len]; + static final String convertBytesToHex(byte[] value, int offset, int len) { + len = Math.min(value.length - offset, len); + char[] buff = new char[2 * len]; char[] hex = HEX_DIGITS; + for (int i = 0; i < len; i++) { - int c = value[i] & 0xff; + int c = value[i + offset] & 0xff; buff[i + i] = hex[c >> 4]; buff[i + i + 1] = hex[c & 0xf]; } + return new String(buff); } @@ -5876,7 +5888,43 @@ final class Tools { * @return the hex encoded string */ static final String convertBytesToHex(byte[] value) { - return convertBytesToHex(value, value.length); + return convertBytesToHex(value, 0, value.length); + } + + /** + * Convert a hex encoded string to a byte array. + * + * @param value the hex encoded string + * @param len the number of bytes to encode + * @return the byte array + */ + static final byte[] convertHexToBytes(String value, int offset, int len) { + len = Math.min(value.length() / 2 - offset, len); + byte[] buff = new byte[len]; + byte[] lookup = HEX_LOOKUP; + int max = lookup.length; + + for (int i = 0; i < len; i++) { + int pos = (i + offset) * 2; + char c1 = value.charAt(pos); + char c2 = value.charAt(pos + 1); + byte v1 = c1 < max ? lookup[c1] : 0; + byte v2 = c2 < max ? lookup[c2] : 0; + + buff[i] = (byte) ((v1 << 4) + v2); + } + + return buff; + } + + /** + * Convert a hex encoded string to a byte array. + * + * @param value the hex encoded string + * @return the byte array + */ + static final byte[] convertHexToBytes(String value) { + return convertHexToBytes(value, 0, value.length()); } static final boolean isNotEmpty(Collection collection) {