@@ -415,6 +415,19 @@ func TestNewConfig(t *testing.T) {
415415 {"host=a,b,c hostaddr=1.1.1.1,2.2.2.2" , nil , "" , "could not match 3 host names to 2 hostaddr values" },
416416 {"host=a hostaddr=1.1.1.1,2.2.2.2" , nil , "" , "could not match 1 host names to 2 hostaddr values" },
417417 {"" , []string {"PGHOST=a,,b" , "PGHOSTADDR=1.1.1.1,,2.2.2.2" , "PGPORT=3,,4" }, "host=a,localhost,b hostaddr=1.1.1.1,,2.2.2.2 port=3,5432,4" , "" },
418+
419+ // Protocol version
420+ {"min_protocol_version=3.0" , nil , "min_protocol_version=3.0" , "" },
421+ {"max_protocol_version=3.2" , nil , "max_protocol_version=3.2" , "" },
422+ {"min_protocol_version=3.2 max_protocol_version=3.2" , nil , "max_protocol_version=3.2 min_protocol_version=3.2" , "" },
423+ {"min_protocol_version=latest max_protocol_version=latest" , nil , "max_protocol_version=latest min_protocol_version=latest" , "" },
424+ {"min_protocol_version=3.0 max_protocol_version=latest" , nil , "max_protocol_version=latest min_protocol_version=3.0" , "" },
425+ {"" , []string {"PGMINPROTOCOLVERSION=3.0" , "PGMAXPROTOCOLVERSION=3.2" }, "max_protocol_version=3.2 min_protocol_version=3.0" , "" },
426+ {"min_protocol_version=bogus" , nil , "" , `pq: wrong value for "min_protocol_version": "bogus" is not supported` },
427+ {"max_protocol_version=bogus" , nil , "" , `pq: wrong value for "max_protocol_version": "bogus" is not supported` },
428+ {"" , []string {"PGMINPROTOCOLVERSION=bogus" }, "" , `pq: wrong value for $PGMINPROTOCOLVERSION: "bogus" is not supported` },
429+ {"" , []string {"PGMAXPROTOCOLVERSION=bogus" }, "" , `pq: wrong value for $PGMAXPROTOCOLVERSION: "bogus" is not supported` },
430+ {"min_protocol_version=3.2 max_protocol_version=3.0" , nil , "" , `min_protocol_version "3.2" cannot be greater than max_protocol_version "3.0"` },
418431 }
419432
420433 t .Parallel ()
@@ -723,3 +736,95 @@ func TestConnectionTargetSessionAttrs(t *testing.T) {
723736 })
724737 }
725738}
739+
740+ func TestProtocolVersion32 (t * testing.T ) {
741+ t .Run ("BackendKeyData" , func (t * testing.T ) {
742+ t .Parallel ()
743+
744+ f := pqtest .NewFake (t , func (f pqtest.Fake , cn net.Conn ) {
745+ if _ , ok := f .ReadStartup (cn ); ! ok {
746+ return
747+ }
748+ f .WriteMsg (cn , proto .AuthenticationRequest , "\x00 \x00 \x00 \x00 " )
749+ f .WriteBackendKeyData (cn , 12345 , make ([]byte , 32 ))
750+ f .WriteMsg (cn , proto .ReadyForQuery , "I" )
751+ for {
752+ code , _ , ok := f .ReadMsg (cn )
753+ if ! ok {
754+ return
755+ }
756+ switch code {
757+ case proto .Query :
758+ f .WriteMsg (cn , proto .EmptyQueryResponse , "" )
759+ f .WriteMsg (cn , proto .ReadyForQuery , "I" )
760+ case proto .Terminate :
761+ cn .Close ()
762+ return
763+ }
764+ }
765+ })
766+ defer f .Close ()
767+
768+ db := pqtest .MustDB (t , f .DSN ()+ " max_protocol_version=3.2" )
769+ if err := db .Ping (); err != nil {
770+ t .Fatal (err )
771+ }
772+ })
773+
774+ t .Run ("NegotiateProtocolVersion accepted" , func (t * testing.T ) {
775+ t .Parallel ()
776+
777+ f := pqtest .NewFake (t , func (f pqtest.Fake , cn net.Conn ) {
778+ if _ , ok := f .ReadStartup (cn ); ! ok {
779+ return
780+ }
781+ f .WriteMsg (cn , proto .AuthenticationRequest , "\x00 \x00 \x00 \x00 " )
782+ // Server says it only supports minor version 0 (i.e. 3.0).
783+ f .WriteNegotiateProtocolVersion (cn , 0 , nil )
784+ f .WriteMsg (cn , proto .ReadyForQuery , "I" )
785+ for {
786+ code , _ , ok := f .ReadMsg (cn )
787+ if ! ok {
788+ return
789+ }
790+ switch code {
791+ case proto .Query :
792+ f .WriteMsg (cn , proto .EmptyQueryResponse , "" )
793+ f .WriteMsg (cn , proto .ReadyForQuery , "I" )
794+ case proto .Terminate :
795+ cn .Close ()
796+ return
797+ }
798+ }
799+ })
800+ defer f .Close ()
801+
802+ // min=3.0, max=3.2: server negotiates down to 3.0, which is >= min, so OK.
803+ db := pqtest .MustDB (t , f .DSN ()+ " min_protocol_version=3.0 max_protocol_version=3.2" )
804+ if err := db .Ping (); err != nil {
805+ t .Fatal (err )
806+ }
807+ })
808+
809+ t .Run ("NegotiateProtocolVersion rejected" , func (t * testing.T ) {
810+ t .Parallel ()
811+
812+ f := pqtest .NewFake (t , func (f pqtest.Fake , cn net.Conn ) {
813+ if _ , ok := f .ReadStartup (cn ); ! ok {
814+ return
815+ }
816+ f .WriteMsg (cn , proto .AuthenticationRequest , "\x00 \x00 \x00 \x00 " )
817+ // Server says it only supports minor version 0 (i.e. 3.0).
818+ f .WriteNegotiateProtocolVersion (cn , 0 , nil )
819+ // Client will disconnect; don't try to read further.
820+ })
821+ defer f .Close ()
822+
823+ // min=3.2, max=3.2: server negotiates down to 3.0, which is < min, so error.
824+ db := pqtest .MustDB (t , f .DSN ()+ " min_protocol_version=3.2 max_protocol_version=3.2" )
825+ err := db .Ping ()
826+ if ! pqtest .ErrorContains (err , "server does not support minimum protocol version" ) {
827+ t .Fatalf ("wrong error\n have: %v\n want: server does not support minimum protocol version" , err )
828+ }
829+ })
830+ }
0 commit comments