[PyQt] QSqlQuery / Firebird: alternating two prepared queries

Sibylle Koczian Sibylle.Koczian at t-online.de
Wed Jan 23 20:17:13 GMT 2008


Hello,

the script below should take the strings in the list newData and put the
contents into two different tables of the Firebird example database
"employee.fdb". Strings starting with "C" belong to the "customer" table and
the insert statement returns the newly created cust_no (new in firebird 2.0).
Strings starting with "O" belong to table "sales" and their content is 
combined with the last new cust_no to form a new record.

In the present form, with all "transaction()" and "commit()" calls commented
out, I get the DatabaseError "insOrder deadlock Unable to execute query". Same
error if I uncomment the calls labeled "Transaction use 1". This probably
shouldn't work because the documentation says "When using transactions you 
must start the transaction before you create your query." - but it would be 
the sensible way to do the inserts.

If I uncomment instead the calls labeled "Transaction use 2", then I get 
another error message from the second call to insCustomer: "insCustomer/exec 
The cursor identified in a FETCH or CLOSE statement is not open. Unable to 
close statement"

In all the cases no new record gets into the database. What is wrong? Of
course, in this very small example I could first put all the "C" records in,
collect the new cust_no values in a list and process them together with 
the "O" records. But what if this is no tiny example list, but a huge file?

Thanks for any shove in the right direction,
Sibylle


import sys
from PyQt4.QtCore import *
from PyQt4.QtSql import *

newData = ['C;Moritz;Germany', 'O;V08A0001;141;520.10', 
           'C;Capitalism Kill & Destroy Ltd.;England', 'O;V08A0002;6;7200', 
           'C;Camorra Corp.;Italy', 'O;V08A0003;121;240', 
           'C;Adam & Eve;Austria', 'O;V08A0004;141;3500', 
           'C;Toblerone Inc.;Switzerland', 'O;V08A0005;141;689.50']

class DatabaseError(Exception):
    pass

def employeeConn(user='sysdba', passwd='masterkey'):
    db = QSqlDatabase.addDatabase('QIBASE')
    db.setHostName('localhost')
    db.setConnectOptions('ISC_DPB_LC_CTYPE=ISO8859_1')
    db.setDatabaseName('Employee')
    db.setUserName(user)
    db.setPassword(passwd)
    ok = db.open()
    msg = (db.lastError().text() if not ok else '')
    return (ok, msg)

def insCustomer(custdata, query):
    (idchar, custname,  custcountry) = custdata.split(';')
    custno_var = QVariant()
    query.bindValue(':customer', QVariant(custname))
    query.bindValue(':country', QVariant(custcountry))
    if not query.exec_():
        raise DatabaseError, 'insCustomer/exec %s' % query.lastError().text()
    if query.first():
        custno_var = query.value(0)
    else:
        raise DatabaseError, 'insCustomer/first %s' % query.lastError().text()
    return custno_var
    
def insOrder(custno_var, orderdata, query):
    (idchar, orderno, salesrep, total) = orderdata.split(';')
    query.bindValue(':po_number', QVariant(orderno))
    query.bindValue(':cust_no', custno_var)
    query.bindValue(':sales_rep', QVariant(salesrep))
    query.bindValue(':total_value', QVariant(total))
    if not query.exec_():
        raise DatabaseError, 'insOrder %s' % query.lastError().text()
   
def main(args):
    app = QCoreApplication(args)
    (ok, msg) = employeeConn()
    if not ok:
        print msg
        sys.exit(1)
    try:
        # Transaction use 2
#        QSqlDatabase.database().transaction()
        custQuery = QSqlQuery()
        custQuery.prepare('INSERT INTO CUSTOMER (customer, country) '
                          'VALUES (:customer, :country) RETURNING cust_no')
        orderQuery = QSqlQuery()
        orderQuery.prepare('INSERT INTO SALES (po_number, cust_no, 
sales_rep, '
                           'total_value) VALUES (:po_number, :cust_no, '
                           ':sales_rep, ':total_value)')
        new_custno = QVariant()
        for data in newData:
            # Transaction use 1
#            QSqlDatabase.database().transaction()
            if data.startswith('C'):
                new_custno = insCustomer(data, custQuery)
            elif data.startswith('O'):
                insOrder(new_custno, data, orderQuery)
            # Transaction use 1
#            QSqlDatabase.database().commit()
            print data
        # Transaction use 2
#        QSqlDatabase.database().commit()
    except DatabaseError, e:
        print e
    finally:
        QSqlDatabase.database().close()
    print 'Ready.'
    
if __name__ == '__main__':
    main(sys.argv)

-- 
Dr. Sibylle Koczian


More information about the PyQt mailing list