Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add xmltype in postgres #1112

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,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, String.class, JDBCType.SQLXML),
XML_ARRAY(143, true, String[].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 @@ -186,8 +186,11 @@ static DataType lookup(Class<?> type) {
for (DataType dataType : values()) {
oidToDataType.put(dataType.id, dataType);
}
encodingTypeToDataType.put(String.class, VARCHAR);
encodingTypeToDataType.put(String[].class, VARCHAR_ARRAY);
// encodingTypeToDataType.put(String.class, VARCHAR);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this commented ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand it, there can only be one mapping per class to a Type. This is the Problem i was talking about in the other comments which we need to solve here - so either there will be a need for a wrapper class or someone can come up with a better solution for this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are totally right, this is because we cannot specify which database type to use in a tuple for a given java type

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there will be something like a new Class like PgXMLType which just holds a String. Would you agree to that?

// encodingTypeToDataType.put(String[].class, VARCHAR_ARRAY);
encodingTypeToDataType.put(String.class, XML);
encodingTypeToDataType.put(String[].class, XML_ARRAY);

encodingTypeToDataType.put(Boolean.class, BOOL);
encodingTypeToDataType.put(Boolean[].class, BOOL_ARRAY);
encodingTypeToDataType.put(Short.class, INT2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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;
Expand Down Expand Up @@ -360,6 +361,12 @@ public static void encodeBinary(DataType id, Object value, ByteBuf buff) {
case MONEY_ARRAY:
binaryEncodeArray((Money[]) value, DataType.MONEY, buff);
break;
case XML:
binaryEncodeXML((String) value, buff);
break;
case XML_ARRAY:
binaryEncodeArray((String[]) 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 +504,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 binaryDecodeXML(index, len, buff);
case XML_ARRAY:
return binaryDecodeArray(STRING_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 +648,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 textDecodeXML(index, len, buff);
case XML_ARRAY:
return textDecodeArray(STRING_ARRAY_FACTORY, DataType.XML, index, len, buff);
default:
return defaultDecodeText(index, len, buff);
}
Expand Down Expand Up @@ -1477,6 +1492,18 @@ private static void binaryEncodeTsQuery(String value, ByteBuf buff) {
buff.writeCharSequence(String.valueOf(value), StandardCharsets.UTF_8);
}

private static String binaryDecodeXML(int index, int len, ByteBuf buff) {
return buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString();
}

private static void binaryEncodeXML(String value, ByteBuf buff) {
buff.writeCharSequence(value, StandardCharsets.UTF_8);
}

private static String textDecodeXML(int index, int len, ByteBuf buff) {
return buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString();
}

private static String textDecodeTsVector(int index, int len, ByteBuf buff) {
return buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString();
}
Expand Down
115 changes: 115 additions & 0 deletions vertx-pg-client/src/test/java/io/vertx/pgclient/data/XMLCodecTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package io.vertx.pgclient.data;

import io.vertx.ext.unit.TestContext;
import io.vertx.pgclient.PgConnection;
import io.vertx.pgclient.PgException;
import io.vertx.sqlclient.*;
import org.junit.Test;

import java.util.function.BiFunction;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class XMLCodecTest extends DataTypeTestBase {

@Test
public void testBinaryEncodePgSQLXMLAsVarcharOrXML(TestContext ctx) {
String asVarchar = "<message><to><be><validated></validated></be></to></message>";
String asXML = "<message><to><be><validated><again></again></validated></be></to></message>";

PgConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
conn.preparedQuery("SELECT ($1::xml)::VARCHAR, ($2::xml)").execute(Tuple.of(asVarchar, asXML),
ctx.asyncAssertSuccess(rows -> {
ctx.assertEquals(1, rows.size());
Row row = rows.iterator().next();
String v1 = row.getString(0);
String v2 = (String)row.getValue(1);
ctx.assertEquals("<message><to><be><validated></validated></be></to></message>", v1);
ctx.assertEquals(asXML, v2);
})
);
}));
}

@Test
public void testBinaryEncodePgSQLXMLMalformed(TestContext ctx) {
String malformedXml = "<message><to><be><validated><malformed>>></validated></be></to></message>";

PgConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
conn.preparedQuery("SELECT ($1::xml)").execute(Tuple.of(malformedXml),
ctx.asyncAssertFailure(err -> {
assertThat(((PgException) err).getCode(), is(equalTo("2200N")));
})
);
}));
}

@Test
public void testTextDecodePgSQLXML(TestContext ctx) {
testDecodePgSQLXML(ctx, SqlClient::query);
}

@Test
public void testBinaryDecodePgSQLXML(TestContext ctx) {
testDecodePgSQLXML(ctx, SqlClient::preparedQuery);
}

private void testDecodePgSQLXML(TestContext ctx, BiFunction<SqlClient, String, Query<RowSet<Row>>> a) {
String first = "<message><to><be><validated></validated></be></to></message>";

PgConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
a.apply(conn, "SELECT '<message><to><be><validated></validated></be></to></message>'::xml")
.execute(ctx.asyncAssertSuccess(rows -> {
ctx.assertEquals(1, rows.size());
Row row = rows.iterator().next();
String v1 = (String) row.getValue(0);
ctx.assertEquals(first, v1);
}));
}));
}

@Test
public void testBinaryDecodePgSQLXMLArray(TestContext ctx) throws Exception {
String first = "<message><to><be><validated></validated></be></to></message>";
String second = "<message><to><be><validated><again></again></validated></be></to></message>";

PgConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
conn.preparedQuery("SELECT ARRAY['<message><to><be><validated></validated></be></to></message>'::xml,'<message><to><be><validated><again></again></validated></be></to></message>'::xml]")
.execute(ctx.asyncAssertSuccess(rows -> {
ctx.assertEquals(1, rows.size());
Row row = rows.iterator().next();
String[] array = (String[]) row.getValue(0);
String v1 = array[0];
String v2 = array[1];
ctx.assertEquals(first, v1);
ctx.assertEquals(second, v2);
}));
}));
}

@Test
public void testBinaryEncodePgSQLXMLArray(TestContext ctx) {
String first = "<message><to><be><validated></validated></be></to></message>";
String second = "<message><to><be><validated><again></again></validated></be></to></message>";


PgConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
conn.preparedQuery("SELECT ($1::xml[])::VARCHAR[]").execute(Tuple.of(
new String[]{
"<message><to><be><validated></validated></be></to></message>",
"<message><to><be><validated><again></again></validated></be></to></message>"}
),
ctx.asyncAssertSuccess(rows -> {
ctx.assertEquals(1, rows.size());
Row row = rows.iterator().next();
String[] array = row.getArrayOfStrings(0);
String v1 = array[0];
String v2 = array[1];
ctx.assertEquals(first, v1);
ctx.assertEquals(second, v2);
}));
}));
}
}