sqlx icon indicating copy to clipboard operation
sqlx copied to clipboard

Add SqlStr

Open joeydewaal opened this issue 11 months ago • 6 comments

Not sure if it's appreciated to take over a PR but I thought I'd try and work #3364 out.

This PR changes the following things:

  • Add the SqlStr, AssertSqlStr types and SqlSafeStr trait.
  • Removes the lifetime of Statement since the underlying sql string is now owned.
  • Updates the Executor trait to take a SqlStr instead of a &'q str.
  • Changes the AnyStatement::try_from_statement method to take a Statement so the prepare_with method on AnyConnectionBackend doesn't have to clone the SqlStr.

There are still lifetimes that should be changed/relaxed, but this works.

joeydewaal avatar Feb 01 '25 20:02 joeydewaal

I appreciate the effort on this, but in #3364 kind of got stuck on some design questions. I was thinking that I would:

  • Delete the Execute trait because it adds unnecessary monomorphization.
  • Replace the methods on Executor with fetch_prepared() and fetch_unprepared()
    • Maybe execute_prepared() and execute_unprepared() as well, to tell the driver to ignore returned rows.
    • Use structs to pass arguments to these so additional parameters can be added without it being a breaking change.
    • Add a batch_size parameter to make queries cancellable (default to 0/infinite to fix #3673)
  • Try to figure out all the lifetime issues with Executor
  • Lay some of the groundwork for the execution model refactor I've been meaning to do (run the connection on a background task for parallelism and cancellation safety)
    • I was experimenting with a new batched SPSC channel design that could achieve insane throughput in 100% safe code (10x faster than flume or tokio::sync::mpsc): https://github.com/launchbadge/sqlx/commit/e5c2380f8dd9e26c641991585f99df5dd017897d
    • This was going to use batch_size by default to set the capacity of the channel but because of #3673 we might need a separate parameter (or just choose a decent default).

It's extremely hard to resist scope creep with major refactors like this. At minimum I would still delete the Execute trait though.

(Also, I don't assume you intended to do this, but you erased my authorship in these commits.)

abonander avatar Feb 02 '25 00:02 abonander

Lay some of the groundwork for the execution model refactor I've been meaning to do (run the connection on a background task for parallelism and cancellation safety)

This would be great, also dropping transactions would probably be easier.

It's extremely hard to resist scope creep with major refactors like this. At minimum I would still delete the Execute trait though.

Ah that's why the Execute trait was missing. I wouldn't mind updating this PR. But you'd have to explain a bit how it should look. Also if you'd rather make these changes (SqlStr, Execute, ...) yourself I wouldn't mind. I don't want to waste your/my time with this PR if you'd rather want to go in a different direction. That said I have the time so I wouldn't mind increasing the scope a bit.

(Also, I don't assume you intended to do this, but you erased my authorship in these commits.)

This wasn't my first time trying to make this PR work, in my first attempt I tried working on top of your PR but there were too things changed in the query{_as, _scalar}.rs files and wanted to work on a clean branch. I eventually just copied over the sql_str.rs file but didn't think about authorship. I'll rebase when I work on this some more.

joeydewaal avatar Feb 02 '25 22:02 joeydewaal

CI is passing and this PR is using your commit, so this should be ready for the next step. What should the replacement for the Execute trait look like?

Also while going through some of the lifetimes I noticed that the Arguments and ArgumentBuffer currently have a lifetime that doesn't feel useful. Only the Sqlite driver is using them but calls SqliteArguments::into_static before sending them through a channel here. If I'd have to guess I'd say that the lifetimes would've probably been used before #1551 but were not touched because of backwards compatibility. Since you're trying to move towards a background task and communicating through channels, should these be removed? The 'static lifetime on channels would make this lifetime unusable in the future. This would also remove the lifetime on the Encode and Execute trait which would clean the lifetimes on the Executor trait up quite a bit.

joeydewaal avatar Feb 19 '25 11:02 joeydewaal

Yeah, deleting the lifetimes on Arguments was an idea, though AnyArguments also uses it when encoding &str and &[u8]. It saves a copy when later encoding into the database-specific format.

abonander avatar Feb 20 '25 10:02 abonander

Ah I forgot to check the Any driver, that's unfortunate because it would solve #1430 and #1151.

joeydewaal avatar Feb 24 '25 10:02 joeydewaal

CI should be fixed if you rebase.

abonander avatar Mar 04 '25 22:03 abonander

@joeydewaal do you have time to address the merge conflicts?

abonander avatar Jul 05 '25 00:07 abonander

Yes, I'll work on this today

joeydewaal avatar Jul 05 '25 05:07 joeydewaal

Merge conflicts are resolved

joeydewaal avatar Jul 05 '25 15:07 joeydewaal

Another bikeshedding question: should we change the name of QueryBuilder::push(), since it allows adding unsanitized data to the query? It's already got a warning on it, but I'm wondering if the name is missing some nuance. I guess use of QueryBuilder is already something that's going to draw a bit of scrutiny since the onus is already on the user to ensure it generates syntactically valid SQL.

abonander avatar Jul 06 '25 14:07 abonander

I don't really have a strong opinion on that, but since we trying to make it really safe we might as well. What name did you have in mind, I'm thinking of push_unsanitized?

joeydewaal avatar Jul 06 '25 14:07 joeydewaal

Yeah, let's deprecate push in favor of push_unsanitized and see what feedback we get on it.

abonander avatar Jul 07 '25 01:07 abonander

On second thought, I'd rather just merge this. I think QueryBuilder already draws enough attention to itself.

abonander avatar Jul 07 '25 07:07 abonander