Using SQLAlchemy I would like to isolate any SQL syntax errors. For instance..
try:
[row for row in db.execute(text("select * from userds"), **args)]
except ProgrammingError as error:
print(error)
I get
(psycopg2.ProgrammingError) relation "userds" does not exist
LINE 1: select * from userds
^
[SQL: 'select * from userds'] (Background on this error at: http://sqlalche.me/e/f405)
And I'm only interested in..
relation "userds" does not exist
Anyone know if this is possible?
I have found a solution to my question. You must catch StatementError and print out the orig attribute on the error object, like so..
from sqlalchemy.exc import StatementError
try:
[r for r in db.execute("invalid statement")]
except StatementError as error:
print(error.orig)
https://github.com/zzzeek/sqlalchemy/blob/699272e4dcb9aa71ebbc0d9487fb6de82d3abc2b/lib/sqlalchemy/exc.py#L280
Related
Trying to automate working process with the tables in MySQL using for-loop
from mysql.connector import connect, Error
def main():
try:
with connect(host="host", user="user",password="password") as connection:
connection.autocommit = True
no_pk_tables_query = """
select tab.table_schema as database_name,
tab.table_name
from information_schema.tables tab
left join information_schema.table_constraints tco
on tab.table_schema = tco.table_schema
and tab.table_name = tco.table_name
and tco.constraint_type = 'PRIMARY KEY'
where tco.constraint_type is null
and tab.table_schema not in('mysql', 'information_schema',
'performance_schema', 'sys')
and tab.table_type = 'BASE TABLE'
order by tab.table_schema,
tab.table_name;
"""
tables_to_cure = []
with connection.cursor() as cursor:
cursor.execute(no_pk_tables_query)
for table in cursor:
tables_to_cure.append(table[1])
print(table[1])
for s_table in tables_to_cure:
cure = """
USE mission_impossible;
ALTER TABLE `{}` MODIFY `ID` int(18) NOT NULL auto_increment PRIMARY KEY;
""".format(s_table)
cursor.execute(cure)
print("Cured {}".format(s_table))
except Error as e:
print(e)
finally:
print("End")
main()
And I get:
quote 2014 (HY000): Commands out of sync; you can't run this command now
If I add connection.commit() inside the for-loop after cursor.execute() I'll get:
_mysql_connector.MySQLInterfaceError: Commands out of sync; you can't run this command now
Does this mean that I'll have to use new connections inside loop instead of cursor?
I've looked it up and found some methods like fetchall() and nextset() but they seem to do other things than simply refreshing current cursor data.
Using connection.autocommit = True seem not to work either as the same error occurs.
Using something like sleep() also doesn't help.
What am I doing wrong here?
Edit
Getting rid of try/except didn't help:
File "/usr/local/lib/python3.8/dist-packages/mysql/connector/connection_cext.py", line 523, in cmd_query
self._cmysql.query(query,
_mysql_connector.MySQLInterfaceError: Commands out of sync; you can't run this command now
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "db.py", line 40, in <module>
main()
File "db.py", line 36, in main
cursor.execute(cure)
File "/usr/local/lib/python3.8/dist-packages/mysql/connector/cursor_cext.py", line 269, in execute
result = self._cnx.cmd_query(stmt, raw=self._raw,
File "/usr/local/lib/python3.8/dist-packages/mysql/connector/connection_cext.py", line 528, in cmd_query
raise errors.get_mysql_exception(exc.errno, msg=exc.msg,
mysql.connector.errors.DatabaseError: 2014 (HY000): Commands out of sync; you can't run this command now
Fixed:
Seems like I've finally figured it out, it's needed to get results from the cursor using fetchall() instead of directly addressing the cursor as an iterator.
with connection.cursor() as cursor:
cursor.execute(no_pk_tables_query)
rows = cursor.fetchall()
with connection.cursor() as cursor:
for table in rows:
try:
print(table[1])
cure = """
ALTER TABLE `{}` MODIFY `ID` int(18) NOT NULL auto_increment PRIMARY KEY;
""".format(table[1])
cursor.execute(cure)
res = cursor.fetchall()
print(res)
except Error as e:
print(e)
Thx everybody
Here's some sample code that shows how the "Commands out of sync" error can occur:
from mysql.connector import connect, Error
# replace asterisks in the CONFIG dictionary with your data
CONFIG = {
'user': '*',
'password': '*',
'host': '*',
'database': '*',
'autocommit': False
}
try:
with connect(**CONFIG) as conn:
try:
with conn.cursor() as cursor:
cursor.execute('select * from ips')
# cursor.fetchall()
finally:
conn.commit()
except Error as e:
print(e)
Explanation:
The code selects all rows from a table called "ips" the contents of which are irrelevant here.
Now, note that we do not attempt to get a rowset (fetchall is commented out). We then try to commit the transaction (even though no changes were made to the table).
This will induce the "Commands out of sync" error.
However, if we take out the comment line and fetch the rowset (fetchall) this problem does not arise.
Explicitly fetching the rowset is equivalent to iterating over the cursor.
If we change the autocommit parameter to True and remove the explicit commit(), we get another error:- "Unread result found".
In other words, it seems that MySQL requires you to get the rowset (or iterate over the cursor) whenever you select anything!
Note that even if autocommit is enabled (True) explicit calls to commit() are permitted
Solutions:
Either ensure that the client application iterates over the entire cursor after SELECT or in the CONFIG dictionary add: 'consume_results': True
whenever I try to run a normal query all works perfectly fine. the code executes and I can get the results but whenever I try to use a prepared statement in python I keep getting the following error:
1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '? WHERE name = ?' at line 1
The code I'm trying to run:
cursor = con.db.cursor(prepared=True)
try:
cursor.execute("SELECT * FROM %s WHERE name = %s", ('operations', 'check', ))
except mysql.connector.Error as error:
print(error)
except TypeError as e:
print(e)
I've tried also to change the tuple object to string and removed one of the '%s' just for checking. but I still get an error for the '%s' synax.
another thing I've tried is to use a dict object so I've changed the '%s' to '%(table)s' and '%(name)s' and used a dict of
{'table': 'operations', 'name': 'check'}
example:
cursor.execute("SELECT * FROM %(table)s WHERE name = %(name)s", {'table': 'operations', 'name': 'check'})
but again it didn't worked and I still got the exception
am I missing something?
Thanks in advance!
-------- Edit --------
Thanks to #khelwood, I've fixed the problem.
as #khelwood mentioned in comments the problem was because I tried to use the '%s' as a parameter for table name.
python prepared statements can't handle parameters for things such as table names
so thats what throwed the exception
You can't insert a table name as a query parameter. You can pass the name you're looking for as a parameter, but it should be in a tuple: ("check",)
So
cursor.execute("SELECT * FROM operations WHERE name = %s", ("check", ))
I'm doing a Python application with MySQL and PyMySQL and I'd like to be able to know the number of the MySQL error when I get one so that I can do something different depending on it.
Is there a way to do that with a try-except statement or another way?
Any exception in Python has an args member that shows you how it was constructed. For example:
>>> e = Exception(1, 2, 3, 4)
>>> e.args
(1, 2, 3, 4)
For pymysql, they're always constructed with (errno, errorvalue). So:
try:
do_stuff()
except MySQLError as e:
print('Got error {!r}, errno is {}'.format(e, e.args[0]))
I'm not sure this is guaranteed by the documentation, but you can see how it works pretty easily from the source.
pymysql maps mysql errors to python errors according to the following table:
_map_error(ProgrammingError, ER.DB_CREATE_EXISTS, ER.SYNTAX_ERROR,
ER.PARSE_ERROR, ER.NO_SUCH_TABLE, ER.WRONG_DB_NAME,
ER.WRONG_TABLE_NAME, ER.FIELD_SPECIFIED_TWICE,
ER.INVALID_GROUP_FUNC_USE, ER.UNSUPPORTED_EXTENSION,
ER.TABLE_MUST_HAVE_COLUMNS, ER.CANT_DO_THIS_DURING_AN_TRANSACTION)
_map_error(DataError, ER.WARN_DATA_TRUNCATED, ER.WARN_NULL_TO_NOTNULL,
ER.WARN_DATA_OUT_OF_RANGE, ER.NO_DEFAULT, ER.PRIMARY_CANT_HAVE_NULL,
ER.DATA_TOO_LONG, ER.DATETIME_FUNCTION_OVERFLOW)
_map_error(IntegrityError, ER.DUP_ENTRY, ER.NO_REFERENCED_ROW,
ER.NO_REFERENCED_ROW_2, ER.ROW_IS_REFERENCED, ER.ROW_IS_REFERENCED_2,
ER.CANNOT_ADD_FOREIGN, ER.BAD_NULL_ERROR)
_map_error(NotSupportedError, ER.WARNING_NOT_COMPLETE_ROLLBACK,
ER.NOT_SUPPORTED_YET, ER.FEATURE_DISABLED, ER.UNKNOWN_STORAGE_ENGINE)
_map_error(OperationalError, ER.DBACCESS_DENIED_ERROR, ER.ACCESS_DENIED_ERROR,
ER.CON_COUNT_ERROR, ER.TABLEACCESS_DENIED_ERROR,
ER.COLUMNACCESS_DENIED_ERROR)
if you want to catch the errors then you will need to catch ProgrammingError, DataError, IntegrityError, NotSupportedError, and OperationalError, individually. You can see specifically which mysql error was caught by coercing the exception to a string using str.
try:
#interact with pymysql
except ProgrammingError as e:
print "Caught a Programming Error:",
print e
for name, ddl in TABLES.iteritems():
try:
print("Creating table {}: ".format(name))
db.execute(ddl)
except pymysql.InternalError as error:
code, message = error.args
print ">>>>>>>>>>>>>", code, message
That's a start but loads of other errors exist eg. OperationalError
This question already has an answer here:
cx_oracle Error handling issue
(1 answer)
Closed 10 years ago.
I'm trying a delete a particular row from a table in a try except block but I get the following error
self.returnvals['ERROR_CD'] = error.code
AttributeError: 'str' object has no attribute 'code'
Code:
try:
# code deleting from a table
except cx_Oracle.DatabaseError, ex:
error, = ex.args
self.conn.rollback()
self.returnerr['ID'] = 0
self.returnerr['ERROR_CD'] = error.code
self.returnerr['ERROR_MSG'] = error.message
self.returnerr['TABLE_NAME'] = self.debug_val
Your exception handling is broken. You're getting some sort of error oracle database error thrown inside your try block and it would be useful to see it, but the line in your code
self.returnerr['ERROR_CD'] = error.code
is throwing the error you're reporting because the "error" object is just a string and doesn't have a .code attribute.
Also...
delete from a table
Doesn't look like the actual DML you are attempting. Why don't you post the actual DELETE statement and maybe we can see if there's a syntax error. If this is your literal code, you need to read the documentation. I believe it's supposed to look more like:
import cx_Oracle as db
conn = db.connection()
cur = conn.cursor()
cur.execute("DELETE FROM TABLE WHERE somecolumn = someval")
conn.commit()
conn.close
I got this code..
.....
try:
task_db.cursor.execute('DROP TABLE IF EXISTS `tasks`')
print "Affected: %d" % task_db.cursor.rowcount
except MySQLdb.Error, e:
print "Error ocurred: %s " % e.args[0]
print e
If the tasks table doesn't exist, then I get a warning like
create_database.py:11: Warning: Unknown table 'tasks'
But if the table does exist then I wont get that warning.
Odd?
Catching the MySQLdb.Warning didn't work for me, so I found another way to suppress warnings:
import warnings
warnings.filterwarnings("ignore", "Unknown table.*")
And you can edit the second parameter with whatever you want to suppress.
The most elegant way to avoid Mysql warnings :
from warnings import filterwarnings
import MySQLdb
filterwarnings('ignore', category = MySQLdb.Warning)
It's perfectly correct behaviour. If the table exists, then it's dropped. If it doesn't exist then you get Warning exception which is not the same as Error - you are free to ignore it and nothing bad should happen, but you have to catch it to allow your script to proceed.
EDIT:
To prevent Warning from bubbling up, just catch it as any other exception:
try:
[some code]
except MySQLdb.Warning:
[exception handling code]