I use sqlite3 version 2.6.0 python 2.7.
Why queries starts with comment ('/* */' or '--') cause an implicit commit?
Example.
#!/usr/bin/python
import os
try:
os.remove('db1')
except OSError:
pass
import sqlite3
cur1 = sqlite3.connect('db1').cursor()
cur2 = sqlite3.connect('db1').cursor()
# In first cursor open a transaction
cur1.execute('CREATE TABLE test(t text);')
cur1.execute('BEGIN;')
cur1.execute('INSERT INTO test(t) VALUES (\'123456\');')
# In first cursor first transaction is invisible.
print 'Cursor 1'
print cur1.execute('SELECT * FROM test;').fetchall()
# In second cursor first transaction is invisible.
print 'Cursor 2'
print cur2.execute('SELECT * FROM test;').fetchall()
# In first cursor execute a query, begin with comments.
# Here is implicit commit!
print 'Cursor 1'
print cur1.execute('/* 123 */ SELECT * FROM test;').fetchall()
# In second cursor data now visible!
print 'Cursor 2'
print cur2.execute('SELECT * FROM test;').fetchall()
After a query with comment at the begin, cursor cur1 implicitly commits its changes. Is it a bug or a feature?
This is a long-standing bug in the Python 2 sqlite3 bindings. See issue 10740:
As evidence of that, note that the existing statement detection code is broken: it doesn't strip comments first! A simple SELECT statement preceeded by a comment will implicitly commit!
The bindings will implicitly commit before DDL statements, but the way this is implemented it will also do so when a line starts with a comment.
Related
I am teaching myself python and have a function called mysqltimedcheck()
This executes a very basic mySQL SELECT statement and returns the rowcount.
If i cange the value of 'shown' from 0 to 1 in the mysql table (while the script is running) for example the rowcount does not change.
I can see when debugging that it reruns the cursor.execute line again but still prints an old value
here is my function:
def mysqltimedcheck():
cursor = mydb.cursor(buffered=True)
window.after(1500, mysqltimedcheck)
cursor.execute("SELECT * FROM alerts WHERE shown = 0")
rc = cursor.rowcount
print(rc)
If i restart my test application then it pulls the correct rowcount value but changing this value while running does not show as correct.
I feel im missing something very basic.
Thanks for your help
All credit to #LabibaKanij
adding mydb.commit() worked correctly and allowed me to change the value in the table and it changed for my script without restarting.
I am trying to call dbms_random.seed(42) on my DB, see ref. I need to use python and the JayDeBeApi connector. So far I've only been able to execute select statement without issue. I fail to understand what I am doing wrong.
It seems that JayDeBeApi does not provide the callproc method, so I cannot use it:
AttributeError: 'Cursor' object has no attribute 'callproc'
I've naively tried:
conn = jaydebeapi.connect('oracle.jdbc.driver.OracleDriver',
['jdbc:oracle:thin:#server:1521/dbname', 'user', 'password'])
curs = conn.cursor()
sql="exec dbms_random.seed(42)"
curs.execute(sql)
but this leads to: Error: ORA-00900: invalid SQL statement
I've tried two solutions which seems to have correct syntax, but since the generator is not deterministic, I believe they actually failed:
Using begin/end:
sql="begin dbms_random.seed(42); end;"
curs.execute(sql)
Using call:
sql="{ call dbms_random.seed(42) }"
curs.execute(sql)
So my question is: how do I call dbms_random.seed(42) on Oracle using JayDeBeApi ? As a side question how do I check that a statement has actually failed to execute (no exception was thrown and return value for execute is undefined.)
Update:
In fact the seed initialization is working as expected, since the results are what I expect for:
sql="SELECT DBMS_RANDOM.value FROM dual"
curs.execute(sql)
data = curs.fetchall()
print(data)
However I still see some odd behavior for my random query selection:
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
For some reason in the latter case, the DBMS_RANDOM.RANDOM is actually random...
After multiple trial and error, I believe this is just a side effect. Since I was not doing the cleanup pass:
curs.close()
conn.close()
jpype.shutdownJVM()
The query would lead to somewhat undefined behavior. Now that I have a proper cleanup code, I am getting deterministic results when calling multiples times my python script.
I'm trying to figure out how to use the MySQLdb library in Python (I am novice at best for both of them).
I'm following the code here, specifically:
cursor = conn.cursor ()
cursor.execute ("DROP TABLE IF EXISTS animal")
cursor.execute ("""
CREATE TABLE animal
(
name CHAR(40),
category CHAR(40)
)
""")
cursor.execute ("""
INSERT INTO animal (name, category)
VALUES
('snake', 'reptile'),
('frog', 'amphibian'),
('tuna', 'fish'),
('racoon', 'mammal')
""")
print "Number of rows inserted: %d" % cursor.rowcount
cursor.close ()
conn.close ()
I can change this code to create or drop tables, but I can't get it to actually commit the INSERT. It returns the row.count value as expected (even when I change the value in the table, it changes to what I expect it to be).
Every time I look into the database with PHPMyAdmin there are no inserts made. How do I commit the INSERT to the database?
You forget commit data changes, autocommit is disabled by default:
cursor.close ()
conn.commit ()
conn.close ()
Quoting Writing MySQL Scripts with Python DB-API documentation:
"The connection object commit() method commits any outstanding changes
in the current transaction to make them permanent in the database. In
DB-API, connections begin with autocommit mode disabled, so you must
call commit() before disconnecting or changes may be lost."
The documentation I've run across researching this indicates that the way to do it for other databases is to use multiple statements in your query, a la:
>>> cursor = connection.cursor()
>>> cursor.execute("set session transaction isolation level read uncommitted;
select stuff from table;
set session transaction isolation level repeatable read;")
Unfortunately, doing that yields no results, as apparently the Python DB API (or maybe just this implementation of it?) doesn't support multiple recordsets within a single query.
Has anyone else had success with this in the past?
I don't think this works for the MySQLdb driver; you'll have to issue separate queries:
cur = conn.cursor()
cur.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED")
cur.execute("SELECT ##session.tx_isolation")
print cur.fetchall()[0]
cur.execute("SELECT * FROM bar")
print cur.fetchall()
cur.execute("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ")
cur.execute("SELECT ##session.tx_isolation")
print cur.fetchall()[0]
# output
('READ-UNCOMMITTED',)
(('foo',), ('bar',))
('REPEATABLE-READ',)
The MySQLdb cursor's execute() method only sees the first query up to the semicolon:
cur.execute("SELECT * FROM bar WHERE thing = 'bar'; SELECT * FROM bar")
print cur.fetchall()
# output
(('bar',),)
cur.executemany("SELECT * FROM bar WHERE thing = 'bar'; SELECT * FROM bar")
print cur.fetchall()
use cur.executemany to run multiple sql statements with ; separated.
I'm having some trouble updating a row in a MySQL database. Here is the code I'm trying to run:
import MySQLdb
conn=MySQLdb.connect(host="localhost", user="root", passwd="pass", db="dbname")
cursor=conn.cursor()
cursor.execute("UPDATE compinfo SET Co_num=4 WHERE ID=100")
cursor.execute("SELECT Co_num FROM compinfo WHERE ID=100")
results = cursor.fetchall()
for row in results:
print row[0]
print "Number of rows updated: %d" % cursor.rowcount
cursor.close()
conn.close()
The output I get when I run this program is:
4Number of rows updated: 1
It seems like it's working but if I query the database from the MySQL command line interface (CLI) I find that it was not updated at all. However, if from the CLI I enter UPDATE compinfo SET Co_num=4 WHERE ID=100; the database is updated as expected.
What is my problem? I'm running Python 2.5.2 with MySQL 5.1.30 on a Windows box.
I am not certain, but I am going to guess you are using a INNODB table, and you haven't done a commit. I believe MySQLdb enable transactions automatically.
Call conn.commit() before calling close.
From the FAQ: Starting with 1.2.0, MySQLdb disables autocommit by default
MySQLdb has autocommit off by default, which may be confusing at first. Your connection exists in its own transaction and you will not be able to see the changes you make from other connections until you commit that transaction.
You can either do conn.commit() after the update statement as others have pointed out, or disable this functionality altogether by setting conn.autocommit(True) right after you create the connection object.
You need to commit changes manually or turn auto-commit on.
The reason SELECT returns the modified (but not persisted) data is because the connection is still in the same transaction.
I've found that Python's connector automatically turns autocommit off, and there doesn't appear to be any way to change this behaviour. Of course you can turn it back on, but then looking at the query logs, it stupidly does two pointless queries after connect to turn autocommit off then back on.
Connector/Python Connection Arguments
Turning on autocommit can be done directly when you connect to a database:
import mysql.connector as db
conn = db.connect(host="localhost", user="root", passwd="pass", db="dbname", autocommit=True)
MySQLConnection.autocommit Property
Or separately:
import MySQLdb
conn = MySQLdb.connect(host="localhost", user="root", passwd="pass", db="dbname")
cursor = conn.cursor()
conn.get_autocommit() # will return **False**
conn.autocommit(True) # will make it True
conn.get_autocommit() # Should return **True** now
cursor = conn.cursor()
Explicitly committing the changes is done with
conn.commit()
I have to execute SET autocommit=true on my mysqlWorkbench app script