This is an automated email from the ASF dual-hosted git repository.
joaoreis pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-gocql-driver.git
The following commit(s) were added to refs/heads/trunk by this push:
new d79b595f Fix protocol version negotiation issues with v5
d79b595f is described below
commit d79b595f714973de5bbb65bd8fbcf8f0f3747dc2
Author: João Reis <[email protected]>
AuthorDate: Tue Aug 26 17:11:31 2025 +0100
Fix protocol version negotiation issues with v5
Driver was automatically setting beta flag when using v5 protocol which
causes issues when trying to connect to Cassandra
versions that supported beta v5 like 3.11.
Also, this patch makes the protocol version discovery process more
resilient. Still not a long term solution since long term
we should make the protocol version negotiation work like in the java
driver.
Patch by João Reis; reviewed by Lukasz Antoniak for CASSGO-88
---
CHANGELOG.md | 4 ++++
conn.go | 16 +++++++++++++++-
control.go | 31 +++++++++++++++++++++++++++----
frame.go | 3 ---
4 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19f353ad..68166e39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -65,6 +65,10 @@ and this project adheres to [Semantic
Versioning](https://semver.org/spec/v2.0.0
### Fixed
+#### 2.0.0
+
+- Do not set beta protocol flag when using v5 (CASSGO-88)
+
#### 2.0.0-rc1
- Cassandra version unmarshal fix (CASSGO-49)
diff --git a/conn.go b/conn.go
index 6cfb6fe9..877c2aae 100644
--- a/conn.go
+++ b/conn.go
@@ -1317,7 +1317,21 @@ func (c *Conn) execInternal(ctx context.Context, req
frameBuilder, tracer Tracer
defer c.releaseStream(call)
if v := resp.framer.header.version.version(); v != c.version {
- return nil, NewErrProtocol("unexpected protocol version
in response: got %d expected %d", v, c.version)
+ errProtocol := NewErrProtocol("unexpected protocol
version in response: got %d expected %d", v, c.version)
+ responseFrame, err := resp.framer.parseFrame()
+ if err != nil {
+ c.logger.Warning("Framer error while attempting
to parse potential protocol error.",
+ newLogFieldError("err", err))
+ return nil, errProtocol
+ }
+ //goland:noinspection GoTypeAssertionOnErrors
+ errFrame, isErrFrame := responseFrame.(errorFrame)
+ if !isErrFrame || errFrame.Code() != ErrCodeProtocol {
+ return nil, errProtocol
+ }
+ return nil, NewErrProtocol("%w", &protocolError{
+ errFrame,
+ })
}
return resp.framer, nil
diff --git a/control.go b/control.go
index b521c41d..e3c835b4 100644
--- a/control.go
+++ b/control.go
@@ -204,13 +204,34 @@ func shuffleHosts(hosts []*HostInfo) []*HostInfo {
// this is going to be version dependant and a nightmare to maintain :(
var protocolSupportRe = regexp.MustCompile(`the lowest supported version is
\d+ and the greatest is (\d+)$`)
+var betaProtocolRe = regexp.MustCompile(`Beta version of the protocol used
\(.*\), but USE_BETA flag is unset`)
func parseProtocolFromError(err error) int {
+ errStr := err.Error()
+
+ var errProtocol ErrProtocol
+ if errors.As(err, &errProtocol) {
+ err = errProtocol.error
+ }
+
// I really wish this had the actual info in the error frame...
- matches := protocolSupportRe.FindAllStringSubmatch(err.Error(), -1)
+ matches := betaProtocolRe.FindAllStringSubmatch(errStr, -1)
+ if len(matches) == 1 {
+ var protoErr *protocolError
+ if errors.As(err, &protoErr) {
+ version := protoErr.frame.Header().version.version()
+ if version > 0 {
+ return int(version - 1)
+ }
+ }
+ return 0
+ }
+
+ matches = protocolSupportRe.FindAllStringSubmatch(errStr, -1)
if len(matches) != 1 || len(matches[0]) != 2 {
- if verr, ok := err.(*protocolError); ok {
- return int(verr.frame.Header().version.version())
+ var protoErr *protocolError
+ if errors.As(err, &protoErr) {
+ return int(protoErr.frame.Header().version.version())
}
return 0
}
@@ -223,11 +244,13 @@ func parseProtocolFromError(err error) int {
return max
}
+const highestProtocolVersionSupported = 5
+
func (c *controlConn) discoverProtocol(hosts []*HostInfo) (int, error) {
hosts = shuffleHosts(hosts)
connCfg := *c.session.connCfg
- connCfg.ProtoVersion = 5 // TODO: define maxProtocol
+ connCfg.ProtoVersion = highestProtocolVersionSupported
handler := connErrorHandlerFn(func(c *Conn, err error, closed bool) {
// we should never get here, but if we do it means we connected
to a
diff --git a/frame.go b/frame.go
index 93af2c67..7e551c23 100644
--- a/frame.go
+++ b/frame.go
@@ -393,9 +393,6 @@ func newFramer(compressor Compressor, version byte, r
*RegisteredTypes) *framer
if compressor != nil {
flags |= flagCompress
}
- if version == protoVersion5 {
- flags |= flagBetaProtocol
- }
version &= protoVersionMask
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]