Repository: GoogleCloudPlatform/pgadapter
Pull request #634 (2023-02-05 11:47:29)

test: ignore SocketException in test
Sending invalid messages can cause the entire socket fail, so ignore these exceptions in the test.

See for example https://github.com/GoogleCloudPlatform/pgadapter/actions/runs/4095487374/jobs/7062433693

codecov[bot]: # [Codecov](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/634?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) Report
> Merging [#634](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/634?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) (8578d48) into [postgresql-dialect](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/commit/54effed2848e04a025980636b57e10a194d6634a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) (54effed) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@                  Coverage Diff                  @@
##             postgresql-dialect     #634   +/-   ##
=====================================================
  Coverage                 89.06%   89.06%           
  Complexity                 2190     2190           
=====================================================
  Files                       126      126           
  Lines                      7308     7308           
  Branches                   1040     1040           
=====================================================
  Hits                       6509     6509           
  Misses                      559      559           
  Partials                    240      240           
```

| Flag | Coverage Δ | |
|---|---|---|
| all_tests | `89.06% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#carryforward-flags-in-the-pull-request-comment) to find out more.


:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f90c874a..e43b7f75 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,36 @@
 # Changelog
 
+## [0.16.0](https://github.com/GoogleCloudPlatform/pgadapter/compare/v0.15.0...v0.16.0) (2023-02-05)
+
+
+### Features
+
+* allow unsupported OIDs as param types ([#604](https://github.com/GoogleCloudPlatform/pgadapter/issues/604)) ([5e9f95a](https://github.com/GoogleCloudPlatform/pgadapter/commit/5e9f95a720f1648236b39167b227cc70bd40e323))
+* make table and function replacements client-aware ([#605](https://github.com/GoogleCloudPlatform/pgadapter/issues/605)) ([ad49e99](https://github.com/GoogleCloudPlatform/pgadapter/commit/ad49e990298d0e91736d4f5afe581d2f1411b5ca))
+
+
+### Bug Fixes
+
+* binary copy header should be included in first data message ([#609](https://github.com/GoogleCloudPlatform/pgadapter/issues/609)) ([2fbf89e](https://github.com/GoogleCloudPlatform/pgadapter/commit/2fbf89e6a6b3ba0b66f126abf019e386e9276d4c))
+* copy to for a query would fail with a column list ([#616](https://github.com/GoogleCloudPlatform/pgadapter/issues/616)) ([16f030e](https://github.com/GoogleCloudPlatform/pgadapter/commit/16f030e3f6b93ae0a243b6c495b0c906403c5e16))
+* CopyResponse did not return correct column format ([#633](https://github.com/GoogleCloudPlatform/pgadapter/issues/633)) ([dc0d482](https://github.com/GoogleCloudPlatform/pgadapter/commit/dc0d482ffb61d1857a3f49fc424a07d72886b460))
+* csv copy header was repeated for each row ([#619](https://github.com/GoogleCloudPlatform/pgadapter/issues/619)) ([622c49a](https://github.com/GoogleCloudPlatform/pgadapter/commit/622c49a02cf2a865874764f44a77b96539382be0))
+* empty copy from stdin statements could be unresponsive ([#617](https://github.com/GoogleCloudPlatform/pgadapter/issues/617)) ([c576124](https://github.com/GoogleCloudPlatform/pgadapter/commit/c576124e40ad7f07ee0d1e2f3090886896c70dc3))
+* empty partitions could skip binary copy header ([#615](https://github.com/GoogleCloudPlatform/pgadapter/issues/615)) ([e7dd650](https://github.com/GoogleCloudPlatform/pgadapter/commit/e7dd6508015ed45147af59c25f95e18628461d85))
+* show statements failed in pgx ([#629](https://github.com/GoogleCloudPlatform/pgadapter/issues/629)) ([734f521](https://github.com/GoogleCloudPlatform/pgadapter/commit/734f52176f75e4ccb0b8bddc96eae49ace9ab19e))
+* support end-of-data record in COPY ([#602](https://github.com/GoogleCloudPlatform/pgadapter/issues/602)) ([8b705e8](https://github.com/GoogleCloudPlatform/pgadapter/commit/8b705e8f917035cbabe9e6751008e93692355158))
+
+
+### Dependencies
+
+* update Spanner client to 6.35.1 ([#607](https://github.com/GoogleCloudPlatform/pgadapter/issues/607)) ([0c607c7](https://github.com/GoogleCloudPlatform/pgadapter/commit/0c607c7c1bce48139f28688a5d7f1e202d839860))
+
+
+### Documentation
+
+* document pgbench usage ([#603](https://github.com/GoogleCloudPlatform/pgadapter/issues/603)) ([5a62bf6](https://github.com/GoogleCloudPlatform/pgadapter/commit/5a62bf64c56a976625e2c707b6d049e593cddc96))
+* document unix domain sockets with Docker ([#622](https://github.com/GoogleCloudPlatform/pgadapter/issues/622)) ([e4e41f7](https://github.com/GoogleCloudPlatform/pgadapter/commit/e4e41f70e5ad23d8e7d6f2a1bc1851458466bbb6))
+
 ## [0.15.0](https://github.com/GoogleCloudPlatform/pgadapter/compare/v0.14.1...v0.15.0) (2023-01-18)
 
 
diff --git a/README.md b/README.md
index bbade18a..6756f34c 100644
--- a/README.md
+++ b/README.md
@@ -68,9 +68,9 @@ Use the `-s` option to specify a different local port than the default 5432 if y
 PostgreSQL running on your local system.
 
 <!--- {x-version-update-start:google-cloud-spanner-pgadapter:released} -->
-You can also download a specific version of the jar. Example (replace `v0.15.0` with the version you want to download):
+You can also download a specific version of the jar. Example (replace `v0.16.0` with the version you want to download):
 ```shell
-VERSION=v0.15.0
+VERSION=v0.16.0
 wget https://storage.googleapis.com/pgadapter-jar-releases/pgadapter-${VERSION}.tar.gz \
   && tar -xzvf pgadapter-${VERSION}.tar.gz
 java -jar pgadapter.jar -p my-project -i my-instance -d my-database
@@ -105,7 +105,7 @@ This option is only available for Java/JVM-based applications.
 <dependency>
   <groupId>com.google.cloud</groupId>
   <artifactId>google-cloud-spanner-pgadapter</artifactId>
-  <version>0.15.0</version>
+  <version>0.16.0</version>
 </dependency>
 <!-- [END pgadapter_dependency] -->
 ```
diff --git a/pom.xml b/pom.xml
index dbd863e0..c4cb90a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,7 @@
 
   <modelVersion>4.0.0</modelVersion>
   <artifactId>google-cloud-spanner-pgadapter</artifactId>
-  <version>0.15.1-SNAPSHOT</version><!-- {x-version-update:google-cloud-spanner-pgadapter:current} -->
+  <version>0.16.0</version><!-- {x-version-update:google-cloud-spanner-pgadapter:current} -->
   <name>Google Cloud Spanner PostgreSQL Adapter</name>
   <packaging>jar</packaging>
   <description>
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java
index e615f107..370cd620 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java
@@ -241,8 +241,8 @@ public class CopyStatement extends IntermediatePortalStatement {
   }
 
   /** @return 0 for text/csv formatting and 1 for binary */
-  public int getFormatCode() {
-    return (parsedCopyStatement.format == Format.BINARY) ? 1 : 0;
+  public byte getFormatCode() {
+    return (parsedCopyStatement.format == Format.BINARY) ? (byte) 1 : (byte) 0;
   }
 
   private void verifyCopyColumns() {
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/utils/CopyDataReceiver.java b/src/main/java/com/google/cloud/spanner/pgadapter/utils/CopyDataReceiver.java
index cba2c259..79d750b2 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/utils/CopyDataReceiver.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/utils/CopyDataReceiver.java
@@ -65,7 +65,7 @@ public class CopyDataReceiver implements Callable<Void> {
       this.connectionHandler.setActiveCopyStatement(copyStatement);
       new CopyInResponse(
               this.connectionHandler.getConnectionMetadata().getOutputStream(),
-              copyStatement.getTableColumns().size(),
+              (short) copyStatement.getTableColumns().size(),
               copyStatement.getFormatCode())
           .send();
       ConnectionStatus initialConnectionStatus = this.connectionHandler.getStatus();
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponse.java b/src/main/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponse.java
index 58eee8e6..13c064ee 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponse.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponse.java
@@ -35,23 +35,25 @@ public class CopyInResponse extends WireOutput {
 
   protected static final char IDENTIFIER = 'G';
 
-  private final int numColumns;
-  private final int formatCode;
-  private final byte[] columnFormat;
+  private final short numColumns;
+  private final byte formatCode;
+  private final short[] columnFormat;
 
-  public CopyInResponse(DataOutputStream output, int numColumns, int formatCode) {
+  public CopyInResponse(DataOutputStream output, short numColumns, byte formatCode) {
     super(output, calculateLength(numColumns));
     this.numColumns = numColumns;
     this.formatCode = formatCode;
-    columnFormat = new byte[COLUMN_NUM_LENGTH * this.numColumns];
-    Arrays.fill(columnFormat, (byte) formatCode);
+    this.columnFormat = new short[this.numColumns];
+    Arrays.fill(this.columnFormat, formatCode);
   }
 
   @Override
   protected void sendPayload() throws IOException {
     this.outputStream.writeByte(this.formatCode);
     this.outputStream.writeShort(this.numColumns);
-    this.outputStream.write(this.columnFormat);
+    for (int i = 0; i < this.numColumns; i++) {
+      this.outputStream.writeShort(this.columnFormat[i]);
+    }
   }
 
   @Override
diff --git a/versions.txt b/versions.txt
index 82f0e7f6..a8293857 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
 # Format:
 # module:released-version:current-version
 
-google-cloud-spanner-pgadapter:0.15.0:0.15.1-SNAPSHOT
+google-cloud-spanner-pgadapter:0.16.0:0.16.0


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/InvalidMessagesTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/InvalidMessagesTest.java
index 8f051bfd..94ac7613 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/InvalidMessagesTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/InvalidMessagesTest.java
@@ -26,6 +26,7 @@ import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.net.Socket;
+import java.net.SocketException;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import org.junit.Test;
@@ -129,6 +130,8 @@ public class InvalidMessagesTest extends AbstractMockServerTest {
         } catch (IOException ignore) {
         }
       }
+    } catch (SocketException ignore) {
+      // Sending non-sense messages sometimes fails the entire socket.
     }
   }
 
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponseTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponseTest.java
new file mode 100644
index 00000000..1f095daf
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/wireoutput/CopyInResponseTest.java
@@ -0,0 +1,70 @@
+// Copyright 2023 Google LLC
+//
+// 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.
+
+package com.google.cloud.spanner.pgadapter.wireoutput;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import com.google.cloud.spanner.pgadapter.ProxyServer.DataFormat;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class CopyInResponseTest {
+
+  @Test
+  public void testSendPayloadText() throws Exception {
+    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+    DataOutputStream output = new DataOutputStream(bytes);
+    short numColumns = 3;
+
+    CopyInResponse response =
+        new CopyInResponse(output, numColumns, (byte) DataFormat.POSTGRESQL_TEXT.getCode());
+    response.sendPayload();
+
+    assertArrayEquals(
+        new byte[] {
+          0, // format
+          0, 3, // numColumns
+          0, 0, // format column 1
+          0, 0, // format column 2
+          0, 0, // format column 3
+        },
+        bytes.toByteArray());
+  }
+
+  @Test
+  public void testSendPayloadBinary() throws Exception {
+    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+    DataOutputStream output = new DataOutputStream(bytes);
+    short numColumns = 3;
+
+    CopyInResponse response =
+        new CopyInResponse(output, numColumns, (byte) DataFormat.POSTGRESQL_BINARY.getCode());
+    response.sendPayload();
+
+    assertArrayEquals(
+        new byte[] {
+          1, // format
+          0, 3, // numColumns
+          0, 1, // format column 1
+          0, 1, // format column 2
+          0, 1, // format column 3
+        },
+        bytes.toByteArray());
+  }
+}