When running this minimal code:
import pypyodbc
conn = pypyodbc.connect(r'Driver={{Microsoft Access Driver (*.mdb, *.accdb)}}; Dbq=C:\temp\example.accdb;'
cur = conn.cursor()
cur.execute('SELECT [Pass#] FROM [Companies]')
I get the following error:
pypyodbc.DatabaseError: ('07002', '[07002] [Microsoft][ODBC Microsoft Access Driver] Too few parameters. Expected 1.')
The cause of the error appears to be the '#' character, which is a special wildcard character for MS Access. However, I can't figure out any way to escape it. Similar errors suggest the the square brackets ([]) are the way to escape, but it doesn't seem to work.
I have tried these variations like these with no success:
cur.execute('SELECT [Pass[#]] FROM [Companies]')
cur.execute('SELECT Pass[#] FROM [Companies]')
cur.execute('SELECT [Pass\\#] FROM [Companies]')
cur.execute('SELECT Pass# FROM [Companies]')
I should also mention the Access DB is not controlled by me or my company, so I am unable to rename the column.
Thanks to Gord Thompson for pointing me in the right direction. Long story short, the schema I was working against was old, and the field [Pass#] had been renamed to [PassID].
As it turns out however, the behavior was still confusing for other fields in my DB. For anyone who finds this answer in the future, it would appear that the Access ODBC driver invoked this way will give the error Too few parameters. Expected N. whenever you have wrong column names, instead of a more helpful Column name not recognized or similar. # characters are allowed in the column names, as long as the name is square-bracketed.
Related
I am using SQL server and need to run the following SQL via Python script
SELECT DISTINCT LEN(Wav)-CHARINDEX('.', Wav) FROM <>;
I have tried to play with the String but couldn’t figure out how to work around the dot character.
sql = 'SELECT DISTINCT LEN(Wav)-CHARINDEX({}, Wav) FROM xxx'.format('.')
print(sql)
cursor = conn.cursor()
cursor.execute(sql)
Any idea how to resolve this
Thank you
'.' is the string ., you want "'.'", the string '.'
>>> print("{}".format('.'))
.
>>> print("{}".format("'.'"))
'.'
As #Justin Ezequiel's answer notes, do beware of SQL injections here!
Specifically, unfiltered user inputs can and will cause an SQL injection where unanticipated commands can be run against the target database by breaking out of the raw string. These can do anything your connection has permission to do, such as retrieving, modifying, or deleting arbitrary data.
A traditional approach is to use prepared statements
In Python, you can also use a regex or other test to explicitly error for statements with control characters (if not re.match(r"^[a-zA-Z\d _+-]+$"), s):raise_) or use (trust) an escaping library to do it for you if you must take arbitrary strings.
Use parameters to avoid SQL-injection attacks.
sql = 'SELECT DISTINCT LEN(Wav)-CHARINDEX(?, Wav) FROM xxx' # note placeholder (?)
print(sql)
params = ('.',) # tuple
cursor = conn.cursor()
cursor.execute(sql, params)
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_%'))-- -
Quick rundown:
The idea here is to read some data in from a csv file, and use that as the list in the NOT IN part of my sql query. I'm connecting to the db (.mdb) with the code below.
Note LP is the tuple/list I'm trying to pass, IRdb is the path to the db
constr = r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=' + IRdb
conn = pyodbc.connect(constr, autocommit=True)
cur = conn.cursor()
IRsql='''SELECT IRRPResults.RRPName, IRRPResults.PointName, IRRPResults.RiskPerTime FROM IRRPResults
WHERE IRRPResults.PointName<>?
AND IRRPResults.RRPName NOT LIKE ? AND IRRPResults.PointName NOT IN ?'''
cur.execute(IRsql,('Total',r'Conn%',LP))
The issue:
Everything works fine except for the execute statement (which did work before i added the NOT IN part). I've tried passing LP as string, tuple, and list, but nothing seems to be working. I get the following error
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Microsoft Access Driver] In operator without () in query expression 'IRRPResults.PointName<>Pa_RaM000 AND IRRPResults.RRPName NOT LIKE Pa_RaM001 AND IRRPResults.PointName NOT IN Pa_RaM002'. (-3100) (SQLExecDirectW)")
Any help would be greatly appreciated.
For anyone interested, or for that guy reading this 2 years from now with the same issue, or my future self when I forget what i did, I've figured out a solution or two.
The first work around was to simply use .format on the sql string to insert LP directly before it gets passed to the execute statement.
IRsql='''SELECT IRRPResults.RRPName, IRRPResults.PointName, IRRPResults.RiskPerTime FROM IRRPResults
WHERE IRRPResults.PointName<>?
AND IRRPResults.RRPName NOT LIKE ? AND IRRPResults.PointName NOT IN {}'''.format(LP)
cur.execute(IRsql,('Total',r'Conn%'))
The other solution, I got from this question, is a little more elegant and clever in that it builds a string of '?' markers for each element in LP. Then LP gets passed as a tuple/list to the execute statement.
placeholders=','.join('?'*len(LP))
IRsql='''SELECT IRRPResults.RRPName, IRRPResults.PointName, IRRPResults.RiskPerTime FROM IRRPResults
WHERE IRRPResults.PointName<>?
AND IRRPResults.RRPName NOT LIKE ? AND IRRPResults.PointName NOT IN ({})'''.format(placeholders)
cur.execute(IRsql,('Total',r'Conn%',*LP))
I am connecting to MS Access using ODBC (Python ODBC module ). There is one part of the code which put some values into DB. Looks similar to this:
for item in changes:
format_str = """INSERT INTO changes (short_description) VALUES ('{short_description}');"""
sql_command = format_str.format(short_description =item.short_description)
cursor.execute(sql_command)
cursor.commit()
The problem is that it returns syttaxt error:
pypyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Microsoft Access Driver] Syntax error (missing operator) in query expression
I found that it is because for one the cases I have short_description like this one:
The Service Request status is not changing to \"OPEN', once dispatched
to another group
the problem is for " ' " after OPEN.
to provide you full picture here. Actually the string I see is this:
The Service Request status is not changing to "OPEN', once dispatched
to another group
The string with "\" I get from the API for the application which serves the data. It adds "\" to escape string, but not everywhere.
The question is - what will be the simplest way to solve it?
Theoretically I could replace\remove unwanted signs, but what in case I want to keep it as it is?
For any other cases all works fine.
You should to use parameters to avoid sql injection:
for item in changes:
sql_command = """INSERT INTO changes (short_description) VALUES (?);"""
cursor.execute(sql_command, (item.short_description,) )
cursor.commit()
I am currently trying to use pyodbc to select data from a table within Database A and insert it into a table within Database B. I was able to establish connections with both databases, so I know there is no error there. Additionally, my first cursor.execute command (line #9) works as I was able to print all the data.
The issue I am running into is when I try and insert the data from the first cursor.execute command into Database B. There are a few questions on SO regarding this same error, however I have checked to ensure I am not committing on of those errors. All the data types are accepted within SQL Server, I have the correct number of parameters and parameter markers, and I have ensured that the columns within my Python code match both the input and output tables. I am completely stuck and would greatly appreciate any help.
The specific error I am getting is:
('HYC00', '[HYC00] [Microsoft][ODBC SQL Server Driver]Optional feature
not implemented (0) (SQLBindParameter)')
Please see my code below:
import pyodbc
import time
cnxn1 = pyodbc.connect(r"DRIVER={SQL Server Native Client 11.0};SERVER='Server';" + \
"DATABASE='DatabaseA';Trusted_Connection=Yes")
cursor1 = cnxn1.cursor()
cnxn2 = pyodbc.connect(r"DRIVER={SQL Server};SERVER='Server'," + \
"user='Username', password='Password', database='DatabaseB'")
cursor2 = cnxn2.cursor()
SQL = cursor1.execute("select * from table.DatabaseA")
SQL2 = """insert into table.DatabaseB([col1], [col2], [col3], [col4],[col5], [col6], [col7],
[col8], [col9], [col10], [col11], [col12], [col13], [col14],
[col15], [col16],[col17], [col18], [col19], [col20], [col21],
[col22], [col23], [col24], [col25], [col26], [col27], [col28],
[col29], [col30], [col31])
values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"""
for row in cursor1.fetchall():
cursor2.execute(SQL2,row)
In regard to the last two lines of code, I have also tried the following with no success:
for row in SQL:
cursor2.execute(SQL2,row)