risingwavelabs / risingwave

Best-in-class stream processing, analytics, and management. Perform continuous analytics, or build event-driven applications, real-time ETL pipelines, and feature stores in minutes. Unified streaming and batch. PostgreSQL compatible.
https://go.risingwave.com/slack
Apache License 2.0
6.78k stars 561 forks source link

clojure pg client receives unexpected packet when I set 'ApplicationName' in connection uri #12166

Closed neverchanje closed 10 months ago

neverchanje commented 1 year ago

Describe the bug

No response

Error message/log

Caused by: java.io.IOException: Unexpected packet type: 0
 at org.postgresql.core.v3.QueryExecutorImpl.processResults (QueryExecutorImpl.java:2518)
    org.postgresql.core.v3.QueryExecutorImpl.execute (QueryExecutorImpl.java:356)
    org.postgresql.core.v3.QueryExecutorImpl.execute (QueryExecutorImpl.java:316)
    org.postgresql.core.SetupQueryRunner.run (SetupQueryRunner.java:55)
    org.postgresql.core.v3.ConnectionFactoryImpl.runInitialQueries (ConnectionFactoryImpl.java:927)
    org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl (ConnectionFactoryImpl.java:327)
    org.postgresql.core.ConnectionFactory.openConnection (ConnectionFactory.java:54)
    org.postgresql.jdbc.PgConnection.<init> (PgConnection.java:253)
    org.postgresql.Driver.makeConnection (Driver.java:434)
    org.postgresql.Driver.connect (Driver.java:291)
    java.sql.DriverManager.getConnection (DriverManager.java:683)
    java.sql.DriverManager.getConnection (DriverManager.java:191)
    clojure.java.jdbc$get_driver_connection.invokeStatic (jdbc.clj:271)
    clojure.java.jdbc$get_driver_connection.invoke (jdbc.clj:250)
    clojure.java.jdbc$get_connection.invokeStatic (jdbc.clj:411)
    clojure.java.jdbc$get_connection.invoke (jdbc.clj:274)
  actual: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
 at org.postgresql.core.v3.QueryExecutorImpl.execute (QueryExecutorImpl.java:383)
    org.postgresql.core.v3.QueryExecutorImpl.execute (QueryExecutorImpl.java:316)
    org.postgresql.core.SetupQueryRunner.run (SetupQueryRunner.java:55)
    org.postgresql.core.v3.ConnectionFactoryImpl.runInitialQueries (ConnectionFactoryImpl.java:927)
    org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl (ConnectionFactoryImpl.java:327)
    org.postgresql.core.ConnectionFactory.openConnection (ConnectionFactory.java:54)
    org.postgresql.jdbc.PgConnection.<init> (PgConnection.java:253)

To Reproduce

(ns clojure-client.core-test
  (:require [clojure.java.jdbc :as jdbc]
            [clojure.test :refer [deftest is testing]]))

(def db-spec {:classname       "org.postgresql.Driver"
              :subprotocol     "postgresql"
              :subname         "//localhost:4566/dev"
              :user            "root"
              :password        ""
              ; the program runs successfully if without ApplicationName
              ;:ApplicationName "Metabase vLOCAL_DEV [572649fd-85b4-4782-a4dd-0b27595588f8]"
              })

(defn can-connect?
  "Checks whether we can perform a simple `SELECT 1` query with given driver and details."
  []
  (let [[first-row] (jdbc/query db-spec ["SELECT 1"])]
    (= 1 (first (vals first-row)))))

(deftest test-can-connect
  (testing "can connect with valid spec"
    (is (can-connect?))))

Expected behavior

No response

How did you deploy RisingWave?

No response

The version of RisingWave

Main b578db6fe0658c16c4a54e18721017b71dfe06b3

Additional context

No response

neverchanje commented 1 year ago

It's likely that we send unexpected pgwire responses after set application_name=''. The driver tests has no similar issues in Java. Looks like it only occurs in Clojure's JDBC. Postgres can pass this test.

neverchanje commented 1 year ago
    static Connection establishConnection() throws SQLException {
        final String url = "jdbc:postgresql://localhost:4566/dev";

        Properties props = new Properties();
        props.setProperty("user", "root");
        props.setProperty("password", "");
        props.setProperty("sslmode", "disable");
        props.setProperty("ApplicationName", "Metabase vLOCAL_DEV [572649fd-85b4-4782-a4dd-0b27595588f8]");

        return DriverManager.getConnection(url, props);
    }

    @Test
    public void testEstablishConnection() throws SQLException {
        Connection conn = establishConnection();
        assertNotNull(conn, "Connection should not be null");

The root cause is that we didn't handle 'Metabase vLOCAL_DEV [572649fd-85b4-4782-a4dd-0b27595588f8]' correctly. Java JDBC fails on this test as well.


It's interesting to know that this issue is related to the application name's length. It only fails when the length exceeds 45 characters, e.g. "0123456789012345678901234567890123456789012345"