define parameter in update query in python psycopg2 - python

This my python code which is used to perform update operation from reading the csv file. I tried with this also. It doesn't work out.
for i in cin:
try:
conn=psycopg2.connect("dbname=pharmaflare user=postgres")
cursor=conn.cursor()
cursor.execute("UPDATE pharmaflare_drug_interaction SET se_interaction ='%s' WHERE primary_drug ='%s' AND secondary_drug ='%s' AND side_effect ='%s'"%(i[3],i[0],i[1],i[2]))
conn.commit()
cursor.close()
conn.close()
#print "done",i[0],i[1],i[2],i[3]
except Exception as e:
cerr.writerow(i)
ferr.flush()
traceback.print_exc(file=sys.stdout)
continue
Here I am facing the exception like syntax error due to the QUOTE's problem:
Wherever the single quotes presents this exception arises.
Traceback (most recent call last):
File "<ipython console>", line 5, in <module>
ProgrammingError: syntax error at or near "S"
LINE 1: ...secondary_drug ='NEUER' AND side_effect ='MENIERE'S DISEASE'
Is there any alternative way available to define query statement without troubling the Quotes problem?

There are a couple ways to solve it. The easy/hack way to do it is to employ the re.escape() function. That function can be thought of as an equivalent to PHP's addslashes() function, though it pains me to make that comparison.
Having said that, my reading indicates psycopg2 takes advantage of PEP 249. If that's true, then you should be able to pass in parameterized queries and have it escape them for you.

Related

Does Pyodbc treat SQLWarnings as errors?

I am writting Python code to connect to a MS SQL Server using Pyodbc.
So far, things have been going smoothly and I managed to call several Stored Procedures on the database.
I have now, however run into troubles. The stored procedure I am calling is outputting sqlwarnings regarding null values
Warning: Null value is eliminated by an aggregate or other SET operation. (8153)
While this is something that could/should be treated in the SQL part I would like to simply ignore it for now on the Python level.
The code is called in a fairly standard way (I think), like so (not providing a minimal code for now)
conn = None
try:
#Connection is created in another class, but retrieved here. Works ok.
conn = db_conn.connect_to_db()
cur = conn.cursor()
cur.execute(str_sql)
# This is a hack, but I think is unrelated to the issue
# Sorry I haven't found a better way to make pyodbc wait for the SP to finish than this
# https://stackoverflow.com/questions/68025109/having-trouble-calling-a-stored-procedure-in-sql-server-from-python-pyodbc
while cur.nextset():
time.sleep(1)
cur.commit()
cur.close()
return True
except db.Error as ex:
log.error(str(ex.args[1]))
raise ConnectionError(ex.args[1])
The problem is the ConnectionError is raised on the SQLWarning. Can pyodbc be configured to ignore this?
Related posts tells me to turn off the ANSI Warnings on the Stored procedure, but I think that is a work around.
Other posts has stuff about importing '''warnings''' and catchAll() warnings, but this is tried, but didn't work. I guess since pyodbc sees it as an error thus the warning part never reached Python.
Did I misunderstand something or is it not possible?
Python version 3.7
Pyodbc version 4.0.32
ODBC Driver 17 for SQL Server
Called from macOS
Okay, so I did somewhat resolve my issue.
The stored procedure actually did produce an error in my call. I found this after testing the call directly on the database.
So to answer my own question no pyodbc doesn't treat warnings as errors.
I did however only see the sql warning in the errors (or at least as far as I could tell). The real error thrown by a THROW 50001, ...... was no where to be seen in the pyodbc.Error.
I tried to make a minimal reproducible example, but failed to do so. The following code seems to ignore the throwing of the error. I assume I made some mistake and this kind of sql string cannot be used. The expected behavior would be to land in the ERROR part, but instead the correct values are returned in the fetchall.
import pyodbc
def test_warnings_after_errors():
# Connect to your own MS SQL database
conn = None
cur = conn.cursor()
try:
cur.execute('''
SELECT C1,
MAX(C2) as MaxC2
FROM (VALUES(1,1),
(1,2),
(2,4),
(1, NULL),
(2,4)) as V(C1, C2)
GROUP BY C1
THROW 51000, 'Will we get this error back?', 1;
'''
)
result = cur.fetchall()
print(result)
except pyodbc.Error as error:
print(error.args[1])
print("Executed sql")
If I remove the whole select part the error is thrown as expected. The code runs as written in Azure Data Studio against the server and in that case it will return the error (and warnings regarding null before that).
To actually remove my error I had to do a cleanup of data, but that was totally unrelated to the issues posted here.
In my case I can live with the "weird" sqlwarning in case of error thrown, but it still puzzles me.

pyodbc MERGE INTO error: HY000: The driver did not supply an error

I'm trying to execute many (~1000) MERGE INTO statements into oracledb 11.2.0.4.0(64bit) using python 3.9.2(64bit) and pyodbc 4.0.30(64bit). However, all the statements return an exception:
HY000: The driver did not supply an error
I've tried everything I can think of to solve this problem, but no luck. I tried changing code, encodings/decodings and ODBC driver from oracle home 12.1(64bit) to oracle home 19.1(64bit). I also tried using pyodbc 4.0.22 in which case the error just changed into:
<class 'pyodbc.ProgrammingError'> returned a result with an error set
Which is not any more helpful error than the first one. The issue I assume cannot be the MERGE INTO statement itself, because when I try running them directly in the database shell, it completes without issue.
Below is my code. I guess I should also mention the commands and parameters are read from stdin before being executed, and oracledb is using utf8 characterset.
cmds = sys.stdin.readlines()
comms = json.loads(cmds[0])
conn = pyodbc.connect(connstring)
conn.setencoding(encoding="utf-8")
cursor = conn.cursor()
cursor.execute("""ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD"T"HH24:MI:SS.....'""")
for comm in comms:
params = [(None) if str(x)=='None' or str(x)=='NULL' else (x) for x in comm["params"]]
try:
cursor.execute(comm["sql"],params)
except Exception as e:
print(e)
conn.commit()
conn.close()
Edit: Another things worth mentioning for sure - this issue began after python2.7 to 3.9.2 update. The code itself didn't require any changes at all in this particular location, though.
I've had my share of HY000 errors in the past. It almost always came down to a syntax error in the SQL query. Double check all your double and single quotes, and makes sure the query works when run independently in an SQL session to your database.

In Python, how can the traceback module be used to find where an exception is generated?

I'm working on a convoluted FOSS project that utilizes GTK+3. When a flow graph is generated and attempted to run it, it generates the following error:
'Page' object has no attribute 'get_flow_graph'
There are 30 different files that have the generic "...object has no attribute..." exception listed in the code, and there are 4 files that call the function get_flow_graph().
So what I want to figure out is which of the 30 files that generate that particular error message is being executed, and preferably which of the 4 files with the function are causing the error in the first place.
I'm trying to use Python's traceback module to figure out where, specifically, the exception is being generated. I think I figured out the file that is calling the function that ultimately errors out, but I can't seem to get the traceback module to provide much more.
For example, if I wrap the function like this:
try:
fg = self.page.get_flow_graph()
except Exception:
traceback.print_exc()
then I just get
File "<redacted>", line 66, in _popen
fg = self.page.get_flow_graph()
AttributeError: 'Page' object has no attribute 'get_flow_graph'
'Page' object has no attribute 'get_proc'
as the output. So I get the original exception but a new get_proc error that doesn't help me but is obviously associated with trying to use traceback.
Maybe I'm not putting the trace in the correct file/location, or maybe I'm asking too much, but how should I write it to figure out the actual stack trace for the original AttributeError?
Does using
except AttributeError as e:
print(e.__traceback__.tb_lineno)
print(e.__traceback__.tb_frame)
instead, helps you further? (really asking, not being ironic)

Import text files into mysqldb

For a current assignment, I must import 2 .txt files into a MySQLdb with python. I'm having immense trouble. I have tried various methods and I simply can't do it.
I've searched through this site and many others over the past few days and I simply cannot get this to work. Whenever I've tried to adapt another person's solution to my own code, it fails - so I figure I should ask for help directly for my own code.
This is what I have so far:
import MySQLdb
# connect to database
mydb = MySQLdb.connect("localhost","root","0dy5seuS","cars_db")
# define the function
def data_entry(cars_for_sale):
# cursor creation
cursor = mydb.cursor()
#load the file 'cars_for_sale.txt' into the database under the table 'cars_for_sale'
sql = """LOAD DATA LOCAL INFILE 'cars_for_sale.TXT'
INTO TABLE cars_for_sale
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\r\n'"""
#execute the sql function above
cursor.execute(sql)
#commit to the database
mydb.commit()
#call data_entry(cars_for_sale) function
data_entry(cars_for_sale)
mydb.close()
I can hardly wrap my head around it, any help would be appreciated it.
I now get the following feedback from the testing function:
Trying:
data_entry("cars_for_sale") Expecting:
The number of rows inserted to cars_for_sale is 7049
**************************************** File "main", line 4, in main Failed example:
data_entry("cars_for_sale") Exception raised:
Traceback (most recent call last):
File "C:\Python27\lib\doctest.py", line 1289, in __run
compileflags, 1) in test.globs
File "", line 1, in
data_entry("cars_for_sale")
File "E:/Uni/104/Portfolio 2/MediumTask_DataStatistics/question/TEST2_data_statistics.py", line 270, in data_entry
data_entry(cars_for_sale) *it repeats this last portion several hundred/thousand times"
The following few lines are after the repeated error above.
File "C:\Python27\lib\site-packages\MySQLdb\connections.py", line
243, in cursor return (cursorclass or self.cursorclass)(self)
File "C:\Python27\lib\site-packages\MySQLdb\cursors.py", line 51, in
init from weakref import proxy RuntimeError: maximum recursion depth exceeded while calling a Python object
I'm aware that this is an infinite recursion although I have no idea how to stop it.
Thanks
The following code reproduces your error "RuntimeError: maximum recursion depth exceeded while calling a Python object":
def data_entry(cars_for_sale):
data_entry(cars_for_sale)
You don't need recursion here (and it is used incorrectly anyway).
I'm aware that this is an infinite recursion although I have no idea how to stop it.
Just remove the data_entry call inside the data_entry function.

Exception binding variables with cx_Oracle in python

Okay, so I'm connected to an oracle database in python 2.7 and cx_Oracle 5.1 compiled against the instant client 11.2. I've got a cursor to the database and running SQL is not an issue, except this:
cursor.execute('ALTER TRIGGER :schema_trigger_name DISABLE',
schema_trigger_name='test.test_trigger')
or
cursor.prepare('ALTER TRIGGER :schema_trigger_name DISABLE')
cursor.execute(None,{'schema_trigger_name': 'test.test_trigger'})
both result in an error from oracle:
Traceback (most recent call last):
File "connect.py", line 257, in
cursor.execute('ALTER TRIGGER :schema_trigger_name DISABLE',
schema_trigger_name='test.test_trigger')
cx_Oracle.DatabaseError: ORA-01036: illegal variable name/number
While running:
cursor.execute('ALTER TRIGGER test.test_trigger DISABLE')
works perfectly. What's the issue with binding that variable?
In your example test.test_trigger is not a variable but an object. You can only bind variables (that can be replaced by a value).
The query you are trying to run would be logically equivalent to:
ALTER TRIGGER 'test.test_trigger' DISABLE
Binding in this case won't work, you will have to build the query dynamically.
You normally can't bind an object name in Oracle. For variables it'll work but not for trigger_names, table_names etc.

Categories