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

feat: support pgx in extended mode #82

Merged
merged 10 commits into from
Apr 10, 2022

Conversation

olavloite
Copy link
Collaborator

Adds support and tests for PGX in extended query mode. This also fixes
some minor issues with sending bytea values in text format. bytea values
in text format should use the newer hex format, as some newer drivers
will not understand the older octal format. Also, any '' characters in
a literal in an array must be escaped.

The Golang PGX driver will by default use extended mode in combination
with DescribeStatement. The problem with DescribeStatement is that we
currently do not have any way of really supporting it. We therefore need
a patch in PGX to be able to work with it. However, that patch is also
valuable for other users of PGX, and hopefully we will be able to get it
merged in the main line of PGX.

Adds support and tests for PGX in extended query mode. This also fixes
some minor issues with sending bytea values in text format. bytea values
in text format should use the newer hex format, as some newer drivers
will not understand the older octal format. Also, any '\' characters in
a literal in an array must be escaped.

The Golang PGX driver will by default use extended mode in combination
with DescribeStatement. The problem with DescribeStatement is that we
currently do not have any way of really supporting it. We therefore need
a patch in PGX to be able to work with it. However, that patch is also
valuable for other users of PGX, and hopefully we will be able to get it
merged in the main line of PGX.
@@ -118,6 +118,9 @@ private boolean stringEquivalence(Code arrayElementType) {
*/
private String stringify(String value) {
if (this.isStringEquivalent) {
if (value.indexOf('\\') > -1) {
value = value.replace("\\", "\\\\");
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As these values are stringifyed, they also need to escape any backslashes inside the strings.

@@ -63,7 +64,7 @@ public int getSqlType() {

@Override
protected String stringParse() {
return this.item == null ? null : PGbytea.toPGString(this.item.toByteArray());
return this.item == null ? null : "\\x" + Utils.toHexString(this.item.toByteArray());
Copy link
Collaborator Author

@olavloite olavloite Mar 25, 2022

Choose a reason for hiding this comment

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

PGAdapter should use the newer hex format when sending bytea values as text: https://www.postgresql.org/docs/current/datatype-binary.html#id-1.5.7.12.9

pgx only supports this hex format, and will refuse the older escape format

@@ -209,7 +209,7 @@ public static int toOid(Type type) {
case BYTES:
return Oid.BYTEA;
case TIMESTAMP:
return Oid.TIMESTAMP;
return Oid.TIMESTAMPTZ;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The timestamps that we return do contain a timezone.

@@ -62,7 +62,7 @@ public short getParameterFormatCode(int index) {
@Override
public short getResultFormatCode(int index) {
if (this.resultFormatCodes == null || this.resultFormatCodes.isEmpty()) {
return 0;
return super.getResultFormatCode(index);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Bubble up to the super implementation. This does nothing at the moment, but we should implement a smarter default than just return 0 (text) when the client did not specify what it wants. That gives us the freedom to choose the binary format when we think that is better.

// See https://github.com/googleapis/java-spanner/pull/1691
resultSet.next();
return new DescribeStatementMetadata(getParameterTypes(), resultSet);
if (PARSER.isQuery(this.sql)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We should not try to describe a DML using analyzeQuery. Instead, we should just return the parameter types.

golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/text v0.3.6 // indirect
)

replace github.com/jackc/pgx/v4 => github.com/olavloite/pgx/v4 v4.15.1
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the patch for the pgx driver that enables skipping the DescribeStatement message, as it is not needed. The JDBC driver already does this.

@@ -305,7 +305,7 @@ public void testTimestampParsingTimestampValidityChecks() {
public void testBinaryParsing() {
ByteArray value = ByteArray.copyFrom(new byte[] {(byte) 0b01010101, (byte) 0b10101010});
byte[] byteResult = {(byte) 0b01010101, (byte) 0b10101010};
byte[] stringResult = {'U', '\\', '2', '5', '2'};
byte[] stringResult = {'\\', 'x', '5', '5', 'a', 'a'};
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changed to hex format from the old escape format for bytea values in text format.

@@ -98,7 +106,9 @@ public static void compile() throws IOException, InterruptedException {

private GoString createConnString() {
return new GoString(
String.format("postgres://uid:pwd@localhost:%d/test-db", pgServer.getLocalPort()));
String.format(
"postgres://uid:pwd@localhost:%d/test-db?statement_cache_capacity=0",
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do not use a local statement cache in the pgx driver. This is needed to enable skipping the DescribeStatement message.

// merged.
// 1. DESCRIBE portal
// 2. EXECUTE portal
assertEquals(2, requests.size());
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yay! One less round trip :-)

And when #80 is merged, it will be down to just one round trip.

@olavloite olavloite merged commit 1fbb35d into postgresql-dialect Apr 10, 2022
@olavloite olavloite deleted the support-pgx-extended-mode branch April 10, 2022 16:36
@libingye816
Copy link
Contributor

libingye816 commented Apr 13, 2022

Hey @olavloite, I observe two failures after merging this pr. Can you check those out?

Failures:
[ERROR] ITPgxTest.testInsertNullsAllDataTypes:165 expected null, but was:<failed to execute insert statement: ERROR: INVALID_ARGUMENT: com.google.api.gax.rpc.InvalidArgumentException: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: [ERROR] there is no parameter $3 (SQLSTATE XX000)>
[ERROR] ITPgxTest.testQueryAllDataTypes:145 expected null, but was:<Failed to execute query: number of field descriptions must equal number of destinations, got 8 and 9>

@olavloite
Copy link
Collaborator Author

Where are you seeing this? I just merged the latest changes into this PR, and all tests were successful.

@libingye816
Copy link
Contributor

Where are you seeing this? I just merged the latest changes into this PR, and all tests were successful.

I cloned support-pgx-extended-mode branch and run ITPgxTest locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants