|
1 | 1 | use crate::utils::{ |
2 | | - DeserializeOwnedValue, PerformDDL, create_new_session_builder, setup_tracing, |
3 | | - unique_keyspace_name, |
| 2 | + DeserializeOwnedValue, PerformDDL, SerializeValueWithFakeType, create_new_session_builder, |
| 3 | + setup_tracing, unique_keyspace_name, |
4 | 4 | }; |
5 | 5 | use scylla::cluster::metadata::NativeType; |
6 | 6 | use scylla::deserialize::value::DeserializeValue; |
@@ -254,6 +254,95 @@ async fn test_cql_tuple() { |
254 | 254 | .unwrap(); |
255 | 255 | } |
256 | 256 |
|
| 257 | +// Cassandra does not support altering column types starting with version 3.0.11 and 3.10. |
| 258 | +// See https://stackoverflow.com/a/76926622 for explanation. |
| 259 | +#[cfg_attr(cassandra_tests, ignore)] |
| 260 | +#[tokio::test] |
| 261 | +async fn test_alter_column_add_field_to_tuple() { |
| 262 | + setup_tracing(); |
| 263 | + let session: Session = connect().await; |
| 264 | + |
| 265 | + let table_name: &str = "test_cql_tuple_alter_tab"; |
| 266 | + create_table(&session, table_name, "tuple<int, int>").await; |
| 267 | + |
| 268 | + let tuple1: (i32, i32) = (1, 2); |
| 269 | + session |
| 270 | + .query_unpaged( |
| 271 | + format!("INSERT INTO {table_name} (p, val) VALUES (0, ?)"), |
| 272 | + &(tuple1,), |
| 273 | + ) |
| 274 | + .await |
| 275 | + .unwrap(); |
| 276 | + |
| 277 | + // Add a field to the tuple. Existing rows will still have 2 fields in the tuple. |
| 278 | + session |
| 279 | + .query_unpaged( |
| 280 | + format!("ALTER TABLE {table_name} ALTER val TYPE tuple<int, int, text>"), |
| 281 | + &(), |
| 282 | + ) |
| 283 | + .await |
| 284 | + .unwrap(); |
| 285 | + |
| 286 | + // Select a tuple - ScyllaDB will send 2-element tuple. |
| 287 | + // Driver should return the third element as null. |
| 288 | + let selected_value: (Option<i32>, Option<i32>, Option<String>) = session |
| 289 | + .query_unpaged(format!("SELECT val FROM {table_name} WHERE p = 0"), ()) |
| 290 | + .await |
| 291 | + .unwrap() |
| 292 | + .into_rows_result() |
| 293 | + .unwrap() |
| 294 | + .single_row::<((Option<i32>, Option<i32>, Option<String>),)>() |
| 295 | + .unwrap() |
| 296 | + .0; |
| 297 | + |
| 298 | + assert!(selected_value.2.is_none()); |
| 299 | + |
| 300 | + session |
| 301 | + .ddl(format!("DROP KEYSPACE {}", session.get_keyspace().unwrap())) |
| 302 | + .await |
| 303 | + .unwrap(); |
| 304 | +} |
| 305 | + |
| 306 | +#[tokio::test] |
| 307 | +async fn test_cql_tuple_db_repr_shorter_than_metadata() { |
| 308 | + use ColumnType::*; |
| 309 | + use NativeType::*; |
| 310 | + |
| 311 | + setup_tracing(); |
| 312 | + let session: Session = connect().await; |
| 313 | + |
| 314 | + { |
| 315 | + let table_name: &str = "test_cql_shorter_tuple_tab"; |
| 316 | + create_table( |
| 317 | + &session, |
| 318 | + table_name, |
| 319 | + "tuple<tuple<int, text, int>, int, tuple<int>>", |
| 320 | + ) |
| 321 | + .await; |
| 322 | + |
| 323 | + // We craft a tuple that is shorter in DB representation than in metadata, |
| 324 | + // and also contains another nested tuple with the same property. |
| 325 | + // In order to do that, we use SerializeValueWithFakeType to lie about the type |
| 326 | + // the value is being serialized to, so that tuple serialization logic does not complain. |
| 327 | + let inner_tuple: (i32, String) = (1, "Ala".to_owned()); |
| 328 | + let inner_tuple_ser = |
| 329 | + SerializeValueWithFakeType::new(inner_tuple, Tuple(vec![Native(Int), Native(Text)])); |
| 330 | + let tuple: (SerializeValueWithFakeType<_>, i32) = (inner_tuple_ser, 2); |
| 331 | + let tuple_ser = SerializeValueWithFakeType::new( |
| 332 | + tuple, |
| 333 | + Tuple(vec![Tuple(vec![Native(Int), Native(Text)]), Native(Int)]), |
| 334 | + ); |
| 335 | + // The expected deserialized tuple has None for the missing elements. |
| 336 | + let tuple_deser = ((1, "Ala".to_owned(), None::<i32>), 2, None::<(i32,)>); |
| 337 | + insert_and_select(&session, table_name, &tuple_ser, &tuple_deser).await; |
| 338 | + } |
| 339 | + |
| 340 | + session |
| 341 | + .ddl(format!("DROP KEYSPACE {}", session.get_keyspace().unwrap())) |
| 342 | + .await |
| 343 | + .unwrap(); |
| 344 | +} |
| 345 | + |
257 | 346 | // TODO: Remove this ignore when vector type is supported in ScyllaDB |
258 | 347 | #[cfg_attr(not(cassandra_tests), ignore)] |
259 | 348 | #[tokio::test] |
|
0 commit comments