Passing strings to pymysql cursor using Python function - python

I'm working on a script that will pull data from a database using pymysql and a simple SELECT statement. I'm going to run this statement many times, so I was hoping to simplify things by putting it in a function and passing the column name, table name, where clause and value as arguments to the function.
def retrieve_value_from_db(connection,column_name,table_name,where_clause,where_value):
with connection:
with connection.cursor() as cursor:
sql = "SELECT %s FROM %s WHERE %s=%s"
logging.debug(cursor.mogrify(sql,(column_name,table_name,where_clause,where_value)))
cursor.execute(sql,(column_name,table_name,where_clause,where_value))
result = cursor.fetchone()
connection.commit()
return result
However calling the function below returns the following error
retrieve_value_from_db(connection,"last_name","mother_table","id","S50000")
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''mother_table' WHERE 'id'='S50000'' at line 1")
Cursor.execute seems to be reading the quotation mark portion of the string, which is causing the programming error. So how do I pass a string argument to the function that cursor.execute can read? Is what I want to do even possible? Thanks in advance.

Perhaps surprisingly, you should not let the database substitution handle table names and column names. It tries to quote them as if they were fields, which is wrong.
sql = "SELECT %s FROM %s WHERE %s=%%s" % (column_name,table_name,where_clause)
...
cursor.execute(sql, (where_value,))

Related

How to do I use %s in a mysql query without errors

I am having some trouble selecting from my database using python to execute a MySql query. I have tried two methods to achieve this, but both methods have returned the error shown below:
mysql.connector.errors.ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%s' at line 1
What Id like to do is return the row count (which is always zero or one) when a username parameter is passed. I have looked at other examples where people have had this issue but I cant find a good fix.
The first method I tried was this:
def check_data(username):
sql = """SELECT count(*) FROM tbl_user WHERE username = %s"""
mycursor.execute(sql, username)
#do something with the data
I then tried using SELECT (CASE WHEN (uname = %s) THEN TRUE ELSE FALSE END) AS IsEmtpy FROM tbl_user limit 1;
This works database side, but still throws the same error when run in the application. I tried wrapping the %s like '%s' but it didn't help.
Any suggestions?
You're missing enclosing the string between quotes (singles or doubles).
You can check the query you're executing by printing it before the mycursor.execute statement, but basically you're sending MySQL something like SELECT count(*) FROM tbl_user WHERE username = foobar.
Try fixing it with SELECT count(*) FROM tbl_user WHERE username = '%s'.
On a side note, your approach is vulnerable to SQL Injection. You should check the documentation of the tool you're using to connect to the DBMS for "prepared statements".

How to make the SQL Injection on INSERT work on SQLite

I don't know how to make this SQL Injection work in SQLite. I'm using a function in Python that connects to a database and inserts a string.
I have "database.db" that has two tables: "feedback" and "users".
The feedback table has 1 column: message.
The users table has 2 columns: username and password.
def send_feedback(feedback):
conn = sqlite3.connect("database.db")
curs = conn.cursor()
curs.execute("INSERT INTO feedback VALUES ('%s')" % (feedback))
print(curs.fetchall())
conn.close()
I know that the execute function allows me to make a single query to the database, so I can't use ";" to
make multiple queries.
What I have tried, is to make the string look like this:
a') SELECT password FROM users --
feedback = "INSERT INTO feedback VALUES ('a') SELECT password FROM users --')"
But this gives me the following error:
sqlite3.OperationalError: near "SELECT": syntax error
So I've tried to use the UNION command:
a') UNION SELECT password FROM users --
feedback = "INSERT INTO feedback VALUES ('a') UNION SELECT password FROM users --')"
This one works but the fetchall function returns an empty list.
Most SQL injections result in nothing useful to the perpetrator, just a syntax error.
For example, pass the string "I'm not satisfied" to this feedback function and the extra ' character would cause the quotes to be imbalanced, and this would result in an error, causing the INSERT to fail.
sqlite3.OperationalError: near "m": syntax error
That's technically SQL injection. The content interpolated into the query has affected the syntax of the SQL statement. That's all. It doesn't necessarily result in a successful "Mission: Impossible" kind of infiltration.
I can't think of a way to exploit the INSERT statement you show to make it do something clever, besides causing an error.
You can't change an INSERT into a SELECT that produces a result set. Even if you try to inject a semicolon followed by a second SQL query, you just get sqlite3.Warning: You can only execute one statement at a time
Your first try above resulted in a syntax error because you had both a VALUES clause and a SELECT as a source for the data to insert. You can use either one but not both in SQL syntax. See https://www.sqlite.org/lang_insert.html
You probably already know how to make the code safe, so unsafe content cannot even cause a syntax error. But I'll include it for other readers:
curs.execute("INSERT INTO feedback VALUES (?)", (feedback,))
You can do it, for example to get table name
a' || (SELECT tbl_name FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%'))-- -

inserting data in a mysql database via python

I'm trying to insert variables as data into a database
I'm using this (part of it)
query = "INSERT INTO table_name (name) VALUES (%S)"
aa="naam"
cursor.execute(query,aa)
and everytime, I get the following error message:
"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%S)' at line 1"
no matter what I try to do, I'm getting this message (put it in """, put () around it, ...)
Hope someone can help me
The format needs to be lowercase, so change the query into: query = "INSERT INTO table_name (name) VALUES (%s)".

Right syntax to use near

I'm trying to run this script, but I have this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(than appear 3 users)' at
line 1
Code:
conn = mysql.connector.connect('localhost','root,'','dbtest')
cursor = conn.cursor()
add_data = ("""INSERT INTO data VALUES %s,%s,%s""" %(user, twet, time))
cursor.execute(add_data)
conn.commit()
cursor.close()
conn.close()
I belive that the error is in the %s,%s,%s, I tried a lot of diferent formats but it's always the same result.
Any ideas?
Thanks.
The correct syntax for your connection to your database should read in the lines of:
conn = mysql.connector.connect('localhost','root','','dbtest')
And maybe change your insert statement to:
add_data = ("INSERT INTO data VALUES (\"%s\",\"%s\",\"%s\")" % (user, twet, time))
You must never ever use string substitution in SQL queries. Use the db-api's parameter substitution. Apart from anything else, it will solve one of your syntax problems, which is that your strings are not quoted; it will do that automatically.
The other syntax issue you have, as Mario pointed out, is that arguments to VALUES need to be in parentheses. So, putting those together:
add_data = """INSERT INTO data VALUES (%s,%s,%s)"""
cursor.execute(add_data, (user, twet, time))
The right syntax should be with parenthesis:
INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country) VALUES ('Cardinal','Tom B. Erichsen','Skagen 21','Stavanger','4006','Norway');

Print if MySQL returns no results

This is my code so far. I'm attempting to print No results found if no results are returned by MySQL however I can't figure it out. Perhaps I'm using incorrect arguments. Could anyone provide me with an example? Much appreciated!
def movie_function(film):
connection = mysql connection info
cursor = connection.cursor()
sql = "SELECT * FROM film_database WHERE film_name = '"+film+"' ORDER BY actor"
cursor.execute(sql)
rows = cursor.fetchall()
for row in rows:
print row[1]
When you execute a select statement, cursor.rowcount is set to the number of results retrieved. Also, there is no real need to call cursor.fetchall(); looping over the cursor directly is easier:
def movie_function(film):
connection = mysql connection info
cursor = connection.cursor()
sql = "SELECT * FROM film_database WHERE film_name = %s ORDER BY actor"
cursor.execute(sql, (film,))
if not cursor.rowcount:
print "No results found"
else:
for row in cursor:
print row[1]
Note that I also switched your code to use SQL parameters; there is no need to use string interpolation here, leave that to the database adapter. The %s placeholder is replaced for you by a correctly quoted value taken from the second argument to cursor.execute(), a sequence of values (here a tuple of one element).
Using SQL parameters also lets a good database reuse the query plan for the select statement, and leaving the quoting up to the database adapter prevents SQL injection attacks.
You could use cursor.rowcount after your code to see how many rows were actually returned. See here for more.
I guess, this should work.
def movie_function(film):
connection = mysql connection info
cursor = connection.cursor()
sql = "SELECT * FROM film_database WHERE film_name = %s ORDER BY actor"
cursor.execute(sql, [film])
rows = cursor.fetchall()
if not rows:
print 'No resulrs found'
return
for row in rows:
print row[1]
Note, that I changed the way the film parameter is passed to query. I don't know, how exactly it should be (this depends on what MySQL driver for python you use), but important thing to know, is that you should not pass your parameters directly to the query string, because of security reasons.
You can also use :
rows_affected=cursor.execute("SELECT ... ") -> you have directly the number of returned rows

Categories

Resources