Add SqlStr
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,AssertSqlStrtypes andSqlSafeStrtrait. - Removes the lifetime of
Statementsince the underlying sql string is now owned. - Updates the
Executortrait to take aSqlStrinstead of a&'q str. - Changes the
AnyStatement::try_from_statementmethod to take aStatementso theprepare_withmethod onAnyConnectionBackenddoesn't have to clone theSqlStr.
There are still lifetimes that should be changed/relaxed, but this works.
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
Executetrait because it adds unnecessary monomorphization. - Replace the methods on
Executorwithfetch_prepared()andfetch_unprepared()- Maybe
execute_prepared()andexecute_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_sizeparameter to make queries cancellable (default to 0/infinite to fix #3673)
- Maybe
- 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
flumeortokio::sync::mpsc): https://github.com/launchbadge/sqlx/commit/e5c2380f8dd9e26c641991585f99df5dd017897d - This was going to use
batch_sizeby default to set the capacity of the channel but because of #3673 we might need a separate parameter (or just choose a decent default).
- I was experimenting with a new batched SPSC channel design that could achieve insane throughput in 100% safe code (10x faster than
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.)
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
Executetrait 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.
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.
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.
Ah I forgot to check the Any driver, that's unfortunate because it would solve #1430 and #1151.
CI should be fixed if you rebase.
@joeydewaal do you have time to address the merge conflicts?
Yes, I'll work on this today
Merge conflicts are resolved
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.
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?
Yeah, let's deprecate push in favor of push_unsanitized and see what feedback we get on it.
On second thought, I'd rather just merge this. I think QueryBuilder already draws enough attention to itself.