Important Note -- Had a breakthrough in Edit #2 at the end, so be sure to read that as well.
I'm in clojure, trying to use JDBC to connect to our company PostgreSQL server. The server is using pgBouncer.
Here are my project dependencies:
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/java.jdbc "0.3.6"]
[org.postgresql/postgresql "9.4-1200-jdbc41"]]
And here's my code:
(ns pg-test.core
(:require [clojure.java.jdbc :as jdbc]))
(def db
{:subprotocol "postgresql"
:subname "//the-server-name:the-port/db-name"
:sslmode "require"
:user "my-username"
:password "super-secret-password"})
(jdbc/query db ["SELECT 5"])
When I run this code, I get one of three results:
- org.postgresql.util.PSQLException: The connection attempt failed.
- org.postgresql.util.PSQLException: ERROR: bad packet header: '70'
- VERY RARELY (three times now, out of hundreds of attempts), it will actually work! It returns
({:?column? 5})
What is going on? Why does this work sometimes, but almost NEVER?
My Setup
- OS X Yosemite (but I was never able to make it work from my Ubuntu virtual machine, either.)
lein repl :headless :port 2358
followed bycider-connect
in emacs.- Server is postgres 9.1.12
Edit #2
Just learned about the :loglevel 2
option. This sets it to "DEBUG" level of output, and I gathered some more interesting data. Here's the output:
21:45:34.921 (31) PostgreSQL 9.4 JDBC4.1 (build 1200)
21:45:34.927 (31) Trying to establish a protocol version 3 connection to the-server-name:the-port
21:45:35.020 (31) FE=> SSLRequest
21:45:35.120 (31) <=BE SSLOk
21:45:35.120 (31) converting regular socket connection to ssl
21:45:35.324 (31) Receive Buffer Size is 131072
21:45:35.324 (31) Send Buffer Size is 131136
21:45:35.324 (31) FE=> StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2)
21:45:35.435 (31) <=BE AuthenticationReqMD5(salt=f244b442)
21:45:35.436 (31) FE=> Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1)
21:45:35.520 (31) <=BE ErrorMessage(ERROR: bad packet header: '70')
It then gives the following stack trace:
org.postgresql.util.PSQLException: ERROR: bad packet header: '70'
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:420)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:195)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
at org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:127)
at org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:29)
at org.postgresql.jdbc3g.AbstractJdbc3gConnection.<init>(AbstractJdbc3gConnection.java:21)
at org.postgresql.jdbc4.AbstractJdbc4Connection.<init>(AbstractJdbc4Connection.java:41)
at org.postgresql.jdbc4.Jdbc4Connection.<init>(Jdbc4Connection.java:24)
at org.postgresql.Driver.makeConnection(Driver.java:414)
at org.postgresql.Driver.connect(Driver.java:282)
at java.sql.DriverManager.getConnection(DriverManager.java:571)
at java.sql.DriverManager.getConnection(DriverManager.java:187)
at clojure.java.jdbc$get_connection.invoke(jdbc.clj:255)
at clojure.java.jdbc$db_query_with_resultset.invoke(jdbc.clj:798)
at clojure.java.jdbc$query.doInvoke(jdbc.clj:832)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at pg_test.core$eval4536.invoke(core.clj:14)
at clojure.lang.Compiler.eval(Compiler.java:6703)
at clojure.lang.Compiler.load(Compiler.java:7130)
at pg_test.core$eval4524.invoke(form-init6588155330850041472.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6703)
at clojure.lang.Compiler.eval(Compiler.java:6666)
at clojure.core$eval.invoke(core.clj:2927)
at clojure.main$repl$read_eval_print__6625$fn__6628.invoke(main.clj:239)
at clojure.main$repl$read_eval_print__6625.invoke(main.clj:239)
at clojure.main$repl$fn__6634.invoke(main.clj:257)
at clojure.main$repl.doInvoke(main.clj:257)
at clojure.lang.RestFn.invoke(RestFn.java:1523)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__592.invoke(interruptible_eval.clj:67)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:51)
at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__634$fn__637.invoke(interruptible_eval.clj:183)
at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__627.invoke(interruptible_eval.clj:152)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
But then it gives this error code!
SQLException: SQLState(08P01)
Which, according to this website means "PROTOCOL VIOLATION".
I searched google for 08P01 protocol violation, and found this bug report for a completely unrelated project on GitHub with the title "'08P01 PROTOCOL VIOLATION' when trying to write encoded unicode characters to string fields".
So let's look at what we're sending:
StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2)
. Notice that our encoding is UTF8.- Then, we send
Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1)
, and immediately we get the "bad packet header '70'" exception.
Is UTF8 ruining my life again? I thought we had left these bad days behind us so long ago.
So now I'm wondering if there's a way to change the client encoding. Or possibly to change the authentication method being used.