2

When creating a user with psycopg, I would create the following composite in order to avoid SQL injection:

from psycopg.sql import SQL, Identifier, Literal

username = "test_user"
password = "test_password"
query = SQL(
    "CREATE USER {username} WITH ENCRYPTED PASSWORD {password};"
).format(username=Identifier(username), password=Literal(password))

This can be tested in the scope of a psycopg.Connection:

print(query.as_string(connection))  # CREATE USER "test_user" WITH ENCRYPTED PASSWORD 'test_password';

What is the recommended way to do the same with sqlalchemy? I tried quoted_name and bind_params, but the former was not successful:

from sqlalchemy import quoted_name, text

query = text(
    f"CREATE USER {quoted_name(username, True)} WITH ENCRYPTED PASSWORD :password;"
).bindparams(password=password).compile(compile_kwargs={"literal_binds": True})

print(query)  # CREATE USER test_user WITH ENCRYPTED PASSWORD 'test_password';

(Changing the second parameter of quoted_name to False or None yields the same result.)

5
  • 1
    I see we have an existing answer that advises the approach you're using here. That's unfortunate. A proper answer will probably use sqlalchemy.schema.DDL with %s placeholders for context -- which we want evaluated only at compile time, not when the query string is built, so the engine's dialect details are available. Commented Jan 12, 2024 at 16:16
  • I would construct the statement with as in the first example, wrap it with sqlalchemy.text and execute it. Database admin actions aren't really the use-case for SQLAlchemy (or most other ORMs). Commented Jan 12, 2024 at 18:44
  • @snakecharmerb The expression text(SQL(...)) leads to a TypeError since text expects a string or bytes-like object. In addition, if I have to use psycopg constructs, I can just do everything in psycopg instead of mixing the two libraries. Nonetheless, I have hope that SQLAlchemy Core supports what I am asking for (SQLAlchemy ORM not, of course). Commented Jan 12, 2024 at 20:16
  • I should been more explicit: you would need to call the SQL object's as_string() method to stringify it prior before passing it to text(). Commented Jan 13, 2024 at 9:51
  • Alas, I've hit my timebox trying to run this down. Back when I used SQLAlchemy on a regular basis (in the 1.x days), @zzzeek was actively available on support channels (largely IRC, at the time). I'd generally suggest trying to go direct to the source on this one, accordingly. Commented Jan 13, 2024 at 22:00

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.