Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Snowflake variable binding in query throw error with table name but not integer?

I am following the Snowflake Python Connector docs for variable binding to avoid SQL injection. I successfully set up a db connection with the following dict of credentials:

import snowflake.connector

CONN = snowflake.connector.connect(
    user=snowflake_creds['user'],
    password=snowflake_creds['password'],
    account=snowflake_creds['account'],
    warehouse=snowflake_creds["warehouse"],
    database=snowflake_creds['database'],
    schema=snowflake_creds['schema'],
)
cur = CONN.cursor(snowflake.connector.DictCursor)

The following block works fine and I get back query results, hard-coding the table name and using the standard format binding:

command = ("SELECT * FROM TEST_INPUT_TABLE WHERE batch_id = %s")
bind_params = (2)
results = cur.execute(command % bind_params).fetchall()

Similarly, this block works fine, using the pyformat binding:

command = ("SELECT * FROM TEST_INPUT_TABLE WHERE batch_id = %(id)s")
bind_params = {"id": 2}
results = cur.execute(command, bind_params).fetchall()

But the following two blocks both result in a ProgrammingError (pasted below the second block):

command = ("SELECT * FROM %s WHERE batch_id = %s")
bind_params = ("TEST_INPUT_TABLE", 2)
results = cur.execute(command, bind_params).fetchall()


command = ("SELECT * FROM %(tablename)s WHERE batch_id = %(id)s")
bind_params = {
    "tablename": "TEST_INPUT_TABLE",
    "id": 2
    }
results = cur.execute(command, bind_params).fetchall()


    ProgrammingError: 001011 (42601): SQL compilation error:
    invalid URL prefix found in: 'TEST_INPUT_TABLE'

Is there some difference between how strings and ints get interpolated? I would not think it would make a difference but that is all I can think of. Am I missing something simple here? I don't want to have to choose between hard-coding the table name and putting the system at risk of SQL injection. Thanks for any guidance.

like image 905
Ezra Citron Avatar asked Nov 16 '25 17:11

Ezra Citron


1 Answers

You should be wrapping your bind variables with an INDENTIFER() function when they reference an object, rather than a string literal. For example:

command = ("SELECT * FROM IDENTIFIER(%(tablename)s) WHERE batch_id = %(id)s")

https://docs.snowflake.com/en/sql-reference/identifier-literal.html

Give that a try.

like image 187
Mike Walton Avatar answered Nov 18 '25 21:11

Mike Walton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!