From e94126a7a5e21094863c2eddfcc1510fbd32043a Mon Sep 17 00:00:00 2001 From: Jan Ciolek Date: Fri, 13 Oct 2023 18:24:47 +0200 Subject: [PATCH 1/6] workspace: set resolver = 2 in the root Cargo.toml manifest Running `cargo check` using `rust 1.73` prints the following warning message: ``` warning: some crates are on edition 2021 which defaults to `resolver = "2"`, but virtual workspaces default to `resolver = "1"` note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest Finished dev [unoptimized + debuginfo] target(s) in 0.05s ``` Documentation about resolver versions can be found here: https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions Let's use the newer resolver in the whole workspace. The newer resolver is the default that Rust uses since edition 2021. It also gets rid of the annoying warning. Signed-off-by: Jan Ciolek --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index fb4fe384f7..c022995c84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ members = [ "scylla-cql", "scylla-proxy", ] +resolver = "2" From 792c235b678e7febe45ba0fa114621a73d68b647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20B=C3=B8ving?= Date: Mon, 16 Oct 2023 11:31:56 +0200 Subject: [PATCH 2/6] Dereference `datacenter` of type `&&str` when comparing with `&str` --- scylla/src/transport/locator/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scylla/src/transport/locator/mod.rs b/scylla/src/transport/locator/mod.rs index db55b9fe69..4ff44891d1 100644 --- a/scylla/src/transport/locator/mod.rs +++ b/scylla/src/transport/locator/mod.rs @@ -275,7 +275,7 @@ impl<'a> ReplicaSet<'a> { datacenter, } => replicas .iter() - .filter(|node| node.datacenter.as_deref() == Some(datacenter)) + .filter(|node| node.datacenter.as_deref() == Some(*datacenter)) .count(), ReplicaSetInner::ChainedNTS { datacenter_repfactors, @@ -317,7 +317,7 @@ impl<'a> ReplicaSet<'a> { datacenter, } => replicas .iter() - .filter(|node| node.datacenter.as_deref() == Some(datacenter)) + .filter(|node| node.datacenter.as_deref() == Some(*datacenter)) .nth(index), ReplicaSetInner::ChainedNTS { datacenter_repfactors, @@ -466,7 +466,7 @@ impl<'a> Iterator for ReplicaSetIterator<'a> { } => { while let Some(replica) = replicas.get(*idx) { *idx += 1; - if replica.datacenter.as_deref() == Some(datacenter) { + if replica.datacenter.as_deref() == Some(*datacenter) { return Some(replica); } } From cbbab90575e64d485fa8d24ea48ca26a4e7b55c0 Mon Sep 17 00:00:00 2001 From: Jan Ciolek Date: Mon, 16 Oct 2023 20:16:09 +0200 Subject: [PATCH 3/6] examples/execution_profile: fix usage of illegal consistency The example in `execution_profile.rs` tried to send a read request using consistency `EACH_QUORUM`. This doesn't work, the query failed with the following message: ``` Error: Database returned an error: The query is syntactically correct but invalid, Error message: EACH_QUORUM ConsistencyLevel is only supported for writes ``` Examples shouldn't fail. Let's fix it by changing `EachQuorum` to `LocalQuorum` which can be used in SELECTs. After this change the example doesn't fail. It still demonstrates how to create an execution profile with a custom consistency level, it doesn't matter what consistency level is used. Fixes: https://github.com/scylladb/scylla-rust-driver/issues/835 Signed-off-by: Jan Ciolek --- examples/execution_profile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/execution_profile.rs b/examples/execution_profile.rs index d8d1b1eed9..13bb44e0e6 100644 --- a/examples/execution_profile.rs +++ b/examples/execution_profile.rs @@ -18,7 +18,7 @@ async fn main() -> Result<()> { println!("Connecting to {} ...", uri); let profile1 = ExecutionProfile::builder() - .consistency(Consistency::EachQuorum) + .consistency(Consistency::LocalQuorum) .serial_consistency(Some(SerialConsistency::Serial)) .request_timeout(Some(Duration::from_secs(42))) .load_balancing_policy(Arc::new(load_balancing::DefaultPolicy::default())) From 82c1c99f0ff86509f9dd1e649ecdaddc5a3660cf Mon Sep 17 00:00:00 2001 From: Samuel Orji Date: Tue, 17 Oct 2023 15:55:39 +0100 Subject: [PATCH 4/6] Fix/batch length (#824) * changed the type of the maximum number of statements in a batch query from an i16 to a u16 according to the CQL protocol spec * add a guard when doing batch statements to prevent making calls to the server when the number of batch queries is greater than u16::MAX, as well as adding some tests --- .github/workflows/cassandra.yml | 2 +- scylla-cql/src/errors.rs | 4 ++ scylla-cql/src/frame/frame_errors.rs | 2 +- scylla-cql/src/frame/request/batch.rs | 2 +- scylla-cql/src/frame/response/result.rs | 4 +- scylla-cql/src/frame/types.rs | 20 +++--- scylla-cql/src/frame/value.rs | 12 ++-- scylla/src/statement/prepared_statement.rs | 2 +- .../transport/large_batch_statements_test.rs | 68 +++++++++++++++++++ scylla/src/transport/mod.rs | 2 + scylla/src/transport/session.rs | 8 +++ 11 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 scylla/src/transport/large_batch_statements_test.rs diff --git a/.github/workflows/cassandra.yml b/.github/workflows/cassandra.yml index 5cc118f1f4..e22b915d46 100644 --- a/.github/workflows/cassandra.yml +++ b/.github/workflows/cassandra.yml @@ -29,7 +29,7 @@ jobs: run: cargo build --verbose --tests - name: Run tests on cassandra run: | - CDC='disabled' SCYLLA_URI=172.42.0.2:9042 SCYLLA_URI2=172.42.0.3:9042 SCYLLA_URI3=172.42.0.4:9042 cargo test --verbose -- --skip test_views_in_schema_info + CDC='disabled' SCYLLA_URI=172.42.0.2:9042 SCYLLA_URI2=172.42.0.3:9042 SCYLLA_URI3=172.42.0.4:9042 cargo test --verbose -- --skip test_views_in_schema_info --skip test_large_batch_statements - name: Stop the cluster if: ${{ always() }} run: docker compose -f test/cluster/cassandra/docker-compose.yml stop diff --git a/scylla-cql/src/errors.rs b/scylla-cql/src/errors.rs index 40587cfef6..9e80247e20 100644 --- a/scylla-cql/src/errors.rs +++ b/scylla-cql/src/errors.rs @@ -348,6 +348,10 @@ pub enum BadQuery { #[error("Passed invalid keyspace name to use: {0}")] BadKeyspaceName(#[from] BadKeyspaceName), + /// Too many queries in the batch statement + #[error("Number of Queries in Batch Statement supplied is {0} which has exceeded the max value of 65,535")] + TooManyQueriesInBatchStatement(usize), + /// Other reasons of bad query #[error("{0}")] Other(String), diff --git a/scylla-cql/src/frame/frame_errors.rs b/scylla-cql/src/frame/frame_errors.rs index 403b6ab5fd..3da4e26d01 100644 --- a/scylla-cql/src/frame/frame_errors.rs +++ b/scylla-cql/src/frame/frame_errors.rs @@ -40,7 +40,7 @@ pub enum ParseError { #[error(transparent)] IoError(#[from] std::io::Error), #[error("type not yet implemented, id: {0}")] - TypeNotImplemented(i16), + TypeNotImplemented(u16), #[error(transparent)] SerializeValuesError(#[from] SerializeValuesError), #[error(transparent)] diff --git a/scylla-cql/src/frame/request/batch.rs b/scylla-cql/src/frame/request/batch.rs index 3c0bad3931..35dd8c3c3b 100644 --- a/scylla-cql/src/frame/request/batch.rs +++ b/scylla-cql/src/frame/request/batch.rs @@ -190,7 +190,7 @@ impl<'b> DeserializableRequest for Batch<'b, BatchStatement<'b>, Vec Result { let batch_type = buf.get_u8().try_into()?; - let statements_count: usize = types::read_short(buf)?.try_into()?; + let statements_count: usize = types::read_short(buf)?.into(); let statements_with_values = (0..statements_count) .map(|_| { let batch_statement = BatchStatement::deserialize(buf)?; diff --git a/scylla-cql/src/frame/response/result.rs b/scylla-cql/src/frame/response/result.rs index 288baf91eb..5ade677343 100644 --- a/scylla-cql/src/frame/response/result.rs +++ b/scylla-cql/src/frame/response/result.rs @@ -437,7 +437,7 @@ fn deser_type(buf: &mut &[u8]) -> StdResult { 0x0030 => { let keyspace_name: String = types::read_string(buf)?.to_string(); let type_name: String = types::read_string(buf)?.to_string(); - let fields_size: usize = types::read_short(buf)?.try_into()?; + let fields_size: usize = types::read_short(buf)?.into(); let mut field_types: Vec<(String, ColumnType)> = Vec::with_capacity(fields_size); @@ -455,7 +455,7 @@ fn deser_type(buf: &mut &[u8]) -> StdResult { } } 0x0031 => { - let len: usize = types::read_short(buf)?.try_into()?; + let len: usize = types::read_short(buf)?.into(); let mut types = Vec::with_capacity(len); for _ in 0..len { types.push(deser_type(buf)?); diff --git a/scylla-cql/src/frame/types.rs b/scylla-cql/src/frame/types.rs index fd2254c8b0..672fe2f97e 100644 --- a/scylla-cql/src/frame/types.rs +++ b/scylla-cql/src/frame/types.rs @@ -16,7 +16,7 @@ use uuid::Uuid; #[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, TryFromPrimitive)] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))] -#[repr(i16)] +#[repr(u16)] pub enum Consistency { Any = 0x0000, One = 0x0001, @@ -169,30 +169,30 @@ fn type_long() { } } -pub fn read_short(buf: &mut &[u8]) -> Result { - let v = buf.read_i16::()?; +pub fn read_short(buf: &mut &[u8]) -> Result { + let v = buf.read_u16::()?; Ok(v) } -pub fn write_short(v: i16, buf: &mut impl BufMut) { - buf.put_i16(v); +pub fn write_short(v: u16, buf: &mut impl BufMut) { + buf.put_u16(v); } pub(crate) fn read_short_length(buf: &mut &[u8]) -> Result { let v = read_short(buf)?; - let v: usize = v.try_into()?; + let v: usize = v.into(); Ok(v) } fn write_short_length(v: usize, buf: &mut impl BufMut) -> Result<(), ParseError> { - let v: i16 = v.try_into()?; + let v: u16 = v.try_into()?; write_short(v, buf); Ok(()) } #[test] fn type_short() { - let vals = [i16::MIN, -1, 0, 1, i16::MAX]; + let vals: [u16; 3] = [0, 1, u16::MAX]; for val in vals.iter() { let mut buf = Vec::new(); write_short(*val, &mut buf); @@ -464,11 +464,11 @@ pub fn read_consistency(buf: &mut &[u8]) -> Result { } pub fn write_consistency(c: Consistency, buf: &mut impl BufMut) { - write_short(c as i16, buf); + write_short(c as u16, buf); } pub fn write_serial_consistency(c: SerialConsistency, buf: &mut impl BufMut) { - write_short(c as i16, buf); + write_short(c as u16, buf); } #[test] diff --git a/scylla-cql/src/frame/value.rs b/scylla-cql/src/frame/value.rs index e9164f2531..17b75ea855 100644 --- a/scylla-cql/src/frame/value.rs +++ b/scylla-cql/src/frame/value.rs @@ -63,7 +63,7 @@ pub struct Time(pub Duration); #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct SerializedValues { serialized_values: Vec, - values_num: i16, + values_num: u16, contains_names: bool, } @@ -77,7 +77,7 @@ pub struct CqlDuration { #[derive(Debug, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum SerializeValuesError { - #[error("Too many values to add, max 32 767 values can be sent in a request")] + #[error("Too many values to add, max 65,535 values can be sent in a request")] TooManyValues, #[error("Mixing named and not named values is not allowed")] MixingNamedAndNotNamedValues, @@ -134,7 +134,7 @@ impl SerializedValues { if self.contains_names { return Err(SerializeValuesError::MixingNamedAndNotNamedValues); } - if self.values_num == i16::MAX { + if self.values_num == u16::MAX { return Err(SerializeValuesError::TooManyValues); } @@ -158,7 +158,7 @@ impl SerializedValues { return Err(SerializeValuesError::MixingNamedAndNotNamedValues); } self.contains_names = true; - if self.values_num == i16::MAX { + if self.values_num == u16::MAX { return Err(SerializeValuesError::TooManyValues); } @@ -184,7 +184,7 @@ impl SerializedValues { } pub fn write_to_request(&self, buf: &mut impl BufMut) { - buf.put_i16(self.values_num); + buf.put_u16(self.values_num); buf.put(&self.serialized_values[..]); } @@ -192,7 +192,7 @@ impl SerializedValues { self.values_num == 0 } - pub fn len(&self) -> i16 { + pub fn len(&self) -> u16 { self.values_num } diff --git a/scylla/src/statement/prepared_statement.rs b/scylla/src/statement/prepared_statement.rs index b57d5d4b23..9814e7350d 100644 --- a/scylla/src/statement/prepared_statement.rs +++ b/scylla/src/statement/prepared_statement.rs @@ -339,7 +339,7 @@ impl PreparedStatement { #[derive(Clone, Debug, Error, PartialEq, Eq, PartialOrd, Ord)] pub enum PartitionKeyExtractionError { #[error("No value with given pk_index! pk_index: {0}, values.len(): {1}")] - NoPkIndexValue(u16, i16), + NoPkIndexValue(u16, u16), } #[derive(Clone, Debug, Error, PartialEq, Eq, PartialOrd, Ord)] diff --git a/scylla/src/transport/large_batch_statements_test.rs b/scylla/src/transport/large_batch_statements_test.rs new file mode 100644 index 0000000000..29482e31ce --- /dev/null +++ b/scylla/src/transport/large_batch_statements_test.rs @@ -0,0 +1,68 @@ +use assert_matches::assert_matches; + +use scylla_cql::errors::{BadQuery, QueryError}; + +use crate::batch::BatchType; +use crate::query::Query; +use crate::{ + batch::Batch, + test_utils::{create_new_session_builder, unique_keyspace_name}, + QueryResult, Session, +}; + +#[tokio::test] +async fn test_large_batch_statements() { + let mut session = create_new_session_builder().build().await.unwrap(); + + let ks = unique_keyspace_name(); + session = create_test_session(session, &ks).await; + + let max_queries = u16::MAX as usize; + let batch_insert_result = write_batch(&session, max_queries, &ks).await; + + batch_insert_result.unwrap(); + + let too_many_queries = u16::MAX as usize + 1; + let batch_insert_result = write_batch(&session, too_many_queries, &ks).await; + assert_matches!( + batch_insert_result.unwrap_err(), + QueryError::BadQuery(BadQuery::TooManyQueriesInBatchStatement(_too_many_queries)) if _too_many_queries == too_many_queries + ) +} + +async fn create_test_session(session: Session, ks: &String) -> Session { + session + .query( + format!("CREATE KEYSPACE {} WITH REPLICATION = {{ 'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1 }}",ks), + &[], + ) + .await.unwrap(); + session + .query( + format!( + "CREATE TABLE {}.pairs (dummy int, k blob, v blob, primary key (dummy, k))", + ks + ), + &[], + ) + .await + .unwrap(); + session +} + +async fn write_batch(session: &Session, n: usize, ks: &String) -> Result { + let mut batch_query = Batch::new(BatchType::Unlogged); + let mut batch_values = Vec::new(); + let query = format!("INSERT INTO {}.pairs (dummy, k, v) VALUES (0, ?, ?)", ks); + let query = Query::new(query); + let prepared_statement = session.prepare(query).await.unwrap(); + for i in 0..n { + let mut key = vec![0]; + key.extend(i.to_be_bytes().as_slice()); + let value = key.clone(); + let values = vec![key, value]; + batch_values.push(values); + batch_query.append_statement(prepared_statement.clone()); + } + session.batch(&batch_query, batch_values).await +} diff --git a/scylla/src/transport/mod.rs b/scylla/src/transport/mod.rs index 939983cfc4..a33943645d 100644 --- a/scylla/src/transport/mod.rs +++ b/scylla/src/transport/mod.rs @@ -35,6 +35,8 @@ mod silent_prepare_batch_test; mod cql_types_test; #[cfg(test)] mod cql_value_test; +#[cfg(test)] +mod large_batch_statements_test; pub use cluster::ClusterData; pub use node::{KnownNode, Node, NodeAddr, NodeRef}; diff --git a/scylla/src/transport/session.rs b/scylla/src/transport/session.rs index 35ff25475f..2f67874f8c 100644 --- a/scylla/src/transport/session.rs +++ b/scylla/src/transport/session.rs @@ -76,6 +76,7 @@ pub use crate::transport::connection_pool::PoolSize; use crate::authentication::AuthenticatorProvider; #[cfg(feature = "ssl")] use openssl::ssl::SslContext; +use scylla_cql::errors::BadQuery; /// Translates IP addresses received from ScyllaDB nodes into locally reachable addresses. /// @@ -1143,6 +1144,13 @@ impl Session { // Shard-awareness behavior for batch will be to pick shard based on first batch statement's shard // If users batch statements by shard, they will be rewarded with full shard awareness + // check to ensure that we don't send a batch statement with more than u16::MAX queries + let batch_statements_length = batch.statements.len(); + if batch_statements_length > u16::MAX as usize { + return Err(QueryError::BadQuery( + BadQuery::TooManyQueriesInBatchStatement(batch_statements_length), + )); + } // Extract first serialized_value let first_serialized_value = values.batch_values_iter().next_serialized().transpose()?; let first_serialized_value = first_serialized_value.as_deref(); From e1dcf51d7009ff1448baabf11f62de792278f0f1 Mon Sep 17 00:00:00 2001 From: Nick Sippl-Swezey Date: Wed, 18 Oct 2023 16:13:11 -0700 Subject: [PATCH 5/6] fixes doc linting error: redundant explicit link target error: redundant explicit link target --> scylla/src/lib.rs:16:55 | 16 | //! All driver activity revolves around the [Session](crate::Session)\ | ------- ^^^^^^^^^^^^^^ explicit target is redundant | | | because label contains path that resolves to same destination | = note: when a link's destination is not specified, the label is used to resolve intra-doc links = note: `-D rustdoc::redundant-explicit-links` implied by `-D warnings` help: remove explicit link target fixes: https://github.com/scylladb/scylla-rust-driver/issues/847 --- scylla/src/lib.rs | 4 ++-- scylla/src/statement/batch.rs | 2 +- scylla/src/statement/prepared_statement.rs | 2 +- scylla/src/statement/query.rs | 2 +- scylla/src/transport/host_filter.rs | 2 +- scylla/src/transport/session.rs | 14 +++++++------- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/scylla/src/lib.rs b/scylla/src/lib.rs index b1c8770eb0..27a3c57471 100644 --- a/scylla/src/lib.rs +++ b/scylla/src/lib.rs @@ -13,7 +13,7 @@ //! //! # Driver overview //! ### Connecting -//! All driver activity revolves around the [Session](crate::Session)\ +//! All driver activity revolves around the [Session]\ //! `Session` is created by specifying a few known nodes and connecting to them: //! //! ```rust,no_run @@ -31,7 +31,7 @@ //! Ok(()) //! } //! ``` -//! `Session` is usually created using the [SessionBuilder](crate::SessionBuilder).\ +//! `Session` is usually created using the [SessionBuilder].\ //! All configuration options for a `Session` can be specified while building. //! //! ### Making queries diff --git a/scylla/src/statement/batch.rs b/scylla/src/statement/batch.rs index 58d8ce411b..6805dcb275 100644 --- a/scylla/src/statement/batch.rs +++ b/scylla/src/statement/batch.rs @@ -76,7 +76,7 @@ impl Batch { /// A query is idempotent if it can be applied multiple times without changing the result of the initial application /// If set to `true` we can be sure that it is idempotent /// If set to `false` it is unknown whether it is idempotent - /// This is used in [`RetryPolicy`](crate::retry_policy::RetryPolicy) to decide if retrying a query is safe + /// This is used in [`RetryPolicy`] to decide if retrying a query is safe pub fn set_is_idempotent(&mut self, is_idempotent: bool) { self.config.is_idempotent = is_idempotent; } diff --git a/scylla/src/statement/prepared_statement.rs b/scylla/src/statement/prepared_statement.rs index 9814e7350d..22f34e60a2 100644 --- a/scylla/src/statement/prepared_statement.rs +++ b/scylla/src/statement/prepared_statement.rs @@ -239,7 +239,7 @@ impl PreparedStatement { /// A query is idempotent if it can be applied multiple times without changing the result of the initial application /// If set to `true` we can be sure that it is idempotent /// If set to `false` it is unknown whether it is idempotent - /// This is used in [`RetryPolicy`](crate::retry_policy::RetryPolicy) to decide if retrying a query is safe + /// This is used in [`RetryPolicy`] to decide if retrying a query is safe pub fn set_is_idempotent(&mut self, is_idempotent: bool) { self.config.is_idempotent = is_idempotent; } diff --git a/scylla/src/statement/query.rs b/scylla/src/statement/query.rs index 956b645833..913aebd1d7 100644 --- a/scylla/src/statement/query.rs +++ b/scylla/src/statement/query.rs @@ -76,7 +76,7 @@ impl Query { /// A query is idempotent if it can be applied multiple times without changing the result of the initial application /// If set to `true` we can be sure that it is idempotent /// If set to `false` it is unknown whether it is idempotent - /// This is used in [`RetryPolicy`](crate::retry_policy::RetryPolicy) to decide if retrying a query is safe + /// This is used in [`RetryPolicy`] to decide if retrying a query is safe pub fn set_is_idempotent(&mut self, is_idempotent: bool) { self.config.is_idempotent = is_idempotent; } diff --git a/scylla/src/transport/host_filter.rs b/scylla/src/transport/host_filter.rs index d59f90a49a..2838f1733c 100644 --- a/scylla/src/transport/host_filter.rs +++ b/scylla/src/transport/host_filter.rs @@ -1,7 +1,7 @@ //! Host filters. //! //! Host filters are essentially just a predicate over -//! [`Peer`](crate::transport::topology::Peer)s. Currently, they are used +//! [`Peer`]s. Currently, they are used //! by the [`Session`](crate::transport::session::Session) to determine whether //! connections should be opened to a given node or not. diff --git a/scylla/src/transport/session.rs b/scylla/src/transport/session.rs index 2f67874f8c..24cc481c93 100644 --- a/scylla/src/transport/session.rs +++ b/scylla/src/transport/session.rs @@ -561,7 +561,7 @@ impl Session { /// /// See [the book](https://rust-driver.docs.scylladb.com/stable/queries/simple.html) for more information /// # Arguments - /// * `query` - query to perform, can be just a `&str` or the [Query](crate::query::Query) struct. + /// * `query` - query to perform, can be just a `&str` or the [Query] struct. /// * `values` - values bound to the query, easiest way is to use a tuple of bound values /// /// # Examples @@ -732,12 +732,12 @@ impl Session { /// This method will query all pages of the result\ /// /// Returns an async iterator (stream) over all received rows\ - /// Page size can be specified in the [Query](crate::query::Query) passed to the function + /// Page size can be specified in the [Query] passed to the function /// /// See [the book](https://rust-driver.docs.scylladb.com/stable/queries/paged.html) for more information /// /// # Arguments - /// * `query` - query to perform, can be just a `&str` or the [Query](crate::query::Query) struct. + /// * `query` - query to perform, can be just a `&str` or the [Query] struct. /// * `values` - values bound to the query, easiest way is to use a tuple of bound values /// /// # Example @@ -799,7 +799,7 @@ impl Session { /// See [the book](https://rust-driver.docs.scylladb.com/stable/queries/prepared.html) for more information /// /// # Arguments - /// * `query` - query to prepare, can be just a `&str` or the [Query](crate::query::Query) struct. + /// * `query` - query to prepare, can be just a `&str` or the [Query] struct. /// /// # Example /// ```rust @@ -876,7 +876,7 @@ impl Session { .as_deref() } - /// Execute a prepared query. Requires a [PreparedStatement](crate::prepared_statement::PreparedStatement) + /// Execute a prepared query. Requires a [PreparedStatement] /// generated using [`Session::prepare`](Session::prepare)\ /// Returns only a single page of results, to receive multiple pages use [execute_iter](Session::execute_iter) /// @@ -1036,7 +1036,7 @@ impl Session { /// This method will query all pages of the result\ /// /// Returns an async iterator (stream) over all received rows\ - /// Page size can be specified in the [PreparedStatement](crate::prepared_statement::PreparedStatement) + /// Page size can be specified in the [PreparedStatement] /// passed to the function /// /// See [the book](https://rust-driver.docs.scylladb.com/stable/queries/paged.html) for more information @@ -1105,7 +1105,7 @@ impl Session { /// See [the book](https://rust-driver.docs.scylladb.com/stable/queries/batch.html) for more information /// /// # Arguments - /// * `batch` - [Batch](crate::batch::Batch) to be performed + /// * `batch` - [Batch] to be performed /// * `values` - List of values for each query, it's the easiest to use a tuple of tuples /// /// # Example From e77713f54a4a99c48f8197495cebbfada9ed9fba Mon Sep 17 00:00:00 2001 From: sylwiaszunejko Date: Thu, 19 Oct 2023 09:36:01 +0200 Subject: [PATCH 6/6] examples: update UDT parsing example to be in line with docs --- examples/user-defined-type.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/user-defined-type.rs b/examples/user-defined-type.rs index d42429c65e..53465b2f10 100644 --- a/examples/user-defined-type.rs +++ b/examples/user-defined-type.rs @@ -48,8 +48,8 @@ async fn main() -> Result<()> { // And read like any normal value if let Some(rows) = session.query("SELECT my FROM ks.udt_tab", &[]).await?.rows { for row in rows.into_typed::<(MyType,)>() { - let (my_val,) = row?; - println!("{:?}", my_val) + let (my_type_value,): (MyType,) = row?; + println!("{:?}", my_type_value) } }