On Fri, Aug 30, 2019 at 3:51 AM Pasha Stetsenko <stpa...@gmail.com> wrote:
>
> My understanding is that for a sql prefix the most valuable part is to be able
> to know that it was created from a literal. No other magic, definitely not
> auto-executing. Then it would be legal to write
>
>     result = conn.execute(sql"SELECT * FROM people WHERE id=?",
>                           user_id)
>
> but not
>
>     result = conn.execute(f"SELECT * FROM people WHERE id={user_id}")
>
> In order to achieve this, the `execute()` method only has to look at
> the type of its argument, and throw an error if it's a plain string.

There's no such thing, though, any more than there's such a thing as a
"raw string". There are only two types of string in Python - text and
bytes. You can't behave differently based on whether you were given a
triple-quoted, raw, or other string literal.

> Perhaps with some more imagination we can make
>
>     result = conn.execute(sql"SELECT * FROM people WHERE id={user_id}")
>
> work too, but in this case the `sql"..."` token would only create an
> `UnpreparedStatement` object, which expects a variable named "user_id",
> and then the `conn.execute()` method would pass locals()/globals() into
> the `.prepare()` method of that statement, binding those values to
> the placeholders. Crucially, the `.prepare()` method shouldn't modify the
> object, but return a new PreparedStatement, which then gets executed
> by the `conn.execute()`.

One way to handle this particular case would be to do it as a variant
of f-string that doesn't join its arguments, but passes the list to
some other function. Just replace the final step BUILD_STRING step
with BUILD_LIST, then call the function. There'd need to be some way
to recognize which sections were in the literal and which came from
interpolations (one option is to simply include empty strings where
necessary such that it always starts with a literal and then
alternates), but otherwise, the "sql" manager could do all the
escaping it wants. However, this wouldn't be enough to truly
parameterize a query; it would only do escaping into the string
itself.

Another option would be to have a single variant of f-string that,
instead of creating a string, creates a "string with formatted
values". That would then be a single object that can be passed around
as normal, and if conn.execute() received such a string, it could do
the proper parameterization.

Not sure either of them would be worth the hassle, though.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/6LEZYLI6KJ2WXWZM2C6PVD3STD5LF2QU/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to