Fix bug 1013 - "connect to QSqlTableModel.primeInsert() causes crash"
This commit is contained in:
parent
f57d4d4dbc
commit
4ba7cd90d6
5 changed files with 62 additions and 25 deletions
|
|
@ -81,6 +81,9 @@
|
||||||
<include file-name="QSqlField" location="global"/>
|
<include file-name="QSqlField" location="global"/>
|
||||||
</extra-includes>
|
</extra-includes>
|
||||||
<modify-function signature="append(QSqlField)" access="non-final"/>
|
<modify-function signature="append(QSqlField)" access="non-final"/>
|
||||||
|
<inject-code position="end">
|
||||||
|
Shiboken::TypeResolver::createReferenceTypeResolver< ::QSqlRecord >("QSqlRecord&");
|
||||||
|
</inject-code>
|
||||||
</value-type>
|
</value-type>
|
||||||
|
|
||||||
<value-type name="QSqlError">
|
<value-type name="QSqlError">
|
||||||
|
|
|
||||||
|
|
@ -456,7 +456,7 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList
|
||||||
(*data)[index++] = m_emptyMethod; // func name
|
(*data)[index++] = m_emptyMethod; // func name
|
||||||
|
|
||||||
(*data)[index++] = nullIndex; // arguments
|
(*data)[index++] = nullIndex; // arguments
|
||||||
(*data)[index++] = (it->type().size() > 0 ? registerString(it->type(), strings) : nullIndex); // normalized type
|
(*data)[index++] = !it->type().isEmpty() ? registerString(it->type(), strings) : nullIndex; // normalized type
|
||||||
(*data)[index++] = nullIndex; // tags
|
(*data)[index++] = nullIndex; // tags
|
||||||
(*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot);
|
(*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ namespace {
|
||||||
static PyObject *metaObjectAttr = 0;
|
static PyObject *metaObjectAttr = 0;
|
||||||
|
|
||||||
static int callMethod(QObject* object, int id, void** args);
|
static int callMethod(QObject* object, int id, void** args);
|
||||||
static PyObject* parseArguments(QList<QByteArray> paramTypese, void** args);
|
static PyObject* parseArguments(const QList< QByteArray >& paramTypes, void** args);
|
||||||
static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args);
|
static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args);
|
||||||
|
|
||||||
#ifdef IS_PY3K
|
#ifdef IS_PY3K
|
||||||
|
|
@ -420,27 +420,33 @@ int SignalManager::callPythonMetaMethod(const QMetaMethod& method, void** args,
|
||||||
Q_ASSERT(pyMethod);
|
Q_ASSERT(pyMethod);
|
||||||
|
|
||||||
Shiboken::GilState gil;
|
Shiboken::GilState gil;
|
||||||
PyObject* pyArguments = NULL;
|
PyObject* pyArguments = 0;
|
||||||
|
|
||||||
if (isShortCuit)
|
if (isShortCuit)
|
||||||
pyArguments = reinterpret_cast<PyObject*>(args[1]);
|
pyArguments = reinterpret_cast<PyObject*>(args[1]);
|
||||||
else
|
else
|
||||||
pyArguments = parseArguments(method.parameterTypes(), args);
|
pyArguments = parseArguments(method.parameterTypes(), args);
|
||||||
|
|
||||||
//keep the returnType this call be destroyed after method call
|
if (pyArguments) {
|
||||||
QByteArray returnType = method.typeName();
|
|
||||||
|
|
||||||
Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, pyArguments));
|
Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, pyArguments));
|
||||||
|
|
||||||
if (!isShortCuit)
|
if (!isShortCuit && pyArguments)
|
||||||
Py_XDECREF(pyArguments);
|
Py_DECREF(pyArguments);
|
||||||
|
|
||||||
if (retval.isNull()) {
|
if (!retval.isNull() && retval != Py_None && !PyErr_Occurred()) {
|
||||||
PyErr_Print();
|
const char* returnType = method.typeName();
|
||||||
} else {
|
if (returnType && std::strcmp("", returnType)) {
|
||||||
if (returnType.size() > 0)
|
Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(returnType);
|
||||||
Shiboken::TypeResolver::get(returnType)->toCpp(retval, &args[0]);
|
if (typeResolver)
|
||||||
|
typeResolver->toCpp(retval, &args[0]);
|
||||||
|
else
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "Can't fidn type resolver \"%s\" to call Python meta method.", returnType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
PyErr_Print();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -541,15 +547,12 @@ static int callMethod(QObject* object, int id, void** args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject* parseArguments(QList<QByteArray> paramTypes, void** args)
|
static PyObject* parseArguments(const QList<QByteArray>& paramTypes, void** args)
|
||||||
{
|
{
|
||||||
PyObject* preparedArgs = NULL;
|
int argsSize = paramTypes.count();
|
||||||
Py_ssize_t argsSize = paramTypes.count();
|
PyObject* preparedArgs = PyTuple_New(argsSize);
|
||||||
|
|
||||||
if (argsSize)
|
for (int i = 0, max = argsSize; i < max; ++i) {
|
||||||
preparedArgs = PyTuple_New(argsSize);
|
|
||||||
|
|
||||||
for (int i = 0, max = paramTypes.count(); i < max; ++i) {
|
|
||||||
void* data = args[i+1];
|
void* data = args[i+1];
|
||||||
const char* dataType = paramTypes[i].constData();
|
const char* dataType = paramTypes[i].constData();
|
||||||
|
|
||||||
|
|
@ -558,12 +561,12 @@ static PyObject* parseArguments(QList<QByteArray> paramTypes, void** args)
|
||||||
PyObject* arg = tr->toPython(data);
|
PyObject* arg = tr->toPython(data);
|
||||||
PyTuple_SET_ITEM(preparedArgs, i, arg);
|
PyTuple_SET_ITEM(preparedArgs, i, arg);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
PyErr_Format(PyExc_TypeError, "Can't call meta function because I have no idea how to handle %s", dataType);
|
PyErr_Format(PyExc_TypeError, "Can't call meta function because I have no idea how to handle %s", dataType);
|
||||||
Py_DECREF(preparedArgs);
|
Py_DECREF(preparedArgs);
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return preparedArgs;
|
return preparedArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
|
PYSIDE_TEST(bug_1013.py)
|
||||||
PYSIDE_TEST(qsqldatabaseandqueries_test.py)
|
PYSIDE_TEST(qsqldatabaseandqueries_test.py)
|
||||||
PYSIDE_TEST(qvarianttype_test.py)
|
PYSIDE_TEST(qvarianttype_test.py)
|
||||||
|
|
|
||||||
30
tests/QtSql/bug_1013.py
Normal file
30
tests/QtSql/bug_1013.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
from PySide.QtCore import *
|
||||||
|
from PySide.QtSql import *
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestBug1013 (unittest.TestCase):
|
||||||
|
|
||||||
|
def someSlot(self, row, record):
|
||||||
|
record.setValue(0, 2)
|
||||||
|
self._wasCalled = True
|
||||||
|
|
||||||
|
def testIt(self):
|
||||||
|
app = QCoreApplication([])
|
||||||
|
db = QSqlDatabase.addDatabase('QSQLITE')
|
||||||
|
db.setDatabaseName(':memory:')
|
||||||
|
db.open()
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.exec_('CREATE TABLE "foo" (id INT);')
|
||||||
|
model = QSqlTableModel()
|
||||||
|
model.setTable('foo')
|
||||||
|
|
||||||
|
self._wasCalled = False
|
||||||
|
model.primeInsert.connect(self.someSlot)
|
||||||
|
model.select()
|
||||||
|
QTimer.singleShot(0,lambda: model.insertRow(0) and app.quit())
|
||||||
|
app.exec_()
|
||||||
|
self.assertTrue(self._wasCalled)
|
||||||
|
self.assertEqual(model.data(model.index(0, 0)), 2)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue