From 3a776a635e3babde73bd69d5b830d2b92b5382e2 Mon Sep 17 00:00:00 2001 From: Martin Sucha Date: Fri, 1 Mar 2024 10:02:42 +0100 Subject: [PATCH] Handle missing values when building a routing key This fixes the following panic when not enough bound values are present: ``` panic: runtime error: index out of range [0] with length 0 goroutine 663 [running]: github.com/gocql/gocql.createRoutingKey(0xc0004b4000, {0x0, 0x0, 0xc000042360?}) /go/pkg/mod/github.com/kiwicom/gocql@v1.20.0/session.go:2097 +0x58d github.com/gocql/gocql.(*Query).GetRoutingKey(0xc00089e8c0) /go/pkg/mod/github.com/kiwicom/gocql@v1.20.0/session.go:1231 +0x446 github.com/gocql/gocql.(*tokenAwareHostPolicy).Pick(0xc0000f2380, {0x195da60, 0xc00089e8c0}) /go/pkg/mod/github.com/kiwicom/gocql@v1.20.0/policies.go:574 +0x64 github.com/gocql/gocql.(*queryExecutor).executeQuery(0xc000a12060, {0x195da60, 0xc00089e8c0}) /go/pkg/mod/github.com/kiwicom/gocql@v1.20.0/query_executor.go:67 +0x96 github.com/gocql/gocql.(*Session).executeQuery(0xc00051fb00, 0x3?) /go/pkg/mod/github.com/kiwicom/gocql@v1.20.0/session.go:548 +0x145 github.com/gocql/gocql.(*Query).Iter(0xc00089e8c0) /go/pkg/mod/github.com/kiwicom/gocql@v1.20.0/session.go:1372 +0x13f github.com/scylladb/gocqlx/v2.(*Queryx).Iter(...) /go/pkg/mod/github.com/scylladb/gocqlx/v2@v2.8.0/queryx.go:344 ``` --- policies.go | 1 + session.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/policies.go b/policies.go index 6373a2c7c..a410581ed 100644 --- a/policies.go +++ b/policies.go @@ -573,6 +573,7 @@ func (t *tokenAwareHostPolicy) Pick(qry ExecutableQuery) NextHost { routingKey, err := qry.GetRoutingKey() if err != nil { + t.logger.Printf("unable to get routing key for query: %v", err) return t.fallback.Pick(qry) } else if routingKey == nil { return t.fallback.Pick(qry) diff --git a/session.go b/session.go index 0d1e9af24..6159c4441 100644 --- a/session.go +++ b/session.go @@ -665,13 +665,16 @@ func (s *Session) routingKeyInfo(ctx context.Context, stmt string) (*routingKeyI if len(info.request.pkeyColumns) > 0 { // proto v4 dont need to calculate primary key columns types := make([]TypeInfo, len(info.request.pkeyColumns)) + names := make([]string, len(info.request.pkeyColumns)) for i, col := range info.request.pkeyColumns { types[i] = info.request.columns[col].TypeInfo + names[i] = info.request.columns[col].Name } routingKeyInfo := &routingKeyInfo{ indexes: info.request.pkeyColumns, types: types, + names: names, lwt: info.request.lwt, partitioner: partitioner, keyspace: keyspace, @@ -709,6 +712,7 @@ func (s *Session) routingKeyInfo(ctx context.Context, stmt string) (*routingKeyI routingKeyInfo := &routingKeyInfo{ indexes: make([]int, size), types: make([]TypeInfo, size), + names: make([]string, size), lwt: info.request.lwt, partitioner: partitioner, keyspace: keyspace, @@ -725,6 +729,7 @@ func (s *Session) routingKeyInfo(ctx context.Context, stmt string) (*routingKeyI // there may be many such bound columns, pick the first routingKeyInfo.indexes[keyIndex] = argIndex routingKeyInfo.types[keyIndex] = boundColumn.TypeInfo + routingKeyInfo.names[keyIndex] = boundColumn.Name break } } @@ -2078,6 +2083,10 @@ func createRoutingKey(routingKeyInfo *routingKeyInfo, values []interface{}) ([]b } if len(routingKeyInfo.indexes) == 1 { + if len(values) <= routingKeyInfo.indexes[0] { + return nil, fmt.Errorf("gocql: missing routing key value at index %d for column %q", + routingKeyInfo.indexes[0], routingKeyInfo.names[0]) + } // single column routing key routingKey, err := Marshal( routingKeyInfo.types[0], @@ -2092,6 +2101,10 @@ func createRoutingKey(routingKeyInfo *routingKeyInfo, values []interface{}) ([]b // composite routing key buf := bytes.NewBuffer(make([]byte, 0, 256)) for i := range routingKeyInfo.indexes { + if len(values) <= routingKeyInfo.indexes[i] { + return nil, fmt.Errorf("gocql: missing routing key value at index %d for column %q", + routingKeyInfo.indexes[i], routingKeyInfo.names[i]) + } encoded, err := Marshal( routingKeyInfo.types[i], values[routingKeyInfo.indexes[i]], @@ -2154,6 +2167,7 @@ type routingKeyInfoLRU struct { type routingKeyInfo struct { indexes []int types []TypeInfo + names []string keyspace string table string lwt bool