#10320 closed New feature (fixed)
CursorDebugWrapper should allow using iterators/generators for executemany().
Reported by: | Vadim Fint | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | yes | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
executemany on cursors can have a little speedup on huge lists if developer sends iterators or generators as args. Thus, they will have no len. CursorDebugWrapper tries to determine length for only one reason: put a record about number of executed queries into connection.queries.
It's good idea probably to determine if args have no len -- dont put info about amount of executed queries into connection.queries.
Right now I can do connection.cursor().cursor.executemany(sql, iterator) for that purpose. I mean -- python db wrappers usually allow iterators in executemany's args. Another ugly way right now - catch TypeError and silently ignore. This is because django do len() after calling executemany on underlying cursor =). Non-pythonic, yeah?
Change History (9)
comment:1 by , 16 years ago
comment:2 by , 16 years ago
Has patch: | set |
---|
comment:4 by , 16 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
comment:5 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → New feature |
comment:6 by , 13 years ago
Easy pickings: | unset |
---|---|
UI/UX: | unset |
Strictly speaking, PEP 249 defines executemany(operation, seq_of_parameters)
, where seq_of_parameters
is a sequence, and len
is always available on sequences.
However, three out of four database backends support calling Cursor.executemany
with an iterator as second argument:
- The built-in
sqlite3
module also allows using an iterator yielding parameters instead of a sequence. - It's clear from the source of pyscopg2, in
cursor_type.c
, thatpsycopg.Cursor.executemany
accepts iterators, and if it receives a non-iterable, it actually converts it to an iterator --if (!PyIter_Check(vars)) { vars = iter = PyObject_GetIter(vars); ... }
. MySQLdb.Cursor.executemany
is implemented in Python, and the two possible code paths usefor row in args
, which clearly works with iterators.- Only
cx_Oracle.Cursor.executemany
fails to accept an iterator as argument: inCursor.c
,Cursor_ExecuteMany
doesnumRows = PyList_GET_SIZE(listOfArguments);
So, it would be a good idea to support iterators in CursorDebugWrapper
. Note that the performance argument is irrelevant for CursorDebugWrapper
itself, since it's only used when DEBUG=True
. The real reason for the fix is that CursorDebugWrapper
shouldn't be more restrictive than regular cursors.
NB: django.db.backends.oracle.base.FormatStylePlaceholderCursor
also relies on params
not being a iterator, since it tries to access params[0]
. But that could be fixed by adding something along the lines of if params is not None: params = list(params)
.
comment:7 by , 13 years ago
Needs tests: | set |
---|---|
Patch needs improvement: | set |
Triage Stage: | Design decision needed → Accepted |
Easiest fixup:
django/db/backends/util.py
, sql),Because param_list may be iterator and already iterated iterator (hmm =)) -- there is no way to determine it's length after underlying executemany() cursor call. Thus, -- '??' is okay, imho :).