Skip to content

Commit dd05ce4

Browse files
authored
Merge pull request #1445 from Lorak-mmk/prepared-mutable-metadata
Mutable metadata in PreparedStatement
2 parents 3b845f3 + 5a86028 commit dd05ce4

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

scylla/src/network/connection.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -930,14 +930,14 @@ impl Connection {
930930

931931
let cached_metadata = prepared_statement
932932
.get_use_cached_result_metadata()
933-
.then(|| prepared_statement.get_result_metadata());
933+
.then(|| prepared_statement.get_current_result_metadata());
934934

935935
let query_response = self
936936
.send_request(
937937
&execute_frame,
938938
true,
939939
prepared_statement.config.tracing,
940-
cached_metadata,
940+
cached_metadata.as_ref(),
941941
)
942942
.await?;
943943

@@ -967,7 +967,7 @@ impl Connection {
967967
&execute_frame,
968968
true,
969969
prepared_statement.config.tracing,
970-
cached_metadata,
970+
cached_metadata.as_ref(),
971971
)
972972
.await?;
973973

scylla/src/statement/prepared.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Defines the [`PreparedStatement`] type, which represents a statement
22
//! that has been prepared in advance on the server.
33
4+
use arc_swap::{ArcSwap, Guard};
45
use bytes::{Bytes, BytesMut};
56
use scylla_cql::frame::response::result::{
67
ColumnSpec, PartitionKeyIndex, ResultMetadata, TableSpec,
@@ -187,6 +188,7 @@ struct PreparedStatementSharedData {
187188
id: Bytes,
188189
metadata: PreparedMetadata,
189190
initial_result_metadata: Arc<ResultMetadata<'static>>,
191+
current_result_metadata: ArcSwap<ResultMetadata<'static>>,
190192
statement: String,
191193
is_confirmed_lwt: bool,
192194
}
@@ -203,6 +205,18 @@ impl Clone for PreparedStatement {
203205
}
204206
}
205207

208+
/// Stores a snapshot of current result metadata column specs.
209+
pub struct ColumnSpecsGuard {
210+
result: Guard<Arc<ResultMetadata<'static>>>,
211+
}
212+
213+
impl ColumnSpecsGuard {
214+
/// Retrieves current result metadata column specs.
215+
pub fn get(&self) -> ColumnSpecs<'_, 'static> {
216+
ColumnSpecs::new(self.result.col_specs())
217+
}
218+
}
219+
206220
impl PreparedStatement {
207221
fn new(
208222
id: Bytes,
@@ -217,7 +231,8 @@ impl PreparedStatement {
217231
shared: Arc::new(PreparedStatementSharedData {
218232
id,
219233
metadata,
220-
initial_result_metadata: result_metadata,
234+
initial_result_metadata: Arc::clone(&result_metadata),
235+
current_result_metadata: ArcSwap::from(result_metadata),
221236
statement,
222237
is_confirmed_lwt: is_lwt,
223238
}),
@@ -507,15 +522,42 @@ impl PreparedStatement {
507522
}
508523

509524
/// Access metadata about the result of prepared statement returned by the database
510-
pub(crate) fn get_result_metadata(&self) -> &Arc<ResultMetadata<'static>> {
511-
&self.shared.initial_result_metadata
525+
pub(crate) fn get_current_result_metadata(&self) -> Arc<ResultMetadata<'static>> {
526+
self.shared.current_result_metadata.load_full()
512527
}
513528

514-
/// Access column specifications of the result set returned after the execution of this statement
529+
/// Update metadata about the result of prepared statement.
530+
// Will be used when we implement support for metadata id extension.
531+
#[allow(dead_code)]
532+
pub(crate) fn update_current_result_metadata(
533+
&self,
534+
new_metadata: Arc<ResultMetadata<'static>>,
535+
) {
536+
self.shared.current_result_metadata.store(new_metadata);
537+
}
538+
539+
/// Access column specifications of the result set returned after the preparation of this statement
540+
///
541+
/// In 1.4.0, result metadata became mutable to allow us to update it when server
542+
/// sends a new one (which happens in CQLv5, or CQLv4 with Scylla's metadata id extension). This method can't
543+
/// be changed to support it because of Copy bound on ColumnSpecs. This method now uses metadata initially sent
544+
/// by the server, which may be different than the one currently used. Please use get_current_result_set_col_specs instead."
545+
// TODO(2.0): Remove this
546+
#[deprecated(
547+
since = "1.4.0",
548+
note = "This method may return outdated metadata. Use get_current_result_set_col_specs() instead."
549+
)]
515550
pub fn get_result_set_col_specs(&self) -> ColumnSpecs<'_, 'static> {
516551
ColumnSpecs::new(self.shared.initial_result_metadata.col_specs())
517552
}
518553

554+
/// Access column specifications of the result set returned after the execution of this statement
555+
pub fn get_current_result_set_col_specs(&self) -> ColumnSpecsGuard {
556+
ColumnSpecsGuard {
557+
result: self.shared.current_result_metadata.load(),
558+
}
559+
}
560+
519561
/// Get the name of the partitioner used for this statement.
520562
pub fn get_partitioner_name(&self) -> &PartitionerName {
521563
&self.partitioner_name

scylla/tests/integration/statements/prepared.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,8 @@ async fn test_prepared_statement_col_specs() {
474474
];
475475
assert_eq!(variable_col_specs, expected_variable_col_specs);
476476

477-
let result_set_col_specs = prepared.get_result_set_col_specs().as_slice();
477+
let col_specs_guard = prepared.get_current_result_set_col_specs();
478+
let result_set_col_specs = col_specs_guard.get().as_slice();
478479
let expected_result_set_col_specs = &[
479480
spec("k1", ColumnType::Native(NativeType::Int)),
480481
spec("k2", ColumnType::Native(NativeType::Varint)),

0 commit comments

Comments
 (0)