]> granicus.if.org Git - python/commitdiff
Applied sqliterow-richcmp.diff patch from Thomas Heller in Issue2152. The
authorGerhard Häring <gh@ghaering.de>
Sun, 4 May 2008 13:15:12 +0000 (13:15 +0000)
committerGerhard Häring <gh@ghaering.de>
Sun, 4 May 2008 13:15:12 +0000 (13:15 +0000)
sqlite3.Row type is now correctly hashable.

Lib/sqlite3/test/factory.py
Modules/_sqlite/row.c

index 9469d79c2eb49732a333d466f2c2ab9bb502bfb3..ff41a9d2aba7ad8691dfa6cf8a855dca4298cdf2 100644 (file)
@@ -131,6 +131,26 @@ class RowFactoryTests(unittest.TestCase):
         self.failUnlessEqual(d["a"], row["a"])
         self.failUnlessEqual(d["b"], row["b"])
 
+    def CheckSqliteRowHashCmp(self):
+        """Checks if the row object compares and hashes correctly"""
+        self.con.row_factory = sqlite.Row
+        row_1 = self.con.execute("select 1 as a, 2 as b").fetchone()
+        row_2 = self.con.execute("select 1 as a, 2 as b").fetchone()
+        row_3 = self.con.execute("select 1 as a, 3 as b").fetchone()
+
+        self.failUnless(row_1 == row_1)
+        self.failUnless(row_1 == row_2)
+        self.failUnless(row_2 != row_3)
+
+        self.failIf(row_1 != row_1)
+        self.failIf(row_1 != row_2)
+        self.failIf(row_2 == row_3)
+
+        self.failUnlessEqual(row_1, row_2)
+        self.failUnlessEqual(hash(row_1), hash(row_2))
+        self.failIfEqual(row_1, row_3)
+        self.failIfEqual(hash(row_1), hash(row_3))
+
     def tearDown(self):
         self.con.close()
 
index 8f155d92a4d7d13ffeceb99decaa6a394cde9773..34192673a63b2a677a9772aba158d1f31db0bbed 100644 (file)
@@ -169,6 +169,30 @@ static PyObject* pysqlite_iter(pysqlite_Row* self)
     return PyObject_GetIter(self->data);
 }
 
+static long pysqlite_row_hash(pysqlite_Row *self)
+{
+    return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
+}
+
+static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
+{
+    if (opid != Py_EQ && opid != Py_NE) {
+       Py_INCREF(Py_NotImplemented);
+       return Py_NotImplemented;
+    }
+    if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) {
+       pysqlite_Row *other = (pysqlite_Row *)_other;
+       PyObject *res = PyObject_RichCompare(self->description, other->description, opid);
+       if (opid == Py_EQ && res == Py_True
+           || opid == Py_NE && res == Py_False) {
+           Py_DECREF(res);
+           return PyObject_RichCompare(self->data, other->data, opid);
+       }
+    }
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+}
+
 PyMappingMethods pysqlite_row_as_mapping = {
     /* mp_length        */ (lenfunc)pysqlite_row_length,
     /* mp_subscript     */ (binaryfunc)pysqlite_row_subscript,
@@ -196,7 +220,7 @@ PyTypeObject pysqlite_RowType = {
         0,                                              /* tp_as_number */
         0,                                              /* tp_as_sequence */
         0,                                              /* tp_as_mapping */
-        0,                                              /* tp_hash */
+        (hashfunc)pysqlite_row_hash,                    /* tp_hash */
         0,                                              /* tp_call */
         0,                                              /* tp_str */
         0,                                              /* tp_getattro */
@@ -206,7 +230,7 @@ PyTypeObject pysqlite_RowType = {
         0,                                              /* tp_doc */
         (traverseproc)0,                                /* tp_traverse */
         0,                                              /* tp_clear */
-        0,                                              /* tp_richcompare */
+        (richcmpfunc)pysqlite_row_richcompare,          /* tp_richcompare */
         0,                                              /* tp_weaklistoffset */
         (getiterfunc)pysqlite_iter,                     /* tp_iter */
         0,                                              /* tp_iternext */