Erlend Egeberg Aasland <erlend.aasl...@innova.no> added the comment:
pysqlite_cursor_iternext() has four users: - sqlite3.Cursor.fetchone() - sqlite3.Cursor.fetchall() - sqlite3.Cursor.fetchmany() - sqlite3.Cursor.__next__() All of these methods pass self to pysqlite_cursor_iternext(). pysqlite_cursor_iternext() starts by checking the state of the cursor (is it initialised, it the database open, etc.). If there is a Statement object, pysqlite_step() is called with the sqlite3_stmt pointer from the Statement object (Cursor->statement->st). The statement pointer of the Cursor object is set in _pysqlite_query_execute() – the last pysqlite_step() user – either from the LRU cache (line 470), or by creating a new Statement object (line 479). The latter only leaves a valid Cursor->statement->st pointer (sqlite3_stmt pointer) if the Statement object was successfully created, and the sqlite3_stmt successfully prepared. (I assume only valid Statement objects are added to the cache.) Before the main loop of _pysqlite_query_execute() starts, the statement is reset. In the loop, the next parameter set is fetched, the statement is (re)bound, and step is called. If Cursor.execute() called _pysqlite_query_execute(), the parameter list is initialised to a single-item list, and the loop is only run once. From what I can read, this function is also safe. (But it is very messy; for instance, if there's an active Statement, it is reset twice before the loop starts.) I tried forcing an error by using an uninitialised cursor: >>> cx = sqlite3.connect(":memory:") >>> cu = sqlite3.Cursor.__new__(sqlite3.Cursor) >>> sqlite3.Cursor.fetchone(cu) Traceback (most recent call last): File "<stdin>", line 1, in <module> sqlite3.ProgrammingError: Base Cursor.__init__ not called. >>> next(cu) Traceback (most recent call last): File "<stdin>", line 1, in <module> sqlite3.ProgrammingError: Base Cursor.__init__ not called. Ditto for fetchmany() and fetchall(). This is consistent with current behaviour. Calling fetch*() without first executing a statement: >>> cu = cx.cursor() >>> cu.fetchone() >>> cu.fetchmany() [] >>> cu.fetchall() [] >>> next(cu) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration This is consistent with current behaviour. I might have missed something, but from what I can see, there are no paths that lead to pysqlite_step() being called with a NULL pointer. Berker, Serhiy, please correct me if I'm wrong. ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue43290> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com