Skip to content

Commit 91cbf12

Browse files
committed
skip metadata only if prepared result included metadata
If the prepare result doesn't include metadata we shouldn't skip metadata when executing the query. Fixes CASSGO-40. Patch by James Hartig; reviewed by João Reis for CASSGO-40
1 parent c63468d commit 91cbf12

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3232

3333
- Don't return error to caller with RetryType Ignore (CASSGO-28)
3434

35+
- Skip metadata only if the prepared result includes metadata (CASSGO-40)
36+
3537
- Don't panic in MapExecuteBatchCAS if no `[applied]` column is returned (CASSGO-42)
3638

3739
## [1.7.0] - 2024-09-23

conn.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1375,7 +1375,8 @@ func (c *Conn) executeQuery(ctx context.Context, qry *Query) *Iter {
13751375
}
13761376
}
13771377

1378-
params.skipMeta = !(c.session.cfg.DisableSkipMetadata || qry.disableSkipMetadata)
1378+
// if the metadata was not present in the response then we should not skip it
1379+
params.skipMeta = !(c.session.cfg.DisableSkipMetadata || qry.disableSkipMetadata) && info != nil && info.response.flags&flagNoMetaData == 0
13791380

13801381
frame = &writeExecuteFrame{
13811382
preparedID: info.id,

conn_test.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"context"
3434
"crypto/tls"
3535
"crypto/x509"
36+
"encoding/binary"
3637
"errors"
3738
"fmt"
3839
"io"
@@ -952,6 +953,28 @@ func TestWriteCoalescing_WriteAfterClose(t *testing.T) {
952953
}
953954
}
954955

956+
func TestSkipMetadata(t *testing.T) {
957+
ctx, cancel := context.WithCancel(context.Background())
958+
defer cancel()
959+
960+
srv := NewTestServer(t, protoVersion4, ctx)
961+
defer srv.Stop()
962+
963+
db, err := newTestSession(protoVersion4, srv.Address)
964+
if err != nil {
965+
t.Fatalf("NewCluster: %v", err)
966+
}
967+
defer db.Close()
968+
969+
if err := db.Query("select nometadata").Exec(); err != nil {
970+
t.Fatalf("expected no error got: %v", err)
971+
}
972+
973+
if err := db.Query("select metadata").Exec(); err != nil {
974+
t.Fatalf("expected no error got: %v", err)
975+
}
976+
}
977+
955978
type recordingFrameHeaderObserver struct {
956979
t *testing.T
957980
mu sync.Mutex
@@ -1264,6 +1287,99 @@ func (srv *TestServer) process(conn net.Conn, reqFrame *framer) {
12641287
case opError:
12651288
respFrame.writeHeader(0, opError, head.stream)
12661289
respFrame.buf = append(respFrame.buf, reqFrame.buf...)
1290+
case opPrepare:
1291+
query := reqFrame.readLongString()
1292+
name := strings.TrimPrefix(query, "select ")
1293+
if n := strings.Index(name, " "); n > 0 {
1294+
name = name[:n]
1295+
}
1296+
switch strings.ToLower(name) {
1297+
case "nometadata":
1298+
respFrame.writeHeader(0, opResult, head.stream)
1299+
respFrame.writeInt(resultKindPrepared)
1300+
// <id>
1301+
respFrame.writeShortBytes(binary.BigEndian.AppendUint64(nil, 1))
1302+
// <metadata>
1303+
respFrame.writeInt(0) // <flags>
1304+
respFrame.writeInt(0) // <columns_count>
1305+
if srv.protocol >= protoVersion4 {
1306+
respFrame.writeInt(0) // <pk_count>
1307+
}
1308+
// <result_metadata>
1309+
respFrame.writeInt(int32(flagNoMetaData)) // <flags>
1310+
respFrame.writeInt(0)
1311+
case "metadata":
1312+
respFrame.writeHeader(0, opResult, head.stream)
1313+
respFrame.writeInt(resultKindPrepared)
1314+
// <id>
1315+
respFrame.writeShortBytes(binary.BigEndian.AppendUint64(nil, 2))
1316+
// <metadata>
1317+
respFrame.writeInt(0) // <flags>
1318+
respFrame.writeInt(0) // <columns_count>
1319+
if srv.protocol >= protoVersion4 {
1320+
respFrame.writeInt(0) // <pk_count>
1321+
}
1322+
// <result_metadata>
1323+
respFrame.writeInt(int32(flagGlobalTableSpec)) // <flags>
1324+
respFrame.writeInt(1) // <columns_count>
1325+
// <global_table_spec>
1326+
respFrame.writeString("keyspace")
1327+
respFrame.writeString("table")
1328+
// <col_spec_0>
1329+
respFrame.writeString("col0") // <name>
1330+
respFrame.writeShort(uint16(TypeBoolean)) // <type>
1331+
default:
1332+
respFrame.writeHeader(0, opError, head.stream)
1333+
respFrame.writeInt(0)
1334+
respFrame.writeString("unsupported query: " + name)
1335+
}
1336+
case opExecute:
1337+
b := reqFrame.readShortBytes()
1338+
id := binary.BigEndian.Uint64(b)
1339+
// <query_parameters>
1340+
reqFrame.readConsistency() // <consistency>
1341+
var flags byte
1342+
if srv.protocol > protoVersion4 {
1343+
ui := reqFrame.readInt()
1344+
flags = byte(ui)
1345+
} else {
1346+
flags = reqFrame.readByte()
1347+
}
1348+
switch id {
1349+
case 1:
1350+
if flags&flagSkipMetaData != 0 {
1351+
respFrame.writeHeader(0, opError, head.stream)
1352+
respFrame.writeInt(0)
1353+
respFrame.writeString("skip metadata unexpected")
1354+
} else {
1355+
respFrame.writeHeader(0, opResult, head.stream)
1356+
respFrame.writeInt(resultKindRows)
1357+
// <metadata>
1358+
respFrame.writeInt(0) // <flags>
1359+
respFrame.writeInt(0) // <columns_count>
1360+
// <rows_count>
1361+
respFrame.writeInt(0)
1362+
}
1363+
case 2:
1364+
if flags&flagSkipMetaData != 0 {
1365+
respFrame.writeHeader(0, opResult, head.stream)
1366+
respFrame.writeInt(resultKindRows)
1367+
// <metadata>
1368+
respFrame.writeInt(0) // <flags>
1369+
respFrame.writeInt(0) // <columns_count>
1370+
// <rows_count>
1371+
respFrame.writeInt(0)
1372+
} else {
1373+
respFrame.writeHeader(0, opError, head.stream)
1374+
respFrame.writeInt(0)
1375+
respFrame.writeString("skip metadata expected")
1376+
}
1377+
default:
1378+
respFrame.writeHeader(0, opError, head.stream)
1379+
respFrame.writeInt(ErrCodeUnprepared)
1380+
respFrame.writeString("unprepared")
1381+
respFrame.writeShortBytes(binary.BigEndian.AppendUint64(nil, id))
1382+
}
12671383
default:
12681384
respFrame.writeHeader(0, opError, head.stream)
12691385
respFrame.writeInt(0)

0 commit comments

Comments
 (0)