Skip to content

Lifetime requirement on Statement is very unergonomic #1337

Description

@tomaka

The examples of this repository do something like connection.prepare("SELECT ...").query(...), in other words they prepare a statement and then immediately execute it.

Correct me if I'm wrong, but an optimized application should at initialization open the database and prepare all the statements that it will need, and then later execute these statements. No statement is prepared after initialization.

However, the fact that Statement has a lifetime parameter makes this very difficult to do. It is for example not possible to store a Connection and a Statement in the same struct.

This is a well-known problem in the Rust ecosystem, and my opinion is that using lifetimes on long-lived objects is almost always "wrong" (in the sense that it leads to unergonomic designs). Lifetimes exist only to represent a temporary access to the inside of an object (typically a container).

I would suggest three possible ways to fix this:

  • Have Statement always hold an Arc<Connection>.
  • Make Statement generic over a pointer to a connection. For example the user could use Statement<&'a Connection> or Statement<Arc<Connection>> at their discretion. Note that this might lead to unsafety because the user could provide a custom malicious implementation of the Deref trait that doesn't always deref to the same connection.
  • Have the Connection hold some kind of Vec<*mut ffi::Statement> (most likely a Slab so that you can insert and remove elements in O(1) time), and turn Statement into some kind of StatementIndex that represents an index in this container.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions