Hello,

I am having problems accessing a SQLite db file across multiple processes. I created an extremely simple app in PySide (a Python binding for Qt) to demonstrate. Given the app code below, my two questions are:

(1.) I would think that, in running this app across multiple processes, db.isOpen() would, in instances of the app opened after the first, evaluate to True. I reviewed the QT source code and it isn't clear to me that this shouldn't be the case. I did notice, though, that the SQLite driver's open() function immediately closes the DB connection if it's already open. (https://qt.gitorious.org/qt/qt/sourc...qlite.cpp#L545)

(2.) If I open more than one instance of this app, then all instances (including the first opened) are prevented at all times from writing to the database file. Calling the model's insertRow() method hangs the app instance for 5 seconds (which I believe is SQLite's default busy signal time) and prints to the console the error "database is locked." To the question "Can multiple applications or multiple instances of the same application access a single database file at the same time?", the SQLite FAQ reads:

Multiple processes can have the same database open at the same time. Multiple processes can be doing a SELECT at the same time. But only one process can be making changes to the database at any moment in time, however.
So my second question is: why is the database locked? After all, I am only attempting to perform a single database write operation from a single process.

Below is the test app I created in PySide. For reference, I am using Python 2.7.3, PySide v1.2.1, Qt 4.8, and SQLite 3, and running on Windows 7.

Qt Code:
  1. from PySide.QtCore import *
  2. from PySide.QtGui import *
  3. from PySide.QtSql import *
  4. import sys
  5.  
  6. class MyDlg(QDialog):
  7.  
  8. def __init__(self):
  9. super(MyDlg, self).__init__()
  10. db = QSqlDatabase.addDatabase("QSQLITE")
  11. db.setDatabaseName("C:/temp/testfile.db")
  12. if db.isOpen():
  13. print "Database is already open by another process!"
  14. db.open()
  15.  
  16. self.model = ListModel()
  17. view = QListView()
  18. view.setModel(self.model)
  19. add_button = QPushButton("Insert row")
  20. layout = QVBoxLayout()
  21. layout.addWidget(view)
  22. layout.addWidget(add_button)
  23. self.setLayout(layout)
  24.  
  25. add_button.clicked.connect(self.addRow)
  26.  
  27. def addRow(self):
  28. text, o = QInputDialog.getText(self, "Enter a row to add", "Text")
  29. self.model.insertRow(self.model.rowCount()+1, QModelIndex(), text)
  30.  
  31. class ListModel(QAbstractListModel):
  32.  
  33. def __init__(self):
  34. super(ListModel, self).__init__()
  35. self.data_query = QSqlQuery()
  36. self.data_query.prepare("SELECT name FROM names WHERE rowid=?")
  37. self.count_query = QSqlQuery()
  38. self.count_query.prepare("SELECT COUNT(1) FROM names")
  39. self.insert_query = QSqlQuery()
  40. self.insert_query.prepare("INSERT INTO names VALUES (?)")
  41.  
  42. def rowCount(self, parent=QModelIndex()):
  43. self.count_query.exec_()
  44. self.count_query.next()
  45. return self.count_query.value(0)
  46.  
  47. def data(self, index, role=Qt.DisplayRole):
  48. if not index.isValid():
  49. return None
  50. if role == Qt.DisplayRole:
  51. self.data_query.addBindValue(index.row() + 1)
  52. self.data_query.exec_()
  53. self.data_query.next()
  54. return self.data_query.value(0)
  55.  
  56. def insertRow(self, row, parent=QModelIndex(), text="Default"):
  57. self.insert_query.addBindValue(text)
  58. if self.insert_query.exec_():
  59. self.dataChanged.emit(self.index(row, 0), self.index(row, 0))
  60. return True
  61. else:
  62. print self.insert_query.lastError().databaseText()
  63. return False
  64.  
  65. def main():
  66. app = QApplication(sys.argv)
  67. dlg = MyDlg()
  68. dlg.show()
  69. app.exec_()
  70.  
  71. main()
To copy to clipboard, switch view to plain text mode 

I know the latter question has more to do with SQLite, but any help is very much appreciated!