I am using Sqlalchemy to interact with Redshift via sqlalchemy-redshift
. I need to run a query to grant some permissions:
GRANT SELECT ON <schema>.<table> TO <user>
As far as I am aware, the only way to run something like this is to use text()
. Thus, I need to somehow provide the schema, table name, and username. The ideal approach is this:
text("GRANT SELECT ON :schema.:table TO :user").bindparams(schema="...", table="...", user="...")
However, this results in a syntax error. My understanding is that's because when the schema and table name parameters are bound, Sqlalchemy adds quotation marks, making the final command look like this:
GRANT SELECT ON '...'.'...' TO '...'
On Redshift (and Postgres) I think this isn't acceptable syntax. The schema and table name need to be provided as-is, without quotes. Previous posts like this and this have suggested psycopg2 constructs like psycopg2.extensions.AsIs
to bind the table name when calling cursor.execute
, or using psycopg2.extensions.quote_ident
, or psycopg2.sql.Identifier
to sanitise the parameters before using string formatting.
Also, I want to avoid the "obvious" solution of just using string formatting as it is bad practice and insecure:
f"GRANT SELECT ON {schema}.{table} TO {user}"
However, these solutions are psycopg2 specific. I don't want to introduce a new dependency in my project, or inconsistently stop using the Redshift connector.
Is there a solution in Sqlalchemy's API that's database agnostic? Or one that uses methods from sqlalchemy-redshift?