Skip to content

Commit

Permalink
add support for xmltype in postgres
Browse files Browse the repository at this point in the history
Signed-off-by: Meier Roman <[email protected]>
  • Loading branch information
Roman Meier committed Dec 22, 2021
1 parent e430bd8 commit 37a791e
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 41 deletions.
36 changes: 36 additions & 0 deletions vertx-pg-client/src/main/java/io/vertx/pgclient/data/PgSQLXML.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.vertx.pgclient.data;

import io.vertx.codegen.annotations.Nullable;

import java.util.Objects;

public class PgSQLXML {

@Nullable final String xmlData;

public PgSQLXML(String xmlData) {
this.xmlData = xmlData;
}

public String getXmlData() {
return xmlData;
}

@Override
public String toString() {
return xmlData;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PgSQLXML pgSQLXML = (PgSQLXML) o;
return Objects.equals(xmlData, pgSQLXML.xmlData);
}

@Override
public int hashCode() {
return Objects.hash(xmlData);
}
}
21 changes: 13 additions & 8 deletions vertx-pg-client/src/main/java/io/vertx/pgclient/impl/RowImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,9 @@

import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.pgclient.data.Box;
import io.vertx.pgclient.data.Circle;
import io.vertx.pgclient.data.Line;
import io.vertx.pgclient.data.LineSegment;
import io.vertx.pgclient.data.*;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.data.Numeric;
import io.vertx.pgclient.data.Path;
import io.vertx.pgclient.data.Polygon;
import io.vertx.pgclient.data.Interval;
import io.vertx.pgclient.data.Point;
import io.vertx.sqlclient.impl.ArrayTuple;
import io.vertx.sqlclient.impl.RowDesc;
import io.vertx.core.buffer.Buffer;
Expand Down Expand Up @@ -118,6 +111,8 @@ public <T> T get(Class<T> type, int position) {
return type.cast(getArrayOfIntervals(position));
} else if (componentType == Box.class) {
return type.cast(getArrayOfBoxs(position));
} else if (componentType == PgSQLXML.class) {
return type.cast(getArrayOfPgXMLSQLs(position));
} else if (componentType == Object.class) {
return type.cast(getJsonArray_(position));
} else if (componentType.isEnum()) {
Expand Down Expand Up @@ -174,6 +169,8 @@ public <T> T get(Class<T> type, int position) {
return type.cast(getJson(position));
} else if (type == JsonArray.class) {
return type.cast(getJson(position));
} else if (type == PgSQLXML.class) {
return type.cast(getPgSQLXML(position));
} else if (type == Object.class) {
return type.cast(getValue(position));
} else if (type.isEnum()) {
Expand Down Expand Up @@ -215,6 +212,10 @@ private Interval getInterval(int pos) {
return (Interval) getValue(pos);
}

private PgSQLXML getPgSQLXML(int pos) {
return (PgSQLXML) getValue(pos);
}

private Object getEnum(Class enumType, int pos) {
Object val = getValue(pos);
if (val instanceof String) {
Expand Down Expand Up @@ -270,6 +271,10 @@ private Interval[] getArrayOfIntervals(int pos) {
return (Interval[]) getValue(pos);
}

private PgSQLXML[] getArrayOfPgXMLSQLs(int pos) {
return (PgSQLXML[]) getValue(pos);
}

private Object[] getArrayOfEnums(Class enumType, int pos) {
Object val = getValue(pos);
if (val instanceof String[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,9 @@
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.pgclient.data.Box;
import io.vertx.pgclient.data.Circle;
import io.vertx.pgclient.data.Inet;
import io.vertx.pgclient.data.Line;
import io.vertx.pgclient.data.LineSegment;
import io.vertx.pgclient.data.Money;
import io.vertx.pgclient.data.*;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.data.Numeric;
import io.vertx.pgclient.data.Interval;
import io.vertx.pgclient.data.Path;
import io.vertx.pgclient.data.Point;
import io.vertx.pgclient.data.Polygon;
import io.vertx.core.buffer.Buffer;

import java.sql.JDBCType;
Expand Down Expand Up @@ -105,8 +96,8 @@ public enum DataType {
JSON_ARRAY(199, true, Object[].class, JDBCType.OTHER, Tuple::getArrayOfJsons),
JSONB(3802, true, Object.class, JDBCType.OTHER, Tuple::getJson),
JSONB_ARRAY(3807, true, Object[].class, JDBCType.OTHER, Tuple::getArrayOfJsons),
XML(142, true, Object.class, JDBCType.OTHER),
XML_ARRAY(143, true, Object[].class, JDBCType.OTHER),
XML(142, true, Object.class, JDBCType.SQLXML),
XML_ARRAY(143, true, Object[].class, JDBCType.SQLXML),
POINT(600, true, Point.class, JDBCType.OTHER),
POINT_ARRAY(1017, true, Point[].class, JDBCType.OTHER),
LINE(628, true, Line.class, JDBCType.OTHER),
Expand Down Expand Up @@ -229,5 +220,8 @@ static DataType lookup(Class<?> type) {
encodingTypeToDataType.put(Polygon[].class, POLYGON_ARRAY);
encodingTypeToDataType.put(Circle.class, CIRCLE);
encodingTypeToDataType.put(Circle[].class, CIRCLE_ARRAY);

encodingTypeToDataType.put(PgSQLXML.class, XML);
encodingTypeToDataType.put(PgSQLXML[].class, XML_ARRAY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.DecoderException;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.Json;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.data.Numeric;
import io.vertx.pgclient.data.*;
import io.vertx.pgclient.impl.util.UTF8StringEndDetector;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.pgclient.data.*;
import io.vertx.pgclient.impl.util.UTF8StringEndDetector;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.data.Numeric;
import io.vertx.sqlclient.impl.codec.CommonCodec;

import java.net.Inet4Address;
Expand All @@ -50,7 +50,7 @@

import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME;
import static java.util.concurrent.TimeUnit.*;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

/**
* @author <a href="mailto:[email protected]">Julien Viet</a>
Expand Down Expand Up @@ -91,6 +91,8 @@ public class DataTypeCodec {
private static final OffsetDateTime OFFSET_DATE_TIME_EPOCH = LocalDateTime.of(2000, 1, 1, 0, 0, 0).atOffset(ZoneOffset.UTC);
private static final Inet[] empty_inet_array = new Inet[0];
private static final Money[] empty_money_array = new Money[0];
private static final PgSQLXML[] empty_pgsqlxml_array = new PgSQLXML[0];


// Sentinel used when an object is refused by the data type
public static final Object REFUSED_SENTINEL = new Object();
Expand All @@ -107,7 +109,7 @@ public class DataTypeCodec {
private static final IntFunction<OffsetTime[]> OFFSETTIME_ARRAY_FACTORY = size -> size == 0 ? empty_offset_time_array : new OffsetTime[size];
private static final IntFunction<LocalDateTime[]> LOCALDATETIME_ARRAY_FACTORY = size -> size == 0 ? empty_local_date_time_array : new LocalDateTime[size];
private static final IntFunction<OffsetDateTime[]> OFFSETDATETIME_ARRAY_FACTORY = size -> size == 0 ? empty_offset_date_time_array : new OffsetDateTime[size];
private static final IntFunction<Buffer[]> BUFFER_ARRAY_FACTORY =size -> size == 0 ? empty_buffer_array : new Buffer[size];
private static final IntFunction<Buffer[]> BUFFER_ARRAY_FACTORY = size -> size == 0 ? empty_buffer_array : new Buffer[size];
private static final IntFunction<UUID[]> UUID_ARRAY_FACTORY = size -> size == 0 ? empty_uuid_array : new UUID[size];
private static final IntFunction<Object[]> JSON_ARRAY_FACTORY = size -> size == 0 ? empty_json_array : new Object[size];
private static final IntFunction<Numeric[]> NUMERIC_ARRAY_FACTORY = size -> size == 0 ? empty_numeric_array : new Numeric[size];
Expand All @@ -121,20 +123,18 @@ public class DataTypeCodec {
private static final IntFunction<Interval[]> INTERVAL_ARRAY_FACTORY = size -> size == 0 ? empty_interval_array : new Interval[size];
private static final IntFunction<Inet[]> INET_ARRAY_FACTORY = size -> size == 0 ? empty_inet_array : new Inet[size];
private static final IntFunction<Money[]> MONEY_ARRAY_FACTORY = size -> size == 0 ? empty_money_array : new Money[size];

private static final IntFunction<PgSQLXML[]> PGSQLXML_ARRAY_FACTORY = size -> size == 0 ? empty_pgsqlxml_array : new PgSQLXML[size];
private static final java.time.format.DateTimeFormatter TIMETZ_FORMAT = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_TIME)
.appendOffset("+HH:mm", "00:00")
.toFormatter();

private static final java.time.format.DateTimeFormatter TIMESTAMP_FORMAT = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(ISO_LOCAL_TIME)
.toFormatter();

private static final java.time.format.DateTimeFormatter TIMESTAMPTZ_FORMAT = new DateTimeFormatterBuilder()
.append(TIMESTAMP_FORMAT)
.appendOffset("+HH:mm", "00:00")
Expand Down Expand Up @@ -360,6 +360,12 @@ public static void encodeBinary(DataType id, Object value, ByteBuf buff) {
case MONEY_ARRAY:
binaryEncodeArray((Money[]) value, DataType.MONEY, buff);
break;
case XML:
binaryEncodePgXMLSQL((PgSQLXML) value, buff);
break;
case XML_ARRAY:
binaryEncodeArray((PgSQLXML[]) value, DataType.XML, buff);
break;
default:
logger.debug("Data type " + id + " does not support binary encoding");
defaultEncodeBinary(value, buff);
Expand Down Expand Up @@ -497,6 +503,10 @@ public static Object decodeBinary(DataType id, int index, int len, ByteBuf buff)
return binaryDecodeMoney(index, len, buff);
case MONEY_ARRAY:
return binaryDecodeArray(MONEY_ARRAY_FACTORY, DataType.MONEY, index, len, buff);
case XML:
return binaryDecodePgXMLSQL(index, len, buff);
case XML_ARRAY:
return binaryDecodeArray(PGSQLXML_ARRAY_FACTORY, DataType.XML, index, len, buff);
default:
logger.debug("Data type " + id + " does not support binary decoding");
return defaultDecodeBinary(index, len, buff);
Expand Down Expand Up @@ -637,6 +647,10 @@ public static Object decodeText(DataType id, int index, int len, ByteBuf buff) {
return textDecodeMoney(index, len, buff);
case MONEY_ARRAY:
return textDecodeArray(MONEY_ARRAY_FACTORY, DataType.MONEY, index, len, buff);
case XML:
return textDecodePgSQLXML(index, len, buff);
case XML_ARRAY:
return textDecodeArray(PGSQLXML_ARRAY_FACTORY, DataType.XML, index, len, buff);
default:
return defaultDecodeText(index, len, buff);
}
Expand Down Expand Up @@ -669,7 +683,7 @@ private static Boolean binaryDecodeBOOL(int index, int len, ByteBuf buff) {
}

private static Boolean textDecodeBOOL(int index, int len, ByteBuf buff) {
if(buff.getByte(index) == 't') {
if (buff.getByte(index) == 't') {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
Expand Down Expand Up @@ -770,7 +784,7 @@ private static Line textDecodeLine(int index, int len, ByteBuf buff) {

private static LineSegment textDecodeLseg(int index, int len, ByteBuf buff) {
// Lseg representation: [p1,p2]
int idxOfPointsSeparator = buff.indexOf(index, index+len, (byte) ')') + 1;
int idxOfPointsSeparator = buff.indexOf(index, index + len, (byte) ')') + 1;
int lenOfP1 = idxOfPointsSeparator - index - 1;
Point p1 = textDecodePOINT(index + 1, lenOfP1, buff);
Point p2 = textDecodePOINT(idxOfPointsSeparator + 1, len - lenOfP1 - 3, buff);
Expand All @@ -779,7 +793,7 @@ private static LineSegment textDecodeLseg(int index, int len, ByteBuf buff) {

private static Box textDecodeBox(int index, int len, ByteBuf buff) {
// Box representation: p1,p2
int idxOfPointsSeparator = buff.indexOf(index, index+len, (byte) ')') + 1;
int idxOfPointsSeparator = buff.indexOf(index, index + len, (byte) ')') + 1;
int lenOfUpperRightCornerPoint = idxOfPointsSeparator - index;
Point upperRightCorner = textDecodePOINT(index, lenOfUpperRightCornerPoint, buff);
Point lowerLeftCorner = textDecodePOINT(idxOfPointsSeparator + 1, len - lenOfUpperRightCornerPoint - 1, buff);
Expand Down Expand Up @@ -905,7 +919,7 @@ private static Interval textDecodeINTERVAL(int index, int len, ByteBuf buff) {
: Integer.parseInt(timeChunk.substring(sidx));
} else {
// seconds with microseconds
seconds = isNeg ? -Integer.parseInt(timeChunk.substring(sidx).substring(0, m))
seconds = isNeg ? -Integer.parseInt(timeChunk.substring(sidx).substring(0, m))
: Integer.parseInt(timeChunk.substring(sidx).substring(0, m));
microseconds = isNeg ? -Integer.parseInt(timeChunk.substring(sidx).substring(m + 1))
: Integer.parseInt(timeChunk.substring(sidx).substring(m + 1));
Expand Down Expand Up @@ -990,7 +1004,6 @@ private static String textDecodeNAME(int index, int len, ByteBuf buff) {
return buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString();
}


private static void binaryEncodeNAME(String value, ByteBuf buff) {
String s = String.valueOf(value);
buff.writeCharSequence(s, StandardCharsets.UTF_8);
Expand Down Expand Up @@ -1466,7 +1479,7 @@ private static void binaryEncodeMoney(Money money, ByteBuf buff) {

private static Money binaryDecodeMoney(int index, int len, ByteBuf buff) {
long value = binaryDecodeINT8(index, len, buff);
return new Money(value / 100, Math.abs(((int)value % 100)));
return new Money(value / 100, Math.abs(((int) value % 100)));
}

private static String binaryDecodeTsQuery(int index, int len, ByteBuf buff) {
Expand All @@ -1477,6 +1490,19 @@ private static void binaryEncodeTsQuery(String value, ByteBuf buff) {
buff.writeCharSequence(String.valueOf(value), StandardCharsets.UTF_8);
}

private static PgSQLXML binaryDecodePgXMLSQL(int index, int len, ByteBuf buff) {
return new PgSQLXML(buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString());
}

private static void binaryEncodePgXMLSQL(PgSQLXML value, ByteBuf buff) {
buff.writeCharSequence(value.toString(), StandardCharsets.UTF_8);
}

private static PgSQLXML textDecodePgSQLXML(int index, int len, ByteBuf buff) {
String s = textDecodeVARCHAR(index, len, buff);
return new PgSQLXML(s);
}

private static String textDecodeTsVector(int index, int len, ByteBuf buff) {
return buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString();
}
Expand Down Expand Up @@ -1535,7 +1561,7 @@ private static Money textDecodeMoney(int index, int len, ByteBuf buff) {
* Decode the specified {@code buff} formatted as an hex string starting at the buffer readable index
* with the specified {@code length} to a {@link Buffer}.
*
* @param len the hex string length
* @param len the hex string length
* @param buff the byte buff to read from
* @return the decoded value as a Buffer
*/
Expand All @@ -1551,7 +1577,7 @@ private static Buffer decodeHexStringToBytes(int index, int len, ByteBuf buff) {
}

private static byte decodeHexChar(byte ch) {
return (byte)(((ch & 0x1F) + ((ch >> 6) * 0x19) - 0x10) & 0x0F);
return (byte) (((ch & 0x1F) + ((ch >> 6) * 0x19) - 0x10) & 0x0F);
}

private static boolean isHexFormat(int index, int len, ByteBuf buff) {
Expand Down Expand Up @@ -1619,7 +1645,7 @@ private static <T> T[] binaryDecodeArray(IntFunction<T[]> supplier, DataType typ
return array;
}

private static <T> void binaryEncodeArray(T[] values, DataType type, ByteBuf buff){
private static <T> void binaryEncodeArray(T[] values, DataType type, ByteBuf buff) {
int startIndex = buff.writerIndex();
buff.writeInt(1); // ndim
buff.writeInt(0); // dataoffset
Expand Down Expand Up @@ -1681,7 +1707,7 @@ private static <T> T textDecodeArrayElement(DataType type, int index, int len, B
// Some escaping - improve that later...
String s = buff.toString(index + 1, len - 2, StandardCharsets.UTF_8);
StringBuilder sb = new StringBuilder();
for (int i = 0;i < s.length();i++) {
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\\') {
c = s.charAt(++i);
Expand All @@ -1696,7 +1722,7 @@ private static <T> T textDecodeArrayElement(DataType type, int index, int len, B
}
}

private static <T> void textEncodeArray(T[] values, DataType type, ByteBuf buff){
private static <T> void textEncodeArray(T[] values, DataType type, ByteBuf buff) {
buff.writeByte('{');
int len = values.length;
for (int i = 0; i < len; i++) {
Expand Down
Loading

0 comments on commit 37a791e

Please sign in to comment.