├── install_test_deps.sh ├── docs ├── source │ ├── sample-page.rst │ └── index.rst ├── _utils │ └── redirects.yaml └── pyproject.toml ├── testdata ├── frames │ ├── bench_parse_result.gz │ ├── big_query_request.bin │ ├── big_query_response.bin │ ├── small_query_request.bin │ ├── medium_query_request.bin │ ├── medium_query_response.bin │ ├── small_query_response.bin │ ├── prepare_statement_request.bin │ └── prepare_statement_response.bin ├── recreate │ ├── keyspace.cql │ ├── keyspace_golden.cql │ ├── scylla_encryption_options_golden.json │ ├── scylla_encryption_options.bin │ ├── index.cql │ ├── udt.cql │ ├── udt_golden.cql │ ├── secondary_index.cql │ ├── materialized_views.cql │ ├── aggregates.cql │ ├── aggregates_golden.cql │ ├── index_golden.cql │ ├── secondary_index_golden.cql │ └── table.cql └── pki │ ├── ca.cnf │ ├── gocql.cnf │ └── cassandra.cnf ├── host_source_scylla.go ├── renovate.json ├── internal ├── tests │ ├── serialization │ │ ├── mod │ │ │ ├── custom_refs.go │ │ │ ├── all.go │ │ │ └── refs.go │ │ ├── utils_new.go │ │ ├── utils_error.go │ │ ├── utils.go │ │ ├── valcases │ │ │ └── get.go │ │ ├── pointers_test.go │ │ ├── utils_str.go │ │ ├── set_negative_marshal.go │ │ ├── pointers.go │ │ ├── set_negative_unmarshal.go │ │ └── utils_equal.go │ ├── err_equal.go │ ├── mock │ │ └── mock_framer.go │ └── common.go ├── debug │ ├── debug_off.go │ └── debug_on.go ├── murmur │ ├── murmur_unsafe.go │ └── murmur_appengine.go └── ccm │ └── ccm_test.go ├── .github ├── dependabot.yml ├── workflows │ ├── bench-tests.yml │ ├── clean_dockerhub_images.yml │ ├── docs-pr.yml │ └── docs-pages.yml ├── issue_template.md └── actions │ └── setup-environment │ └── action.yml ├── .gitignore ├── tests ├── bench │ ├── go.mod │ └── go.sum └── serialization │ ├── marshal_1_boolean_corrupt_test.go │ ├── marshal_12_ascii_corrupt_test.go │ ├── marshal_8_float_corrupt_test.go │ ├── marshal_9_double_corrupt_test.go │ ├── marshal_12_ascii_test.go │ ├── marshal_2_tinyint_corrupt_test.go │ ├── marshal_10_decimal_corrupt_test.go │ ├── marshal_1_boolean_test.go │ └── marshal_15_time_test.go ├── export_test.go ├── serialization ├── duration │ ├── duration.go │ ├── marshal.go │ ├── unmarshal.go │ ├── unmarshal_vint_test.go │ ├── marshal_str_test.go │ ├── marshal_vint_test.go │ └── unmarshal_str_test.go ├── boolean │ ├── marshal.go │ ├── unmarshal.go │ ├── marshal_utils.go │ └── unmarshal_utils.go ├── float │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── double │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── blob │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── text │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── ascii │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── varchar │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── timestamp │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── cqltime │ ├── marshal.go │ ├── unmarshal.go │ └── marshal_utils.go ├── decimal │ ├── marshal.go │ ├── unmarshal.go │ └── unmarshal_ints.go ├── uuid │ ├── marshal.go │ └── unmarshal.go ├── timeuuid │ ├── marshal.go │ └── unmarshal.go ├── date │ ├── marshal.go │ └── unmarshal.go ├── inet │ ├── marshal.go │ └── unmarshal.go ├── bigint │ ├── marshal.go │ └── unmarshal.go ├── cqlint │ ├── marshal.go │ └── unmarshal.go ├── varint │ ├── marshal.go │ ├── marshal_bigint_test.go │ ├── unmarshal_bigint_test.go │ ├── unmarshal.go │ └── marshal_custom.go ├── counter │ ├── marshal.go │ └── unmarshal.go ├── smallint │ ├── marshal.go │ └── unmarshal.go └── tinyint │ ├── marshal.go │ └── unmarshal.go ├── exec_test.go ├── schema_queries_test.go ├── warning_handler.go ├── .golangci.yml ├── scylla_shard_aware_port_integration_test.go ├── debounce └── simple_debouncer.go ├── session_event_bus_test.go ├── lz4 ├── go.mod ├── go.sum └── lz4_test.go ├── cqltypes.go ├── integration.sh ├── tracer_test.go ├── version.go ├── control_integration_test.go ├── hostpolicy └── hostpool_test.go ├── go.mod ├── compressor.go ├── events_test.go ├── errors_test.go ├── tablet_integration_test.go ├── tablets └── tabets_utils_test.go ├── framer_bench_test.go ├── session_unit_test.go ├── address_translators_test.go ├── integration_only.go ├── session_event_bus_integration_test.go ├── logger.go ├── ci └── clean-old-temporary-docker-images.py ├── session_connect_test.go ├── batch_test.go └── events └── event_converter.go /install_test_deps.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/source/sample-page.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Sample page 3 | =========== 4 | 5 | Lorem ipsum. -------------------------------------------------------------------------------- /testdata/frames/bench_parse_result.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/bench_parse_result.gz -------------------------------------------------------------------------------- /testdata/frames/big_query_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/big_query_request.bin -------------------------------------------------------------------------------- /testdata/frames/big_query_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/big_query_response.bin -------------------------------------------------------------------------------- /testdata/frames/small_query_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/small_query_request.bin -------------------------------------------------------------------------------- /testdata/frames/medium_query_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/medium_query_request.bin -------------------------------------------------------------------------------- /testdata/frames/medium_query_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/medium_query_response.bin -------------------------------------------------------------------------------- /testdata/frames/small_query_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/small_query_response.bin -------------------------------------------------------------------------------- /testdata/frames/prepare_statement_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/prepare_statement_request.bin -------------------------------------------------------------------------------- /testdata/frames/prepare_statement_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scylladb/gocql/HEAD/testdata/frames/prepare_statement_response.bin -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | ScyllaDB gocql driver 3 | ===================== 4 | 5 | Lorem ipsum. 6 | 7 | .. toctree:: 8 | 9 | sample-page -------------------------------------------------------------------------------- /host_source_scylla.go: -------------------------------------------------------------------------------- 1 | package gocql 2 | 3 | func (h *HostInfo) SetDatacenter(dc string) { 4 | h.mu.Lock() 5 | defer h.mu.Unlock() 6 | h.dataCenter = dc 7 | } 8 | -------------------------------------------------------------------------------- /testdata/recreate/keyspace.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_keyspace WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ], 6 | "prConcurrentLimit": 2 7 | } 8 | -------------------------------------------------------------------------------- /internal/tests/serialization/mod/custom_refs.go: -------------------------------------------------------------------------------- 1 | package mod 2 | 3 | var CustomTypeRef Mod = func(vals ...interface{}) []interface{} { 4 | return Reference(CustomType(vals...)...) 5 | } 6 | -------------------------------------------------------------------------------- /testdata/recreate/keyspace_golden.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_keyspace WITH replication = {'class': 'org.apache.cassandra.locator.NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true; -------------------------------------------------------------------------------- /docs/_utils/redirects.yaml: -------------------------------------------------------------------------------- 1 | ### a dictionary of redirects 2 | #old path: new path 3 | # 4 | 5 | # removing redirection html script files 6 | # test: / 7 | 8 | # /stable/test-redirect.html: /stable/index.html 9 | -------------------------------------------------------------------------------- /internal/tests/err_equal.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | func ErrEqual(err1, err2 error) bool { 4 | if err1 != nil && err2 != nil { 5 | return err1.Error() == err2.Error() 6 | } 7 | return err1 == nil && err2 == nil 8 | } 9 | -------------------------------------------------------------------------------- /testdata/recreate/scylla_encryption_options_golden.json: -------------------------------------------------------------------------------- 1 | {"cipher_algorithm":"AES/ECB/PKCS5Padding","secret_key_strength":128,"key_provider":"LocalFileSystemKeyProviderFactory","secret_key_file":"/etc/scylla/encryption_keys/data_encryption_keys"} -------------------------------------------------------------------------------- /testdata/recreate/scylla_encryption_options.bin: -------------------------------------------------------------------------------- 1 | cipher_algorithmAES/ECB/PKCS5Padding key_provider!LocalFileSystemKeyProviderFactorysecret_key_file0/etc/scylla/encryption_keys/data_encryption_keyssecret_key_strength128 -------------------------------------------------------------------------------- /testdata/pki/ca.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | prompt = no 4 | default_md = sha256 5 | distinguished_name = dn 6 | 7 | [req_ext] 8 | basicConstraints = CA:TRUE 9 | keyUsage = digitalSignature, keyCertSign 10 | 11 | [dn] 12 | CN = ca 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/docs" 5 | schedule: 6 | interval: "daily" 7 | allow: 8 | - dependency-name: "sphinx-scylladb-theme" 9 | - dependency-name: "sphinx-multiversion-scylla" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | gocql-fuzz 2 | fuzz-corpus 3 | fuzz-work 4 | gocql.test 5 | .idea 6 | 7 | bin/ 8 | 9 | testdata/pki/.keystore 10 | testdata/pki/.truststore 11 | testdata/pki/*.crt 12 | testdata/pki/*.key 13 | testdata/pki/*.p12 14 | 15 | docs/_build/ 16 | docs/source/.doctrees 17 | 18 | # Claude / AI assistant metadata 19 | CLAUDE.md 20 | .claude/ -------------------------------------------------------------------------------- /testdata/recreate/index.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_idx WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | 6 | CREATE TABLE gocqlx_idx.menus ( 7 | location text, 8 | name text, 9 | price float, 10 | dish_type text, 11 | PRIMARY KEY(location, name) 12 | ); 13 | 14 | CREATE INDEX ON gocqlx_idx.menus(name); 15 | -------------------------------------------------------------------------------- /testdata/pki/gocql.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | prompt = no 4 | default_md = sha256 5 | distinguished_name = dn 6 | 7 | [dn] 8 | CN = gocql 9 | 10 | [req_ext] 11 | basicConstraints = CA:FALSE 12 | keyUsage = digitalSignature, keyEncipherment 13 | subjectAltName = @alt_names 14 | 15 | [alt_names] 16 | URI = spiffe://test.cassandra.apache.org/cassandra-gocql-driver/integrationTest/gocql 17 | -------------------------------------------------------------------------------- /testdata/recreate/udt.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_udt WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | 6 | CREATE TYPE gocqlx_udt.phone ( 7 | country_code int, 8 | number text 9 | ); 10 | 11 | CREATE TYPE gocqlx_udt.address ( 12 | street text, 13 | city text, 14 | zip text, 15 | phones map> 16 | ); 17 | -------------------------------------------------------------------------------- /tests/bench/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gocql/gocql/bench_test 2 | 3 | go 1.25.0 4 | 5 | require ( 6 | github.com/brianvoe/gofakeit/v6 v6.28.0 7 | github.com/gocql/gocql v1.7.0 8 | ) 9 | 10 | require ( 11 | github.com/google/uuid v1.6.0 // indirect 12 | github.com/klauspost/compress v1.18.1 // indirect 13 | gopkg.in/inf.v0 v0.9.1 // indirect 14 | ) 15 | 16 | replace github.com/gocql/gocql => ../.. 17 | -------------------------------------------------------------------------------- /testdata/pki/cassandra.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | prompt = no 4 | default_md = sha256 5 | distinguished_name = dn 6 | 7 | [dn] 8 | CN = cassandra 9 | 10 | [req_ext] 11 | basicConstraints = CA:FALSE 12 | keyUsage = digitalSignature, keyEncipherment 13 | subjectAltName = @alt_names 14 | 15 | [alt_names] 16 | URI = spiffe://test.cassandra.apache.org/cassandra-gocql-driver/integrationTest/cassandra 17 | -------------------------------------------------------------------------------- /testdata/recreate/udt_golden.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_udt WITH replication = {'class': 'org.apache.cassandra.locator.NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true; 2 | CREATE TYPE gocqlx_udt.phone ( 3 | country_code int, 4 | number text 5 | ); 6 | CREATE TYPE gocqlx_udt.address ( 7 | street text, 8 | city text, 9 | zip text, 10 | phones map> 11 | ); -------------------------------------------------------------------------------- /export_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | var FlagRunSslTest = flagRunSslTest 7 | var FlagDistribution = flagDistribution 8 | var CreateCluster = createCluster 9 | var TestLogger = &testLogger{} 10 | var WaitUntilPoolsStopFilling = waitUntilPoolsStopFilling 11 | 12 | func GetRingAllHosts(sess *Session) []*HostInfo { 13 | return sess.hostSource.getHostsList() 14 | } 15 | -------------------------------------------------------------------------------- /testdata/recreate/secondary_index.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_sec_idx WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | 6 | 7 | CREATE TABLE gocqlx_sec_idx.menus ( 8 | location text, 9 | name text, 10 | price float, 11 | dish_type text, 12 | PRIMARY KEY(location, name) 13 | ); 14 | 15 | CREATE INDEX ON gocqlx_sec_idx.menus((location), name); 16 | -------------------------------------------------------------------------------- /internal/tests/serialization/mod/all.go: -------------------------------------------------------------------------------- 1 | package mod 2 | 3 | var All = []Mod{CustomType, Reference, CustomTypeRef} 4 | 5 | // Mod - value modifiers. 6 | type Mod func(vals ...interface{}) []interface{} 7 | 8 | type Values []interface{} 9 | 10 | func (v Values) AddVariants(mods ...Mod) Values { 11 | out := append(make([]interface{}, 0), v...) 12 | for _, mod := range mods { 13 | out = append(out, mod(v...)...) 14 | } 15 | return out 16 | } 17 | -------------------------------------------------------------------------------- /internal/tests/serialization/utils_new.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func newRef(in interface{}) interface{} { 8 | out := reflect.New(reflect.TypeOf(in)).Interface() 9 | return out 10 | } 11 | 12 | func newRefToZero(in interface{}) interface{} { 13 | rv := reflect.ValueOf(in) 14 | nw := reflect.New(rv.Type().Elem()) 15 | out := reflect.New(rv.Type()) 16 | out.Elem().Set(nw) 17 | return out.Interface() 18 | } 19 | -------------------------------------------------------------------------------- /serialization/duration/duration.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | type Duration struct { 4 | Months int32 5 | Days int32 6 | Nanoseconds int64 7 | } 8 | 9 | func (d Duration) Valid() bool { 10 | return validDuration(d.Months, d.Days, d.Nanoseconds) 11 | } 12 | 13 | func validDuration(m, d int32, n int64) bool { 14 | if m >= 0 && d >= 0 && n >= 0 { 15 | return true 16 | } 17 | if m <= 0 && d <= 0 && n <= 0 { 18 | return true 19 | } 20 | return false 21 | } 22 | -------------------------------------------------------------------------------- /internal/tests/mock/mock_framer.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | type MockFramer struct { 4 | Data [][]byte 5 | pos int 6 | } 7 | 8 | func (m *MockFramer) ReadBytesInternal() ([]byte, error) { 9 | if m.pos < len(m.Data) { 10 | m.pos = m.pos + 1 11 | return m.Data[m.pos-1], nil 12 | } 13 | return []byte{}, nil 14 | } 15 | 16 | func (*MockFramer) GetCustomPayload() map[string][]byte { return map[string][]byte{} } 17 | func (*MockFramer) GetHeaderWarnings() []string { return []string{} } 18 | -------------------------------------------------------------------------------- /internal/tests/serialization/mod/refs.go: -------------------------------------------------------------------------------- 1 | package mod 2 | 3 | import "reflect" 4 | 5 | var Reference Mod = func(vals ...interface{}) []interface{} { 6 | out := make([]interface{}, 0) 7 | for i := range vals { 8 | if vals[i] != nil { 9 | out = append(out, reference(vals[i])) 10 | } 11 | } 12 | return out 13 | } 14 | 15 | func reference(val interface{}) interface{} { 16 | inV := reflect.ValueOf(val) 17 | out := reflect.New(reflect.TypeOf(val)) 18 | out.Elem().Set(inV) 19 | return out.Interface() 20 | } 21 | -------------------------------------------------------------------------------- /exec_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func TestSingleHostQueryExecutor(t *testing.T) { 11 | cluster := createCluster() 12 | 13 | e, err := NewSingleHostQueryExecutor(cluster) 14 | if err != nil { 15 | t.Fatal(err) 16 | } 17 | defer e.Close() 18 | 19 | iter := e.Iter("SELECT now() FROM system.local") 20 | 21 | var date []byte 22 | iter.Scan(&date) 23 | if err := iter.Close(); err != nil { 24 | t.Fatal(err) 25 | } 26 | if len(date) == 0 { 27 | t.Fatal("expected date") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "sphinx-docs" 3 | description = "ScyllaDB gocql driver documentation" 4 | version = "0.1.0" 5 | authors = ["ScyllaDB Documentation Contributors"] 6 | package-mode = false 7 | 8 | [tool.poetry.dependencies] 9 | python = ">=3.11,<3.14" 10 | pygments = "^2.19.2" 11 | sphinx-scylladb-theme = "^1.8.2" 12 | myst-parser = "^4.0.1" 13 | sphinx-autobuild = "^2025.0.0" 14 | Sphinx = "^8.0.0" 15 | sphinx-multiversion-scylla = "^0.3.2" 16 | sphinx-sitemap = "^2.8.0" 17 | redirects_cli ="^0.1.3" 18 | 19 | [build-system] 20 | requires = ["poetry==2.2.0"] 21 | build-backend = "poetry.masonry.api" -------------------------------------------------------------------------------- /internal/tests/serialization/utils_error.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var unmarshalErr = errors.New("unmarshal unexpectedly failed with error") 9 | var marshalErr = errors.New("marshal unexpectedly failed with error") 10 | 11 | type unequalError struct { 12 | Expected string 13 | Got string 14 | } 15 | 16 | func (e unequalError) Error() string { 17 | return fmt.Sprintf("expect %s but got %s", e.Expected, e.Got) 18 | } 19 | 20 | type panicErr struct { 21 | err error 22 | stack []byte 23 | } 24 | 25 | func (e panicErr) Error() string { 26 | return fmt.Sprintf("%v\n%s", e.err, e.stack) 27 | } 28 | -------------------------------------------------------------------------------- /testdata/recreate/materialized_views.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_mv WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | 6 | CREATE TABLE gocqlx_mv.mv_buildings ( 7 | name text, 8 | city text, 9 | built int, 10 | meters int, 11 | PRIMARY KEY (name) 12 | ); 13 | 14 | CREATE MATERIALIZED VIEW gocqlx_mv.mv_building_by_city AS 15 | SELECT * FROM mv_buildings 16 | WHERE city IS NOT NULL 17 | PRIMARY KEY(city, name); 18 | 19 | CREATE MATERIALIZED VIEW gocqlx_mv.mv_building_by_city2 AS 20 | SELECT meters FROM mv_buildings 21 | WHERE city IS NOT NULL 22 | PRIMARY KEY(city, name); 23 | -------------------------------------------------------------------------------- /internal/tests/serialization/utils.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func GetTypes(values ...interface{}) []reflect.Type { 8 | types := make([]reflect.Type, len(values)) 9 | for i, value := range values { 10 | types[i] = reflect.TypeOf(value) 11 | } 12 | return types 13 | } 14 | 15 | func isTypeOf(value interface{}, types []reflect.Type) bool { 16 | valueType := reflect.TypeOf(value) 17 | for i := range types { 18 | if types[i] == valueType { 19 | return true 20 | } 21 | } 22 | return false 23 | } 24 | 25 | func deReference(in interface{}) interface{} { 26 | return reflect.Indirect(reflect.ValueOf(in)).Interface() 27 | } 28 | -------------------------------------------------------------------------------- /serialization/boolean/marshal.go: -------------------------------------------------------------------------------- 1 | package boolean 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case bool: 12 | return EncBool(v) 13 | case *bool: 14 | return EncBoolR(v) 15 | default: 16 | // Custom types (type MyBool bool) can be serialized only via `reflect` package. 17 | // Later, when generic-based serialization is introduced we can do that via generics. 18 | rv := reflect.TypeOf(value) 19 | if rv.Kind() != reflect.Ptr { 20 | return EncReflect(reflect.ValueOf(v)) 21 | } 22 | return EncReflectR(reflect.ValueOf(v)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /serialization/float/marshal.go: -------------------------------------------------------------------------------- 1 | package float 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case float32: 12 | return EncFloat32(v) 13 | case *float32: 14 | return EncFloat32R(v) 15 | default: 16 | // Custom types (type MyFloat float32) can be serialized only via `reflect` package. 17 | // Later, when generic-based serialization is introduced we can do that via generics. 18 | rv := reflect.TypeOf(value) 19 | if rv.Kind() != reflect.Ptr { 20 | return EncReflect(reflect.ValueOf(v)) 21 | } 22 | return EncReflectR(reflect.ValueOf(v)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /serialization/double/marshal.go: -------------------------------------------------------------------------------- 1 | package double 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case float64: 12 | return EncFloat64(v) 13 | case *float64: 14 | return EncFloat64R(v) 15 | default: 16 | // Custom types (type MyFloat float64) can be serialized only via `reflect` package. 17 | // Later, when generic-based serialization is introduced we can do that via generics. 18 | rv := reflect.TypeOf(value) 19 | if rv.Kind() != reflect.Ptr { 20 | return EncReflect(reflect.ValueOf(v)) 21 | } 22 | return EncReflectR(reflect.ValueOf(v)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/bench-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run benchmark tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | 10 | jobs: 11 | bench-tests: 12 | if: contains(github.event.pull_request.labels.*.name, 'run-benchmark-tests') 13 | name: Run benchmark tests 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v6 17 | - uses: actions/setup-go@v6 18 | with: 19 | go-version-file: go.mod 20 | cache-dependency-path: | 21 | lz4/go.sum 22 | tests/bench/go.sum 23 | go.sum 24 | 25 | 26 | - name: Run benchmark tests 27 | run: make test-bench 28 | -------------------------------------------------------------------------------- /serialization/blob/marshal.go: -------------------------------------------------------------------------------- 1 | package blob 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case string: 12 | return EncString(v) 13 | case *string: 14 | return EncStringR(v) 15 | case []byte: 16 | return EncBytes(v) 17 | case *[]byte: 18 | return EncBytesR(v) 19 | default: 20 | // Custom types (type MyString string) can be serialized only via `reflect` package. 21 | // Later, when generic-based serialization is introduced we can do that via generics. 22 | rv := reflect.ValueOf(value) 23 | if rv.Kind() != reflect.Ptr { 24 | return EncReflect(rv) 25 | } 26 | return EncReflectR(rv) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /serialization/text/marshal.go: -------------------------------------------------------------------------------- 1 | package text 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case string: 12 | return EncString(v) 13 | case *string: 14 | return EncStringR(v) 15 | case []byte: 16 | return EncBytes(v) 17 | case *[]byte: 18 | return EncBytesR(v) 19 | default: 20 | // Custom types (type MyString string) can be serialized only via `reflect` package. 21 | // Later, when generic-based serialization is introduced we can do that via generics. 22 | rv := reflect.ValueOf(value) 23 | if rv.Kind() != reflect.Ptr { 24 | return EncReflect(rv) 25 | } 26 | return EncReflectR(rv) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /serialization/ascii/marshal.go: -------------------------------------------------------------------------------- 1 | package ascii 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case string: 12 | return EncString(v) 13 | case *string: 14 | return EncStringR(v) 15 | case []byte: 16 | return EncBytes(v) 17 | case *[]byte: 18 | return EncBytesR(v) 19 | default: 20 | // Custom types (type MyString string) can be serialized only via `reflect` package. 21 | // Later, when generic-based serialization is introduced we can do that via generics. 22 | rv := reflect.ValueOf(value) 23 | if rv.Kind() != reflect.Ptr { 24 | return EncReflect(rv) 25 | } 26 | return EncReflectR(rv) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /serialization/varchar/marshal.go: -------------------------------------------------------------------------------- 1 | package varchar 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case string: 12 | return EncString(v) 13 | case *string: 14 | return EncStringR(v) 15 | case []byte: 16 | return EncBytes(v) 17 | case *[]byte: 18 | return EncBytesR(v) 19 | default: 20 | // Custom types (type MyString string) can be serialized only via `reflect` package. 21 | // Later, when generic-based serialization is introduced we can do that via generics. 22 | rv := reflect.ValueOf(value) 23 | if rv.Kind() != reflect.Ptr { 24 | return EncReflect(rv) 25 | } 26 | return EncReflectR(rv) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /internal/tests/serialization/valcases/get.go: -------------------------------------------------------------------------------- 1 | package valcases 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | type SimpleTypes []SimpleTypeCases 8 | 9 | type SimpleTypeCases struct { 10 | CQLName string 11 | Cases []SimpleTypeCase 12 | CQLType int 13 | } 14 | 15 | type SimpleTypeCase struct { 16 | Name string 17 | Data []byte 18 | LangCases []LangCase 19 | } 20 | 21 | type LangCase struct { 22 | Value interface{} 23 | LangType string 24 | ErrInsert bool 25 | ErrSelect bool 26 | } 27 | 28 | var nilBytes = ([]byte)(nil) 29 | 30 | func GetSimple() SimpleTypes { 31 | return simpleTypesCases 32 | } 33 | 34 | func nilRef(in interface{}) interface{} { 35 | out := reflect.NewAt(reflect.TypeOf(in), nil).Interface() 36 | return out 37 | } 38 | -------------------------------------------------------------------------------- /schema_queries_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql/internal/tests" 10 | ) 11 | 12 | func TestSchemaQueries(t *testing.T) { 13 | cluster := createCluster() 14 | 15 | fallback := RoundRobinHostPolicy() 16 | cluster.PoolConfig.HostSelectionPolicy = TokenAwareHostPolicy(fallback) 17 | 18 | session := createSessionFromCluster(cluster, t) 19 | defer session.Close() 20 | 21 | keyspaceMetadata, err := session.metadataDescriber.getSchema("gocql_test") 22 | if err != nil { 23 | t.Fatal("unable to get keyspace metadata for keyspace: ", err) 24 | } 25 | tests.AssertTrue(t, "keyspace present in metadataDescriber", keyspaceMetadata.Name == "gocql_test") 26 | } 27 | -------------------------------------------------------------------------------- /warning_handler.go: -------------------------------------------------------------------------------- 1 | package gocql 2 | 3 | type DefaultWarningHandler struct { 4 | logger StdLogger 5 | } 6 | 7 | func DefaultWarningHandlerBuilder(session *Session) WarningHandler { 8 | return DefaultWarningHandler{ 9 | logger: session.logger, 10 | } 11 | } 12 | 13 | func (d DefaultWarningHandler) HandleWarnings(qry ExecutableQuery, host *HostInfo, warnings []string) { 14 | if d.logger == nil { 15 | return 16 | } 17 | if host != nil && len(host.hostId) > 0 { 18 | d.logger.Printf("[%s] warnings: %v", host.hostId, warnings) 19 | } else { 20 | d.logger.Printf("Cluster warnings: %v", warnings) 21 | } 22 | } 23 | 24 | var _ WarningHandler = DefaultWarningHandler{} 25 | 26 | func NoopWarningHandlerBuilder(session *Session) WarningHandler { 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | Please answer these questions before submitting your issue. Thanks! 2 | 3 | ### What version of ScyllaDB or Cassandra are you using? 4 | 5 | 6 | ### What version of ScyllaDB Gocql driver are you using? 7 | 8 | 9 | ### What version of Go are you using? 10 | 11 | 12 | ### What did you do? 13 | 14 | 15 | ### What did you expect to see? 16 | 17 | 18 | ### What did you see instead? 19 | 20 | --- 21 | 22 | If you are having connectivity related issues please share the following additional information 23 | 24 | ### Describe your Cassandra cluster 25 | please provide the following information 26 | 27 | - output of `nodetool status` 28 | - output of `SELECT peer, rpc_address FROM system.peers` 29 | - rebuild your application with the `gocql_debug` tag and post the output 30 | -------------------------------------------------------------------------------- /serialization/timestamp/marshal.go: -------------------------------------------------------------------------------- 1 | package timestamp 2 | 3 | import ( 4 | "reflect" 5 | "time" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int64: 13 | return EncInt64(v) 14 | case *int64: 15 | return EncInt64R(v) 16 | case time.Time: 17 | return EncTime(v) 18 | case *time.Time: 19 | return EncTimeR(v) 20 | 21 | default: 22 | // Custom types (type MyTime int64) can be serialized only via `reflect` package. 23 | // Later, when generic-based serialization is introduced we can do that via generics. 24 | rv := reflect.TypeOf(value) 25 | if rv.Kind() != reflect.Ptr { 26 | return EncReflect(reflect.ValueOf(v)) 27 | } 28 | return EncReflectR(reflect.ValueOf(v)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /testdata/recreate/aggregates.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_aggregates WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | 6 | CREATE FUNCTION gocqlx_aggregates.avgstate( 7 | state tuple, 8 | val double) 9 | CALLED ON NULL INPUT 10 | RETURNS frozen> 11 | LANGUAGE lua 12 | AS $$ 13 | return { state[1]+1, state[2]+val } 14 | $$; 15 | 16 | CREATE FUNCTION gocqlx_aggregates.avgfinal( 17 | state tuple) 18 | CALLED ON NULL INPUT 19 | RETURNS double 20 | LANGUAGE lua 21 | as $$ 22 | r=0 23 | r=state[2] 24 | r=r/state[1] 25 | return r 26 | $$; 27 | 28 | CREATE AGGREGATE gocqlx_aggregates.average(double) 29 | SFUNC avgstate STYPE tuple 30 | FINALFUNC avgfinal 31 | INITCOND (0,0.0); 32 | -------------------------------------------------------------------------------- /serialization/cqltime/marshal.go: -------------------------------------------------------------------------------- 1 | package cqltime 2 | 3 | import ( 4 | "reflect" 5 | "time" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int64: 13 | return EncInt64(v) 14 | case *int64: 15 | return EncInt64R(v) 16 | case time.Duration: 17 | return EncDuration(v) 18 | case *time.Duration: 19 | return EncDurationR(v) 20 | 21 | default: 22 | // Custom types (type MyTime int64) can be serialized only via `reflect` package. 23 | // Later, when generic-based serialization is introduced we can do that via generics. 24 | rv := reflect.TypeOf(value) 25 | if rv.Kind() != reflect.Ptr { 26 | return EncReflect(reflect.ValueOf(v)) 27 | } 28 | return EncReflectR(reflect.ValueOf(v)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /serialization/decimal/marshal.go: -------------------------------------------------------------------------------- 1 | package decimal 2 | 3 | import ( 4 | "reflect" 5 | 6 | "gopkg.in/inf.v0" 7 | ) 8 | 9 | func Marshal(value interface{}) ([]byte, error) { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil, nil 13 | case inf.Dec: 14 | return EncInfDec(v) 15 | case *inf.Dec: 16 | return EncInfDecR(v) 17 | case string: 18 | return EncString(v) 19 | case *string: 20 | return EncStringR(v) 21 | default: 22 | // Custom types (type MyString string) can be serialized only via `reflect` package. 23 | // Later, when generic-based serialization is introduced we can do that via generics. 24 | rv := reflect.TypeOf(value) 25 | if rv.Kind() != reflect.Ptr { 26 | return EncReflect(reflect.ValueOf(v)) 27 | } 28 | return EncReflectR(reflect.ValueOf(v)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /testdata/recreate/aggregates_golden.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_aggregates WITH replication = {'class': 'org.apache.cassandra.locator.NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true; 2 | CREATE FUNCTION gocqlx_aggregates.avgfinal(state frozen>) 3 | CALLED ON NULL INPUT 4 | RETURNS double 5 | LANGUAGE lua 6 | AS $$ 7 | r=0 8 | r=state[2] 9 | r=r/state[1] 10 | return r 11 | 12 | $$; 13 | CREATE FUNCTION gocqlx_aggregates.avgstate(state frozen>, val double) 14 | CALLED ON NULL INPUT 15 | RETURNS frozen> 16 | LANGUAGE lua 17 | AS $$ 18 | return { state[1]+1, state[2]+val } 19 | 20 | $$; 21 | CREATE AGGREGATE gocqlx_aggregates.average(double) 22 | SFUNC avgstate 23 | STYPE frozen> 24 | FINALFUNC avgfinal 25 | INITCOND (0, 0); -------------------------------------------------------------------------------- /serialization/uuid/marshal.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case [16]byte: 12 | return EncArray(v) 13 | case *[16]byte: 14 | return EncArrayR(v) 15 | case []byte: 16 | return EncSlice(v) 17 | case *[]byte: 18 | return EncSliceR(v) 19 | case string: 20 | return EncString(v) 21 | case *string: 22 | return EncStringR(v) 23 | default: 24 | // Custom types (type MyUUID [16]byte) can be serialized only via `reflect` package. 25 | // Later, when generic-based serialization is introduced we can do that via generics. 26 | rv := reflect.ValueOf(value) 27 | if rv.Kind() != reflect.Ptr { 28 | return EncReflect(rv) 29 | } 30 | return EncReflectR(rv) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /serialization/timeuuid/marshal.go: -------------------------------------------------------------------------------- 1 | package timeuuid 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func Marshal(value interface{}) ([]byte, error) { 8 | switch v := value.(type) { 9 | case nil: 10 | return nil, nil 11 | case [16]byte: 12 | return EncArray(v) 13 | case *[16]byte: 14 | return EncArrayR(v) 15 | case []byte: 16 | return EncSlice(v) 17 | case *[]byte: 18 | return EncSliceR(v) 19 | case string: 20 | return EncString(v) 21 | case *string: 22 | return EncStringR(v) 23 | default: 24 | // Custom types (type MyUUID [16]byte) can be serialized only via `reflect` package. 25 | // Later, when generic-based serialization is introduced we can do that via generics. 26 | rv := reflect.ValueOf(value) 27 | if rv.Kind() != reflect.Ptr { 28 | return EncReflect(rv) 29 | } 30 | return EncReflectR(rv) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /serialization/boolean/unmarshal.go: -------------------------------------------------------------------------------- 1 | package boolean 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *bool: 13 | return DecBool(data, v) 14 | case **bool: 15 | return DecBoolR(data, v) 16 | default: 17 | // Custom types (type MyBool bool) can be deserialized only via `reflect` package. 18 | // Later, when generic-based serialization is introduced we can do that via generics. 19 | rv := reflect.ValueOf(value) 20 | rt := rv.Type() 21 | if rt.Kind() != reflect.Ptr { 22 | return fmt.Errorf("failed to unmarshal boolean: unsupported value type (%T)(%[1]v)", v) 23 | } 24 | if rt.Elem().Kind() != reflect.Ptr { 25 | return DecReflect(data, rv) 26 | } 27 | return DecReflectR(data, rv) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | formatters: 4 | enable: 5 | - goimports 6 | 7 | settings: 8 | goimports: 9 | local-prefixes: 10 | - github.com/gocql/gocql 11 | - github.com/apache/cassandra-gocql-driver 12 | - github.com/apache/cassandra-gocql-driver/v2 13 | golines: 14 | max-len: 120 15 | 16 | linters: 17 | exclusions: 18 | rules: 19 | - path: '(.+)_test\.go' 20 | text: "fieldalignment" 21 | linters: 22 | - govet 23 | 24 | default: none 25 | enable: 26 | - nolintlint 27 | - govet 28 | settings: 29 | govet: 30 | enable-all: true 31 | disable: 32 | - shadow 33 | 34 | nolintlint: 35 | allow-no-explanation: [ golines ] 36 | require-explanation: true 37 | require-specific: true 38 | 39 | run: 40 | build-tags: 41 | - integration 42 | - unit -------------------------------------------------------------------------------- /serialization/double/unmarshal.go: -------------------------------------------------------------------------------- 1 | package double 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *float64: 13 | return DecFloat64(data, v) 14 | case **float64: 15 | return DecFloat64R(data, v) 16 | default: 17 | // Custom types (type MyFloat float64) can be deserialized only via `reflect` package. 18 | // Later, when generic-based serialization is introduced we can do that via generics. 19 | rv := reflect.ValueOf(value) 20 | rt := rv.Type() 21 | if rt.Kind() != reflect.Ptr { 22 | return fmt.Errorf("failed to unmarshal double: unsupported value type (%T)(%[1]v), supported types: ~float64", v) 23 | } 24 | if rt.Elem().Kind() != reflect.Ptr { 25 | return DecReflect(data, rv) 26 | } 27 | return DecReflectR(data, rv) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /serialization/float/unmarshal.go: -------------------------------------------------------------------------------- 1 | package float 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *float32: 13 | return DecFloat32(data, v) 14 | case **float32: 15 | return DecFloat32R(data, v) 16 | default: 17 | // Custom types (type MyFloat float32) can be deserialized only via `reflect` package. 18 | // Later, when generic-based serialization is introduced we can do that via generics. 19 | rv := reflect.ValueOf(value) 20 | rt := rv.Type() 21 | if rt.Kind() != reflect.Ptr { 22 | return fmt.Errorf("failed to unmarshal float: unsupported value type (%T)(%[1]v), supported types: ~float32", v) 23 | } 24 | if rt.Elem().Kind() != reflect.Ptr { 25 | return DecReflect(data, rv) 26 | } 27 | return DecReflectR(data, rv) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/clean_dockerhub_images.yml: -------------------------------------------------------------------------------- 1 | name: Docker Cleanup 2 | 3 | on: 4 | schedule: 5 | - cron: '0 12 * * 1' # Runs every Monday at noon (UTC) 6 | workflow_dispatch: 7 | 8 | jobs: 9 | cleanup: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out the repository 13 | uses: actions/checkout@v6 14 | 15 | - name: Set up Python 16 | uses: actions/setup-python@v6 17 | with: 18 | python-version: "3.x" 19 | 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install requests 24 | 25 | - name: Run Docker image cleanup 26 | run: make clean-old-temporary-docker-images 27 | env: 28 | DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} 29 | DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} 30 | DELETE_AFTER_DAYS: 30 31 | -------------------------------------------------------------------------------- /serialization/duration/marshal.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "reflect" 5 | "time" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int64: 13 | return EncInt64(v) 14 | case time.Duration: 15 | return EncDur(v) 16 | case string: 17 | return EncString(v) 18 | case Duration: 19 | return EncDuration(v) 20 | 21 | case *int64: 22 | return EncInt64R(v) 23 | case *time.Duration: 24 | return EncDurR(v) 25 | case *string: 26 | return EncStringR(v) 27 | case *Duration: 28 | return EncDurationR(v) 29 | default: 30 | // Custom types (type MyDate uint32) can be serialized only via `reflect` package. 31 | // Later, when generic-based serialization is introduced we can do that via generics. 32 | rv := reflect.TypeOf(value) 33 | if rv.Kind() != reflect.Ptr { 34 | return EncReflect(reflect.ValueOf(v)) 35 | } 36 | return EncReflectR(reflect.ValueOf(v)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /serialization/ascii/unmarshal.go: -------------------------------------------------------------------------------- 1 | package ascii 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *string: 13 | return DecString(data, v) 14 | case **string: 15 | return DecStringR(data, v) 16 | case *[]byte: 17 | return DecBytes(data, v) 18 | case **[]byte: 19 | return DecBytesR(data, v) 20 | default: 21 | // Custom types (type MyString string) can be deserialized only via `reflect` package. 22 | // Later, when generic-based serialization is introduced we can do that via generics. 23 | rv := reflect.ValueOf(value) 24 | rt := rv.Type() 25 | if rt.Kind() != reflect.Ptr { 26 | return fmt.Errorf("failed to unmarshal ascii: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte", v) 27 | } 28 | if rt.Elem().Kind() != reflect.Ptr { 29 | return DecReflect(data, rv) 30 | } 31 | return DecReflectR(data, rv) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scylla_shard_aware_port_integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import "testing" 7 | 8 | func TestShardAwarePortIntegrationNoReconnections(t *testing.T) { 9 | testShardAwarePortNoReconnections(t, func() *ClusterConfig { 10 | c := createCluster() 11 | c.Port = 9042 12 | return c 13 | }) 14 | } 15 | 16 | func TestShardAwarePortIntegrationMaliciousNAT(t *testing.T) { 17 | testShardAwarePortMaliciousNAT(t, func() *ClusterConfig { 18 | c := createCluster() 19 | c.Port = 9042 20 | return c 21 | }) 22 | } 23 | 24 | func TestShardAwarePortIntegrationUnreachable(t *testing.T) { 25 | testShardAwarePortUnreachable(t, func() *ClusterConfig { 26 | c := createCluster() 27 | c.Port = 9042 28 | return c 29 | }) 30 | } 31 | 32 | func TestShardAwarePortIntegrationUnusedIfNotEnabled(t *testing.T) { 33 | testShardAwarePortUnusedIfNotEnabled(t, func() *ClusterConfig { 34 | c := createCluster() 35 | c.Port = 9042 36 | return c 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /serialization/timestamp/unmarshal.go: -------------------------------------------------------------------------------- 1 | package timestamp 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int64: 15 | return DecInt64(data, v) 16 | case **int64: 17 | return DecInt64R(data, v) 18 | case *time.Time: 19 | return DecTime(data, v) 20 | case **time.Time: 21 | return DecTimeR(data, v) 22 | default: 23 | 24 | // Custom types (type MyTime int64) can be deserialized only via `reflect` package. 25 | // Later, when generic-based serialization is introduced we can do that via generics. 26 | rv := reflect.ValueOf(value) 27 | rt := rv.Type() 28 | if rt.Kind() != reflect.Ptr { 29 | return fmt.Errorf("failed to unmarshal timestamp: unsupported value type (%T)(%[1]v), supported types: ~int64, time.Time", value) 30 | } 31 | if rt.Elem().Kind() != reflect.Ptr { 32 | return DecReflect(data, rv) 33 | } 34 | return DecReflectR(data, rv) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /serialization/decimal/unmarshal.go: -------------------------------------------------------------------------------- 1 | package decimal 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "gopkg.in/inf.v0" 8 | ) 9 | 10 | func Unmarshal(data []byte, value interface{}) error { 11 | switch v := value.(type) { 12 | case nil: 13 | return nil 14 | case *inf.Dec: 15 | return DecInfDec(data, v) 16 | case **inf.Dec: 17 | return DecInfDecR(data, v) 18 | case *string: 19 | return DecString(data, v) 20 | case **string: 21 | return DecStringR(data, v) 22 | default: 23 | // Custom types (type MyString string) can be deserialized only via `reflect` package. 24 | // Later, when generic-based serialization is introduced we can do that via generics. 25 | rv := reflect.ValueOf(value) 26 | rt := rv.Type() 27 | if rt.Kind() != reflect.Ptr { 28 | return fmt.Errorf("failed to unmarshal decimal: unsupported value type (%T)(%#[1]v), supported types: ~string, inf.Dec", value) 29 | } 30 | if rt.Elem().Kind() != reflect.Ptr { 31 | return DecReflect(data, rv) 32 | } 33 | return DecReflectR(data, rv) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /serialization/cqltime/unmarshal.go: -------------------------------------------------------------------------------- 1 | package cqltime 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int64: 15 | return DecInt64(data, v) 16 | case **int64: 17 | return DecInt64R(data, v) 18 | case *time.Duration: 19 | return DecDuration(data, v) 20 | case **time.Duration: 21 | return DecDurationR(data, v) 22 | default: 23 | 24 | // Custom types (type MyTime int64) can be deserialized only via `reflect` package. 25 | // Later, when generic-based serialization is introduced we can do that via generics. 26 | rv := reflect.ValueOf(value) 27 | rt := rv.Type() 28 | if rt.Kind() != reflect.Ptr { 29 | return fmt.Errorf("failed to unmarshal time: unsupported value type (%T)(%[1]v), supported types: ~int64, time.Duration", value) 30 | } 31 | if rt.Elem().Kind() != reflect.Ptr { 32 | return DecReflect(data, rv) 33 | } 34 | return DecReflectR(data, rv) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /serialization/blob/unmarshal.go: -------------------------------------------------------------------------------- 1 | package blob 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *string: 13 | return DecString(data, v) 14 | case **string: 15 | return DecStringR(data, v) 16 | case *[]byte: 17 | return DecBytes(data, v) 18 | case **[]byte: 19 | return DecBytesR(data, v) 20 | case *interface{}: 21 | return DecInterface(data, v) 22 | default: 23 | // Custom types (type MyString string) can be deserialized only via `reflect` package. 24 | // Later, when generic-based serialization is introduced we can do that via generics. 25 | rv := reflect.ValueOf(value) 26 | rt := rv.Type() 27 | if rt.Kind() != reflect.Ptr { 28 | return fmt.Errorf("failed to unmarshal blob: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte", v) 29 | } 30 | if rt.Elem().Kind() != reflect.Ptr { 31 | return DecReflect(data, rv) 32 | } 33 | return DecReflectR(data, rv) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /serialization/text/unmarshal.go: -------------------------------------------------------------------------------- 1 | package text 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *string: 13 | return DecString(data, v) 14 | case **string: 15 | return DecStringR(data, v) 16 | case *[]byte: 17 | return DecBytes(data, v) 18 | case **[]byte: 19 | return DecBytesR(data, v) 20 | case *interface{}: 21 | return DecInterface(data, v) 22 | default: 23 | // Custom types (type MyString string) can be deserialized only via `reflect` package. 24 | // Later, when generic-based serialization is introduced we can do that via generics. 25 | rv := reflect.ValueOf(value) 26 | rt := rv.Type() 27 | if rt.Kind() != reflect.Ptr { 28 | return fmt.Errorf("failed to unmarshal text: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte", v) 29 | } 30 | if rt.Elem().Kind() != reflect.Ptr { 31 | return DecReflect(data, rv) 32 | } 33 | return DecReflectR(data, rv) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /debounce/simple_debouncer.go: -------------------------------------------------------------------------------- 1 | package debounce 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | // SimpleDebouncer is are tool for queuing immutable functions calls. It provides: 9 | // 1. Blocking simultaneous calls 10 | // 2. If there is no running call and no waiting call, then the current call go through 11 | // 3. If there is running call and no waiting call, then the current call go waiting 12 | // 4. If there is running call and waiting call, then the current call are voided 13 | type SimpleDebouncer struct { 14 | m sync.Mutex 15 | count atomic.Int32 16 | } 17 | 18 | // NewSimpleDebouncer creates a new SimpleDebouncer. 19 | func NewSimpleDebouncer() *SimpleDebouncer { 20 | return &SimpleDebouncer{} 21 | } 22 | 23 | // Debounce attempts to execute the function if the logic of the SimpleDebouncer allows it. 24 | func (d *SimpleDebouncer) Debounce(fn func()) bool { 25 | if d.count.Add(1) > 2 { 26 | d.count.Add(-1) 27 | return false 28 | } 29 | d.m.Lock() 30 | fn() 31 | d.count.Add(-1) 32 | d.m.Unlock() 33 | return true 34 | } 35 | -------------------------------------------------------------------------------- /serialization/date/marshal.go: -------------------------------------------------------------------------------- 1 | package date 2 | 3 | import ( 4 | "reflect" 5 | "time" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int32: 13 | return EncInt32(v) 14 | case int64: 15 | return EncInt64(v) 16 | case uint32: 17 | return EncUint32(v) 18 | case string: 19 | return EncString(v) 20 | case time.Time: 21 | return EncTime(v) 22 | 23 | case *int32: 24 | return EncInt32R(v) 25 | case *int64: 26 | return EncInt64R(v) 27 | case *uint32: 28 | return EncUint32R(v) 29 | case *string: 30 | return EncStringR(v) 31 | case *time.Time: 32 | return EncTimeR(v) 33 | default: 34 | // Custom types (type MyDate uint32) can be serialized only via `reflect` package. 35 | // Later, when generic-based serialization is introduced we can do that via generics. 36 | rv := reflect.TypeOf(value) 37 | if rv.Kind() != reflect.Ptr { 38 | return EncReflect(reflect.ValueOf(v)) 39 | } 40 | return EncReflectR(reflect.ValueOf(v)) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /serialization/inet/marshal.go: -------------------------------------------------------------------------------- 1 | package inet 2 | 3 | import ( 4 | "net" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case []byte: 13 | return EncBytes(v) 14 | case *[]byte: 15 | return EncBytesR(v) 16 | case net.IP: 17 | return EncNetIP(v) 18 | case *net.IP: 19 | return EncNetIPr(v) 20 | case [4]byte: 21 | return EncArray4(v) 22 | case *[4]byte: 23 | return EncArray4R(v) 24 | case [16]byte: 25 | return EncArray16(v) 26 | case *[16]byte: 27 | return EncArray16R(v) 28 | case string: 29 | return EncString(v) 30 | case *string: 31 | return EncStringR(v) 32 | default: 33 | // Custom types (type MyIP []byte) can be serialized only via `reflect` package. 34 | // Later, when generic-based serialization is introduced we can do that via generics. 35 | rv := reflect.TypeOf(value) 36 | if rv.Kind() != reflect.Ptr { 37 | return EncReflect(reflect.ValueOf(v)) 38 | } 39 | return EncReflectR(reflect.ValueOf(v)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /serialization/varchar/unmarshal.go: -------------------------------------------------------------------------------- 1 | package varchar 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *string: 13 | return DecString(data, v) 14 | case **string: 15 | return DecStringR(data, v) 16 | case *[]byte: 17 | return DecBytes(data, v) 18 | case **[]byte: 19 | return DecBytesR(data, v) 20 | case *interface{}: 21 | return DecInterface(data, v) 22 | default: 23 | // Custom types (type MyString string) can be deserialized only via `reflect` package. 24 | // Later, when generic-based serialization is introduced we can do that via generics. 25 | rv := reflect.ValueOf(value) 26 | rt := rv.Type() 27 | if rt.Kind() != reflect.Ptr { 28 | return fmt.Errorf("failed to unmarshal varchar: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte", v) 29 | } 30 | if rt.Elem().Kind() != reflect.Ptr { 31 | return DecReflect(data, rv) 32 | } 33 | return DecReflectR(data, rv) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /serialization/uuid/unmarshal.go: -------------------------------------------------------------------------------- 1 | package uuid 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Unmarshal(data []byte, value interface{}) error { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil 12 | case *[16]byte: 13 | return DecArray(data, v) 14 | case **[16]byte: 15 | return DecArrayR(data, v) 16 | case *[]byte: 17 | return DecSlice(data, v) 18 | case **[]byte: 19 | return DecSliceR(data, v) 20 | case *string: 21 | return DecString(data, v) 22 | case **string: 23 | return DecStringR(data, v) 24 | default: 25 | // Custom types (type MyFloat float32) can be deserialized only via `reflect` package. 26 | // Later, when generic-based serialization is introduced we can do that via generics. 27 | rv := reflect.ValueOf(value) 28 | if rv.Kind() != reflect.Ptr { 29 | return fmt.Errorf("failed to unmarshal uuid: unsupported value type (%T)(%[1]v), supported types: ~[]byte, ~[16]byte, ~string", v) 30 | } 31 | if rv.Type().Elem().Kind() != reflect.Ptr { 32 | return DecReflect(data, rv) 33 | } 34 | return DecReflectR(data, rv) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /session_event_bus_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package gocql 5 | 6 | import ( 7 | "net" 8 | "testing" 9 | "time" 10 | 11 | "github.com/gocql/gocql/events" 12 | "github.com/gocql/gocql/internal/eventbus" 13 | ) 14 | 15 | func TestSessionEventBusPublishesEvents(t *testing.T) { 16 | s := &Session{ 17 | eventBus: eventbus.New[events.Event](eventbus.EventBusConfig{ 18 | InputEventsQueueSize: 1, 19 | }, nil), 20 | logger: &nopLogger{}, 21 | } 22 | 23 | if err := s.eventBus.Start(); err != nil { 24 | t.Fatalf("starting event bus: %v", err) 25 | } 26 | defer s.eventBus.Stop() 27 | 28 | sub := s.SubscribeToEvents("test", 1, nil) 29 | defer sub.Stop() 30 | 31 | ev := &events.StatusChangeEvent{ 32 | Change: "UP", 33 | Host: net.ParseIP("127.0.0.1"), 34 | Port: 9042, 35 | } 36 | 37 | s.publishEvent(ev) 38 | 39 | select { 40 | case received := <-sub.Events(): 41 | if received != ev { 42 | t.Fatalf("unexpected event pointer: got %p want %p", received, ev) 43 | } 44 | case <-time.After(2 * time.Second): 45 | t.Fatal("timeout waiting for event") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /testdata/recreate/index_golden.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_idx WITH replication = {'class': 'org.apache.cassandra.locator.NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true; 2 | CREATE TABLE gocqlx_idx.menus ( 3 | location text, 4 | name text, 5 | dish_type text, 6 | price float, 7 | PRIMARY KEY (location, name) 8 | ) WITH CLUSTERING ORDER BY (name ASC) 9 | AND bloom_filter_fp_chance = 0.01 10 | AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'} 11 | AND comment = '' 12 | AND compaction = {'class': 'SizeTieredCompactionStrategy'} 13 | AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'} 14 | AND crc_check_chance = 1 15 | AND default_time_to_live = 0 16 | AND gc_grace_seconds = 864000 17 | AND max_index_interval = 2048 18 | AND memtable_flush_period_in_ms = 0 19 | AND min_index_interval = 128 20 | AND speculative_retry = '99.0PERCENTILE' 21 | AND paxos_grace_seconds = 864000 22 | AND tombstone_gc = {'mode': 'timeout', 'propagation_delay_in_seconds': '3600'}; 23 | CREATE INDEX menus_name_idx ON gocqlx_idx.menus(name); 24 | -------------------------------------------------------------------------------- /serialization/boolean/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package boolean 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func EncBool(v bool) ([]byte, error) { 9 | return encBool(v), nil 10 | } 11 | 12 | func EncBoolR(v *bool) ([]byte, error) { 13 | if v == nil { 14 | return nil, nil 15 | } 16 | return encBool(*v), nil 17 | } 18 | 19 | func EncReflect(v reflect.Value) ([]byte, error) { 20 | switch v.Kind() { 21 | case reflect.Bool: 22 | return encBool(v.Bool()), nil 23 | case reflect.Struct: 24 | if v.Type().String() == "gocql.unsetColumn" { 25 | return nil, nil 26 | } 27 | return nil, fmt.Errorf("failed to marshal boolean: unsupported value type (%T)(%[1]v), supported types: ~bool, unsetColumn", v.Interface()) 28 | default: 29 | return nil, fmt.Errorf("failed to marshal boolean: unsupported value type (%T)(%[1]v), supported types: ~bool, unsetColumn", v.Interface()) 30 | } 31 | } 32 | 33 | func EncReflectR(v reflect.Value) ([]byte, error) { 34 | if v.IsNil() { 35 | return nil, nil 36 | } 37 | return EncReflect(v.Elem()) 38 | } 39 | 40 | func encBool(v bool) []byte { 41 | if v { 42 | return []byte{1} 43 | } 44 | return []byte{0} 45 | } 46 | -------------------------------------------------------------------------------- /testdata/recreate/secondary_index_golden.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_sec_idx WITH replication = {'class': 'org.apache.cassandra.locator.NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true; 2 | CREATE TABLE gocqlx_sec_idx.menus ( 3 | location text, 4 | name text, 5 | dish_type text, 6 | price float, 7 | PRIMARY KEY (location, name) 8 | ) WITH CLUSTERING ORDER BY (name ASC) 9 | AND bloom_filter_fp_chance = 0.01 10 | AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'} 11 | AND comment = '' 12 | AND compaction = {'class': 'SizeTieredCompactionStrategy'} 13 | AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'} 14 | AND crc_check_chance = 1 15 | AND default_time_to_live = 0 16 | AND gc_grace_seconds = 864000 17 | AND max_index_interval = 2048 18 | AND memtable_flush_period_in_ms = 0 19 | AND min_index_interval = 128 20 | AND speculative_retry = '99.0PERCENTILE' 21 | AND paxos_grace_seconds = 864000 22 | AND tombstone_gc = {'mode': 'timeout', 'propagation_delay_in_seconds': '3600'}; 23 | CREATE INDEX menus_name_idx ON gocqlx_sec_idx.menus((location), name); 24 | -------------------------------------------------------------------------------- /lz4/go.mod: -------------------------------------------------------------------------------- 1 | // 2 | // Licensed to the Apache Software Foundation (ASF) under one 3 | // or more contributor license agreements. See the NOTICE file 4 | // distributed with this work for additional information 5 | // regarding copyright ownership. The ASF licenses this file 6 | // to you under the Apache License, Version 2.0 (the 7 | // "License"); you may not use this file except in compliance 8 | // with the License. You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | module github.com/gocql/gocql/lz4 19 | 20 | go 1.25.0 21 | 22 | require ( 23 | github.com/pierrec/lz4/v4 v4.1.23 24 | github.com/stretchr/testify v1.11.1 25 | ) 26 | 27 | require ( 28 | github.com/davecgh/go-spew v1.1.1 // indirect 29 | github.com/pmezard/go-difflib v1.0.0 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /serialization/timeuuid/unmarshal.go: -------------------------------------------------------------------------------- 1 | package timeuuid 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | case *[16]byte: 14 | return DecArray(data, v) 15 | case **[16]byte: 16 | return DecArrayR(data, v) 17 | case *[]byte: 18 | return DecSlice(data, v) 19 | case **[]byte: 20 | return DecSliceR(data, v) 21 | case *string: 22 | return DecString(data, v) 23 | case **string: 24 | return DecStringR(data, v) 25 | case *time.Time: 26 | return DecTime(data, v) 27 | case **time.Time: 28 | return DecTimeR(data, v) 29 | default: 30 | // Custom types (type MyFloat float32) can be deserialized only via `reflect` package. 31 | // Later, when generic-based serialization is introduced we can do that via generics. 32 | rv := reflect.ValueOf(value) 33 | if rv.Kind() != reflect.Ptr { 34 | return fmt.Errorf("failed to unmarshal timeuuid: unsupported value type (%T)(%[1]v), supported types: ~[]byte, ~[16]byte, ~string", v) 35 | } 36 | if rv.Type().Elem().Kind() != reflect.Ptr { 37 | return DecReflect(data, rv) 38 | } 39 | return DecReflectR(data, rv) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /internal/debug/debug_off.go: -------------------------------------------------------------------------------- 1 | //go:build !gocql_debug 2 | // +build !gocql_debug 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package debug 29 | 30 | const Enabled = false 31 | -------------------------------------------------------------------------------- /internal/debug/debug_on.go: -------------------------------------------------------------------------------- 1 | //go:build gocql_debug 2 | // +build gocql_debug 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package debug 29 | 30 | const Enabled = true 31 | -------------------------------------------------------------------------------- /lz4/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= 4 | github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 5 | github.com/pierrec/lz4/v4 v4.1.23 h1:oJE7T90aYBGtFNrI8+KbETnPymobAhzRrR8Mu8n1yfU= 6 | github.com/pierrec/lz4/v4 v4.1.23/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 10 | github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 14 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /cqltypes.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | /* 19 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 20 | * Copyright (c) 2012, The Gocql authors, 21 | * provided under the BSD-3-Clause License. 22 | * See the NOTICE file distributed with this work for additional information. 23 | */ 24 | 25 | package gocql 26 | 27 | type Duration struct { 28 | Months int32 29 | Days int32 30 | Nanoseconds int64 31 | } 32 | -------------------------------------------------------------------------------- /serialization/duration/unmarshal.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int64: 15 | return DecInt64(data, v) 16 | case *string: 17 | return DecString(data, v) 18 | case *time.Duration: 19 | return DecDur(data, v) 20 | case *Duration: 21 | return DecDuration(data, v) 22 | 23 | case **int64: 24 | return DecInt64R(data, v) 25 | case **string: 26 | return DecStringR(data, v) 27 | case **time.Duration: 28 | return DecDurR(data, v) 29 | case **Duration: 30 | return DecDurationR(data, v) 31 | default: 32 | 33 | // Custom types (type MyDate uint32) can be deserialized only via `reflect` package. 34 | // Later, when generic-based serialization is introduced we can do that via generics. 35 | rv := reflect.ValueOf(value) 36 | rt := rv.Type() 37 | if rt.Kind() != reflect.Ptr { 38 | return fmt.Errorf("failed to unmarshal duration: unsupported value type (%T)(%[1]v), supported types: ~int64, ~string, time.Duration, gocql.Duration", value) 39 | } 40 | if rt.Elem().Kind() != reflect.Ptr { 41 | return DecReflect(data, rv) 42 | } 43 | return DecReflectR(data, rv) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /serialization/inet/unmarshal.go: -------------------------------------------------------------------------------- 1 | package inet 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | case *[]byte: 14 | return DecBytes(data, v) 15 | case **[]byte: 16 | return DecBytesR(data, v) 17 | case *net.IP: 18 | return DecNetIP(data, v) 19 | case **net.IP: 20 | return DecNetIPr(data, v) 21 | case *[4]byte: 22 | return DecArray4(data, v) 23 | case **[4]byte: 24 | return DecArray4R(data, v) 25 | case *[16]byte: 26 | return DecArray16(data, v) 27 | case **[16]byte: 28 | return DecArray16R(data, v) 29 | case *string: 30 | return DecString(data, v) 31 | case **string: 32 | return DecStringR(data, v) 33 | default: 34 | // Custom types (type MyIP []byte) can be deserialized only via `reflect` package. 35 | // Later, when generic-based serialization is introduced we can do that via generics. 36 | rv := reflect.ValueOf(value) 37 | rt := rv.Type() 38 | if rt.Kind() != reflect.Ptr { 39 | return fmt.Errorf("failed to unmarshal inet: unsupported value type (%T)(%[1]v), supported types: ~[]byte, ~[4]byte, ~[16]byte, ~string, net.IP", v) 40 | } 41 | if rt.Elem().Kind() != reflect.Ptr { 42 | return DecReflect(data, rv) 43 | } 44 | return DecReflectR(data, rv) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /serialization/date/unmarshal.go: -------------------------------------------------------------------------------- 1 | package date 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int32: 15 | return DecInt32(data, v) 16 | case *int64: 17 | return DecInt64(data, v) 18 | case *uint32: 19 | return DecUint32(data, v) 20 | case *string: 21 | return DecString(data, v) 22 | case *time.Time: 23 | return DecTime(data, v) 24 | 25 | case **int32: 26 | return DecInt32R(data, v) 27 | case **int64: 28 | return DecInt64R(data, v) 29 | case **uint32: 30 | return DecUint32R(data, v) 31 | case **string: 32 | return DecStringR(data, v) 33 | case **time.Time: 34 | return DecTimeR(data, v) 35 | default: 36 | 37 | // Custom types (type MyDate uint32) can be deserialized only via `reflect` package. 38 | // Later, when generic-based serialization is introduced we can do that via generics. 39 | rv := reflect.ValueOf(value) 40 | rt := rv.Type() 41 | if rt.Kind() != reflect.Ptr { 42 | return fmt.Errorf("failed to unmarshal date: unsupported value type (%T)(%[1]v), supported types: ~int32, ~int64, ~uint32, ~string, time.Time", value) 43 | } 44 | if rt.Elem().Kind() != reflect.Ptr { 45 | return DecReflect(data, rv) 46 | } 47 | return DecReflectR(data, rv) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /internal/tests/serialization/pointers_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization 5 | 6 | import "testing" 7 | 8 | func Test1Pointers(t *testing.T) { 9 | t.Parallel() 10 | 11 | val1 := new(int16) 12 | *val1 = int16(0) 13 | testPtr := getPointers(val1) 14 | 15 | // the first pointer has not been changed - it must be not error. 16 | if err := testPtr.Valid(val1); err != nil { 17 | t.Error("valid function not should return error") 18 | } 19 | 20 | val2 := new(int16) 21 | // the first pointer has been changed - it must be an error. 22 | if err := testPtr.Valid(val2); err == nil { 23 | t.Error("valid function should return error") 24 | } 25 | } 26 | 27 | func Test2Pointers(t *testing.T) { 28 | t.Parallel() 29 | 30 | val1 := new(*int16) 31 | *val1 = new(int16) 32 | testPtr := getPointers(val1) 33 | // the first pointer has not been changed - it must be not error, 34 | // but the second pointer has not been changed too - it must be an error. 35 | if err := testPtr.Valid(val1); err == nil { 36 | t.Error("valid function should return error") 37 | } 38 | 39 | *val1 = new(int16) 40 | // the first pointer has not been changed - it must be not error, 41 | // the second pointer has been changed - it must be not error. 42 | if err := testPtr.Valid(val1); err != nil { 43 | t.Error("valid function not should return error") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /integration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2017 ScyllaDB 4 | # 5 | 6 | readonly SCYLLA_IMAGE=${SCYLLA_IMAGE} 7 | 8 | set -eu -o pipefail 9 | 10 | function scylla_up() { 11 | local -r exec="docker compose exec -T" 12 | 13 | echo "==> Running Scylla ${SCYLLA_IMAGE}" 14 | docker pull ${SCYLLA_IMAGE} 15 | docker compose up -d --wait || ( docker compose ps --format json | jq -M 'select(.Health == "unhealthy") | .Service' | xargs docker compose logs; exit 1 ) 16 | } 17 | 18 | function scylla_down() { 19 | echo "==> Stopping Scylla" 20 | docker compose down 21 | } 22 | 23 | function scylla_restart() { 24 | scylla_down 25 | scylla_up 26 | } 27 | 28 | scylla_restart 29 | 30 | sudo chmod 0777 /tmp/scylla_node_1/cql.m 31 | sudo chmod 0777 /tmp/scylla_node_2/cql.m 32 | sudo chmod 0777 /tmp/scylla_node_3/cql.m 33 | 34 | readonly clusterSize=3 35 | readonly scylla_liveset="192.168.100.11,192.168.100.12,192.168.100.13" 36 | readonly cversion="3.11.4" 37 | readonly proto=4 38 | readonly args="-cluster-socket /tmp/scylla_node_1/cql.m -gocql.timeout=60s -proto=${proto} -rf=1 -clusterSize=${clusterSize} -autowait=2000ms -compressor=snappy -gocql.cversion=${cversion} -cluster=${scylla_liveset}" 39 | 40 | TAGS=$* 41 | 42 | if [ ! -z "$TAGS" ]; 43 | then 44 | echo "==> Running ${TAGS} tests with args: ${args}" 45 | go test -v -timeout=5m -race -tags="$TAGS" ${args} ./... 46 | fi 47 | -------------------------------------------------------------------------------- /testdata/recreate/table.cql: -------------------------------------------------------------------------------- 1 | CREATE KEYSPACE gocqlx_table WITH replication = { 2 | 'class': 'NetworkTopologyStrategy', 3 | 'replication_factor': '2' 4 | }; 5 | 6 | CREATE TABLE gocqlx_table.monkeySpecies ( 7 | species text PRIMARY KEY, 8 | common_name text, 9 | population varint, 10 | average_size int 11 | ) WITH comment='Important biological records'; 12 | 13 | CREATE TABLE gocqlx_table.timeline ( 14 | userid uuid, 15 | posted_month int, 16 | posted_time uuid, 17 | body text, 18 | posted_by text, 19 | PRIMARY KEY (userid, posted_month, posted_time) 20 | ) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; 21 | 22 | CREATE TABLE gocqlx_table.loads ( 23 | machine inet, 24 | cpu int, 25 | mtime timeuuid, 26 | load float, 27 | PRIMARY KEY ((machine, cpu), mtime) 28 | ) WITH CLUSTERING ORDER BY (mtime DESC) 29 | AND caching = {'keys':'ALL', 'rows_per_partition':'NONE'} 30 | AND compaction = {'compaction_window_size': '14', 31 | 'compaction_window_unit': 'DAYS', 32 | 'class': 'org.apache.cassandra.db.compaction.TimeWindowCompactionStrategy'}; 33 | 34 | CREATE TABLE gocqlx_table.users_picture ( 35 | userid uuid, 36 | pictureid uuid, 37 | body text static, 38 | posted_by text, 39 | PRIMARY KEY (userid, pictureid, posted_by) 40 | ) WITH compression = {'sstable_compression': 'LZ4Compressor'}; 41 | -------------------------------------------------------------------------------- /serialization/duration/unmarshal_vint_test.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestDecVint32(t *testing.T) { 9 | for i := int32(math.MaxInt32); i != 1; i = i / 2 { 10 | testDec32(t, i) 11 | testDec32(t, -i-1) 12 | } 13 | } 14 | 15 | func TestDecVint64(t *testing.T) { 16 | for i := int64(math.MaxInt64); i != 1; i = i / 2 { 17 | testDec64(t, i) 18 | testDec64(t, -i-1) 19 | } 20 | } 21 | 22 | func testDec32(t *testing.T, expected int32) { 23 | t.Helper() 24 | // appending one byte is necessary because the `decVint32` function looks at the length of the data for the next vint len read. 25 | data := append(genVintData(int64(expected)), 0) 26 | 27 | vint, read := decVint32(data, 0) 28 | if read == 0 { 29 | t.Fatalf("decVint32 function can`t read vint data: value %d, data %b", expected, data) 30 | } 31 | 32 | received := decZigZag32(vint) 33 | if expected != received { 34 | t.Fatalf("\nexpected:%d\nreceived:%d\ndata:%b", expected, received, data) 35 | } 36 | } 37 | 38 | func testDec64(t *testing.T, expected int64) { 39 | t.Helper() 40 | data := genVintData(int64(expected)) 41 | 42 | vint, read := decVint64(data, 0) 43 | if read == 0 { 44 | t.Fatalf("decVint64 function can`t read vint data: value %d, data %b", expected, data) 45 | } 46 | 47 | received := decZigZag64(vint) 48 | if expected != received { 49 | t.Fatalf("\nexpected:%d\nreceived:%d\ndata:%b", expected, received, data) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /internal/murmur/murmur_unsafe.go: -------------------------------------------------------------------------------- 1 | //go:build !appengine && !s390x 2 | // +build !appengine,!s390x 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package murmur 29 | 30 | import ( 31 | "unsafe" 32 | ) 33 | 34 | func getBlock(data []byte, n int) (int64, int64) { 35 | block := (*[2]int64)(unsafe.Pointer(&data[n*16])) 36 | 37 | k1 := block[0] 38 | k2 := block[1] 39 | return k1, k2 40 | } 41 | -------------------------------------------------------------------------------- /internal/murmur/murmur_appengine.go: -------------------------------------------------------------------------------- 1 | //go:build appengine || s390x 2 | // +build appengine s390x 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package murmur 29 | 30 | import "encoding/binary" 31 | 32 | func getBlock(data []byte, n int) (int64, int64) { 33 | k1 := int64(binary.LittleEndian.Uint64(data[n*16:])) 34 | k2 := int64(binary.LittleEndian.Uint64(data[(n*16)+8:])) 35 | return k1, k2 36 | } 37 | -------------------------------------------------------------------------------- /internal/tests/serialization/utils_str.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "net" 7 | "reflect" 8 | "time" 9 | 10 | "gopkg.in/inf.v0" 11 | ) 12 | 13 | const printLimit = 100 14 | 15 | // stringValue returns (value_type)(value) in the human-readable format. 16 | func stringValue(in interface{}) string { 17 | valStr := stringVal(in) 18 | if len(valStr) > printLimit { 19 | return fmt.Sprintf("(%T)", in) 20 | } 21 | return fmt.Sprintf("(%T)(%s)", in, valStr) 22 | } 23 | 24 | func stringData(p []byte) string { 25 | if len(p) > printLimit { 26 | p = p[:printLimit] 27 | } 28 | if p == nil { 29 | return "[nil]" 30 | } 31 | return fmt.Sprintf("[%x]", p) 32 | } 33 | 34 | func stringVal(in interface{}) string { 35 | switch i := in.(type) { 36 | case string: 37 | return i 38 | case inf.Dec: 39 | return fmt.Sprintf("%v", i.String()) 40 | case big.Int: 41 | return fmt.Sprintf("%v", i.String()) 42 | case net.IP: 43 | return fmt.Sprintf("%v", []byte(i)) 44 | case time.Time: 45 | return fmt.Sprintf("%v", i.UnixMilli()) 46 | case nil: 47 | return "nil" 48 | } 49 | 50 | rv := reflect.ValueOf(in) 51 | switch rv.Kind() { 52 | case reflect.Ptr: 53 | if rv.IsNil() { 54 | return "*nil" 55 | } 56 | return fmt.Sprintf("*%s", stringVal(rv.Elem().Interface())) 57 | case reflect.Slice: 58 | if rv.IsNil() { 59 | return "[nil]" 60 | } 61 | return fmt.Sprintf("%v", rv.Interface()) 62 | default: 63 | return fmt.Sprintf("%v", in) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/serialization/marshal_1_boolean_corrupt_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql/serialization/boolean" 10 | 11 | "github.com/gocql/gocql" 12 | "github.com/gocql/gocql/internal/tests/serialization" 13 | "github.com/gocql/gocql/internal/tests/serialization/mod" 14 | ) 15 | 16 | func TestMarshalBooleanCorrupt(t *testing.T) { 17 | t.Parallel() 18 | 19 | tType := gocql.NewNativeType(4, gocql.TypeBoolean) 20 | 21 | type testSuite struct { 22 | name string 23 | marshal func(interface{}) ([]byte, error) 24 | unmarshal func(bytes []byte, i interface{}) error 25 | } 26 | 27 | testSuites := [2]testSuite{ 28 | { 29 | name: "serialization.boolean", 30 | marshal: boolean.Marshal, 31 | unmarshal: boolean.Unmarshal, 32 | }, 33 | { 34 | name: "glob", 35 | marshal: func(i interface{}) ([]byte, error) { 36 | return gocql.Marshal(tType, i) 37 | }, 38 | unmarshal: func(bytes []byte, i interface{}) error { 39 | return gocql.Unmarshal(tType, bytes, i) 40 | }, 41 | }, 42 | } 43 | 44 | for _, tSuite := range testSuites { 45 | unmarshal := tSuite.unmarshal 46 | 47 | t.Run(tSuite.name, func(t *testing.T) { 48 | t.Parallel() 49 | 50 | serialization.NegativeUnmarshalSet{ 51 | Data: []byte("\x00\x00"), 52 | Values: mod.Values{ 53 | false, 54 | }.AddVariants(mod.All...), 55 | }.Run("big_data", t, unmarshal) 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tracer_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import "testing" 7 | 8 | func TestTracingNewAPI(t *testing.T) { 9 | session := createSession(t) 10 | defer session.Close() 11 | 12 | if err := createTable(session, `CREATE TABLE gocql_test.trace2 (id int primary key)`); err != nil { 13 | t.Fatal("create:", err) 14 | } 15 | 16 | trace := NewTracer(session) 17 | if err := session.Query(`INSERT INTO trace2 (id) VALUES (?)`, 42).Trace(trace).Exec(); err != nil { 18 | t.Fatal("insert:", err) 19 | } 20 | 21 | var value int 22 | if err := session.Query(`SELECT id FROM trace2 WHERE id = ?`, 42).Trace(trace).Scan(&value); err != nil { 23 | t.Fatal("select:", err) 24 | } else if value != 42 { 25 | t.Fatalf("value: expected %d, got %d", 42, value) 26 | } 27 | 28 | for _, traceID := range trace.AllTraceIDs() { 29 | var ( 30 | isReady bool 31 | err error 32 | ) 33 | for !isReady { 34 | isReady, err = trace.IsReady(traceID) 35 | if err != nil { 36 | t.Fatal("Error: ", err) 37 | } 38 | } 39 | activities, err := trace.GetActivities(traceID) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | coordinator, _, err := trace.GetCoordinatorTime(traceID) 44 | if err != nil { 45 | t.Fatal(err) 46 | } 47 | if len(activities) == 0 { 48 | t.Fatal("Failed to obtain any tracing for tradeID: ", traceID) 49 | } else if coordinator == "" { 50 | t.Fatal("Failed to obtain coordinator for traceID: ", traceID) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/docs-pr.yml: -------------------------------------------------------------------------------- 1 | name: "Docs / Build PR" 2 | # For more information, 3 | # see https://sphinx-theme.scylladb.com/stable/deployment/production.html#available-workflows 4 | 5 | on: 6 | push: 7 | paths: 8 | - "docs/**" 9 | - ".github/workflows/docs-pr.yml" 10 | pull_request: 11 | types: [opened, synchronize, reopened] 12 | paths: 13 | - "docs/**" 14 | - ".github/workflows/docs-pr.yml" 15 | workflow_dispatch: 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v6 26 | with: 27 | persist-credentials: false 28 | fetch-depth: 0 29 | 30 | - uses: actions/cache@v5 31 | # actions/setup-python@v6 poetry cache feature requires poetry to be installed beforehand 32 | # which makes use of it extremely awkward. 33 | with: 34 | path: | 35 | /home/runner/.cache/pip 36 | /home/runner/.cache/pypoetry 37 | # python and poetry version are in docs/pyproject.toml 38 | key: docs-cache-${{ runner.os }}-${{ hashFiles('docs/pyproject.toml', 'docs/Makefile') }} 39 | 40 | - name: Set up Python 41 | uses: actions/setup-python@v6 42 | with: 43 | python-version-file: docs/pyproject.toml 44 | 45 | - name: Set up env 46 | run: make -C docs setupenv 47 | 48 | - name: Build docs 49 | run: make -C docs test -------------------------------------------------------------------------------- /serialization/float/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package float 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | func EncFloat32(v float32) ([]byte, error) { 10 | return encFloat32(v), nil 11 | } 12 | 13 | func EncFloat32R(v *float32) ([]byte, error) { 14 | if v == nil { 15 | return nil, nil 16 | } 17 | return encFloat32R(v), nil 18 | } 19 | 20 | func EncReflect(v reflect.Value) ([]byte, error) { 21 | switch v.Kind() { 22 | case reflect.Float32: 23 | return encFloat32(float32(v.Float())), nil 24 | case reflect.Struct: 25 | if v.Type().String() == "gocql.unsetColumn" { 26 | return nil, nil 27 | } 28 | return nil, fmt.Errorf("failed to marshal float: unsupported value type (%T)(%[1]v), supported types: ~float32, unsetColumn", v.Interface()) 29 | default: 30 | return nil, fmt.Errorf("failed to marshal float: unsupported value type (%T)(%[1]v), supported types: ~float32, unsetColumn", v.Interface()) 31 | } 32 | } 33 | 34 | func EncReflectR(v reflect.Value) ([]byte, error) { 35 | if v.IsNil() { 36 | return nil, nil 37 | } 38 | return EncReflect(v.Elem()) 39 | } 40 | 41 | func encFloat32(v float32) []byte { 42 | return encUint32(floatToUint(v)) 43 | } 44 | 45 | func encFloat32R(v *float32) []byte { 46 | return encUint32(floatToUintR(v)) 47 | } 48 | 49 | func encUint32(v uint32) []byte { 50 | return []byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} 51 | } 52 | 53 | func floatToUint(v float32) uint32 { 54 | return *(*uint32)(unsafe.Pointer(&v)) 55 | } 56 | 57 | func floatToUintR(v *float32) uint32 { 58 | return *(*uint32)(unsafe.Pointer(v)) 59 | } 60 | -------------------------------------------------------------------------------- /serialization/duration/marshal_str_test.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestEncStr(t *testing.T) { 9 | for n := int64(math.MaxInt64); n != 1; n = n / 2 { 10 | m, d := int32(n), int32(n) 11 | if n > math.MaxInt32 { 12 | m, d = math.MaxInt32, math.MaxInt32 13 | } 14 | testEncString(t, m, d, n) 15 | testEncString(t, 0, d, n) 16 | testEncString(t, m, 0, n) 17 | testEncString(t, m, d, 0) 18 | } 19 | 20 | for n := int64(math.MinInt64); n != -1; n = n / 2 { 21 | m, d := int32(n), int32(n) 22 | if n < math.MinInt32 { 23 | m, d = math.MinInt32, math.MinInt32 24 | } 25 | testEncString(t, m, d, n) 26 | testEncString(t, 0, d, n) 27 | testEncString(t, m, 0, n) 28 | testEncString(t, m, d, 0) 29 | } 30 | } 31 | 32 | func testEncString(t *testing.T, m, d int32, n int64) { 33 | t.Helper() 34 | testStr := getTestString(m, d, n) 35 | mu, du, nu, neg, err := encStringToUints(testStr) 36 | if err != nil { 37 | t.Fatalf("failed on encoding testcase value:m:%d,d:%d,n:%d\ntest string:%s\nerror:%s", m, d, n, testStr, err) 38 | } 39 | me, de, ne := int32(mu), int32(du), int64(nu) 40 | if neg { 41 | me, de, ne = -me, -de, -ne 42 | } 43 | if me != m { 44 | t.Fatalf("testcase:%s\nexpected and recieved months not equal expected:%d received:%d", testStr, m, me) 45 | } 46 | if de != d { 47 | t.Fatalf("testcase:%s\nexpected and recieved days not equal expected:%d received:%d", testStr, d, de) 48 | } 49 | if ne != n { 50 | t.Fatalf("testcase:%s\nexpected and recieved nonoseconds not equal expected:%d received:%d", testStr, n, ne) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /serialization/duration/marshal_vint_test.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "bytes" 5 | "math" 6 | "math/bits" 7 | "testing" 8 | ) 9 | 10 | func TestEncVint32(t *testing.T) { 11 | for i := int32(math.MaxInt32); i != 1; i = i / 2 { 12 | testEnc32(t, i) 13 | testEnc32(t, -i-1) 14 | } 15 | } 16 | 17 | func TestEncVint64(t *testing.T) { 18 | for i := int64(math.MaxInt64); i != 1; i = i / 2 { 19 | testEnc64(t, i) 20 | testEnc64(t, -i-1) 21 | } 22 | } 23 | 24 | func testEnc32(t *testing.T, v int32) { 25 | t.Helper() 26 | expected := genVintData(int64(v)) 27 | received := encVint32(encIntZigZag32(v)) 28 | 29 | if !bytes.Equal(expected, received) { 30 | t.Fatalf("expected and recieved data not equal\nvalue:%d\ndata expected:%b\ndata received:%b", v, expected, received) 31 | } 32 | } 33 | 34 | func testEnc64(t *testing.T, v int64) { 35 | t.Helper() 36 | expected := genVintData(v) 37 | received := encVint64(encIntZigZag64(v)) 38 | 39 | if !bytes.Equal(expected, received) { 40 | t.Fatalf("expected and recieved data not equal\nvalue:%d\ndata expected:%b\ndata received:%b", v, expected, received) 41 | } 42 | } 43 | 44 | func genVintData(v int64) []byte { 45 | vEnc := encIntZigZag64(v) 46 | lead0 := bits.LeadingZeros64(vEnc) 47 | numBytes := (639 - lead0*9) >> 6 48 | 49 | // It can be 1 or 0 is v ==0 50 | if numBytes <= 1 { 51 | return []byte{byte(vEnc)} 52 | } 53 | extraBytes := numBytes - 1 54 | var buf = make([]byte, numBytes) 55 | for i := extraBytes; i >= 0; i-- { 56 | buf[i] = byte(vEnc) 57 | vEnc >>= 8 58 | } 59 | buf[0] |= byte(^(0xff >> uint(extraBytes))) 60 | return buf 61 | } 62 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | /* 19 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 20 | * Copyright (c) 2016, The Gocql authors, 21 | * provided under the BSD-3-Clause License. 22 | * See the NOTICE file distributed with this work for additional information. 23 | */ 24 | 25 | package gocql 26 | 27 | import "runtime/debug" 28 | 29 | const ( 30 | mainPackage = "github.com/gocql/gocql" 31 | ) 32 | 33 | var defaultDriverVersion string 34 | 35 | func init() { 36 | buildInfo, ok := debug.ReadBuildInfo() 37 | if ok { 38 | for _, d := range buildInfo.Deps { 39 | if d.Path == mainPackage { 40 | defaultDriverVersion = d.Version 41 | if d.Replace != nil { 42 | defaultDriverVersion = d.Replace.Version 43 | } 44 | break 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /serialization/double/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package double 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | ) 8 | 9 | func EncFloat64(v float64) ([]byte, error) { 10 | return encFloat64(v), nil 11 | } 12 | 13 | func EncFloat64R(v *float64) ([]byte, error) { 14 | if v == nil { 15 | return nil, nil 16 | } 17 | return encFloat64R(v), nil 18 | } 19 | 20 | func EncReflect(v reflect.Value) ([]byte, error) { 21 | switch v.Kind() { 22 | case reflect.Float64: 23 | return encFloat64(v.Float()), nil 24 | case reflect.Struct: 25 | if v.Type().String() == "gocql.unsetColumn" { 26 | return nil, nil 27 | } 28 | return nil, fmt.Errorf("failed to marshal double: unsupported value type (%T)(%[1]v), supported types: ~float64, unsetColumn", v.Interface()) 29 | default: 30 | return nil, fmt.Errorf("failed to marshal double: unsupported value type (%T)(%[1]v), supported types: ~float64, unsetColumn", v.Interface()) 31 | } 32 | } 33 | 34 | func EncReflectR(v reflect.Value) ([]byte, error) { 35 | if v.IsNil() { 36 | return nil, nil 37 | } 38 | return EncReflect(v.Elem()) 39 | } 40 | 41 | func encFloat64(v float64) []byte { 42 | return encUint64(floatToUint(v)) 43 | } 44 | 45 | func encFloat64R(v *float64) []byte { 46 | return encUint64(floatToUintR(v)) 47 | } 48 | 49 | func encUint64(v uint64) []byte { 50 | return []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} 51 | } 52 | 53 | func floatToUint(v float64) uint64 { 54 | return *(*uint64)(unsafe.Pointer(&v)) 55 | } 56 | 57 | func floatToUintR(v *float64) uint64 { 58 | return *(*uint64)(unsafe.Pointer(v)) 59 | } 60 | -------------------------------------------------------------------------------- /internal/tests/serialization/set_negative_marshal.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | "runtime/debug" 7 | "testing" 8 | ) 9 | 10 | // NegativeMarshalSet is a tool for marshal funcs testing for cases when the function should an error. 11 | type NegativeMarshalSet struct { 12 | Values []interface{} 13 | BrokenTypes []reflect.Type 14 | } 15 | 16 | func (s NegativeMarshalSet) Run(name string, t *testing.T, marshal func(interface{}) ([]byte, error)) { 17 | if name == "" { 18 | t.Fatal("name should be provided") 19 | } 20 | if marshal == nil { 21 | t.Fatal("marshal function should be provided") 22 | } 23 | t.Run(name, func(t *testing.T) { 24 | for m := range s.Values { 25 | val := s.Values[m] 26 | 27 | t.Run(stringValue(val), func(t *testing.T) { 28 | _, err := func() (d []byte, err error) { 29 | defer func() { 30 | if r := recover(); r != nil { 31 | err = panicErr{err: r.(error), stack: debug.Stack()} 32 | } 33 | }() 34 | return marshal(val) 35 | }() 36 | 37 | testFailed := false 38 | wasPanic := errors.As(err, &panicErr{}) 39 | if err == nil || wasPanic { 40 | testFailed = true 41 | } 42 | 43 | if isTypeOf(val, s.BrokenTypes) { 44 | if testFailed { 45 | t.Skipf("skipped bacause there is unsolved problem") 46 | } 47 | t.Fatalf("expected to panic or no error for (%T), but got an error", val) 48 | } 49 | 50 | if testFailed { 51 | if wasPanic { 52 | t.Fatalf("was panic %s", err) 53 | } 54 | t.Errorf("expected an error for (%T), but got no error", val) 55 | } 56 | }) 57 | } 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /tests/serialization/marshal_12_ascii_corrupt_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql" 10 | "github.com/gocql/gocql/internal/tests/serialization" 11 | "github.com/gocql/gocql/internal/tests/serialization/mod" 12 | "github.com/gocql/gocql/serialization/ascii" 13 | ) 14 | 15 | func TestMarshalAsciiMustFail(t *testing.T) { 16 | t.Parallel() 17 | 18 | tType := gocql.NewNativeType(4, gocql.TypeAscii) 19 | 20 | type testSuite struct { 21 | name string 22 | marshal func(interface{}) ([]byte, error) 23 | unmarshal func(bytes []byte, i interface{}) error 24 | } 25 | 26 | testSuites := [2]testSuite{ 27 | { 28 | name: "serialization.ascii", 29 | marshal: ascii.Marshal, 30 | unmarshal: ascii.Unmarshal, 31 | }, 32 | { 33 | name: "glob", 34 | marshal: func(i interface{}) ([]byte, error) { 35 | return gocql.Marshal(tType, i) 36 | }, 37 | unmarshal: func(bytes []byte, i interface{}) error { 38 | return gocql.Unmarshal(tType, bytes, i) 39 | }, 40 | }, 41 | } 42 | 43 | for _, tSuite := range testSuites { 44 | unmarshal := tSuite.unmarshal 45 | 46 | t.Run(tSuite.name, func(t *testing.T) { 47 | t.Parallel() 48 | 49 | serialization.NegativeUnmarshalSet{ 50 | Data: []byte{255}, 51 | Values: mod.Values{[]byte{}, ""}.AddVariants(mod.All...), 52 | }.Run("corrupt_data1", t, unmarshal) 53 | 54 | serialization.NegativeUnmarshalSet{ 55 | Data: []byte{127, 255, 127}, 56 | Values: mod.Values{[]byte{}, ""}.AddVariants(mod.All...), 57 | }.Run("corrupt_data2", t, unmarshal) 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /serialization/blob/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package blob 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func EncString(v string) ([]byte, error) { 9 | return encString(v), nil 10 | } 11 | 12 | func EncStringR(v *string) ([]byte, error) { 13 | if v == nil { 14 | return nil, nil 15 | } 16 | return encString(*v), nil 17 | } 18 | 19 | func EncBytes(v []byte) ([]byte, error) { 20 | return v, nil 21 | } 22 | 23 | func EncBytesR(v *[]byte) ([]byte, error) { 24 | if v == nil { 25 | return nil, nil 26 | } 27 | return *v, nil 28 | } 29 | 30 | func EncReflect(v reflect.Value) ([]byte, error) { 31 | switch v.Kind() { 32 | case reflect.String: 33 | return encString(v.String()), nil 34 | case reflect.Slice: 35 | if v.Type().Elem().Kind() != reflect.Uint8 { 36 | return nil, fmt.Errorf("failed to marshal blob: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 37 | } 38 | return EncBytes(v.Bytes()) 39 | case reflect.Struct: 40 | if v.Type().String() == "gocql.unsetColumn" { 41 | return nil, nil 42 | } 43 | return nil, fmt.Errorf("failed to marshal blob: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 44 | default: 45 | return nil, fmt.Errorf("failed to marshal blob: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 46 | } 47 | } 48 | 49 | func EncReflectR(v reflect.Value) ([]byte, error) { 50 | if v.IsNil() { 51 | return nil, nil 52 | } 53 | return EncReflect(v.Elem()) 54 | } 55 | 56 | func encString(v string) []byte { 57 | if v == "" { 58 | return make([]byte, 0) 59 | } 60 | return []byte(v) 61 | } 62 | -------------------------------------------------------------------------------- /serialization/text/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package text 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func EncString(v string) ([]byte, error) { 9 | return encString(v), nil 10 | } 11 | 12 | func EncStringR(v *string) ([]byte, error) { 13 | if v == nil { 14 | return nil, nil 15 | } 16 | return encString(*v), nil 17 | } 18 | 19 | func EncBytes(v []byte) ([]byte, error) { 20 | return v, nil 21 | } 22 | 23 | func EncBytesR(v *[]byte) ([]byte, error) { 24 | if v == nil { 25 | return nil, nil 26 | } 27 | return *v, nil 28 | } 29 | 30 | func EncReflect(v reflect.Value) ([]byte, error) { 31 | switch v.Kind() { 32 | case reflect.String: 33 | return encString(v.String()), nil 34 | case reflect.Slice: 35 | if v.Type().Elem().Kind() != reflect.Uint8 { 36 | return nil, fmt.Errorf("failed to marshal text: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 37 | } 38 | return EncBytes(v.Bytes()) 39 | case reflect.Struct: 40 | if v.Type().String() == "gocql.unsetColumn" { 41 | return nil, nil 42 | } 43 | return nil, fmt.Errorf("failed to marshal text: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 44 | default: 45 | return nil, fmt.Errorf("failed to marshal text: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 46 | } 47 | } 48 | 49 | func EncReflectR(v reflect.Value) ([]byte, error) { 50 | if v.IsNil() { 51 | return nil, nil 52 | } 53 | return EncReflect(v.Elem()) 54 | } 55 | 56 | func encString(v string) []byte { 57 | if v == "" { 58 | return make([]byte, 0) 59 | } 60 | return []byte(v) 61 | } 62 | -------------------------------------------------------------------------------- /serialization/ascii/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package ascii 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func EncString(v string) ([]byte, error) { 9 | return encString(v), nil 10 | } 11 | 12 | func EncStringR(v *string) ([]byte, error) { 13 | if v == nil { 14 | return nil, nil 15 | } 16 | return encString(*v), nil 17 | } 18 | 19 | func EncBytes(v []byte) ([]byte, error) { 20 | return v, nil 21 | } 22 | 23 | func EncBytesR(v *[]byte) ([]byte, error) { 24 | if v == nil { 25 | return nil, nil 26 | } 27 | return *v, nil 28 | } 29 | 30 | func EncReflect(v reflect.Value) ([]byte, error) { 31 | switch v.Kind() { 32 | case reflect.String: 33 | return encString(v.String()), nil 34 | case reflect.Slice: 35 | if v.Type().Elem().Kind() != reflect.Uint8 { 36 | return nil, fmt.Errorf("failed to marshal ascii: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 37 | } 38 | return EncBytes(v.Bytes()) 39 | case reflect.Struct: 40 | if v.Type().String() == "gocql.unsetColumn" { 41 | return nil, nil 42 | } 43 | return nil, fmt.Errorf("failed to marshal ascii: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 44 | default: 45 | return nil, fmt.Errorf("failed to marshal ascii: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 46 | } 47 | } 48 | 49 | func EncReflectR(v reflect.Value) ([]byte, error) { 50 | if v.IsNil() { 51 | return nil, nil 52 | } 53 | return EncReflect(v.Elem()) 54 | } 55 | 56 | func encString(v string) []byte { 57 | if v == "" { 58 | return make([]byte, 0) 59 | } 60 | return []byte(v) 61 | } 62 | -------------------------------------------------------------------------------- /serialization/bigint/marshal.go: -------------------------------------------------------------------------------- 1 | package bigint 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int8: 13 | return EncInt8(v) 14 | case int16: 15 | return EncInt16(v) 16 | case int32: 17 | return EncInt32(v) 18 | case int64: 19 | return EncInt64(v) 20 | case int: 21 | return EncInt(v) 22 | 23 | case uint8: 24 | return EncUint8(v) 25 | case uint16: 26 | return EncUint16(v) 27 | case uint32: 28 | return EncUint32(v) 29 | case uint64: 30 | return EncUint64(v) 31 | case uint: 32 | return EncUint(v) 33 | 34 | case big.Int: 35 | return EncBigInt(v) 36 | case string: 37 | return EncString(v) 38 | 39 | case *int8: 40 | return EncInt8R(v) 41 | case *int16: 42 | return EncInt16R(v) 43 | case *int32: 44 | return EncInt32R(v) 45 | case *int64: 46 | return EncInt64R(v) 47 | case *int: 48 | return EncIntR(v) 49 | 50 | case *uint8: 51 | return EncUint8R(v) 52 | case *uint16: 53 | return EncUint16R(v) 54 | case *uint32: 55 | return EncUint32R(v) 56 | case *uint64: 57 | return EncUint64R(v) 58 | case *uint: 59 | return EncUintR(v) 60 | 61 | case *big.Int: 62 | return EncBigIntR(v) 63 | case *string: 64 | return EncStringR(v) 65 | default: 66 | // Custom types (type MyInt int) can be serialized only via `reflect` package. 67 | // Later, when generic-based serialization is introduced we can do that via generics. 68 | rv := reflect.TypeOf(value) 69 | if rv.Kind() != reflect.Ptr { 70 | return EncReflect(reflect.ValueOf(v)) 71 | } 72 | return EncReflectR(reflect.ValueOf(v)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /serialization/cqlint/marshal.go: -------------------------------------------------------------------------------- 1 | package cqlint 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int8: 13 | return EncInt8(v) 14 | case int32: 15 | return EncInt32(v) 16 | case int16: 17 | return EncInt16(v) 18 | case int64: 19 | return EncInt64(v) 20 | case int: 21 | return EncInt(v) 22 | 23 | case uint8: 24 | return EncUint8(v) 25 | case uint16: 26 | return EncUint16(v) 27 | case uint32: 28 | return EncUint32(v) 29 | case uint64: 30 | return EncUint64(v) 31 | case uint: 32 | return EncUint(v) 33 | 34 | case big.Int: 35 | return EncBigInt(v) 36 | case string: 37 | return EncString(v) 38 | 39 | case *int8: 40 | return EncInt8R(v) 41 | case *int16: 42 | return EncInt16R(v) 43 | case *int32: 44 | return EncInt32R(v) 45 | case *int64: 46 | return EncInt64R(v) 47 | case *int: 48 | return EncIntR(v) 49 | 50 | case *uint8: 51 | return EncUint8R(v) 52 | case *uint16: 53 | return EncUint16R(v) 54 | case *uint32: 55 | return EncUint32R(v) 56 | case *uint64: 57 | return EncUint64R(v) 58 | case *uint: 59 | return EncUintR(v) 60 | 61 | case *big.Int: 62 | return EncBigIntR(v) 63 | case *string: 64 | return EncStringR(v) 65 | default: 66 | // Custom types (type MyInt int) can be serialized only via `reflect` package. 67 | // Later, when generic-based serialization is introduced we can do that via generics. 68 | rv := reflect.TypeOf(value) 69 | if rv.Kind() != reflect.Ptr { 70 | return EncReflect(reflect.ValueOf(v)) 71 | } 72 | return EncReflectR(reflect.ValueOf(v)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /serialization/varint/marshal.go: -------------------------------------------------------------------------------- 1 | package varint 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int8: 13 | return EncInt8(v) 14 | case int32: 15 | return EncInt32(v) 16 | case int16: 17 | return EncInt16(v) 18 | case int64: 19 | return EncInt64(v) 20 | case int: 21 | return EncInt(v) 22 | 23 | case uint8: 24 | return EncUint8(v) 25 | case uint16: 26 | return EncUint16(v) 27 | case uint32: 28 | return EncUint32(v) 29 | case uint64: 30 | return EncUint64(v) 31 | case uint: 32 | return EncUint(v) 33 | 34 | case big.Int: 35 | return EncBigInt(v) 36 | case string: 37 | return EncString(v) 38 | 39 | case *int8: 40 | return EncInt8R(v) 41 | case *int16: 42 | return EncInt16R(v) 43 | case *int32: 44 | return EncInt32R(v) 45 | case *int64: 46 | return EncInt64R(v) 47 | case *int: 48 | return EncIntR(v) 49 | 50 | case *uint8: 51 | return EncUint8R(v) 52 | case *uint16: 53 | return EncUint16R(v) 54 | case *uint32: 55 | return EncUint32R(v) 56 | case *uint64: 57 | return EncUint64R(v) 58 | case *uint: 59 | return EncUintR(v) 60 | 61 | case *big.Int: 62 | return EncBigIntR(v) 63 | case *string: 64 | return EncStringR(v) 65 | default: 66 | // Custom types (type MyInt int) can be serialized only via `reflect` package. 67 | // Later, when generic-based serialization is introduced we can do that via generics. 68 | rv := reflect.TypeOf(value) 69 | if rv.Kind() != reflect.Ptr { 70 | return EncReflect(reflect.ValueOf(v)) 71 | } 72 | return EncReflectR(reflect.ValueOf(v)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /serialization/counter/marshal.go: -------------------------------------------------------------------------------- 1 | package counter 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int8: 13 | return EncInt8(v) 14 | case int16: 15 | return EncInt16(v) 16 | case int32: 17 | return EncInt32(v) 18 | case int64: 19 | return EncInt64(v) 20 | case int: 21 | return EncInt(v) 22 | 23 | case uint8: 24 | return EncUint8(v) 25 | case uint16: 26 | return EncUint16(v) 27 | case uint32: 28 | return EncUint32(v) 29 | case uint64: 30 | return EncUint64(v) 31 | case uint: 32 | return EncUint(v) 33 | 34 | case big.Int: 35 | return EncBigInt(v) 36 | case string: 37 | return EncString(v) 38 | 39 | case *int8: 40 | return EncInt8R(v) 41 | case *int16: 42 | return EncInt16R(v) 43 | case *int32: 44 | return EncInt32R(v) 45 | case *int64: 46 | return EncInt64R(v) 47 | case *int: 48 | return EncIntR(v) 49 | 50 | case *uint8: 51 | return EncUint8R(v) 52 | case *uint16: 53 | return EncUint16R(v) 54 | case *uint32: 55 | return EncUint32R(v) 56 | case *uint64: 57 | return EncUint64R(v) 58 | case *uint: 59 | return EncUintR(v) 60 | 61 | case *big.Int: 62 | return EncBigIntR(v) 63 | case *string: 64 | return EncStringR(v) 65 | default: 66 | // Custom types (type MyInt int) can be serialized only via `reflect` package. 67 | // Later, when generic-based serialization is introduced we can do that via generics. 68 | rv := reflect.TypeOf(value) 69 | if rv.Kind() != reflect.Ptr { 70 | return EncReflect(reflect.ValueOf(v)) 71 | } 72 | return EncReflectR(reflect.ValueOf(v)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /serialization/smallint/marshal.go: -------------------------------------------------------------------------------- 1 | package smallint 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int8: 13 | return EncInt8(v) 14 | case int32: 15 | return EncInt32(v) 16 | case int16: 17 | return EncInt16(v) 18 | case int64: 19 | return EncInt64(v) 20 | case int: 21 | return EncInt(v) 22 | 23 | case uint8: 24 | return EncUint8(v) 25 | case uint16: 26 | return EncUint16(v) 27 | case uint32: 28 | return EncUint32(v) 29 | case uint64: 30 | return EncUint64(v) 31 | case uint: 32 | return EncUint(v) 33 | 34 | case big.Int: 35 | return EncBigInt(v) 36 | case string: 37 | return EncString(v) 38 | 39 | case *int8: 40 | return EncInt8R(v) 41 | case *int16: 42 | return EncInt16R(v) 43 | case *int32: 44 | return EncInt32R(v) 45 | case *int64: 46 | return EncInt64R(v) 47 | case *int: 48 | return EncIntR(v) 49 | 50 | case *uint8: 51 | return EncUint8R(v) 52 | case *uint16: 53 | return EncUint16R(v) 54 | case *uint32: 55 | return EncUint32R(v) 56 | case *uint64: 57 | return EncUint64R(v) 58 | case *uint: 59 | return EncUintR(v) 60 | 61 | case *big.Int: 62 | return EncBigIntR(v) 63 | case *string: 64 | return EncStringR(v) 65 | default: 66 | // Custom types (type MyInt int) can be serialized only via `reflect` package. 67 | // Later, when generic-based serialization is introduced we can do that via generics. 68 | rv := reflect.TypeOf(value) 69 | if rv.Kind() != reflect.Ptr { 70 | return EncReflect(reflect.ValueOf(v)) 71 | } 72 | return EncReflectR(reflect.ValueOf(v)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /serialization/tinyint/marshal.go: -------------------------------------------------------------------------------- 1 | package tinyint 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | ) 7 | 8 | func Marshal(value interface{}) ([]byte, error) { 9 | switch v := value.(type) { 10 | case nil: 11 | return nil, nil 12 | case int8: 13 | return EncInt8(v) 14 | case int32: 15 | return EncInt32(v) 16 | case int16: 17 | return EncInt16(v) 18 | case int64: 19 | return EncInt64(v) 20 | case int: 21 | return EncInt(v) 22 | 23 | case uint8: 24 | return EncUint8(v) 25 | case uint16: 26 | return EncUint16(v) 27 | case uint32: 28 | return EncUint32(v) 29 | case uint64: 30 | return EncUint64(v) 31 | case uint: 32 | return EncUint(v) 33 | 34 | case big.Int: 35 | return EncBigInt(v) 36 | case string: 37 | return EncString(v) 38 | 39 | case *int8: 40 | return EncInt8R(v) 41 | case *int16: 42 | return EncInt16R(v) 43 | case *int32: 44 | return EncInt32R(v) 45 | case *int64: 46 | return EncInt64R(v) 47 | case *int: 48 | return EncIntR(v) 49 | 50 | case *uint8: 51 | return EncUint8R(v) 52 | case *uint16: 53 | return EncUint16R(v) 54 | case *uint32: 55 | return EncUint32R(v) 56 | case *uint64: 57 | return EncUint64R(v) 58 | case *uint: 59 | return EncUintR(v) 60 | 61 | case *big.Int: 62 | return EncBigIntR(v) 63 | case *string: 64 | return EncStringR(v) 65 | default: 66 | // Custom types (type MyInt int) can be serialized only via `reflect` package. 67 | // Later, when generic-based serialization is introduced we can do that via generics. 68 | rv := reflect.TypeOf(value) 69 | if rv.Kind() != reflect.Ptr { 70 | return EncReflect(reflect.ValueOf(v)) 71 | } 72 | return EncReflectR(reflect.ValueOf(v)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /serialization/varchar/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package varchar 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func EncString(v string) ([]byte, error) { 9 | return encString(v), nil 10 | } 11 | 12 | func EncStringR(v *string) ([]byte, error) { 13 | if v == nil { 14 | return nil, nil 15 | } 16 | return encString(*v), nil 17 | } 18 | 19 | func EncBytes(v []byte) ([]byte, error) { 20 | return v, nil 21 | } 22 | 23 | func EncBytesR(v *[]byte) ([]byte, error) { 24 | if v == nil { 25 | return nil, nil 26 | } 27 | return *v, nil 28 | } 29 | 30 | func EncReflect(v reflect.Value) ([]byte, error) { 31 | switch v.Kind() { 32 | case reflect.String: 33 | return encString(v.String()), nil 34 | case reflect.Slice: 35 | if v.Type().Elem().Kind() != reflect.Uint8 { 36 | return nil, fmt.Errorf("failed to marshal varchar: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 37 | } 38 | return EncBytes(v.Bytes()) 39 | case reflect.Struct: 40 | if v.Type().String() == "gocql.unsetColumn" { 41 | return nil, nil 42 | } 43 | return nil, fmt.Errorf("failed to marshal varchar: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 44 | default: 45 | return nil, fmt.Errorf("failed to marshal varchar: unsupported value type (%T)(%[1]v), supported types: ~string, ~[]byte, unsetColumn", v.Interface()) 46 | } 47 | } 48 | 49 | func EncReflectR(v reflect.Value) ([]byte, error) { 50 | if v.IsNil() { 51 | return nil, nil 52 | } 53 | return EncReflect(v.Elem()) 54 | } 55 | 56 | func encString(v string) []byte { 57 | if v == "" { 58 | return make([]byte, 0) 59 | } 60 | return []byte(v) 61 | } 62 | -------------------------------------------------------------------------------- /internal/tests/common.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strconv" 7 | "testing" 8 | 9 | "github.com/google/uuid" 10 | ) 11 | 12 | func AssertTrue(t *testing.T, description string, value bool) { 13 | t.Helper() 14 | if !value { 15 | t.Fatalf("expected %s to be true", description) 16 | } 17 | } 18 | 19 | func AssertEqual(t *testing.T, description string, expected, actual interface{}) { 20 | t.Helper() 21 | if expected != actual { 22 | t.Fatalf("expected %s to be (%+v) but was (%+v) instead", description, expected, actual) 23 | } 24 | } 25 | 26 | func AssertDeepEqual(t *testing.T, description string, expected, actual interface{}) { 27 | t.Helper() 28 | if !reflect.DeepEqual(expected, actual) { 29 | t.Fatalf("expected %s to be (%+v) but was (%+v) instead", description, expected, actual) 30 | } 31 | } 32 | 33 | func AssertNil(t *testing.T, description string, actual interface{}) { 34 | t.Helper() 35 | if actual != nil { 36 | t.Fatalf("expected %s to be (nil) but was (%+v) instead", description, actual) 37 | } 38 | } 39 | 40 | func RandomUUID() string { 41 | val, err := uuid.NewRandom() 42 | if err != nil { 43 | panic(fmt.Sprintf("failed to generate UUID: %s", err.Error())) 44 | } 45 | return val.String() 46 | } 47 | 48 | // GenerateHostNames generates a slice of host names with the format "host0", "host1", ..., "hostN-1", 49 | // where N is the specified hostCount. 50 | // 51 | // Parameters: 52 | // 53 | // hostCount - the number of host names to generate. 54 | // 55 | // Returns: 56 | // 57 | // A slice of strings containing host names. 58 | func GenerateHostNames(hostCount int) []string { 59 | hosts := make([]string, hostCount) 60 | for i := 0; i < hostCount; i++ { 61 | hosts[i] = "host" + strconv.Itoa(i) 62 | } 63 | return hosts 64 | } 65 | -------------------------------------------------------------------------------- /tests/serialization/marshal_8_float_corrupt_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql" 10 | "github.com/gocql/gocql/internal/tests/serialization" 11 | "github.com/gocql/gocql/internal/tests/serialization/mod" 12 | "github.com/gocql/gocql/serialization/float" 13 | ) 14 | 15 | func TestMarshalFloatCorrupt(t *testing.T) { 16 | t.Parallel() 17 | 18 | type testSuite struct { 19 | name string 20 | marshal func(interface{}) ([]byte, error) 21 | unmarshal func(bytes []byte, i interface{}) error 22 | } 23 | 24 | tType := gocql.NewNativeType(4, gocql.TypeFloat) 25 | 26 | testSuites := [2]testSuite{ 27 | { 28 | name: "serialization.float", 29 | marshal: float.Marshal, 30 | unmarshal: float.Unmarshal, 31 | }, 32 | { 33 | name: "glob", 34 | marshal: func(i interface{}) ([]byte, error) { 35 | return gocql.Marshal(tType, i) 36 | }, 37 | unmarshal: func(bytes []byte, i interface{}) error { 38 | return gocql.Unmarshal(tType, bytes, i) 39 | }, 40 | }, 41 | } 42 | 43 | for _, tSuite := range testSuites { 44 | unmarshal := tSuite.unmarshal 45 | 46 | t.Run(tSuite.name, func(t *testing.T) { 47 | t.Parallel() 48 | 49 | serialization.NegativeUnmarshalSet{ 50 | Data: []byte("\x80\x00\x00\x00\x00"), 51 | Values: mod.Values{float32(0)}.AddVariants(mod.All...), 52 | }.Run("big_data", t, unmarshal) 53 | 54 | serialization.NegativeUnmarshalSet{ 55 | Data: []byte("\x80"), 56 | Values: mod.Values{float32(0)}.AddVariants(mod.All...), 57 | }.Run("small_data1", t, unmarshal) 58 | 59 | serialization.NegativeUnmarshalSet{ 60 | Data: []byte("\x80\x00\x00"), 61 | Values: mod.Values{float32(0)}.AddVariants(mod.All...), 62 | }.Run("small_data2", t, unmarshal) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/serialization/marshal_9_double_corrupt_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql" 10 | "github.com/gocql/gocql/internal/tests/serialization" 11 | "github.com/gocql/gocql/internal/tests/serialization/mod" 12 | "github.com/gocql/gocql/serialization/double" 13 | ) 14 | 15 | func TestMarshalDoubleCorrupt(t *testing.T) { 16 | t.Parallel() 17 | 18 | type testSuite struct { 19 | name string 20 | marshal func(interface{}) ([]byte, error) 21 | unmarshal func(bytes []byte, i interface{}) error 22 | } 23 | 24 | tType := gocql.NewNativeType(4, gocql.TypeDouble) 25 | 26 | testSuites := [2]testSuite{ 27 | { 28 | name: "serialization.double", 29 | marshal: double.Marshal, 30 | unmarshal: double.Unmarshal, 31 | }, 32 | { 33 | name: "glob", 34 | marshal: func(i interface{}) ([]byte, error) { 35 | return gocql.Marshal(tType, i) 36 | }, 37 | unmarshal: func(bytes []byte, i interface{}) error { 38 | return gocql.Unmarshal(tType, bytes, i) 39 | }, 40 | }, 41 | } 42 | 43 | for _, tSuite := range testSuites { 44 | unmarshal := tSuite.unmarshal 45 | 46 | t.Run(tSuite.name, func(t *testing.T) { 47 | t.Parallel() 48 | 49 | serialization.NegativeUnmarshalSet{ 50 | Data: []byte("\x80\x00\x00\x00\x00\x00\x00\x00\x00"), 51 | Values: mod.Values{float64(0)}.AddVariants(mod.All...), 52 | }.Run("big_data", t, unmarshal) 53 | 54 | serialization.NegativeUnmarshalSet{ 55 | Data: []byte("\x80"), 56 | Values: mod.Values{float64(0)}.AddVariants(mod.All...), 57 | }.Run("small_data1", t, unmarshal) 58 | 59 | serialization.NegativeUnmarshalSet{ 60 | Data: []byte("\x80\x00\x00\x00"), 61 | Values: mod.Values{float64(0)}.AddVariants(mod.All...), 62 | }.Run("small_data2", t, unmarshal) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /control_integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | "net" 10 | "testing" 11 | ) 12 | 13 | // unixSocketDialer is a special dialer which connects only to the maintenance_socket. 14 | type unixSocketDialer struct { 15 | dialer net.Dialer 16 | socketPath string 17 | } 18 | 19 | func (d unixSocketDialer) DialContext(_ context.Context, _, _ string) (net.Conn, error) { 20 | return d.dialer.Dial("unix", d.socketPath) 21 | } 22 | 23 | func TestUnixSockets(t *testing.T) { 24 | socketFiles := getClusterSocketFile() 25 | if len(socketFiles) == 0 { 26 | t.Skip("this test needs path to socket file provided into -cluster-socket cli option") 27 | } 28 | 29 | c := createCluster() 30 | c.NumConns = 1 31 | c.DisableInitialHostLookup = true 32 | c.ProtoVersion = protoVersion3 33 | c.ReconnectInterval = 0 34 | c.WriteCoalesceWaitTime = 0 35 | 36 | c.Events.DisableNodeStatusEvents = true 37 | c.Events.DisableTopologyEvents = true 38 | c.Events.DisableSchemaEvents = true 39 | 40 | d := net.Dialer{ 41 | Timeout: c.Timeout, 42 | } 43 | if c.SocketKeepalive > 0 { 44 | d.KeepAlive = c.SocketKeepalive 45 | } 46 | 47 | c.Dialer = unixSocketDialer{ 48 | dialer: d, 49 | socketPath: socketFiles[0], 50 | } 51 | 52 | sess, err := c.CreateSession() 53 | if err != nil { 54 | t.Fatalf("unable to create session: %v", err) 55 | } 56 | 57 | defer sess.Close() 58 | 59 | keyspace := "test1" 60 | 61 | err = createTable(sess, `DROP KEYSPACE IF EXISTS `+keyspace) 62 | if err != nil { 63 | t.Fatal("unable to drop keyspace if exists:", err) 64 | } 65 | 66 | err = createTable(sess, fmt.Sprintf(`CREATE KEYSPACE %s 67 | WITH replication = { 68 | 'class' : 'NetworkTopologyStrategy', 69 | 'replication_factor' : 1 70 | }`, keyspace)) 71 | if err != nil { 72 | t.Fatal("unable to create keyspace:", err) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /internal/tests/serialization/pointers.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | ) 7 | 8 | // errFirstPtrChanged this error indicates that a double or single reference was passed to the Unmarshal function 9 | // (example (**int)(**0) or (*int)(*0)) and Unmarshal overwritten first reference. 10 | var errFirstPtrChanged = errors.New("unmarshal function rewrote first pointer") 11 | 12 | // errSecondPtrNotChanged this error indicates that a double reference was passed to the Unmarshal function 13 | // (example (**int)(**0)) and the function did not overwrite the second reference. 14 | // Of course, it's not friendly to the garbage collector, overwriting references to values all the time, 15 | // but this is the current implementation `gocql` and changing it can lead to unexpected results in some cases. 16 | var errSecondPtrNotChanged = errors.New("unmarshal function did not rewrite second pointer") 17 | 18 | func getPointers(i interface{}) *pointer { 19 | rv := reflect.ValueOf(i) 20 | if rv.Kind() != reflect.Ptr { 21 | return nil 22 | } 23 | out := pointer{ 24 | Fist: rv.Pointer(), 25 | } 26 | rt := rv.Type() 27 | if rt.Elem().Kind() == reflect.Ptr && !rv.Elem().IsNil() { 28 | out.Second = rv.Elem().Pointer() 29 | } 30 | return &out 31 | } 32 | 33 | type pointer struct { 34 | Fist uintptr 35 | Second uintptr 36 | } 37 | 38 | func (p *pointer) NotNil() bool { 39 | return p != nil 40 | } 41 | 42 | // Valid validates if pointers has been manipulated by unmarshal functions in an expected manner: 43 | // Fist pointer should not be overwritten, 44 | // Second pointer, if applicable, should be overwritten. 45 | func (p *pointer) Valid(v interface{}) error { 46 | p2 := getPointers(v) 47 | if p.Fist != p2.Fist { 48 | return errFirstPtrChanged 49 | } 50 | if p.Second != 0 && p2.Second != 0 && p2.Second == p.Second { 51 | return errSecondPtrNotChanged 52 | } 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /hostpolicy/hostpool_test.go: -------------------------------------------------------------------------------- 1 | package hostpolicy 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "testing" 7 | 8 | "github.com/hailocab/go-hostpool" 9 | 10 | "github.com/gocql/gocql" 11 | ) 12 | 13 | // Tests of the host pool host selection policy implementation 14 | func TestHostPolicy_HostPool(t *testing.T) { 15 | policy := HostPool(hostpool.New(nil)) 16 | 17 | //hosts := []*gocql.HostInfo{ 18 | // {hostId: "0", connectAddress: net.IPv4(10, 0, 0, 0)}, 19 | // {hostId: "1", connectAddress: net.IPv4(10, 0, 0, 1)}, 20 | //} 21 | firstHost := gocql.HostInfoBuilder{ 22 | HostId: "0", 23 | ConnectAddress: net.IPv4(10, 0, 0, 0), 24 | }.Build() 25 | secHost := gocql.HostInfoBuilder{ 26 | HostId: "1", 27 | ConnectAddress: net.IPv4(10, 0, 0, 1), 28 | }.Build() 29 | hosts := []*gocql.HostInfo{&firstHost, &secHost} 30 | // Using set host to control the ordering of the hosts as calling "AddHost" iterates the map 31 | // which will result in an unpredictable ordering 32 | policy.(*hostPoolHostPolicy).SetHosts(hosts) 33 | 34 | // the first host selected is actually at [1], but this is ok for RR 35 | // interleaved iteration should always increment the host 36 | iter := policy.Pick(nil) 37 | actualA := iter() 38 | if actualA.Info().HostID() != "0" { 39 | t.Errorf("Expected hosts[0] but was hosts[%s]", actualA.Info().HostID()) 40 | } 41 | actualA.Mark(nil) 42 | 43 | actualB := iter() 44 | if actualB.Info().HostID() != "1" { 45 | t.Errorf("Expected hosts[1] but was hosts[%s]", actualB.Info().HostID()) 46 | } 47 | actualB.Mark(fmt.Errorf("error")) 48 | 49 | actualC := iter() 50 | if actualC.Info().HostID() != "0" { 51 | t.Errorf("Expected hosts[0] but was hosts[%s]", actualC.Info().HostID()) 52 | } 53 | actualC.Mark(nil) 54 | 55 | actualD := iter() 56 | if actualD.Info().HostID() != "0" { 57 | t.Errorf("Expected hosts[0] but was hosts[%s]", actualD.Info().HostID()) 58 | } 59 | actualD.Mark(nil) 60 | } 61 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // 2 | // Licensed to the Apache Software Foundation (ASF) under one 3 | // or more contributor license agreements. See the NOTICE file 4 | // distributed with this work for additional information 5 | // regarding copyright ownership. The ASF licenses this file 6 | // to you under the Apache License, Version 2.0 (the 7 | // "License"); you may not use this file except in compliance 8 | // with the License. You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | module github.com/gocql/gocql 19 | 20 | require ( 21 | github.com/google/go-cmp v0.7.0 22 | github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed 23 | github.com/klauspost/compress v1.18.2 24 | golang.org/x/net v0.48.0 25 | gopkg.in/inf.v0 v0.9.1 26 | sigs.k8s.io/yaml v1.6.0 27 | ) 28 | 29 | require ( 30 | github.com/davecgh/go-spew v1.1.1 // indirect 31 | github.com/pmezard/go-difflib v1.0.0 // indirect 32 | go.yaml.in/yaml/v2 v2.4.3 // indirect 33 | gopkg.in/yaml.v3 v3.0.1 // indirect 34 | ) 35 | 36 | require ( 37 | github.com/bitly/go-hostpool v0.1.1 // indirect 38 | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect 39 | github.com/google/uuid v1.6.0 40 | github.com/kr/pretty v0.3.1 // indirect 41 | github.com/stretchr/testify v1.11.1 42 | ) 43 | 44 | retract ( 45 | v1.10.0 // tag from kiwicom/gocql added by mistake to scylladb/gocql 46 | v1.9.0 // tag from kiwicom/gocql added by mistake to scylladb/gocql 47 | v1.8.1 // tag from kiwicom/gocql added by mistake to scylladb/gocql 48 | v1.8.0 // tag from kiwicom/gocql added by mistake to scylladb/gocql 49 | ) 50 | 51 | go 1.25.0 52 | -------------------------------------------------------------------------------- /serialization/varint/marshal_bigint_test.go: -------------------------------------------------------------------------------- 1 | package varint 2 | 3 | import ( 4 | "bytes" 5 | "math" 6 | "math/big" 7 | "math/rand" 8 | "testing" 9 | ) 10 | 11 | func TestEnc2BigInt(t *testing.T) { 12 | t.Parallel() 13 | 14 | genData := func(v int64) []byte { 15 | data := []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} 16 | out := make([]byte, 0) 17 | add := false 18 | 19 | for i, b := range data { 20 | if !add { 21 | if v < 0 { 22 | if b != 255 || b == 255 && data[i+1] < 128 { 23 | add = true 24 | } else { 25 | continue 26 | } 27 | } else { 28 | if b != 0 || b == 0 && data[i+1] > 127 { 29 | add = true 30 | } else { 31 | continue 32 | } 33 | } 34 | } 35 | out = append(out, b) 36 | } 37 | 38 | return out 39 | } 40 | 41 | t.Run("positive", func(t *testing.T) { 42 | rnd := rand.New(rand.NewSource(rand.Int63())) 43 | for i := int64(math.MaxInt16); i < 1<<24; i = i + int64(rnd.Int31n(300)) { 44 | expected := genData(i) 45 | 46 | received := EncBigIntRS(big.NewInt(i)) 47 | if !bytes.Equal(expected, received) { 48 | t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) 49 | } 50 | 51 | received = EncInt64Ext(i) 52 | if !bytes.Equal(expected, received) { 53 | t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) 54 | } 55 | } 56 | }) 57 | 58 | t.Run("negative", func(t *testing.T) { 59 | rnd := rand.New(rand.NewSource(rand.Int63())) 60 | for i := int64(math.MinInt16); i > -1<<24; i = i - int64(rnd.Int31n(300)) { 61 | expected := genData(i) 62 | 63 | received := EncBigIntRS(big.NewInt(i)) 64 | if !bytes.Equal(expected, received) { 65 | t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) 66 | } 67 | 68 | received = EncInt64Ext(i) 69 | if !bytes.Equal(expected, received) { 70 | t.Fatalf("%d\nexpected:%x\nreceived:%x", i, expected, received) 71 | } 72 | } 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /compressor.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | /* 19 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 20 | * Copyright (c) 2016, The Gocql authors, 21 | * provided under the BSD-3-Clause License. 22 | * See the NOTICE file distributed with this work for additional information. 23 | */ 24 | 25 | package gocql 26 | 27 | import ( 28 | "github.com/klauspost/compress/s2" 29 | ) 30 | 31 | type Compressor interface { 32 | Name() string 33 | Encode(data []byte) ([]byte, error) 34 | Decode(data []byte) ([]byte, error) 35 | } 36 | 37 | // SnappyCompressor implements the Compressor interface and can be used to 38 | // compress incoming and outgoing frames. It uses S2 compression algorithm 39 | // that is compatible with snappy and aims for high throughput, which is why 40 | // it features concurrent compression for bigger payloads. 41 | type SnappyCompressor struct{} 42 | 43 | func (s SnappyCompressor) Name() string { 44 | return "snappy" 45 | } 46 | 47 | func (s SnappyCompressor) Encode(data []byte) ([]byte, error) { 48 | return s2.EncodeSnappy(nil, data), nil 49 | } 50 | 51 | func (s SnappyCompressor) Decode(data []byte) ([]byte, error) { 52 | return s2.Decode(nil, data) 53 | } 54 | -------------------------------------------------------------------------------- /events_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package gocql 29 | 30 | import ( 31 | "net" 32 | "sync" 33 | "testing" 34 | 35 | frm "github.com/gocql/gocql/internal/frame" 36 | ) 37 | 38 | func TestEventDebounce(t *testing.T) { 39 | t.Parallel() 40 | 41 | const eventCount = 150 42 | wg := &sync.WaitGroup{} 43 | wg.Add(1) 44 | 45 | eventsSeen := 0 46 | debouncer := newEventDebouncer("testDebouncer", func(events []frame) { 47 | defer wg.Done() 48 | eventsSeen += len(events) 49 | }, &defaultLogger{}) 50 | defer debouncer.stop() 51 | 52 | for i := 0; i < eventCount; i++ { 53 | debouncer.debounce(&frm.StatusChangeEventFrame{ 54 | Change: "UP", 55 | Host: net.IPv4(127, 0, 0, 1), 56 | Port: 9042, 57 | }) 58 | } 59 | 60 | wg.Wait() 61 | if eventCount != eventsSeen { 62 | t.Fatalf("expected to see %d events but got %d", eventCount, eventsSeen) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /serialization/varint/unmarshal_bigint_test.go: -------------------------------------------------------------------------------- 1 | package varint 2 | 3 | import ( 4 | "math" 5 | "math/big" 6 | "math/rand" 7 | "testing" 8 | ) 9 | 10 | func TestDec2BigInt(t *testing.T) { 11 | t.Parallel() 12 | 13 | genData := func(v int64) []byte { 14 | data := []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} 15 | out := make([]byte, 0) 16 | add := false 17 | for i, b := range data { 18 | if !add { 19 | if v < 0 { 20 | if b != 255 || b == 255 && data[i+1] < 128 { 21 | add = true 22 | } else { 23 | continue 24 | } 25 | } else { 26 | if b != 0 || b == 0 && data[i+1] > 127 { 27 | add = true 28 | } else { 29 | continue 30 | } 31 | } 32 | } 33 | out = append(out, b) 34 | } 35 | 36 | return out 37 | } 38 | 39 | t.Run("positive", func(t *testing.T) { 40 | rnd := rand.New(rand.NewSource(rand.Int63())) 41 | for i := int64(math.MaxInt16); i < 1<<23; i = i + int64(rnd.Int31n(300)) { 42 | data := genData(i) 43 | expected := big.NewInt(i) 44 | 45 | received := Dec2BigInt(data) 46 | if expected.Cmp(received) != 0 { 47 | t.Fatalf("%d\nexpected:%s\nreceived:%s", i, expected, received) 48 | } 49 | 50 | _ = DecBigInt(data, received) 51 | if expected.Cmp(received) != 0 { 52 | t.Fatalf("%d\nexpected:%s\nreceived:%s", i, expected, received) 53 | } 54 | } 55 | }) 56 | 57 | t.Run("negative", func(t *testing.T) { 58 | rnd := rand.New(rand.NewSource(rand.Int63())) 59 | for i := int64(math.MinInt16); i > -1<<23; i = i - int64(rnd.Int31n(300)) { 60 | data := genData(i) 61 | expected := big.NewInt(i) 62 | 63 | received := Dec2BigInt(data) 64 | if expected.Cmp(received) != 0 { 65 | t.Fatalf("%d\nexpected:%s\nreceived:%s", i, expected, received) 66 | } 67 | 68 | _ = DecBigInt(data, received) 69 | if expected.Cmp(received) != 0 { 70 | t.Fatalf("%d\nexpected:%s\nreceived:%s", i, expected, received) 71 | } 72 | } 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /serialization/smallint/unmarshal.go: -------------------------------------------------------------------------------- 1 | package smallint 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int8: 15 | return DecInt8(data, v) 16 | case *int16: 17 | return DecInt16(data, v) 18 | case *int32: 19 | return DecInt32(data, v) 20 | case *int64: 21 | return DecInt64(data, v) 22 | case *int: 23 | return DecInt(data, v) 24 | 25 | case *uint8: 26 | return DecUint8(data, v) 27 | case *uint16: 28 | return DecUint16(data, v) 29 | case *uint32: 30 | return DecUint32(data, v) 31 | case *uint64: 32 | return DecUint64(data, v) 33 | case *uint: 34 | return DecUint(data, v) 35 | 36 | case *big.Int: 37 | return DecBigInt(data, v) 38 | case *string: 39 | return DecString(data, v) 40 | 41 | case **int8: 42 | return DecInt8R(data, v) 43 | case **int16: 44 | return DecInt16R(data, v) 45 | case **int32: 46 | return DecInt32R(data, v) 47 | case **int64: 48 | return DecInt64R(data, v) 49 | case **int: 50 | return DecIntR(data, v) 51 | 52 | case **uint8: 53 | return DecUint8R(data, v) 54 | case **uint16: 55 | return DecUint16R(data, v) 56 | case **uint32: 57 | return DecUint32R(data, v) 58 | case **uint64: 59 | return DecUint64R(data, v) 60 | case **uint: 61 | return DecUintR(data, v) 62 | 63 | case **big.Int: 64 | return DecBigIntR(data, v) 65 | case **string: 66 | return DecStringR(data, v) 67 | default: 68 | 69 | // Custom types (type MyInt int) can be deserialized only via `reflect` package. 70 | // Later, when generic-based serialization is introduced we can do that via generics. 71 | rv := reflect.ValueOf(value) 72 | rt := rv.Type() 73 | if rt.Kind() != reflect.Ptr { 74 | return fmt.Errorf("failed to unmarshal smallint: unsupported value type (%T)(%[1]v)", value) 75 | } 76 | if rt.Elem().Kind() != reflect.Ptr { 77 | return DecReflect(data, rv) 78 | } 79 | return DecReflectR(data, rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/bench/go.sum: -------------------------------------------------------------------------------- 1 | github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= 2 | github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 6 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 7 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 8 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 9 | github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= 10 | github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= 11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 13 | github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 14 | github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 15 | go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= 16 | go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= 17 | golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= 18 | golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= 19 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 20 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 21 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 22 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 23 | sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= 24 | sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= 25 | -------------------------------------------------------------------------------- /errors_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package gocql 29 | 30 | import ( 31 | "errors" 32 | "testing" 33 | ) 34 | 35 | func TestErrorsParse(t *testing.T) { 36 | session := createSession(t) 37 | defer session.Close() 38 | 39 | if err := createTable(session, `CREATE TABLE gocql_test.errors_parse (id int primary key)`); err != nil { 40 | t.Fatal("create:", err) 41 | } 42 | 43 | if err := createTable(session, `CREATE TABLE gocql_test.errors_parse (id int primary key)`); err == nil { 44 | t.Fatal("Should have gotten already exists error from cassandra server.") 45 | } else { 46 | e := &RequestErrAlreadyExists{} 47 | if errors.As(err, &e) { 48 | if e.Table != "errors_parse" { 49 | t.Fatalf("expected error table to be 'errors_parse' but was %q", e.Table) 50 | } 51 | } else { 52 | t.Fatalf("expected to get RequestErrAlreadyExists instead got %T", e) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /serialization/bigint/unmarshal.go: -------------------------------------------------------------------------------- 1 | package bigint 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int8: 15 | return DecInt8(data, v) 16 | case *int16: 17 | return DecInt16(data, v) 18 | case *int32: 19 | return DecInt32(data, v) 20 | case *int64: 21 | return DecInt64(data, v) 22 | case *int: 23 | return DecInt(data, v) 24 | 25 | case *uint8: 26 | return DecUint8(data, v) 27 | case *uint16: 28 | return DecUint16(data, v) 29 | case *uint32: 30 | return DecUint32(data, v) 31 | case *uint64: 32 | return DecUint64(data, v) 33 | case *uint: 34 | return DecUint(data, v) 35 | 36 | case *big.Int: 37 | return DecBigInt(data, v) 38 | case *string: 39 | return DecString(data, v) 40 | 41 | case **int8: 42 | return DecInt8R(data, v) 43 | case **int16: 44 | return DecInt16R(data, v) 45 | case **int32: 46 | return DecInt32R(data, v) 47 | case **int64: 48 | return DecInt64R(data, v) 49 | case **int: 50 | return DecIntR(data, v) 51 | 52 | case **uint8: 53 | return DecUint8R(data, v) 54 | case **uint16: 55 | return DecUint16R(data, v) 56 | case **uint32: 57 | return DecUint32R(data, v) 58 | case **uint64: 59 | return DecUint64R(data, v) 60 | case **uint: 61 | return DecUintR(data, v) 62 | 63 | case **big.Int: 64 | return DecBigIntR(data, v) 65 | case **string: 66 | return DecStringR(data, v) 67 | default: 68 | 69 | // Custom types (type MyInt int) can be deserialized only via `reflect` package. 70 | // Later, when generic-based serialization is introduced we can do that via generics. 71 | rv := reflect.ValueOf(value) 72 | rt := rv.Type() 73 | if rt.Kind() != reflect.Ptr { 74 | return fmt.Errorf("failed to unmarshal bigint: unsupported value type (%T)(%[1]v), supported types: %s", value, supportedTypes) 75 | } 76 | if rt.Elem().Kind() != reflect.Ptr { 77 | return DecReflect(data, rv) 78 | } 79 | return DecReflectR(data, rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /serialization/cqlint/unmarshal.go: -------------------------------------------------------------------------------- 1 | package cqlint 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int8: 15 | return DecInt8(data, v) 16 | case *int16: 17 | return DecInt16(data, v) 18 | case *int32: 19 | return DecInt32(data, v) 20 | case *int64: 21 | return DecInt64(data, v) 22 | case *int: 23 | return DecInt(data, v) 24 | 25 | case *uint8: 26 | return DecUint8(data, v) 27 | case *uint16: 28 | return DecUint16(data, v) 29 | case *uint32: 30 | return DecUint32(data, v) 31 | case *uint64: 32 | return DecUint64(data, v) 33 | case *uint: 34 | return DecUint(data, v) 35 | 36 | case *big.Int: 37 | return DecBigInt(data, v) 38 | case *string: 39 | return DecString(data, v) 40 | 41 | case **int8: 42 | return DecInt8R(data, v) 43 | case **int16: 44 | return DecInt16R(data, v) 45 | case **int32: 46 | return DecInt32R(data, v) 47 | case **int64: 48 | return DecInt64R(data, v) 49 | case **int: 50 | return DecIntR(data, v) 51 | 52 | case **uint8: 53 | return DecUint8R(data, v) 54 | case **uint16: 55 | return DecUint16R(data, v) 56 | case **uint32: 57 | return DecUint32R(data, v) 58 | case **uint64: 59 | return DecUint64R(data, v) 60 | case **uint: 61 | return DecUintR(data, v) 62 | 63 | case **big.Int: 64 | return DecBigIntR(data, v) 65 | case **string: 66 | return DecStringR(data, v) 67 | default: 68 | 69 | // Custom types (type MyInt int) can be deserialized only via `reflect` package. 70 | // Later, when generic-based serialization is introduced we can do that via generics. 71 | rv := reflect.ValueOf(value) 72 | rt := rv.Type() 73 | if rt.Kind() != reflect.Ptr { 74 | return fmt.Errorf("failed to unmarshal int: unsupported value type (%T)(%[1]v), supported types: %s", value, supportedTypes) 75 | } 76 | if rt.Elem().Kind() != reflect.Ptr { 77 | return DecReflect(data, rv) 78 | } 79 | return DecReflectR(data, rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /serialization/tinyint/unmarshal.go: -------------------------------------------------------------------------------- 1 | package tinyint 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int8: 15 | return DecInt8(data, v) 16 | case *int16: 17 | return DecInt16(data, v) 18 | case *int32: 19 | return DecInt32(data, v) 20 | case *int64: 21 | return DecInt64(data, v) 22 | case *int: 23 | return DecInt(data, v) 24 | 25 | case *uint8: 26 | return DecUint8(data, v) 27 | case *uint16: 28 | return DecUint16(data, v) 29 | case *uint32: 30 | return DecUint32(data, v) 31 | case *uint64: 32 | return DecUint64(data, v) 33 | case *uint: 34 | return DecUint(data, v) 35 | 36 | case *big.Int: 37 | return DecBigInt(data, v) 38 | case *string: 39 | return DecString(data, v) 40 | 41 | case **int8: 42 | return DecInt8R(data, v) 43 | case **int16: 44 | return DecInt16R(data, v) 45 | case **int32: 46 | return DecInt32R(data, v) 47 | case **int64: 48 | return DecInt64R(data, v) 49 | case **int: 50 | return DecIntR(data, v) 51 | 52 | case **uint8: 53 | return DecUint8R(data, v) 54 | case **uint16: 55 | return DecUint16R(data, v) 56 | case **uint32: 57 | return DecUint32R(data, v) 58 | case **uint64: 59 | return DecUint64R(data, v) 60 | case **uint: 61 | return DecUintR(data, v) 62 | 63 | case **big.Int: 64 | return DecBigIntR(data, v) 65 | case **string: 66 | return DecStringR(data, v) 67 | default: 68 | 69 | // Custom types (type MyInt int) can be deserialized only via `reflect` package. 70 | // Later, when generic-based serialization is introduced we can do that via generics. 71 | rv := reflect.ValueOf(value) 72 | rt := rv.Type() 73 | if rt.Kind() != reflect.Ptr { 74 | return fmt.Errorf("failed to unmarshal tinyint: unsupported value type (%T)(%[1]v), supported types: %s", v, supportedTypes) 75 | } 76 | if rt.Elem().Kind() != reflect.Ptr { 77 | return DecReflect(data, rv) 78 | } 79 | return DecReflectR(data, rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /serialization/varint/unmarshal.go: -------------------------------------------------------------------------------- 1 | package varint 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int8: 15 | return DecInt8(data, v) 16 | case *int16: 17 | return DecInt16(data, v) 18 | case *int32: 19 | return DecInt32(data, v) 20 | case *int64: 21 | return DecInt64(data, v) 22 | case *int: 23 | return DecInt(data, v) 24 | 25 | case *uint8: 26 | return DecUint8(data, v) 27 | case *uint16: 28 | return DecUint16(data, v) 29 | case *uint32: 30 | return DecUint32(data, v) 31 | case *uint64: 32 | return DecUint64(data, v) 33 | case *uint: 34 | return DecUint(data, v) 35 | 36 | case *big.Int: 37 | return DecBigInt(data, v) 38 | case *string: 39 | return DecString(data, v) 40 | 41 | case **int8: 42 | return DecInt8R(data, v) 43 | case **int16: 44 | return DecInt16R(data, v) 45 | case **int32: 46 | return DecInt32R(data, v) 47 | case **int64: 48 | return DecInt64R(data, v) 49 | case **int: 50 | return DecIntR(data, v) 51 | 52 | case **uint8: 53 | return DecUint8R(data, v) 54 | case **uint16: 55 | return DecUint16R(data, v) 56 | case **uint32: 57 | return DecUint32R(data, v) 58 | case **uint64: 59 | return DecUint64R(data, v) 60 | case **uint: 61 | return DecUintR(data, v) 62 | 63 | case **big.Int: 64 | return DecBigIntR(data, v) 65 | case **string: 66 | return DecStringR(data, v) 67 | default: 68 | 69 | // Custom types (type MyInt int) can be deserialized only via `reflect` package. 70 | // Later, when generic-based serialization is introduced we can do that via generics. 71 | rv := reflect.ValueOf(value) 72 | rt := rv.Type() 73 | if rt.Kind() != reflect.Ptr { 74 | return fmt.Errorf("failed to unmarshal varint: unsupported value type (%T)(%#[1]v), supported types: %s", value, supportedTypes) 75 | } 76 | if rt.Elem().Kind() != reflect.Ptr { 77 | return DecReflect(data, rv) 78 | } 79 | return DecReflectR(data, rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /serialization/counter/unmarshal.go: -------------------------------------------------------------------------------- 1 | package counter 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | ) 8 | 9 | func Unmarshal(data []byte, value interface{}) error { 10 | switch v := value.(type) { 11 | case nil: 12 | return nil 13 | 14 | case *int8: 15 | return DecInt8(data, v) 16 | case *int16: 17 | return DecInt16(data, v) 18 | case *int32: 19 | return DecInt32(data, v) 20 | case *int64: 21 | return DecInt64(data, v) 22 | case *int: 23 | return DecInt(data, v) 24 | 25 | case *uint8: 26 | return DecUint8(data, v) 27 | case *uint16: 28 | return DecUint16(data, v) 29 | case *uint32: 30 | return DecUint32(data, v) 31 | case *uint64: 32 | return DecUint64(data, v) 33 | case *uint: 34 | return DecUint(data, v) 35 | 36 | case *big.Int: 37 | return DecBigInt(data, v) 38 | case *string: 39 | return DecString(data, v) 40 | 41 | case **int8: 42 | return DecInt8R(data, v) 43 | case **int16: 44 | return DecInt16R(data, v) 45 | case **int32: 46 | return DecInt32R(data, v) 47 | case **int64: 48 | return DecInt64R(data, v) 49 | case **int: 50 | return DecIntR(data, v) 51 | 52 | case **uint8: 53 | return DecUint8R(data, v) 54 | case **uint16: 55 | return DecUint16R(data, v) 56 | case **uint32: 57 | return DecUint32R(data, v) 58 | case **uint64: 59 | return DecUint64R(data, v) 60 | case **uint: 61 | return DecUintR(data, v) 62 | 63 | case **big.Int: 64 | return DecBigIntR(data, v) 65 | case **string: 66 | return DecStringR(data, v) 67 | default: 68 | 69 | // Custom types (type MyInt int) can be deserialized only via `reflect` package. 70 | // Later, when generic-based serialization is introduced we can do that via generics. 71 | rv := reflect.ValueOf(value) 72 | rt := rv.Type() 73 | if rt.Kind() != reflect.Ptr { 74 | return fmt.Errorf("failed to unmarshal counter: unsupported value type (%T)(%[1]v), supported types: %s", value, supportedTypes) 75 | } 76 | if rt.Elem().Kind() != reflect.Ptr { 77 | return DecReflect(data, rv) 78 | } 79 | return DecReflectR(data, rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tablet_integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | "testing" 10 | ) 11 | 12 | // Check if TokenAwareHostPolicy works correctly when using tablets 13 | func TestTablets(t *testing.T) { 14 | if !isTabletsSupported() { 15 | t.Skip("Tablets are not supported by this server") 16 | } 17 | cluster := createCluster() 18 | 19 | fallback := RoundRobinHostPolicy() 20 | cluster.PoolConfig.HostSelectionPolicy = TokenAwareHostPolicy(fallback) 21 | 22 | session := createSessionFromCluster(cluster, t) 23 | defer session.Close() 24 | 25 | if err := createTable(session, fmt.Sprintf(`CREATE TABLE %s (pk int, ck int, v int, PRIMARY KEY (pk, ck)); 26 | `, "test_tablets")); err != nil { 27 | t.Fatalf("unable to create table: %v", err) 28 | } 29 | 30 | hosts := session.hostSource.getHostsList() 31 | 32 | hostAddresses := []string{} 33 | for _, host := range hosts { 34 | hostAddresses = append(hostAddresses, host.connectAddress.String()) 35 | } 36 | 37 | ctx := context.Background() 38 | 39 | for i := 0; i < 5; i++ { 40 | err := session.Query(`INSERT INTO test_tablets (pk, ck, v) VALUES (?, ?, ?);`, i, i%5, i%2).WithContext(ctx).Exec() 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | } 45 | 46 | for i := 0; i < 5; i++ { 47 | for attempt := 1; true; attempt++ { 48 | iter := session.Query(`SELECT pk, ck, v FROM test_tablets WHERE pk = ?;`, i).WithContext(ctx).Consistency(One).Iter() 49 | if payload := iter.GetCustomPayload(); payload != nil { 50 | if hint, ok := payload["tablets-routing-v1"]; ok { 51 | tablet, err := unmarshalTabletHint(hint, 4, "", "") 52 | if err != nil { 53 | t.Fatalf("failed to extract tablet information: %s", err.Error()) 54 | } 55 | t.Logf("%s", tablet.Replicas()) 56 | if attempt >= 3 { 57 | t.Fatalf("Tablet hint from the server should not be sent") 58 | } 59 | } else { 60 | break 61 | } 62 | } else { 63 | break 64 | } 65 | if err := iter.Close(); err != nil { 66 | t.Fatal(err) 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/serialization/marshal_12_ascii_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql" 10 | "github.com/gocql/gocql/internal/tests/serialization" 11 | "github.com/gocql/gocql/internal/tests/serialization/mod" 12 | "github.com/gocql/gocql/serialization/ascii" 13 | ) 14 | 15 | func TestMarshalAscii(t *testing.T) { 16 | tType := gocql.NewNativeType(4, gocql.TypeAscii) 17 | 18 | type testSuite struct { 19 | name string 20 | marshal func(interface{}) ([]byte, error) 21 | unmarshal func(bytes []byte, i interface{}) error 22 | } 23 | 24 | testSuites := [2]testSuite{ 25 | { 26 | name: "serialization.int", 27 | marshal: ascii.Marshal, 28 | unmarshal: ascii.Unmarshal, 29 | }, 30 | { 31 | name: "glob", 32 | marshal: func(i interface{}) ([]byte, error) { 33 | return gocql.Marshal(tType, i) 34 | }, 35 | unmarshal: func(bytes []byte, i interface{}) error { 36 | return gocql.Unmarshal(tType, bytes, i) 37 | }, 38 | }, 39 | } 40 | 41 | for _, tSuite := range testSuites { 42 | marshal := tSuite.marshal 43 | unmarshal := tSuite.unmarshal 44 | 45 | t.Run(tSuite.name, func(t *testing.T) { 46 | t.Parallel() 47 | 48 | serialization.PositiveSet{ 49 | Data: nil, 50 | Values: mod.Values{ 51 | ([]byte)(nil), 52 | (*[]byte)(nil), 53 | (*string)(nil), 54 | }.AddVariants(mod.CustomType), 55 | }.Run("[nil]nullable", t, marshal, unmarshal) 56 | 57 | serialization.PositiveSet{ 58 | Data: nil, 59 | Values: mod.Values{""}.AddVariants(mod.CustomType), 60 | }.Run("[nil]unmarshal", t, nil, unmarshal) 61 | 62 | serialization.PositiveSet{ 63 | Data: make([]byte, 0), 64 | Values: mod.Values{make([]byte, 0), ""}.AddVariants(mod.All...), 65 | }.Run("[]unmarshal", t, nil, unmarshal) 66 | 67 | serialization.PositiveSet{ 68 | Data: []byte("test text string"), 69 | Values: mod.Values{[]byte("test text string"), "test text string"}.AddVariants(mod.All...), 70 | }.Run("text", t, nil, unmarshal) 71 | }) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lz4/lz4_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package lz4 29 | 30 | import ( 31 | "testing" 32 | 33 | "github.com/stretchr/testify/require" 34 | ) 35 | 36 | func TestLZ4Compressor(t *testing.T) { 37 | t.Parallel() 38 | 39 | var c LZ4Compressor 40 | require.Equal(t, "lz4", c.Name()) 41 | 42 | _, err := c.Decode([]byte{0, 1, 2}) 43 | require.EqualError(t, err, "cassandra lz4 block size should be >4, got=3") 44 | 45 | _, err = c.Decode([]byte{0, 1, 2, 4, 5}) 46 | require.EqualError(t, err, "lz4: invalid source or destination buffer too short") 47 | 48 | // If uncompressed size is zero then nothing is decoded even if present. 49 | decoded, err := c.Decode([]byte{0, 0, 0, 0, 5, 7, 8}) 50 | require.NoError(t, err) 51 | require.Nil(t, decoded) 52 | 53 | original := []byte("My Test String") 54 | encoded, err := c.Encode(original) 55 | require.NoError(t, err) 56 | decoded, err = c.Decode(encoded) 57 | require.NoError(t, err) 58 | require.Equal(t, original, decoded) 59 | } 60 | -------------------------------------------------------------------------------- /tablets/tabets_utils_test.go: -------------------------------------------------------------------------------- 1 | package tablets 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | 7 | "github.com/gocql/gocql/internal/tests" 8 | ) 9 | 10 | func TestCreateTablets(t *testing.T) { 11 | t.Run("BasicDistribution", func(t *testing.T) { 12 | hosts := tests.GenerateHostNames(3) 13 | tl := createTablets("ks", "tbl", hosts, 2, 6, 6) 14 | if len(tl) != 6 { 15 | t.Errorf("expected 6 tablets, got %d", len(tl)) 16 | } 17 | 18 | for _, tablet := range tl { 19 | if len(tablet.replicas) != 2 { 20 | t.Errorf("each tablet should have 2 replicas, got %d", len(tablet.replicas)) 21 | } 22 | replicaSet := map[string]bool{} 23 | for _, r := range tablet.replicas { 24 | if replicaSet[r.hostId] { 25 | t.Errorf("duplicate replica %s in tablet", r.hostId) 26 | } 27 | replicaSet[r.hostId] = true 28 | } 29 | } 30 | }) 31 | 32 | t.Run("SingleTabletFullRange", func(t *testing.T) { 33 | hosts := tests.GenerateHostNames(3) 34 | tl := createTablets("ks", "tbl", hosts, 3, 1, 1) 35 | t0 := tl[0] 36 | if t0.firstToken != math.MinInt64 { 37 | t.Errorf("unexpected firstToken: %d", t0.firstToken) 38 | } 39 | if t0.lastToken != math.MaxInt64 { 40 | t.Errorf("unexpected lastToken: %d", t0.lastToken) 41 | } 42 | }) 43 | } 44 | 45 | func TestReplicaGenerator(t *testing.T) { 46 | hosts := []string{"a", "b", "c", "d"} 47 | rf := 2 48 | g := NewReplicaSetGenerator(hosts, rf) 49 | 50 | var seen [][]string 51 | for i := 0; i < 6; i++ { 52 | gen := g.Next() 53 | 54 | if len(gen) != rf { 55 | t.Fatalf("expected %d replicas, got %d", rf, len(gen)) 56 | } 57 | 58 | var ids []string 59 | for _, r := range gen { 60 | ids = append(ids, r.HostID()) 61 | } 62 | seen = append(seen, ids) 63 | } 64 | 65 | for i := 0; i < len(seen); i++ { 66 | outer: 67 | for j := i + 1; j < len(seen); j++ { 68 | for k := 0; k < len(seen[i]); k++ { 69 | if seen[i][k] != seen[j][k] { 70 | continue outer 71 | } 72 | } 73 | t.Errorf("expected different output for different seeds, but found same seeds for %d and %d: %s == %s", i, j, seen[i], seen[j]) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /framer_bench_test.go: -------------------------------------------------------------------------------- 1 | //go:build bench 2 | // +build bench 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package gocql 29 | 30 | import ( 31 | "compress/gzip" 32 | "io/ioutil" 33 | "os" 34 | "testing" 35 | ) 36 | 37 | func readGzipData(path string) ([]byte, error) { 38 | f, err := os.Open(path) 39 | if err != nil { 40 | return nil, err 41 | } 42 | defer f.Close() 43 | 44 | r, err := gzip.NewReader(f) 45 | if err != nil { 46 | return nil, err 47 | } 48 | defer r.Close() 49 | 50 | return ioutil.ReadAll(r) 51 | } 52 | 53 | func BenchmarkParseRowsFrame(b *testing.B) { 54 | data, err := readGzipData("testdata/frames/bench_parse_result.gz") 55 | if err != nil { 56 | b.Fatal(err) 57 | } 58 | 59 | b.ResetTimer() 60 | for i := 0; i < b.N; i++ { 61 | framer := &framer{ 62 | header: &frameHeader{ 63 | version: protoVersion4 | 0x80, 64 | op: frm.OpResult, 65 | length: len(data), 66 | }, 67 | buf: data, 68 | } 69 | 70 | _, err = framer.parseFrame() 71 | if err != nil { 72 | b.Fatal(err) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /internal/ccm/ccm_test.go: -------------------------------------------------------------------------------- 1 | //go:build all || ccm 2 | // +build all ccm 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package ccm 29 | 30 | import ( 31 | "testing" 32 | ) 33 | 34 | func TestCCM(t *testing.T) { 35 | if err := AllUp(); err != nil { 36 | t.Fatal(err) 37 | } 38 | 39 | status, err := Status() 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | 44 | if host, ok := status["node1"]; !ok { 45 | t.Fatal("node1 not in status list") 46 | } else if !host.State.IsUp() { 47 | t.Fatal("node1 is not up") 48 | } 49 | 50 | NodeDown("node1") 51 | status, err = Status() 52 | if err != nil { 53 | t.Fatal(err) 54 | } 55 | 56 | if host, ok := status["node1"]; !ok { 57 | t.Fatal("node1 not in status list") 58 | } else if host.State.IsUp() { 59 | t.Fatal("node1 is not down") 60 | } 61 | 62 | NodeUp("node1") 63 | status, err = Status() 64 | if err != nil { 65 | t.Fatal(err) 66 | } 67 | 68 | if host, ok := status["node1"]; !ok { 69 | t.Fatal("node1 not in status list") 70 | } else if !host.State.IsUp() { 71 | t.Fatal("node1 is not up") 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /session_unit_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package gocql 29 | 30 | import ( 31 | "context" 32 | "testing" 33 | ) 34 | 35 | func TestAsyncSessionInit(t *testing.T) { 36 | t.Parallel() 37 | 38 | // Build a 3 node cluster to test host metric mapping 39 | var addresses = []string{ 40 | "127.0.0.1", 41 | "127.0.0.2", 42 | "127.0.0.3", 43 | } 44 | // only build 1 of the servers so that we can test not connecting to the last 45 | // one 46 | srv := NewTestServerWithAddress(addresses[0]+":0", t, defaultProto, context.Background()) 47 | defer srv.Stop() 48 | 49 | // just choose any port 50 | cluster := testCluster(defaultProto, srv.Address, addresses[1]+":9999", addresses[2]+":9999") 51 | cluster.PoolConfig.HostSelectionPolicy = SingleHostReadyPolicy(RoundRobinHostPolicy()) 52 | db, err := cluster.CreateSession() 53 | if err != nil { 54 | t.Fatalf("NewCluster: %v", err) 55 | } 56 | defer db.Close() 57 | 58 | // make sure the session works 59 | if err := db.Query("void").Exec(); err != nil { 60 | t.Fatalf("unexpected error from void") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/serialization/marshal_2_tinyint_corrupt_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "math/big" 8 | "testing" 9 | 10 | "github.com/gocql/gocql" 11 | "github.com/gocql/gocql/internal/tests/serialization" 12 | "github.com/gocql/gocql/internal/tests/serialization/mod" 13 | "github.com/gocql/gocql/serialization/tinyint" 14 | ) 15 | 16 | func TestMarshalTinyintCorrupt(t *testing.T) { 17 | t.Parallel() 18 | 19 | type testSuite struct { 20 | name string 21 | marshal func(interface{}) ([]byte, error) 22 | unmarshal func(bytes []byte, i interface{}) error 23 | } 24 | 25 | tType := gocql.NewNativeType(4, gocql.TypeTinyInt) 26 | 27 | testSuites := [2]testSuite{ 28 | { 29 | name: "serialization.tinyint", 30 | marshal: tinyint.Marshal, 31 | unmarshal: tinyint.Unmarshal, 32 | }, 33 | { 34 | name: "glob", 35 | marshal: func(i interface{}) ([]byte, error) { 36 | return gocql.Marshal(tType, i) 37 | }, 38 | unmarshal: func(bytes []byte, i interface{}) error { 39 | return gocql.Unmarshal(tType, bytes, i) 40 | }, 41 | }, 42 | } 43 | 44 | for _, tSuite := range testSuites { 45 | marshal := tSuite.marshal 46 | unmarshal := tSuite.unmarshal 47 | 48 | t.Run(tSuite.name, func(t *testing.T) { 49 | t.Parallel() 50 | 51 | serialization.NegativeMarshalSet{ 52 | Values: mod.Values{ 53 | int16(128), int32(128), int64(128), int(128), 54 | "128", *big.NewInt(128), 55 | int16(-129), int32(-129), int64(-129), int(-129), 56 | "-129", *big.NewInt(-129), 57 | uint16(256), uint32(256), uint64(256), uint(256), 58 | }.AddVariants(mod.All...), 59 | }.Run("big_vals", t, marshal) 60 | 61 | serialization.NegativeMarshalSet{ 62 | Values: mod.Values{"1s2", "1s", "-1s", ".1", ",1", "0.1", "0,1"}.AddVariants(mod.All...), 63 | }.Run("corrupt_vals", t, marshal) 64 | 65 | serialization.NegativeUnmarshalSet{ 66 | Data: []byte("\x80\x00"), 67 | Values: mod.Values{ 68 | int8(0), int16(0), int32(0), int64(0), int(0), 69 | uint8(0), uint16(0), uint32(0), uint64(0), uint(0), 70 | "", *big.NewInt(0), 71 | }.AddVariants(mod.All...), 72 | }.Run("big_data", t, unmarshal) 73 | }) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /serialization/timestamp/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package timestamp 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | var ( 10 | maxTimestamp = time.Date(292278994, 8, 17, 7, 12, 55, 807*1000000, time.UTC) 11 | minTimestamp = time.Date(-292275055, 5, 16, 16, 47, 4, 192*1000000, time.UTC) 12 | ) 13 | 14 | func EncInt64(v int64) ([]byte, error) { 15 | return encInt64(v), nil 16 | } 17 | 18 | func EncInt64R(v *int64) ([]byte, error) { 19 | if v == nil { 20 | return nil, nil 21 | } 22 | return EncInt64(*v) 23 | } 24 | 25 | func EncTime(v time.Time) ([]byte, error) { 26 | if v.After(maxTimestamp) || v.Before(minTimestamp) { 27 | return nil, fmt.Errorf("failed to marshal timestamp: the (%T)(%s) value should be in the range from -292275055-05-16T16:47:04.192Z to 292278994-08-17T07:12:55.807", v, v.Format(time.RFC3339Nano)) 28 | } 29 | // It supposed to be v.UTC().UnixMilli(), for backward compatibility map `time.Time{}` to nil value 30 | if v.IsZero() { 31 | return make([]byte, 0), nil 32 | } 33 | ms := v.UTC().UnixMilli() 34 | return []byte{byte(ms >> 56), byte(ms >> 48), byte(ms >> 40), byte(ms >> 32), byte(ms >> 24), byte(ms >> 16), byte(ms >> 8), byte(ms)}, nil 35 | } 36 | 37 | func EncTimeR(v *time.Time) ([]byte, error) { 38 | if v == nil { 39 | return nil, nil 40 | } 41 | return EncTime(*v) 42 | } 43 | 44 | func EncReflect(v reflect.Value) ([]byte, error) { 45 | switch v.Kind() { 46 | case reflect.Int64: 47 | return encInt64(v.Int()), nil 48 | case reflect.Struct: 49 | if v.Type().String() == "gocql.unsetColumn" { 50 | return nil, nil 51 | } 52 | return nil, fmt.Errorf("failed to marshal timestamp: unsupported value type (%T)(%[1]v), supported types: ~int64, time.Time, unsetColumn", v.Interface()) 53 | default: 54 | return nil, fmt.Errorf("failed to marshal timestamp: unsupported value type (%T)(%[1]v), supported types: ~int64, time.Time, unsetColumn", v.Interface()) 55 | } 56 | } 57 | 58 | func EncReflectR(v reflect.Value) ([]byte, error) { 59 | if v.IsNil() { 60 | return nil, nil 61 | } 62 | return EncReflect(v.Elem()) 63 | } 64 | 65 | func encInt64(v int64) []byte { 66 | return []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} 67 | } 68 | -------------------------------------------------------------------------------- /tests/serialization/marshal_10_decimal_corrupt_test.go: -------------------------------------------------------------------------------- 1 | package serialization_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "gopkg.in/inf.v0" 7 | 8 | "github.com/gocql/gocql" 9 | "github.com/gocql/gocql/internal/tests/serialization" 10 | "github.com/gocql/gocql/internal/tests/serialization/mod" 11 | "github.com/gocql/gocql/serialization/decimal" 12 | ) 13 | 14 | func TestMarshalDecimalCorrupt(t *testing.T) { 15 | type testSuite struct { 16 | marshal func(interface{}) ([]byte, error) 17 | unmarshal func(bytes []byte, i interface{}) error 18 | name string 19 | } 20 | 21 | tType := gocql.NewNativeType(4, gocql.TypeDecimal) 22 | 23 | testSuites := [2]testSuite{ 24 | { 25 | name: "serialization.decimal", 26 | marshal: decimal.Marshal, 27 | unmarshal: decimal.Unmarshal, 28 | }, 29 | { 30 | name: "glob", 31 | marshal: func(i interface{}) ([]byte, error) { 32 | return gocql.Marshal(tType, i) 33 | }, 34 | unmarshal: func(bytes []byte, i interface{}) error { 35 | return gocql.Unmarshal(tType, bytes, i) 36 | }, 37 | }, 38 | } 39 | 40 | for _, tSuite := range testSuites { 41 | marshal := tSuite.marshal 42 | unmarshal := tSuite.unmarshal 43 | 44 | t.Run(tSuite.name, func(t *testing.T) { 45 | t.Parallel() 46 | 47 | serialization.NegativeMarshalSet{ 48 | Values: mod.Values{"1s2", "1s", "-1s", ",1", "0,1"}.AddVariants(mod.All...), 49 | }.Run("corrupt_vals", t, marshal) 50 | 51 | serialization.NegativeUnmarshalSet{ 52 | Data: []byte("\x00\x00\x00\x00\x00\x7f"), 53 | Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), 54 | }.Run("corrupt_data+", t, unmarshal) 55 | 56 | serialization.NegativeUnmarshalSet{ 57 | Data: []byte("\x00\x00\x00\x00\xff\x80"), 58 | Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), 59 | }.Run("corrupt_data-", t, unmarshal) 60 | 61 | serialization.NegativeUnmarshalSet{ 62 | Data: []byte("\x00\x00\x00\x00"), 63 | Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), 64 | }.Run("small_data1", t, unmarshal) 65 | 66 | serialization.NegativeUnmarshalSet{ 67 | Data: []byte("\x00"), 68 | Values: mod.Values{*inf.NewDec(0, 0), ""}.AddVariants(mod.All...), 69 | }.Run("small_data2", t, unmarshal) 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /internal/tests/serialization/set_negative_unmarshal.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "runtime/debug" 9 | "testing" 10 | ) 11 | 12 | // NegativeUnmarshalSet is a tool for unmarshal funcs testing for cases when the function should an error. 13 | type NegativeUnmarshalSet struct { 14 | Data []byte 15 | Values []interface{} 16 | BrokenTypes []reflect.Type 17 | } 18 | 19 | func (s NegativeUnmarshalSet) Run(name string, t *testing.T, unmarshal func([]byte, interface{}) error) { 20 | if name == "" { 21 | t.Fatal("name should be provided") 22 | } 23 | if unmarshal == nil { 24 | t.Fatal("unmarshal function should be provided") 25 | } 26 | t.Run(name, func(t *testing.T) { 27 | for m := range s.Values { 28 | val := s.Values[m] 29 | 30 | if rt := reflect.TypeOf(val); rt.Kind() != reflect.Ptr { 31 | unmarshalIn := newRef(val) 32 | s.run(fmt.Sprintf("%T", val), t, unmarshal, val, unmarshalIn) 33 | } else { 34 | // Test unmarshal to (*type)(nil) 35 | unmarshalIn := newRef(val) 36 | s.run(fmt.Sprintf("%T**nil", val), t, unmarshal, val, unmarshalIn) 37 | 38 | // Test unmarshal to &type{} 39 | unmarshalInZero := newRefToZero(val) 40 | s.run(fmt.Sprintf("%T**zero", val), t, unmarshal, val, unmarshalInZero) 41 | } 42 | } 43 | }) 44 | } 45 | 46 | func (s NegativeUnmarshalSet) run(name string, t *testing.T, f func([]byte, interface{}) error, val, unmarshalIn interface{}) { 47 | t.Run(name, func(t *testing.T) { 48 | err := func() (err error) { 49 | defer func() { 50 | if r := recover(); r != nil { 51 | err = panicErr{err: r.(error), stack: debug.Stack()} 52 | } 53 | }() 54 | return f(bytes.Clone(s.Data), unmarshalIn) 55 | }() 56 | 57 | testFailed := false 58 | wasPanic := errors.As(err, &panicErr{}) 59 | if err == nil || wasPanic { 60 | testFailed = true 61 | } 62 | 63 | if isTypeOf(val, s.BrokenTypes) { 64 | if testFailed { 65 | t.Skipf("skipped bacause there is unsolved problem") 66 | } 67 | t.Fatalf("expected to panic or no error for (%T), but got an error", unmarshalIn) 68 | } 69 | 70 | if testFailed { 71 | if wasPanic { 72 | t.Fatalf("was panic %s", err) 73 | } 74 | t.Errorf("expected an error for (%T), but got no error", unmarshalIn) 75 | } 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /address_translators_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package gocql 29 | 30 | import ( 31 | "net" 32 | "testing" 33 | 34 | "github.com/gocql/gocql/internal/tests" 35 | ) 36 | 37 | func TestIdentityAddressTranslator_NilAddrAndZeroPort(t *testing.T) { 38 | t.Parallel() 39 | 40 | var tr AddressTranslator = IdentityTranslator() 41 | hostIP := net.ParseIP("") 42 | if hostIP != nil { 43 | t.Errorf("expected host ip to be (nil) but was (%+v) instead", hostIP) 44 | } 45 | 46 | addr, port := tr.Translate(hostIP, 0) 47 | if addr != nil { 48 | t.Errorf("expected translated host to be (nil) but was (%+v) instead", addr) 49 | } 50 | tests.AssertEqual(t, "translated port", 0, port) 51 | } 52 | 53 | func TestIdentityAddressTranslator_HostProvided(t *testing.T) { 54 | t.Parallel() 55 | 56 | var tr AddressTranslator = IdentityTranslator() 57 | hostIP := net.ParseIP("10.1.2.3") 58 | if hostIP == nil { 59 | t.Error("expected host ip not to be (nil)") 60 | } 61 | 62 | addr, port := tr.Translate(hostIP, 9042) 63 | if !hostIP.Equal(addr) { 64 | t.Errorf("expected translated addr to be (%+v) but was (%+v) instead", hostIP, addr) 65 | } 66 | tests.AssertEqual(t, "translated port", 9042, port) 67 | } 68 | -------------------------------------------------------------------------------- /integration_only.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | // This file contains code to enable easy access to driver internals 7 | // To be used only for integration test 8 | 9 | import "fmt" 10 | 11 | func (p *policyConnPool) MissingConnections() (int, error) { 12 | p.mu.Lock() 13 | defer p.mu.Unlock() 14 | 15 | total := 0 16 | 17 | // close the pools 18 | for _, pool := range p.hostConnPools { 19 | missing := pool.GetShardCount() - pool.GetConnectionCount() 20 | if pool.IsClosed() { 21 | return 0, fmt.Errorf("pool for %s is closed", pool.host.HostID()) 22 | } 23 | total += missing 24 | } 25 | return total, nil 26 | } 27 | 28 | func (s *Session) MissingConnections() (int, error) { 29 | if s.pool == nil { 30 | return 0, fmt.Errorf("pool is nil") 31 | } 32 | return s.pool.MissingConnections() 33 | } 34 | 35 | type ConnPickerIntegration interface { 36 | Pick(Token, ExecutableQuery) *Conn 37 | Put(*Conn) error 38 | Remove(conn *Conn) 39 | InFlight() int 40 | Size() (int, int) 41 | Close() 42 | CloseAllConnections() 43 | 44 | // NextShard returns the shardID to connect to. 45 | // nrShard specifies how many shards the host has. 46 | // If nrShards is zero, the caller shouldn't use shard-aware port. 47 | NextShard() (shardID, nrShards int) 48 | } 49 | 50 | func (p *scyllaConnPicker) CloseAllConnections() { 51 | p.nrConns = 0 52 | closeConns(p.conns...) 53 | for id := range p.conns { 54 | p.conns[id] = nil 55 | } 56 | } 57 | 58 | func (p *defaultConnPicker) CloseAllConnections() { 59 | closeConns(p.conns...) 60 | p.conns = p.conns[:0] 61 | } 62 | 63 | func (p *nopConnPicker) CloseAllConnections() { 64 | } 65 | 66 | func (pool *hostConnPool) CloseAllConnections() { 67 | if !pool.closed { 68 | return 69 | } 70 | pool.mu.Lock() 71 | println("Closing all connections in a pool") 72 | pool.connPicker.(ConnPickerIntegration).CloseAllConnections() 73 | println("Filling the pool") 74 | pool.mu.Unlock() 75 | pool.fill() 76 | } 77 | 78 | func (p *policyConnPool) CloseAllConnections() { 79 | p.mu.Lock() 80 | defer p.mu.Unlock() 81 | 82 | // close the pools 83 | for _, pool := range p.hostConnPools { 84 | pool.CloseAllConnections() 85 | } 86 | } 87 | 88 | func (s *Session) CloseAllConnections() { 89 | if s.pool != nil { 90 | s.pool.CloseAllConnections() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /session_event_bus_integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | package gocql 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | "time" 10 | 11 | "github.com/gocql/gocql/events" 12 | ) 13 | 14 | func TestSessionEventBusReceivesSchemaChangeEvent(t *testing.T) { 15 | cluster := createCluster() 16 | cluster.Events.DisableSchemaEvents = false 17 | 18 | sess, err := cluster.CreateSession() 19 | if err != nil { 20 | t.Fatalf("unable to create session: %v", err) 21 | } 22 | defer sess.Close() 23 | 24 | sub := sess.SubscribeToEvents("schema-event", 10, func(ev events.Event) bool { 25 | return ev.Type() == events.ClusterEventTypeSchemaChangeKeyspace 26 | }) 27 | defer sub.Stop() 28 | 29 | keyspace := fmt.Sprintf("eventbus_schema_%d", time.Now().UnixNano()) 30 | createStmt := fmt.Sprintf(`CREATE KEYSPACE %s WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1}`, keyspace) 31 | if err := sess.Query(createStmt).Exec(); err != nil { 32 | t.Fatalf("create keyspace: %v", err) 33 | } 34 | defer sess.Query("DROP KEYSPACE " + keyspace).Exec() 35 | 36 | select { 37 | case ev := <-sub.Events(): 38 | if _, ok := ev.(*events.SchemaChangeKeyspaceEvent); !ok { 39 | t.Fatalf("unexpected event type: %T", ev) 40 | } 41 | case <-time.After(30 * time.Second): 42 | t.Fatal("timeout waiting for schema change event") 43 | } 44 | } 45 | 46 | func TestSessionEventBusReceivesControlReconnectEvent(t *testing.T) { 47 | cluster := createCluster() 48 | cluster.Events.DisableTopologyEvents = true 49 | cluster.Events.DisableNodeStatusEvents = true 50 | 51 | sess, err := cluster.CreateSession() 52 | if err != nil { 53 | t.Fatalf("unable to create session: %v", err) 54 | } 55 | defer sess.Close() 56 | 57 | sub := sess.SubscribeToEvents("control-reconnect", 10, func(ev events.Event) bool { 58 | return ev.Type() == events.SessionEventTypeControlConnectionRecreated 59 | }) 60 | defer sub.Stop() 61 | 62 | if err := sess.control.reconnect(); err != nil { 63 | t.Fatalf("control reconnect: %v", err) 64 | } 65 | 66 | select { 67 | case ev := <-sub.Events(): 68 | if _, ok := ev.(*events.ControlConnectionRecreatedEvent); !ok { 69 | t.Fatalf("unexpected event type: %T", ev) 70 | } 71 | case <-time.After(30 * time.Second): 72 | t.Fatal("timeout waiting for control reconnect event") 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | /* 19 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 20 | * Copyright (c) 2016, The Gocql authors, 21 | * provided under the BSD-3-Clause License. 22 | * See the NOTICE file distributed with this work for additional information. 23 | */ 24 | 25 | package gocql 26 | 27 | import ( 28 | "bytes" 29 | "fmt" 30 | "log" 31 | ) 32 | 33 | type StdLogger interface { 34 | Print(v ...interface{}) 35 | Printf(format string, v ...interface{}) 36 | Println(v ...interface{}) 37 | } 38 | 39 | type nopLogger struct{} 40 | 41 | func (n nopLogger) Print(_ ...interface{}) {} 42 | 43 | func (n nopLogger) Printf(_ string, _ ...interface{}) {} 44 | 45 | func (n nopLogger) Println(_ ...interface{}) {} 46 | 47 | type testLogger struct { 48 | capture bytes.Buffer 49 | } 50 | 51 | func (l *testLogger) Print(v ...interface{}) { fmt.Fprint(&l.capture, v...) } 52 | func (l *testLogger) Printf(format string, v ...interface{}) { fmt.Fprintf(&l.capture, format, v...) } 53 | func (l *testLogger) Println(v ...interface{}) { fmt.Fprintln(&l.capture, v...) } 54 | func (l *testLogger) String() string { return l.capture.String() } 55 | 56 | type defaultLogger struct{} 57 | 58 | func (l *defaultLogger) Print(v ...interface{}) { log.Print(v...) } 59 | func (l *defaultLogger) Printf(format string, v ...interface{}) { log.Printf(format, v...) } 60 | func (l *defaultLogger) Println(v ...interface{}) { log.Println(v...) } 61 | -------------------------------------------------------------------------------- /tests/serialization/marshal_1_boolean_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/gocql/gocql" 10 | "github.com/gocql/gocql/internal/tests/serialization" 11 | "github.com/gocql/gocql/internal/tests/serialization/mod" 12 | "github.com/gocql/gocql/serialization/boolean" 13 | ) 14 | 15 | func TestMarshalBoolean(t *testing.T) { 16 | t.Parallel() 17 | 18 | tType := gocql.NewNativeType(4, gocql.TypeBoolean) 19 | 20 | type testSuite struct { 21 | name string 22 | marshal func(interface{}) ([]byte, error) 23 | unmarshal func(bytes []byte, i interface{}) error 24 | } 25 | 26 | testSuites := [2]testSuite{ 27 | { 28 | name: "serialization.boolean", 29 | marshal: boolean.Marshal, 30 | unmarshal: boolean.Unmarshal, 31 | }, 32 | { 33 | name: "glob", 34 | marshal: func(i interface{}) ([]byte, error) { 35 | return gocql.Marshal(tType, i) 36 | }, 37 | unmarshal: func(bytes []byte, i interface{}) error { 38 | return gocql.Unmarshal(tType, bytes, i) 39 | }, 40 | }, 41 | } 42 | 43 | for _, tSuite := range testSuites { 44 | marshal := tSuite.marshal 45 | unmarshal := tSuite.unmarshal 46 | 47 | t.Run(tSuite.name, func(t *testing.T) { 48 | t.Parallel() 49 | 50 | serialization.PositiveSet{ 51 | Data: nil, 52 | Values: mod.Values{(*bool)(nil)}.AddVariants(mod.CustomType), 53 | }.Run("[nil]nullable", t, marshal, unmarshal) 54 | 55 | serialization.PositiveSet{ 56 | Data: nil, 57 | Values: mod.Values{false}.AddVariants(mod.CustomType), 58 | }.Run("[nil]unmarshal", t, nil, unmarshal) 59 | 60 | serialization.PositiveSet{ 61 | Data: make([]byte, 0), 62 | Values: mod.Values{false}.AddVariants(mod.All...), 63 | }.Run("[]unmarshal", t, nil, unmarshal) 64 | 65 | serialization.PositiveSet{ 66 | Data: []byte("\x00"), 67 | Values: mod.Values{false}.AddVariants(mod.All...), 68 | }.Run("zeros", t, marshal, unmarshal) 69 | 70 | serialization.PositiveSet{ 71 | Data: []byte("\x01"), 72 | Values: mod.Values{true}.AddVariants(mod.All...), 73 | }.Run("[1]unmarshal", t, nil, unmarshal) 74 | 75 | serialization.PositiveSet{ 76 | Data: []byte("\xff"), 77 | Values: mod.Values{true}.AddVariants(mod.All...), 78 | }.Run("[255]", t, nil, unmarshal) 79 | }) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /ci/clean-old-temporary-docker-images.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from datetime import datetime, timedelta 4 | 5 | DOCKERHUB_USERNAME = os.environ["DOCKERHUB_USERNAME"] 6 | DOCKERHUB_TOKEN = os.environ["DOCKERHUB_TOKEN"] 7 | DELETE_AFTER_DAYS = os.environ["DELETE_AFTER_DAYS"] 8 | 9 | def get_docker_token(username, password): 10 | url = "https://hub.docker.com/v2/users/login/" 11 | headers = {"Content-Type": "application/json"} 12 | data = {"username": username, "password": password} 13 | 14 | response = requests.post(url, json=data, headers=headers) 15 | if response.status_code == 200: 16 | return response.json()["token"] 17 | else: 18 | print(f"Failed to login to DockerHub: {response.status_code}") 19 | return None 20 | 21 | def get_repo_tags(token): 22 | url = f"https://hub.docker.com/v2/repositories/scylladb/gocql-extended-ci/tags/" 23 | headers = {"Authorization": f"Bearer {token}"} 24 | response = requests.get(url, headers=headers) 25 | if response.status_code != 200: 26 | print(f"Failed to get tags, Status Code: {response.status_code}, {response.text}") 27 | return None 28 | return response.json()["results"] 29 | 30 | def delete_tag(tag, token): 31 | url = f"https://hub.docker.com/v2/repositories/scylladb/gocql-extended-ci/tags/{tag}/" 32 | headers = {"Authorization": f"Bearer {token}"} 33 | response = requests.delete(url, headers=headers) 34 | if response.status_code > 200 and response.status_code < 300: 35 | print(f"Deleted tag: {tag}") 36 | return True 37 | print(f"Failed to delete tag: {tag}, Status Code: {response.status_code}") 38 | return False 39 | 40 | def clean_old_images(): 41 | token = get_docker_token(DOCKERHUB_USERNAME, DOCKERHUB_TOKEN) 42 | if token is None: 43 | return False 44 | tags = get_repo_tags(token) 45 | if tags is None: 46 | return False 47 | threshold_date = datetime.now() - timedelta(days=int(DELETE_AFTER_DAYS)) 48 | status = True 49 | for tag in tags: 50 | last_updated = datetime.strptime(tag["last_updated"], "%Y-%m-%dT%H:%M:%S.%fZ") 51 | if last_updated < threshold_date: 52 | status = status and delete_tag(tag["name"], token) 53 | return status 54 | 55 | if __name__ == "__main__": 56 | if not clean_old_images(): 57 | exit(1) 58 | exit(0) 59 | -------------------------------------------------------------------------------- /serialization/cqltime/marshal_utils.go: -------------------------------------------------------------------------------- 1 | package cqltime 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | const ( 10 | maxValInt64 int64 = 86399999999999 11 | minValInt64 int64 = 0 12 | maxValDur time.Duration = 86399999999999 13 | minValDur time.Duration = 0 14 | ) 15 | 16 | var ( 17 | errOutRangeInt64 = fmt.Errorf("failed to marshal time: the (int64) should be in the range 0 to 86399999999999") 18 | errOutRangeDur = fmt.Errorf("failed to marshal time: the (time.Duration) should be in the range 0 to 86399999999999") 19 | ) 20 | 21 | func EncInt64(v int64) ([]byte, error) { 22 | if v > maxValInt64 || v < minValInt64 { 23 | return nil, errOutRangeInt64 24 | } 25 | return encInt64(v), nil 26 | } 27 | 28 | func EncInt64R(v *int64) ([]byte, error) { 29 | if v == nil { 30 | return nil, nil 31 | } 32 | return EncInt64(*v) 33 | } 34 | 35 | func EncDuration(v time.Duration) ([]byte, error) { 36 | if v > maxValDur || v < minValDur { 37 | return nil, errOutRangeDur 38 | } 39 | return []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil 40 | } 41 | 42 | func EncDurationR(v *time.Duration) ([]byte, error) { 43 | if v == nil { 44 | return nil, nil 45 | } 46 | return EncDuration(*v) 47 | } 48 | 49 | func EncReflect(v reflect.Value) ([]byte, error) { 50 | switch v.Kind() { 51 | case reflect.Int64: 52 | val := v.Int() 53 | if val > maxValInt64 || val < minValInt64 { 54 | return nil, fmt.Errorf("failed to marshal time: the (%T) should be in the range 0 to 86399999999999", v.Interface()) 55 | } 56 | return encInt64(val), nil 57 | case reflect.Struct: 58 | if v.Type().String() == "gocql.unsetColumn" { 59 | return nil, nil 60 | } 61 | return nil, fmt.Errorf("failed to marshal time: unsupported value type (%T)(%[1]v), supported types: ~int64, time.Duration, unsetColumn", v.Interface()) 62 | default: 63 | return nil, fmt.Errorf("failed to marshal time: unsupported value type (%T)(%[1]v), supported types: ~int64, time.Duration, unsetColumn", v.Interface()) 64 | } 65 | } 66 | 67 | func EncReflectR(v reflect.Value) ([]byte, error) { 68 | if v.IsNil() { 69 | return nil, nil 70 | } 71 | return EncReflect(v.Elem()) 72 | } 73 | 74 | func encInt64(v int64) []byte { 75 | return []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} 76 | } 77 | -------------------------------------------------------------------------------- /serialization/duration/unmarshal_str_test.go: -------------------------------------------------------------------------------- 1 | package duration 2 | 3 | import ( 4 | "math" 5 | "strconv" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestDecStr(t *testing.T) { 11 | for n := int64(math.MaxInt64); n != 1; n = n / 2 { 12 | m, d := int32(n), int32(n) 13 | if n > math.MaxInt32 { 14 | m, d = math.MaxInt32, math.MaxInt32 15 | } 16 | testDecString(t, m, d, n) 17 | testDecString(t, 0, d, n) 18 | testDecString(t, m, 0, n) 19 | testDecString(t, m, d, 0) 20 | } 21 | 22 | for n := int64(math.MinInt64); n != -1; n = n / 2 { 23 | m, d := int32(n), int32(n) 24 | if n < math.MinInt32 { 25 | m, d = math.MinInt32, math.MinInt32 26 | } 27 | testDecString(t, m, d, n) 28 | testDecString(t, 0, d, n) 29 | testDecString(t, m, 0, n) 30 | testDecString(t, m, d, 0) 31 | } 32 | } 33 | 34 | func testDecString(t *testing.T, m, d int32, n int64) { 35 | t.Helper() 36 | expected := getTestString(m, d, n) 37 | received := decString(m, d, n) 38 | 39 | if expected != received { 40 | t.Fatalf("expected and recieved strings not equal\nvalue:m:%d,d:%d,n:%d\nexpected:%s\nreceived:%s", m, d, n, expected, received) 41 | } 42 | } 43 | 44 | func getTestString(m, d int32, n int64) string { 45 | out := "" 46 | if m < 0 || d < 0 || n < 0 { 47 | out += "-" 48 | } 49 | if m != 0 { 50 | out += getStringMonths(m) 51 | } 52 | if d != 0 { 53 | out += getStringDays(d) 54 | } 55 | if n != 0 { 56 | out += getStringNanos(n) 57 | } 58 | if out == "" { 59 | return zeroDuration 60 | } 61 | return out 62 | } 63 | 64 | func getStringMonths(m int32) string { 65 | out := "" 66 | mu := uint64(m) 67 | if m < 0 { 68 | mu = -mu 69 | } 70 | y := mu / 12 71 | if mu = mu % 12; mu == 0 { 72 | y-- 73 | mu = 12 74 | } 75 | if y != 0 { 76 | out += strconv.FormatUint(y, 10) + "y" 77 | } 78 | out += strconv.FormatUint(mu, 10) + "mo" 79 | return out 80 | } 81 | 82 | func getStringDays(d int32) string { 83 | out := "" 84 | du := uint64(d) 85 | if d < 0 { 86 | du = -du 87 | } 88 | w := du / 7 89 | if du = du % 7; du == 0 { 90 | w-- 91 | du = 7 92 | } 93 | if w != 0 { 94 | out += strconv.FormatUint(w, 10) + "w" 95 | } 96 | out += strconv.FormatUint(du, 10) + "d" 97 | return out 98 | } 99 | 100 | func getStringNanos(d int64) string { 101 | out := time.Duration(d).String() 102 | if d < 0 { 103 | out = out[1:] 104 | } 105 | return out 106 | } 107 | -------------------------------------------------------------------------------- /tests/serialization/marshal_15_time_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | // +build unit 3 | 4 | package serialization_test 5 | 6 | import ( 7 | "testing" 8 | "time" 9 | 10 | "github.com/gocql/gocql" 11 | "github.com/gocql/gocql/internal/tests/serialization" 12 | "github.com/gocql/gocql/internal/tests/serialization/mod" 13 | "github.com/gocql/gocql/serialization/cqltime" 14 | ) 15 | 16 | func TestMarshalsTime(t *testing.T) { 17 | t.Parallel() 18 | 19 | tType := gocql.NewNativeType(4, gocql.TypeTime) 20 | 21 | type testSuite struct { 22 | name string 23 | marshal func(interface{}) ([]byte, error) 24 | unmarshal func(bytes []byte, i interface{}) error 25 | } 26 | 27 | testSuites := [2]testSuite{ 28 | { 29 | name: "serialization.cqltime", 30 | marshal: cqltime.Marshal, 31 | unmarshal: cqltime.Unmarshal, 32 | }, 33 | { 34 | name: "glob", 35 | marshal: func(i interface{}) ([]byte, error) { 36 | return gocql.Marshal(tType, i) 37 | }, 38 | unmarshal: func(bytes []byte, i interface{}) error { 39 | return gocql.Unmarshal(tType, bytes, i) 40 | }, 41 | }, 42 | } 43 | 44 | for _, tSuite := range testSuites { 45 | marshal := tSuite.marshal 46 | unmarshal := tSuite.unmarshal 47 | 48 | t.Run(tSuite.name, func(t *testing.T) { 49 | t.Parallel() 50 | 51 | serialization.PositiveSet{ 52 | Data: nil, 53 | Values: mod.Values{ 54 | (*int64)(nil), (*time.Duration)(nil), 55 | }.AddVariants(mod.CustomType), 56 | }.Run("[nil]nullable", t, marshal, unmarshal) 57 | 58 | serialization.PositiveSet{ 59 | Data: nil, 60 | Values: mod.Values{ 61 | int64(0), time.Duration(0), 62 | }.AddVariants(mod.CustomType), 63 | }.Run("[nil]unmarshal", t, nil, unmarshal) 64 | 65 | serialization.PositiveSet{ 66 | Data: make([]byte, 0), 67 | Values: mod.Values{ 68 | int64(0), time.Duration(0), 69 | }.AddVariants(mod.All...), 70 | }.Run("[]unmarshal", t, nil, unmarshal) 71 | 72 | serialization.PositiveSet{ 73 | Data: []byte("\x00\x00\x00\x00\x00\x00\x00\x00"), 74 | Values: mod.Values{ 75 | int64(0), time.Duration(0), 76 | }.AddVariants(mod.All...), 77 | }.Run("zeros", t, marshal, unmarshal) 78 | 79 | serialization.PositiveSet{ 80 | Data: []byte("\x00\x00\x4e\x94\x91\x4e\xff\xff"), 81 | Values: mod.Values{ 82 | int64(86399999999999), time.Duration(86399999999999), 83 | }.AddVariants(mod.All...), 84 | }.Run("max", t, marshal, unmarshal) 85 | }) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /serialization/varint/marshal_custom.go: -------------------------------------------------------------------------------- 1 | package varint 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "reflect" 7 | "strconv" 8 | ) 9 | 10 | const supportedTypes = "~int8, ~int16, ~int32, ~int64, ~int, ~uint8, ~uint16, ~uint32, ~uint64, ~uint, ~string, big.Int" 11 | 12 | func EncReflect(v reflect.Value) ([]byte, error) { 13 | switch v.Type().Kind() { 14 | case reflect.Int8: 15 | return EncInt8(int8(v.Int())) 16 | case reflect.Int16: 17 | return EncInt16(int16(v.Int())) 18 | case reflect.Int32: 19 | return EncInt32(int32(v.Int())) 20 | case reflect.Int, reflect.Int64: 21 | return EncInt64(v.Int()) 22 | case reflect.Uint8: 23 | return EncUint8(uint8(v.Uint())) 24 | case reflect.Uint16: 25 | return EncUint16(uint16(v.Uint())) 26 | case reflect.Uint32: 27 | return EncUint32(uint32(v.Uint())) 28 | case reflect.Uint, reflect.Uint64: 29 | return EncUint64(v.Uint()) 30 | case reflect.String: 31 | return encReflectString(v) 32 | case reflect.Struct: 33 | if v.Type().String() == "gocql.unsetColumn" { 34 | return nil, nil 35 | } 36 | return nil, fmt.Errorf("failed to marshal varint: unsupported value type (%T)(%[1]v), supported types: %s, unsetColumn", v.Interface(), supportedTypes) 37 | 38 | default: 39 | return nil, fmt.Errorf("failed to marshal varint: unsupported value type (%T)(%[1]v), supported types: %s, unsetColumn", v.Interface(), supportedTypes) 40 | } 41 | } 42 | 43 | func EncReflectR(v reflect.Value) ([]byte, error) { 44 | if v.IsNil() { 45 | return nil, nil 46 | } 47 | return EncReflect(v.Elem()) 48 | } 49 | 50 | func encReflectString(v reflect.Value) ([]byte, error) { 51 | val := v.String() 52 | switch { 53 | case len(val) == 0: 54 | return nil, nil 55 | case len(val) <= 18: 56 | n, err := strconv.ParseInt(val, 10, 64) 57 | if err != nil { 58 | return nil, fmt.Errorf("failed to marshal varint: can not marshal (%T)(%[1]v), %s", v.Interface(), err) 59 | } 60 | return EncInt64Ext(n), nil 61 | case len(val) <= 20: 62 | n, err := strconv.ParseInt(val, 10, 64) 63 | if err == nil { 64 | return EncInt64Ext(n), nil 65 | } 66 | 67 | t, ok := new(big.Int).SetString(val, 10) 68 | if !ok { 69 | return nil, fmt.Errorf("failed to marshal varint: can not marshal (%T)(%[1]v)", v.Interface()) 70 | } 71 | return EncBigIntRS(t), nil 72 | default: 73 | t, ok := new(big.Int).SetString(val, 10) 74 | if !ok { 75 | return nil, fmt.Errorf("failed to marshal varint: can not marshal (%T)(%[1]v)", v.Interface()) 76 | } 77 | return EncBigIntRS(t), nil 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /internal/tests/serialization/utils_equal.go: -------------------------------------------------------------------------------- 1 | package serialization 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "math/big" 7 | "reflect" 8 | "unsafe" 9 | 10 | "gopkg.in/inf.v0" 11 | 12 | "github.com/gocql/gocql/internal/tests/serialization/mod" 13 | ) 14 | 15 | func equalData(in1, in2 []byte) bool { 16 | if in1 == nil || in2 == nil { 17 | return in1 == nil && in2 == nil 18 | } 19 | return bytes.Equal(in1, in2) 20 | } 21 | 22 | func equalVals(in1, in2 interface{}) bool { 23 | rin1 := reflect.ValueOf(in1) 24 | rin2 := reflect.ValueOf(in2) 25 | if rin1.Kind() != rin2.Kind() { 26 | return false 27 | } 28 | if rin1.Kind() == reflect.Ptr && (rin1.IsNil() || rin2.IsNil()) { 29 | return rin1.IsNil() && rin2.IsNil() 30 | } 31 | 32 | switch vin1 := in1.(type) { 33 | case float32: 34 | vin2 := in2.(float32) 35 | return *(*[4]byte)(unsafe.Pointer(&vin1)) == *(*[4]byte)(unsafe.Pointer(&vin2)) 36 | case *float32: 37 | vin2 := in2.(*float32) 38 | return *(*[4]byte)(unsafe.Pointer(vin1)) == *(*[4]byte)(unsafe.Pointer(vin2)) 39 | case *mod.Float32: 40 | vin2 := in2.(*mod.Float32) 41 | return *(*[4]byte)(unsafe.Pointer(vin1)) == *(*[4]byte)(unsafe.Pointer(vin2)) 42 | case mod.Float32: 43 | vin2 := in2.(mod.Float32) 44 | return *(*[4]byte)(unsafe.Pointer(&vin1)) == *(*[4]byte)(unsafe.Pointer(&vin2)) 45 | case float64: 46 | vin2 := in2.(float64) 47 | return *(*[8]byte)(unsafe.Pointer(&vin1)) == *(*[8]byte)(unsafe.Pointer(&vin2)) 48 | case *float64: 49 | vin2 := in2.(*float64) 50 | return *(*[8]byte)(unsafe.Pointer(vin1)) == *(*[8]byte)(unsafe.Pointer(vin2)) 51 | case *mod.Float64: 52 | vin2 := in2.(*mod.Float64) 53 | return *(*[8]byte)(unsafe.Pointer(vin1)) == *(*[8]byte)(unsafe.Pointer(vin2)) 54 | case mod.Float64: 55 | vin2 := in2.(mod.Float64) 56 | return *(*[8]byte)(unsafe.Pointer(&vin1)) == *(*[8]byte)(unsafe.Pointer(&vin2)) 57 | case big.Int: 58 | vin2 := in2.(big.Int) 59 | return vin1.Cmp(&vin2) == 0 60 | case *big.Int: 61 | vin2 := in2.(*big.Int) 62 | return vin1.Cmp(vin2) == 0 63 | case inf.Dec: 64 | vin2 := in2.(inf.Dec) 65 | if vin1.Scale() != vin2.Scale() { 66 | return false 67 | } 68 | return vin1.UnscaledBig().Cmp(vin2.UnscaledBig()) == 0 69 | case *inf.Dec: 70 | vin2 := in2.(*inf.Dec) 71 | if vin1.Scale() != vin2.Scale() { 72 | return false 73 | } 74 | return vin1.UnscaledBig().Cmp(vin2.UnscaledBig()) == 0 75 | case fmt.Stringer: 76 | vin2 := in2.(fmt.Stringer) 77 | return vin1.String() == vin2.String() 78 | default: 79 | return reflect.DeepEqual(in1, in2) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /.github/actions/setup-environment/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup environment 2 | description: Setup environment for integration tests execution 3 | inputs: 4 | ccm_version: 5 | description: 'CCM version' 6 | required: true 7 | docker_compose_version: 8 | description: 'Docker compose version' 9 | required: true 10 | java_version: 11 | description: 'java version' 12 | required: true 13 | runs: 14 | using: "composite" 15 | steps: 16 | - name: Set up cache for SDKMAN 17 | uses: actions/cache@v5 18 | with: 19 | path: ~/.sdkman 20 | key: ${{ runner.os }}-sdkman 21 | 22 | - name: Set up cache for PIP 23 | uses: actions/cache@v5 24 | with: 25 | path: ~/.cache/pip 26 | key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} 27 | restore-keys: | 28 | ${{ runner.os }}-pip- 29 | 30 | # - name: Install Java 31 | # shell: bash 32 | # run: | 33 | # echo "Installing SDKMAN..." 34 | # curl -s "https://get.sdkman.io" | bash 35 | # source "$HOME/.sdkman/bin/sdkman-init.sh" 36 | # echo "sdkman_auto_answer=true" >> ~/.sdkman/etc/config 37 | # 38 | # echo "Installing Java versions..." 39 | # sdk install java 11.0.24-zulu 40 | # sdk install java 17.0.12-zulu 41 | # 42 | # sdk default java 11.0.24-zulu 43 | # sdk use java 11.0.24-zulu 44 | # 45 | # echo "JAVA11_HOME=$JAVA_HOME_11_X64" >> $GITHUB_ENV 46 | # echo "JAVA17_HOME=$JAVA_HOME_17_X64" >> $GITHUB_ENV 47 | # echo "JAVA_HOME=$JAVA_HOME_11_X64" >> $GITHUB_ENV 48 | # echo "PATH=$PATH" >> $GITHUB_ENV 49 | - name: Install Java 50 | uses: actions/setup-java@v5 51 | with: 52 | java-version: ${{ inputs.java_version }} 53 | distribution: 'temurin' 54 | 55 | - name: Install CCM 56 | shell: bash 57 | run: | 58 | echo "Creating Python virtual environment..." 59 | VENV_DIR="$HOME/venv" 60 | python3 -m venv $VENV_DIR 61 | source $VENV_DIR/bin/activate 62 | pip install setuptools==77.0.3 63 | pip install --upgrade pip 64 | 65 | echo "Installing CCM..." 66 | pip install "git+https://github.com/scylladb/scylla-ccm.git@${{ inputs.ccm_version }}" 67 | 68 | - name: Install Docker compose 69 | shell: bash 70 | run: sudo curl -L "https://github.com/docker/compose/releases/download/${{ inputs.docker_compose_version }}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 71 | -------------------------------------------------------------------------------- /serialization/decimal/unmarshal_ints.go: -------------------------------------------------------------------------------- 1 | package decimal 2 | 3 | import ( 4 | "gopkg.in/inf.v0" 5 | ) 6 | 7 | const ( 8 | neg8 = int64(-1) << 8 9 | neg16 = int64(-1) << 16 10 | neg24 = int64(-1) << 24 11 | neg32 = int64(-1) << 32 12 | neg40 = int64(-1) << 40 13 | neg48 = int64(-1) << 48 14 | neg56 = int64(-1) << 56 15 | neg32Int = int(-1) << 32 16 | ) 17 | 18 | func decScale(p []byte) inf.Scale { 19 | return inf.Scale(p[0])<<24 | inf.Scale(p[1])<<16 | inf.Scale(p[2])<<8 | inf.Scale(p[3]) 20 | } 21 | 22 | func decScaleInt64(p []byte) int64 { 23 | if p[0] > 127 { 24 | return neg32 | int64(p[0])<<24 | int64(p[1])<<16 | int64(p[2])<<8 | int64(p[3]) 25 | } 26 | return int64(p[0])<<24 | int64(p[1])<<16 | int64(p[2])<<8 | int64(p[3]) 27 | } 28 | 29 | func dec1toInt64(p []byte) int64 { 30 | if p[4] > 127 { 31 | return neg8 | int64(p[4]) 32 | } 33 | return int64(p[4]) 34 | } 35 | 36 | func dec2toInt64(p []byte) int64 { 37 | if p[4] > 127 { 38 | return neg16 | int64(p[4])<<8 | int64(p[5]) 39 | } 40 | return int64(p[4])<<8 | int64(p[5]) 41 | } 42 | 43 | func dec3toInt64(p []byte) int64 { 44 | if p[4] > 127 { 45 | return neg24 | int64(p[4])<<16 | int64(p[5])<<8 | int64(p[6]) 46 | } 47 | return int64(p[4])<<16 | int64(p[5])<<8 | int64(p[6]) 48 | } 49 | 50 | func dec4toInt64(p []byte) int64 { 51 | if p[4] > 127 { 52 | return neg32 | int64(p[4])<<24 | int64(p[5])<<16 | int64(p[6])<<8 | int64(p[7]) 53 | } 54 | return int64(p[4])<<24 | int64(p[5])<<16 | int64(p[6])<<8 | int64(p[7]) 55 | } 56 | 57 | func dec5toInt64(p []byte) int64 { 58 | if p[4] > 127 { 59 | return neg40 | int64(p[4])<<32 | int64(p[5])<<24 | int64(p[6])<<16 | int64(p[7])<<8 | int64(p[8]) 60 | } 61 | return int64(p[4])<<32 | int64(p[5])<<24 | int64(p[6])<<16 | int64(p[7])<<8 | int64(p[8]) 62 | } 63 | 64 | func dec6toInt64(p []byte) int64 { 65 | if p[4] > 127 { 66 | return neg48 | int64(p[4])<<40 | int64(p[5])<<32 | int64(p[6])<<24 | int64(p[7])<<16 | int64(p[8])<<8 | int64(p[9]) 67 | } 68 | return int64(p[4])<<40 | int64(p[5])<<32 | int64(p[6])<<24 | int64(p[7])<<16 | int64(p[8])<<8 | int64(p[9]) 69 | } 70 | 71 | func dec7toInt64(p []byte) int64 { 72 | if p[4] > 127 { 73 | return neg56 | int64(p[4])<<48 | int64(p[5])<<40 | int64(p[6])<<32 | int64(p[7])<<24 | int64(p[8])<<16 | int64(p[9])<<8 | int64(p[10]) 74 | } 75 | return int64(p[4])<<48 | int64(p[5])<<40 | int64(p[6])<<32 | int64(p[7])<<24 | int64(p[8])<<16 | int64(p[9])<<8 | int64(p[10]) 76 | } 77 | 78 | func dec8toInt64(p []byte) int64 { 79 | return int64(p[4])<<56 | int64(p[5])<<48 | int64(p[6])<<40 | int64(p[7])<<32 | int64(p[8])<<24 | int64(p[9])<<16 | int64(p[10])<<8 | int64(p[11]) 80 | } 81 | -------------------------------------------------------------------------------- /serialization/boolean/unmarshal_utils.go: -------------------------------------------------------------------------------- 1 | package boolean 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | var errWrongDataLen = fmt.Errorf("failed to unmarshal boolean: the length of the data should be 0 or 1") 9 | 10 | func errNilReference(v interface{}) error { 11 | return fmt.Errorf("failed to unmarshal boolean: can not unmarshal into nil reference(%T)(%[1]v)", v) 12 | } 13 | 14 | func DecBool(p []byte, v *bool) error { 15 | if v == nil { 16 | return errNilReference(v) 17 | } 18 | switch len(p) { 19 | case 0: 20 | *v = false 21 | case 1: 22 | *v = decBool(p) 23 | default: 24 | return errWrongDataLen 25 | } 26 | return nil 27 | } 28 | 29 | func DecBoolR(p []byte, v **bool) error { 30 | if v == nil { 31 | return errNilReference(v) 32 | } 33 | switch len(p) { 34 | case 0: 35 | if p == nil { 36 | *v = nil 37 | } else { 38 | *v = new(bool) 39 | } 40 | case 1: 41 | val := decBool(p) 42 | *v = &val 43 | default: 44 | return errWrongDataLen 45 | } 46 | return nil 47 | } 48 | 49 | func DecReflect(p []byte, v reflect.Value) error { 50 | if v.IsNil() { 51 | return errNilReference(v) 52 | } 53 | 54 | switch v = v.Elem(); v.Kind() { 55 | case reflect.Bool: 56 | return decReflectBool(p, v) 57 | default: 58 | return fmt.Errorf("failed to unmarshal boolean: unsupported value type (%T)(%[1]v), supported types: ~bool", v.Interface()) 59 | } 60 | } 61 | 62 | func DecReflectR(p []byte, v reflect.Value) error { 63 | if v.IsNil() { 64 | return errNilReference(v) 65 | } 66 | 67 | switch v.Type().Elem().Elem().Kind() { 68 | case reflect.Bool: 69 | return decReflectBoolR(p, v) 70 | default: 71 | return fmt.Errorf("failed to unmarshal boolean: unsupported value type (%T)(%[1]v), supported types: ~bool", v.Interface()) 72 | } 73 | } 74 | 75 | func decReflectBool(p []byte, v reflect.Value) error { 76 | switch len(p) { 77 | case 0: 78 | v.SetBool(false) 79 | case 1: 80 | v.SetBool(decBool(p)) 81 | default: 82 | return errWrongDataLen 83 | } 84 | return nil 85 | } 86 | 87 | func decReflectBoolR(p []byte, v reflect.Value) error { 88 | switch len(p) { 89 | case 0: 90 | if p == nil { 91 | v.Elem().Set(reflect.Zero(v.Type().Elem())) 92 | } else { 93 | val := reflect.New(v.Type().Elem().Elem()) 94 | v.Elem().Set(val) 95 | } 96 | case 1: 97 | val := reflect.New(v.Type().Elem().Elem()) 98 | val.Elem().SetBool(decBool(p)) 99 | v.Elem().Set(val) 100 | default: 101 | return errWrongDataLen 102 | } 103 | return nil 104 | } 105 | 106 | func decBool(p []byte) bool { 107 | return p[0] != 0 108 | } 109 | -------------------------------------------------------------------------------- /session_connect_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | /* 19 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 20 | * Copyright (c) 2016, The Gocql authors, 21 | * provided under the BSD-3-Clause License. 22 | * See the NOTICE file distributed with this work for additional information. 23 | */ 24 | 25 | package gocql 26 | 27 | import ( 28 | "net" 29 | "strconv" 30 | "sync" 31 | ) 32 | 33 | type OneConnTestServer struct { 34 | Err error 35 | listener net.Listener 36 | acceptChan chan struct{} 37 | Addr net.IP 38 | Port int 39 | mu sync.Mutex 40 | closed bool 41 | } 42 | 43 | func NewOneConnTestServer() (*OneConnTestServer, error) { 44 | lstn, err := net.Listen("tcp4", "localhost:0") 45 | if err != nil { 46 | return nil, err 47 | } 48 | addr, port := parseAddressPort(lstn.Addr().String()) 49 | return &OneConnTestServer{ 50 | listener: lstn, 51 | acceptChan: make(chan struct{}), 52 | Addr: addr, 53 | Port: port, 54 | }, nil 55 | } 56 | 57 | func (c *OneConnTestServer) Accepted() chan struct{} { 58 | return c.acceptChan 59 | } 60 | 61 | func (c *OneConnTestServer) Close() { 62 | c.lockedClose() 63 | } 64 | 65 | func (c *OneConnTestServer) Serve() { 66 | conn, err := c.listener.Accept() 67 | c.Err = err 68 | if conn != nil { 69 | conn.Close() 70 | } 71 | c.lockedClose() 72 | } 73 | 74 | func (c *OneConnTestServer) lockedClose() { 75 | c.mu.Lock() 76 | defer c.mu.Unlock() 77 | if !c.closed { 78 | close(c.acceptChan) 79 | c.listener.Close() 80 | c.closed = true 81 | } 82 | } 83 | 84 | func parseAddressPort(hostPort string) (net.IP, int) { 85 | host, portStr, err := net.SplitHostPort(hostPort) 86 | if err != nil { 87 | return net.ParseIP(""), 0 88 | } 89 | port, _ := strconv.Atoi(portStr) 90 | return net.ParseIP(host), port 91 | } 92 | -------------------------------------------------------------------------------- /batch_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | // +build integration 3 | 4 | /* 5 | * Licensed to the Apache Software Foundation (ASF) under one 6 | * or more contributor license agreements. See the NOTICE file 7 | * distributed with this work for additional information 8 | * regarding copyright ownership. The ASF licenses this file 9 | * to you under the Apache License, Version 2.0 (the 10 | * "License"); you may not use this file except in compliance 11 | * with the License. You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | /* 22 | * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 23 | * Copyright (c) 2016, The Gocql authors, 24 | * provided under the BSD-3-Clause License. 25 | * See the NOTICE file distributed with this work for additional information. 26 | */ 27 | 28 | package gocql 29 | 30 | import ( 31 | "testing" 32 | "time" 33 | ) 34 | 35 | func TestBatch_Errors(t *testing.T) { 36 | session := createSession(t) 37 | defer session.Close() 38 | 39 | if err := createTable(session, `CREATE TABLE gocql_test.batch_errors (id int primary key, val inet)`); err != nil { 40 | t.Fatal(err) 41 | } 42 | 43 | b := session.Batch(LoggedBatch) 44 | b = b.Query("SELECT * FROM gocql_test.batch_errors WHERE id=2 AND val=?", nil) 45 | if err := b.Exec(); err == nil { 46 | t.Fatal("expected to get error for invalid query in batch") 47 | } 48 | } 49 | 50 | func TestBatch_WithTimestamp(t *testing.T) { 51 | session := createSession(t) 52 | defer session.Close() 53 | 54 | if err := createTable(session, `CREATE TABLE gocql_test.batch_ts (id int primary key, val text)`); err != nil { 55 | t.Fatal(err) 56 | } 57 | 58 | micros := time.Now().UnixNano()/1e3 - 1000 59 | 60 | b := session.Batch(LoggedBatch) 61 | b.WithTimestamp(micros) 62 | b = b.Query("INSERT INTO gocql_test.batch_ts (id, val) VALUES (?, ?)", 1, "val") 63 | b = b.Query("INSERT INTO gocql_test.batch_ts (id, val) VALUES (?, ?)", 2, "val") 64 | 65 | if err := b.Exec(); err != nil { 66 | t.Fatal(err) 67 | } 68 | 69 | var storedTs int64 70 | if err := session.Query(`SELECT writetime(val) FROM gocql_test.batch_ts WHERE id = ?`, 1).Scan(&storedTs); err != nil { 71 | t.Fatal(err) 72 | } 73 | 74 | if storedTs != micros { 75 | t.Errorf("got ts %d, expected %d", storedTs, micros) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /events/event_converter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package events 20 | 21 | import ( 22 | frm "github.com/gocql/gocql/internal/frame" 23 | ) 24 | 25 | // FrameToEvent converts an internal frame to a public Event interface. 26 | // This function has access to internal frame types and can perform 27 | // type-safe conversions. 28 | // Returns nil if the frame is not an event frame. 29 | func FrameToEvent(f interface{}) Event { 30 | if f == nil { 31 | return nil 32 | } 33 | 34 | switch frame := f.(type) { 35 | case *frm.TopologyChangeEventFrame: 36 | return &TopologyChangeEvent{ 37 | Change: frame.Change, 38 | Host: frame.Host, 39 | Port: frame.Port, 40 | } 41 | 42 | case *frm.StatusChangeEventFrame: 43 | return &StatusChangeEvent{ 44 | Change: frame.Change, 45 | Host: frame.Host, 46 | Port: frame.Port, 47 | } 48 | 49 | case *frm.SchemaChangeKeyspace: 50 | return &SchemaChangeKeyspaceEvent{ 51 | Change: frame.Change, 52 | Keyspace: frame.Keyspace, 53 | } 54 | 55 | case *frm.SchemaChangeTable: 56 | return &SchemaChangeTableEvent{ 57 | Change: frame.Change, 58 | Keyspace: frame.Keyspace, 59 | Table: frame.Object, 60 | } 61 | 62 | case *frm.SchemaChangeType: 63 | return &SchemaChangeTypeEvent{ 64 | Change: frame.Change, 65 | Keyspace: frame.Keyspace, 66 | TypeName: frame.Object, 67 | } 68 | 69 | case *frm.SchemaChangeFunction: 70 | return &SchemaChangeFunctionEvent{ 71 | Change: frame.Change, 72 | Keyspace: frame.Keyspace, 73 | Function: frame.Name, 74 | Arguments: frame.Args, 75 | } 76 | 77 | case *frm.SchemaChangeAggregate: 78 | return &SchemaChangeAggregateEvent{ 79 | Change: frame.Change, 80 | Keyspace: frame.Keyspace, 81 | Aggregate: frame.Name, 82 | Arguments: frame.Args, 83 | } 84 | 85 | default: 86 | return nil 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /.github/workflows/docs-pages.yml: -------------------------------------------------------------------------------- 1 | name: "Docs / Publish" 2 | # For more information, 3 | # see https://sphinx-theme.scylladb.com/stable/deployment/production.html#available-workflows 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | - 'branch-**' 10 | paths: 11 | - "docs/**" 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v6 20 | with: 21 | ref: ${{ github.event.repository.default_branch }} 22 | persist-credentials: false 23 | fetch-depth: 0 24 | 25 | - uses: actions/cache@v5 26 | # actions/setup-python@v6 poetry cache feature requires poetry to be installed beforehand 27 | # which makes use of it extremely awkward. 28 | with: 29 | path: | 30 | /home/runner/.cache/pip 31 | /home/runner/.cache/pypoetry 32 | # python and poetry version are in docs/pyproject.toml 33 | key: docs-cache-${{ runner.os }}-${{ hashFiles('docs/pyproject.toml', 'docs/Makefile') }} 34 | 35 | - name: Set up Python 36 | uses: actions/setup-python@v6 37 | with: 38 | python-version-file: docs/pyproject.toml 39 | 40 | - name: Set up env 41 | run: make -C docs setupenv 42 | 43 | - name: Build docs 44 | run: make -C docs multiversion 45 | 46 | - name: Build redirects 47 | run: make -C docs redirects 48 | 49 | - name: Tar folder 50 | run: | 51 | tar \ 52 | --dereference --hard-dereference \ 53 | --directory docs/_build/dirhtml/ \ 54 | -cvf ${{ runner.temp }}/artifact.tar \ 55 | . 56 | 57 | - name: Upload artifact 58 | uses: actions/upload-artifact@v6 59 | with: 60 | name: github-pages 61 | path: ${{ runner.temp }}/artifact.tar 62 | retention-days: "1" 63 | 64 | release: 65 | # Add a dependency to the build job 66 | needs: build 67 | 68 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 69 | permissions: 70 | pages: write # to deploy to Pages 71 | id-token: write # to verify the deployment originates from an appropriate source 72 | contents: read # to read private repo 73 | 74 | # Deploy to the github-pages environment 75 | environment: 76 | name: github-pages 77 | url: ${{ steps.deployment.outputs.page_url }} 78 | 79 | # Specify runner + deployment step 80 | runs-on: ubuntu-latest 81 | steps: 82 | - name: Deploy to GitHub Pages 83 | id: deployment 84 | uses: actions/deploy-pages@v4 85 | --------------------------------------------------------------------------------