Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PreparedMetadata is not updated during repreparation #575

Open
cvybhu opened this issue Oct 10, 2022 · 3 comments
Open

PreparedMetadata is not updated during repreparation #575

cvybhu opened this issue Oct 10, 2022 · 3 comments
Milestone

Comments

@cvybhu
Copy link
Contributor

cvybhu commented Oct 10, 2022

A PreparedStatement sometimes has to be prepared again.
This happens when its removed from the cache, or the schema changes.

PreparedStatement contains PreparedMetadata, which keeps types of values bound to the query.
After a schema change this field should be updated during repreparation.
For now this doesn't cause any issues, but in the future we might add more validation to the bound values (#463) and some problems may arise.

Here's an example, which creates a user type, prepares a statement and adds a new field to the user type.
The PreparedStatement still thinks that there's only one field in the user type.

use scylla::{Session, SessionBuilder};

#[tokio::main]
async fn main() {
    let uri = std::env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string());
    let session: Session = SessionBuilder::new().known_node(uri).build().await.unwrap();

    session
        .query("DROP KEYSPACE IF EXISTS ks", ())
        .await
        .unwrap();
    session
    .query(
        "CREATE KEYSPACE IF NOT EXISTS ks WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1}",
        &[],
    )
    .await.unwrap();
    session.use_keyspace("ks", true).await.unwrap();

    session.query("CREATE TYPE mytype (a int)", ()).await.unwrap();
    session
        .query("CREATE TABLE tab (p int primary key, m mytype)", ())
        .await
        .unwrap();

    let prepared = session.prepare("INSERT INTO tab (p, m) VALUES (0, ?)").await.unwrap();
    println!("{:#?}", prepared.get_prepared_metadata());

    session
        .query("ALTER TYPE mytype ADD b int", ())
        .await
        .unwrap();
    
    session.execute(&prepared, ((1, 2),)).await.unwrap();

    println!("{:#?}", prepared.get_prepared_metadata());
}

Output:

PreparedMetadata {
    col_count: 1,
    pk_indexes: [],
    col_specs: [
        ColumnSpec {
            table_spec: TableSpec {
                ks_name: "ks",
                table_name: "tab",
            },
            name: "m",
            typ: UserDefinedType {
                type_name: "mytype",
                keyspace: "ks",
                field_types: [
                    (
                        "a",
                        Int,
                    ),
                ],
            },
        },
    ],
}
PreparedMetadata {
    col_count: 1,
    pk_indexes: [],
    col_specs: [
        ColumnSpec {
            table_spec: TableSpec {
                ks_name: "ks",
                table_name: "tab",
            },
            name: "m",
            typ: UserDefinedType {
                type_name: "mytype",
                keyspace: "ks",
                field_types: [
                    (
                        "a",
                        Int,
                    ),
                ],
            },
        },
    ],
}
@piodul
Copy link
Collaborator

piodul commented Oct 13, 2022

Hmm, that's a tough pickle. I'm not sure this can be fixed without changes to the protocol/database. The issue with changing types of columns sounds prone to a race like in the prepared SELECT * fiasco (https://docs.datastax.com/en/developer/java-driver/3.0/manual/statements/prepared/#avoid-preparing-select-queries), i.e. another client may quickly re-prepare the statement and our current client will not even notice that it needs to update the metadata.

I think there are some fixes for the problem in protocol version 5, although I'm not familiar with them and ScyllaDB doesn't implement V5 (apart from the duration datatype, AFAIK).

@wprzytula
Copy link
Collaborator

The problem has been described in #986. Let's consider closing this. @Lorak-mmk @muzarski

@Lorak-mmk
Copy link
Collaborator

The problem is described, but not fixed.

@Lorak-mmk Lorak-mmk removed their assignment Jul 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants