{"html_url": "https://github.com/simonw/sqlite-utils/issues/506#issuecomment-1298879701", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/506", "id": 1298879701, "node_id": "IC_kwDOCGYnMM5Na1TV", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-11-01T17:37:13Z", "updated_at": "2022-11-01T17:37:13Z", "author_association": "OWNER", "body": "The question I was originally trying to answer here was this: how many rows were actually inserted by that call to `.insert_all()`?\r\n\r\nI don't know that `.rowcount` would ever be useful here, since the \"correct\" answer depends on other factors - had I determined to ignore or replace records with a primary key that matches an existing record for example?\r\n\r\nSo I think if people need `rowcount` they can get it by using a `cursor` directly.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1429029604, "label": "Make `cursor.rowcount` accessible (wontfix)"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/506#issuecomment-1298877872", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/506", "id": 1298877872, "node_id": "IC_kwDOCGYnMM5Na02w", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-11-01T17:35:30Z", "updated_at": "2022-11-01T17:35:30Z", "author_association": "OWNER", "body": "This may not make sense.\r\n\r\nFirst, `.last_rowid` is a property on table - but that doesn't make sense for `rowcount` since it should clearly be a property on the database itself (you can run a query directly using `db.execute()` without going through a `Table` object).\r\n\r\nSo I tried this prototype:\r\n\r\n```diff\r\ndiff --git a/docs/python-api.rst b/docs/python-api.rst\r\nindex 206e5e6..78d3a8d 100644\r\n--- a/docs/python-api.rst\r\n+++ b/docs/python-api.rst\r\n@@ -186,6 +186,15 @@ The ``db.query(sql)`` function executes a SQL query and returns an iterator over\r\n # {'name': 'Cleo'}\r\n # {'name': 'Pancakes'}\r\n \r\n+After executing a query the ``db.rowcount`` property on that database instance will reflect the number of rows affected by any insert, update or delete operations performed by that query:\r\n+\r\n+.. code-block:: python\r\n+\r\n+ db = Database(memory=True)\r\n+ db[\"dogs\"].insert_all([{\"name\": \"Cleo\"}, {\"name\": \"Pancakes\"}])\r\n+ print(db.rowcount)\r\n+ # Outputs: 2\r\n+\r\n .. _python_api_execute:\r\n \r\n db.execute(sql, params)\r\ndiff --git a/sqlite_utils/db.py b/sqlite_utils/db.py\r\nindex a06f4b7..c19c2dd 100644\r\n--- a/sqlite_utils/db.py\r\n+++ b/sqlite_utils/db.py\r\n@@ -294,6 +294,8 @@ class Database:\r\n \r\n _counts_table_name = \"_counts\"\r\n use_counts_table = False\r\n+ # Number of rows inserted, updated or deleted\r\n+ rowcount: Optional[int] = None\r\n \r\n def __init__(\r\n self,\r\n@@ -480,9 +482,11 @@ class Database:\r\n if self._tracer:\r\n self._tracer(sql, parameters)\r\n if parameters is not None:\r\n- return self.conn.execute(sql, parameters)\r\n+ cursor = self.conn.execute(sql, parameters)\r\n else:\r\n- return self.conn.execute(sql)\r\n+ cursor = self.conn.execute(sql)\r\n+ self.rowcount = cursor.rowcount\r\n+ return cursor\r\n \r\n def executescript(self, sql: str) -> sqlite3.Cursor:\r\n \"\"\"\r\n```\r\nBut this happens:\r\n```pycon\r\n>>> from sqlite_utils import Database\r\n>>> db = Database(memory=True)\r\n>>> db[\"dogs\"].insert_all([{\"name\": \"Cleo\"}, {\"name\": \"Pancakes\"}])\r\n\r\n>>> db.rowcount\r\n-1\r\n```\r\nTurning on query tracing demonstrates why:\r\n```pycon\r\n>>> db = Database(memory=True, tracer=print)\r\nPRAGMA recursive_triggers=on; None\r\n>>> db[\"dogs\"].insert_all([{\"name\": \"Cleo\"}, {\"name\": \"Pancakes\"}])\r\nselect name from sqlite_master where type = 'view' None\r\nselect name from sqlite_master where type = 'table' None\r\nselect name from sqlite_master where type = 'view' None\r\nCREATE TABLE [dogs] (\r\n [name] TEXT\r\n);\r\n None\r\nselect name from sqlite_master where type = 'view' None\r\nINSERT INTO [dogs] ([name]) VALUES (?), (?); ['Cleo', 'Pancakes']\r\nselect name from sqlite_master where type = 'table' None\r\nselect name from sqlite_master where type = 'table' None\r\nPRAGMA table_info([dogs]) None\r\n
\r\n>>>\r\n```\r\nThe `.insert_all()` function does a bunch of other queries too, so `.rowcount` is quickly over-ridden by the same result from extra queries that it executed.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1429029604, "label": "Make `cursor.rowcount` accessible (wontfix)"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/sqlite-utils/issues/506#issuecomment-1296358636", "issue_url": "https://api.github.com/repos/simonw/sqlite-utils/issues/506", "id": 1296358636, "node_id": "IC_kwDOCGYnMM5NRNzs", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-10-30T21:52:11Z", "updated_at": "2022-10-30T21:52:11Z", "author_association": "OWNER", "body": "This could work in a similar way to `db.insert(...).last_rowid`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1429029604, "label": "Make `cursor.rowcount` accessible (wontfix)"}, "performed_via_github_app": null}