Python sqlite3 operational error when string formatting? - python

I have this small decorator function where I am going to find an unknown number of entries in a table:
def Deco(func):
func
conn = sqlite3.connect('/home/User/vocab_database/vocab.db')
with conn:
cur = conn.cursor()
cur.execute("SELECT name FROM sqlite_master WHERE type='table'")
total = cur.fetchall()
print "You have %d tables " % len(total)
## this line below, is where I wanted to use a formatted string ##
cur.execute("SELECT * FROM %s") % total[0]
entries = cur.fetchall()
print "You have %d entries" % len(entries)
Then I get this error message:
Traceback (most recent call last):
File "./database_trial.py", line 19, in <module>
class Vocab:
File "./database_trial.py", line 25, in Vocab
#Deco
File "./database_trial.py", line 15, in Deco
cur.execute("SELECT * FROM %s") % total[0]
sqlite3.OperationalError: near "%": syntax error
Does sqlite3 only accept ? operators? Or is there something I'm mucking up?

You're trying to replace metadata, so unfortunately a parametrized query won't work. You must use interpolation or the like here, but make sure that the value is sanitized; this is a possible vector for a SQL injection.
cur.execute("SELECT * FROM %s" % (total[0],))

In the line cur.execute("SELECT * FROM %s") % total[0], you are applying the % operator to the result of the cur.execute call. I think you want to do the substitution inside the call, e.g., cur.execute("SELECT * FROM ?", (total[0],)).

Related

Is there a way to pass a Python variable into an SQL Query? [duplicate]

This question already has answers here:
How do I get around not being able to parse a table name into a python sqlite query?
(3 answers)
Closed 3 years ago.
I am trying to pass the result of a user input into an SQL query, like so:
def select_rows(conn):
table_choice = input("Choose a table: ")
cur = conn.cursor()
cur.execute("SELECT * FROM %s", table_choice)
rows = cur.fetchall()
for row in rows:
print(row)
but I get this Error:
Database Path: C:\Users\Morgan\Desktop\SQL\chinook.db
Choose a table: album
Traceback (most recent call last):
File "C:\Users\Morgan\Desktop\SQL\SQL.py", line 27, in <module>
select_rows(conn)
File "C:\Users\Morgan\Desktop\SQL\SQL.py", line 20, in select_rows
cur.execute("SELECT * FROM %s", table_choice)
sqlite3.OperationalError: near "%": syntax error
Any suggestions?
You can use f-string as well:
cur.execute(f"SELECT * FROM {table_choice}")
But be careful with user's input and query. You should write a function to validate the input.
you need to format the query before executing it...:
cur.execute("SELECT * FROM {}".format(table_choice))
cur.execute("SELECT * FROM ?", (table_choice,))

psycopg2 escaping characters

I have a postgres query that looks like the following, and runs find on psql:
select
gcaseid,
count (*) as N,
array_agg(distinct nvchquestion) as questions,
array_agg(nvchanswer) as answers
from
case_script,
case_script_answer
where
case_script.gscriptid = case_script_answer.gscriptid and
nvchquestion ilike '%blood pressure%'
group by
gcaseid
order by
N desc
;
Now, I wanted to have a similar query in Python, And this is what I came up with:
import psycopg2
def getAnswers(question):
query = '''
select
gcaseid,
count (*) as N,
array_agg(distinct nvchquestion) as questions,
array_agg(nvchanswer) as answers
from
case_script,
case_script_answer
where
case_script.gscriptid = case_script_answer.gscriptid and
nvchquestion ilike %s
group by
gcaseid
order by
N desc
;
'''%(r"'%%s%'")
conn = psycopg2.connect("dbname='sos' user='postgres' host='localhost'")
cur = conn.cursor()
cur.mogrify(query, (question,))
# cur.execute(query, (question,))
# result = cur.fetchall()
cur.close()
conn.close()
return result
if __name__ == '__main__':
print getAnswers('blood pressure')
print 'done'
Now, when I ran this query, I got the error:
$ python updateTable.py
Traceback (most recent call last):
File "updateTable.py", line 39, in <module>
print getAnswers('blood pressure')
File "updateTable.py", line 27, in getAnswers
cur.mogrify(query, (question,))
ValueError: unsupported format character ''' (0x27) at index 442
Not sure what is happening. Anyone can clarify please?
Use %% in your query to represent LIKE wildchars:
execute(" ... ilike %%%s%%", [question])
Or surround your value by %s in your value:
execute(" ... ilike %s", ['%' + question + '%']
See the docs about parameters.
The simplest it to pass the % concatenated to the parameter as suggested by #piro:
query = "select 'x' ilike %s"
print (cursor.mogrify(query, ('%x%',)).decode('utf8'))
cursor.execute(query, ('%x%',))
print (cursor.fetchone()[0])
Output:
select 'x' ilike '%x%'
True
But if you want to keep the parameters clean use format:
query = "select 'x' ilike format('%%%%%%1$s%%%%', %s)"
print (cursor.mogrify(query, ('x',)).decode('utf8'))
cursor.execute(query, ('x',))
print (cursor.fetchone()[0])
Output:
select 'x' ilike format('%%%1$s%%', 'x')
True

mysql is showing error in the syntax

I am having trouble in executing this query in python. I have an IP database which has 3 column startip, endip and country. Now I want to the location of the ip. this is my code
def get_country(ip):
try:
conn = MySQLConnection(host='localhost', database='ipdb', user ='root', password='password')
cursor = conn.cursor()
query = 'SELECT * FROM db6 WHERE %s BETWEEN INET_ATON(startip) AND INET_ATON(endip)'
ip_inint= ip2int(ip)
cursor.execute(query,ip_inint)
row = cursor.fetchone()
while row is not None:
print " Start range %s end range %s country %s " %(row[0], row[1], row[2])
row = cursor.fetchone()
except Error as error:
print(error)
ip2int function is
def ip2int(addr):
return struct.unpack("!I", socket.inet_aton(addr))[0]
error i am receiving is
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 BETWEEN INET_ATON(startip) AND INET_ATON(endip)' at line 1
what could be the issue?
You need to pass a tuple to execute():
cursor.execute(query, (ip_inint,))
A list will probably work too:
cursor.execute(query, [ip_inint])
An alternative is to use a dictionary with named variables in the query:
query = 'SELECT * FROM db6 WHERE %(ip_inint)s BETWEEN INET_ATON(startip) AND INET_ATON(endip)'
cursor.execute(query, {'ip_inint': ip_inint})
Reference: http://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html

sqlite3.OperationalError: no such column. But that's not a column

I seem to be getting a rather odd error. And, for the life of me I can't figure out what's wrong. But on a piece of SQLite code, I'm getting this error:
Traceback (most recent call last):
File "test.py", line 38, in <module>
populateTables()
File "test.py", line 20, in populateTables
curs.execute("SELECT * FROM tracks WHERE ISRC = " + line[8])
sqlite3.OperationalError: no such column: USTCZ0993316
The odd part is that USTCZ0993316 is a piece of data that I want to compare to. I don't know why it seems to think it is a column. Here is a much small version that gives the same issue.
import sqlite3
import csv
def tableSetup(name):
if(name=="tracks"):
curs.execute("CREATE TABLE tracks(id INT UNIQUE, name TINYTEXT, album_id INT, client_id INT, acr_record_num INT, ISRC TINYTEXT UNIQUE, track_length TINYTEXT, client_share FLOAT)")
def populateTables():
tracks_csv=csv.reader(open('tables/tracks.csv', 'rU'), delimiter=";", quotechar='"')
tracks_csv.next()
for line in tracks_csv:
curs.execute("SELECT * FROM tracks WHERE id = " + line[0])
if not curs.fetchall():
if "\"" in line[1]:
line[1]=line[1].replace("\"","'")
curs.execute("INSERT INTO tracks VALUES("+line[0]+",\""+line[1]+"\","+line[2]+","+line[3]+","+line[4]+",\""+line[5]+"\",\""+line[7]+"\","+line[12]+")")
override_csv=csv.reader(open('tables/artist_override.csv', 'rU'), delimiter=",", quotechar='"')
override_csv.next()
for line in override_csv:
curs.execute("SELECT * FROM tracks WHERE ISRC = " + line[8])
print curs.fetchone()
#Set required Table Names
tables = ["tracks"]
testOut=open('tables/testOut.txt','w')
conn = sqlite3.connect('tables/test.db')
curs = conn.cursor()
# Create table if they don't already exist
curs.execute("SELECT name FROM sqlite_master WHERE type='table'")
tableResults = curs.fetchall()
print
for table in tables:
if not any(table == result[0] for result in tableResults):
tableSetup(table)
populateTables()
conn.commit()
curs.close()
If it doesn't have quotes then it's a column or a number.
curs.execute("SELECT * FROM tracks WHERE ISRC = ?", (line[8],))
[Edit: "%s" isn't proper syntax. It should be "?". Also, if you're going to be condescending, at least be right about it.]

python's trackback error - using pymssql

am trying to execute the below code using python 2.5.2. The script is establishing the connection and creating the table, but then its failing with the below error.
The script
import pymssql
conn = pymssql.connect(host='10.103.8.75', user='mo', password='the_password', database='SR_WF_MODEL')
cur = conn.cursor()
cur.execute('CREATE TABLE persons(id INT, name VARCHAR(100))')
cur.executemany("INSERT INTO persons VALUES(%d, %s)", \
[ (1, 'John Doe'), (2, 'Jane Doe') ])
conn.commit()
cur.execute("SELECT * FROM persons WHERE salesrep='%s'", 'John Doe')
row = cur.fetchone()
while row:
print "ID=%d, Name=%s" % (row[0], row[1])
row = cur.fetchone()
cur.execute("SELECT * FROM persons WHERE salesrep LIKE 'J%'")
conn.close()
The error
Traceback (most recent call last):
File "connect_to_mssql.py", line 9, in <module>
cur.execute("SELECT * FROM persons WHERE salesrep='%s'", 'John Doe')
File "/var/lib/python-support/python2.5/pymssql.py", line 126, in execute
self.executemany(operation, (params,))
File "/var/lib/python-support/python2.5/pymssql.py", line 152, in executemany
raise DatabaseError, "internal error: %s" % self.__source.errmsg()
pymssql.DatabaseError: internal error: None
any suggestions? plus, how do you read the traceback error, anyone can help me understand the error message? how do you read it? bottom up?
I think you are assuming the regular python string interpolation behavior, ie:
>>> a = "we should never do '%s' when working with dbs"
>>> a % 'this'
"we should never do 'this' when working with dbs"
The % operator within the execute method looks like the normal string formatting operator but that is more of a convenience or mnemonic; your code should read:
cur.execute("SELECT * FROM persons WHERE salesrep=%s", 'John Doe')
without the quotes, and this will work with names like O'Reilly, and help prevent SQL injection per the database adapter design. This is really what the database adapter is there for -- converting the python objects into sql; it will know how to quote a string and properly escape punctuation, etc. It would work if you did:
>>> THING_ONE_SHOULD_NEVER_DO = "select * from table where cond = '%s'"
>>> query = THING_ONE_SHOULD_NEVER_DO % 'john doe'
>>> query
"select * from table where cond = 'john doe'"
>>> cur.execute(query)
but this is bad practice.

Categories