comparison src/results.c @ 75:3b03cb566032 MySQLdb

More serious restructuring and cleaning, especially in the handling of result sets. All tests pass.
author adustman
date Mon, 22 Feb 2010 03:56:44 +0000
parents 24fa6a40c706
children
comparison
equal deleted inserted replaced
74:80164eb2f090 75:3b03cb566032
35 Py_XDECREF(fields); 35 Py_XDECREF(fields);
36 return NULL; 36 return NULL;
37 } 37 }
38 38
39 static char _mysql_ResultObject__doc__[] = 39 static char _mysql_ResultObject__doc__[] =
40 "result(connection, use=0, decoder_stack=[]) -- Result set from a query.\n\ 40 "result(connection, use=0) -- Result set from a query.\n\
41 \n\ 41 \n\
42 Creating instances of this class directly is an excellent way to\n\ 42 Creating instances of this class directly is an excellent way to\n\
43 shoot yourself in the foot. If using _mysql.connection directly,\n\ 43 shoot yourself in the foot. If using _mysql.connection directly,\n\
44 use connection.store_result() or connection.use_result() instead.\n\ 44 use connection.store_result() or connection.use_result() instead.\n\
45 If using MySQLdb.Connection, this is done by the cursor class.\n\ 45 If using MySQLdb.Connection, this is done by the cursor class.\n\
49 _mysql_ResultObject_Initialize( 49 _mysql_ResultObject_Initialize(
50 _mysql_ResultObject *self, 50 _mysql_ResultObject *self,
51 PyObject *args, 51 PyObject *args,
52 PyObject *kwargs) 52 PyObject *kwargs)
53 { 53 {
54 static char *kwlist[] = {"connection", "use", "decoder_stack", NULL}; 54 static char *kwlist[] = {"connection", "use", NULL};
55 MYSQL_RES *result; 55 MYSQL_RES *result;
56 _mysql_ConnectionObject *conn = NULL; 56 _mysql_ConnectionObject *conn = NULL;
57 int use = 0; 57 int use = 0;
58 PyObject *decoder_stack = NULL; 58 int n;
59 int n, ns, i, j; 59
60 60 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", kwlist,
61 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iO", kwlist, 61 &conn, &use))
62 &conn, &use, &decoder_stack))
63 return -1; 62 return -1;
64 if (!decoder_stack) decoder_stack = PyList_New(0); 63
65 if (!decoder_stack) return -1;
66 self->conn = (PyObject *) conn; 64 self->conn = (PyObject *) conn;
67 Py_INCREF(conn); 65 Py_INCREF(conn);
68 self->use = use; 66 self->use = use;
69 Py_BEGIN_ALLOW_THREADS ; 67 Py_BEGIN_ALLOW_THREADS ;
70 if (use) 68 if (use)
72 else 70 else
73 result = mysql_store_result(&(conn->connection)); 71 result = mysql_store_result(&(conn->connection));
74 self->result = result; 72 self->result = result;
75 Py_END_ALLOW_THREADS ; 73 Py_END_ALLOW_THREADS ;
76 if (!result) { 74 if (!result) {
77 self->decoders = PyTuple_New(0);
78 return 0; 75 return 0;
79 } 76 }
80 n = mysql_num_fields(result); 77 n = mysql_num_fields(result);
81 ns = PySequence_Length(decoder_stack);
82 self->nfields = n; 78 self->nfields = n;
83 if (!(self->decoders = PyTuple_New(n))) return -1;
84 self->fields = _mysql_ResultObject_get_fields(self, NULL); 79 self->fields = _mysql_ResultObject_get_fields(self, NULL);
85 for (i=0; i<n; i++) { 80
86 PyObject *field = PyTuple_GET_ITEM(self->fields, i);
87 for (j=0; j<ns; j++) {
88 PyObject *df = PySequence_GetItem(decoder_stack, j);
89 if (!df) goto error;
90 PyObject *f = PyObject_CallFunctionObjArgs(df, field, NULL);
91 Py_DECREF(df);
92 if (!f) goto error;
93 if (f != Py_None) {
94 PyTuple_SET_ITEM(self->decoders, i, f);
95 break;
96 }
97 Py_DECREF(f);
98 }
99 }
100 return 0; 81 return 0;
101 error:
102 return -1;
103 } 82 }
104 83
105 static int 84 static int
106 _mysql_ResultObject_traverse( 85 _mysql_ResultObject_traverse(
107 _mysql_ResultObject *self, 86 _mysql_ResultObject *self,
108 visitproc visit, 87 visitproc visit,
109 void *arg) 88 void *arg)
110 { 89 {
111 int r; 90 int r;
112 if (self->decoders) { 91 if (self->fields) {
113 if (!(r = visit(self->decoders, arg))) return r; 92 if (!(r = visit(self->fields, arg))) return r;
114 } 93 }
115 if (self->conn) 94 if (self->conn)
116 return visit(self->conn, arg); 95 return visit(self->conn, arg);
117 return 0;
118 }
119
120 static int
121 _mysql_ResultObject_clear(
122 _mysql_ResultObject *self)
123 {
124 Py_XDECREF(self->decoders);
125 self->decoders = NULL;
126 Py_XDECREF(self->conn);
127 self->conn = NULL;
128 return 0; 96 return 0;
129 } 97 }
130 98
131 static char _mysql_ResultObject_describe__doc__[] = 99 static char _mysql_ResultObject_describe__doc__[] =
132 "Returns the sequence of 7-tuples required by the DB-API for\n\ 100 "Returns the sequence of 7-tuples required by the DB-API for\n\
163 error: 131 error:
164 Py_XDECREF(d); 132 Py_XDECREF(d);
165 return NULL; 133 return NULL;
166 } 134 }
167 135
168 static char _mysql_ResultObject_field_flags__doc__[] =
169 "Returns a tuple of field flags, one for each column in the result.\n\
170 " ;
171
172 static PyObject *
173 _mysql_ResultObject_field_flags(
174 _mysql_ResultObject *self,
175 PyObject *unused)
176 {
177 PyObject *d;
178 MYSQL_FIELD *fields;
179 unsigned int i, n;
180
181 check_result_connection(self);
182 n = mysql_num_fields(self->result);
183 fields = mysql_fetch_fields(self->result);
184 if (!(d = PyTuple_New(n))) return NULL;
185 for (i=0; i<n; i++) {
186 PyObject *f;
187 if (!(f = PyInt_FromLong((long)fields[i].flags))) goto error;
188 PyTuple_SET_ITEM(d, i, f);
189 }
190 return d;
191 error:
192 Py_XDECREF(d);
193 return NULL;
194 }
195
196 static PyObject *
197 _mysql_field_to_python(
198 PyObject *decoder,
199 char *rowitem,
200 unsigned long length)
201 {
202 PyObject *v;
203 if (rowitem) {
204 if (decoder != Py_None)
205 v = PyObject_CallFunction(decoder,
206 "s#",
207 rowitem,
208 (int)length);
209 else
210 v = PyString_FromStringAndSize(rowitem,
211 (int)length);
212 if (!v)
213 return NULL;
214 } else {
215 Py_INCREF(Py_None);
216 v = Py_None;
217 }
218 return v;
219 }
220
221 static PyObject *
222 _mysql_row_to_tuple(
223 _mysql_ResultObject *self,
224 MYSQL_ROW row)
225 {
226 unsigned int n, i;
227 unsigned long *length;
228 PyObject *r, *c;
229
230 n = mysql_num_fields(self->result);
231 if (!(r = PyTuple_New(n))) return NULL;
232 length = mysql_fetch_lengths(self->result);
233 for (i=0; i<n; i++) {
234 PyObject *v;
235 c = PyTuple_GET_ITEM(self->decoders, i);
236 v = _mysql_field_to_python(c, row[i], length[i]);
237 if (!v) goto error;
238 PyTuple_SET_ITEM(r, i, v);
239 }
240 return r;
241 error:
242 Py_XDECREF(r);
243 return NULL;
244 }
245
246 static PyObject *
247 _mysql_row_to_dict(
248 _mysql_ResultObject *self,
249 MYSQL_ROW row)
250 {
251 unsigned int n, i;
252 unsigned long *length;
253 PyObject *r, *c;
254 MYSQL_FIELD *fields;
255
256 n = mysql_num_fields(self->result);
257 if (!(r = PyDict_New())) return NULL;
258 length = mysql_fetch_lengths(self->result);
259 fields = mysql_fetch_fields(self->result);
260 for (i=0; i<n; i++) {
261 PyObject *v;
262 c = PyTuple_GET_ITEM(self->decoders, i);
263 v = _mysql_field_to_python(c, row[i], length[i]);
264 if (!v) goto error;
265 if (!PyMapping_HasKeyString(r, fields[i].name)) {
266 PyMapping_SetItemString(r, fields[i].name, v);
267 } else {
268 int len;
269 char buf[256];
270 strncpy(buf, fields[i].table, 256);
271 len = strlen(buf);
272 strncat(buf, ".", 256-len);
273 len = strlen(buf);
274 strncat(buf, fields[i].name, 256-len);
275 PyMapping_SetItemString(r, buf, v);
276 }
277 Py_DECREF(v);
278 }
279 return r;
280 error:
281 Py_XDECREF(r);
282 return NULL;
283 }
284
285 static PyObject *
286 _mysql_row_to_dict_old(
287 _mysql_ResultObject *self,
288 MYSQL_ROW row)
289 {
290 unsigned int n, i;
291 unsigned long *length;
292 PyObject *r, *c;
293 MYSQL_FIELD *fields;
294
295 n = mysql_num_fields(self->result);
296 if (!(r = PyDict_New())) return NULL;
297 length = mysql_fetch_lengths(self->result);
298 fields = mysql_fetch_fields(self->result);
299 for (i=0; i<n; i++) {
300 PyObject *v;
301 c = PyTuple_GET_ITEM(self->decoders, i);
302 v = _mysql_field_to_python(c, row[i], length[i]);
303 if (!v) goto error;
304 {
305 int len=0;
306 char buf[256]="";
307 if (strlen(fields[i].table)) {
308 strncpy(buf, fields[i].table, 256);
309 len = strlen(buf);
310 strncat(buf, ".", 256-len);
311 len = strlen(buf);
312 }
313 strncat(buf, fields[i].name, 256-len);
314 PyMapping_SetItemString(r, buf, v);
315 }
316 Py_DECREF(v);
317 }
318 return r;
319 error:
320 Py_XDECREF(r);
321 return NULL;
322 }
323
324 typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
325
326 int
327 _mysql__fetch_row(
328 _mysql_ResultObject *self,
329 PyObject **r,
330 int skiprows,
331 int maxrows,
332 _PYFUNC *convert_row)
333 {
334 unsigned int i;
335 MYSQL_ROW row;
336
337 for (i = skiprows; i<(skiprows+maxrows); i++) {
338 PyObject *v;
339 if (!self->use)
340 row = mysql_fetch_row(self->result);
341 else {
342 Py_BEGIN_ALLOW_THREADS;
343 row = mysql_fetch_row(self->result);
344 Py_END_ALLOW_THREADS;
345 }
346 if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
347 _mysql_Exception((_mysql_ConnectionObject *)self->conn);
348 goto error;
349 }
350 if (!row) {
351 if (_PyTuple_Resize(r, i) == -1) goto error;
352 break;
353 }
354 v = convert_row(self, row);
355 if (!v) goto error;
356 PyTuple_SET_ITEM(*r, i, v);
357 }
358 return i-skiprows;
359 error:
360 return -1;
361 }
362
363 static char _mysql_ResultObject_fetch_row__doc__[] = 136 static char _mysql_ResultObject_fetch_row__doc__[] =
364 "fetch_row([maxrows, how]) -- Fetches up to maxrows as a tuple.\n\ 137 "fetchrow()\n\
365 The rows are formatted according to how:\n\
366 \n\
367 0 -- tuples (default)\n\
368 1 -- dictionaries, key=column or table.column if duplicated\n\
369 2 -- dictionaries, key=table.column\n\
370 ";
371
372 static PyObject *
373 _mysql_ResultObject_fetch_row(
374 _mysql_ResultObject *self,
375 PyObject *args,
376 PyObject *kwargs)
377 {
378 typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
379 static char *kwlist[] = { "maxrows", "how", NULL };
380 static _PYFUNC *row_converters[] =
381 {
382 _mysql_row_to_tuple,
383 _mysql_row_to_dict,
384 _mysql_row_to_dict_old
385 };
386 _PYFUNC *convert_row;
387 unsigned int maxrows=1, how=0, skiprows=0, rowsadded;
388 PyObject *r=NULL;
389
390 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
391 &maxrows, &how))
392 return NULL;
393 check_result_connection(self);
394 if (how < 0 || how >= sizeof(row_converters)) {
395 PyErr_SetString(PyExc_ValueError, "how out of range");
396 return NULL;
397 }
398 convert_row = row_converters[how];
399 if (maxrows) {
400 if (!(r = PyTuple_New(maxrows))) goto error;
401 rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows,
402 convert_row);
403 if (rowsadded == -1) goto error;
404 } else {
405 if (self->use) {
406 maxrows = 1000;
407 if (!(r = PyTuple_New(maxrows))) goto error;
408 while (1) {
409 rowsadded = _mysql__fetch_row(self, &r, skiprows,
410 maxrows, convert_row);
411 if (rowsadded == -1) goto error;
412 skiprows += rowsadded;
413 if (rowsadded < maxrows) break;
414 if (_PyTuple_Resize(&r, skiprows + maxrows) == -1)
415 goto error;
416 }
417 } else {
418 /* XXX if overflow, maxrows<0? */
419 maxrows = (int) mysql_num_rows(self->result);
420 if (!(r = PyTuple_New(maxrows))) goto error;
421 rowsadded = _mysql__fetch_row(self, &r, 0,
422 maxrows, convert_row);
423 if (rowsadded == -1) goto error;
424 }
425 }
426 return r;
427 error:
428 Py_XDECREF(r);
429 return NULL;
430 }
431
432 static char _mysql_ResultObject_simple_fetch_row__doc__[] =
433 "simple_fetchrow()\n\
434 Fetches one row as a tuple of strings.\n\ 138 Fetches one row as a tuple of strings.\n\
435 NULL is returned as None.\n\ 139 NULL is returned as None.\n\
140 A single None indicates the end of the result set.\n\
436 "; 141 ";
437 142
438 static PyObject * 143 static PyObject *
439 _mysql_ResultObject_simple_fetch_row( 144 _mysql_ResultObject_fetch_row(
440 _mysql_ResultObject *self, 145 _mysql_ResultObject *self,
441 PyObject *unused) 146 PyObject *unused)
442 { 147 {
443 unsigned int n, i; 148 unsigned int n, i;
444 unsigned long *length; 149 unsigned long *length;
445 PyObject *r=NULL; 150 PyObject *r=NULL;
446 MYSQL_ROW row; 151 MYSQL_ROW row;
447 152
448 check_result_connection(self); 153 check_result_connection(self);
449 154
450 if (!self->use) 155 if (!self->use)
451 row = mysql_fetch_row(self->result); 156 row = mysql_fetch_row(self->result);
452 else { 157 else {
453 Py_BEGIN_ALLOW_THREADS; 158 Py_BEGIN_ALLOW_THREADS;
454 row = mysql_fetch_row(self->result); 159 row = mysql_fetch_row(self->result);
455 Py_END_ALLOW_THREADS; 160 Py_END_ALLOW_THREADS;
456 } 161 }
457 if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) { 162 if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
458 _mysql_Exception((_mysql_ConnectionObject *)self->conn); 163 _mysql_Exception((_mysql_ConnectionObject *)self->conn);
459 goto error; 164 goto error;
460 } 165 }
472 v = PyString_FromStringAndSize(row[i], length[i]); 177 v = PyString_FromStringAndSize(row[i], length[i]);
473 if (!v) goto error; 178 if (!v) goto error;
474 } else /* NULL */ { 179 } else /* NULL */ {
475 v = Py_None; 180 v = Py_None;
476 Py_INCREF(v); 181 Py_INCREF(v);
477 } 182 }
478 PyTuple_SET_ITEM(r, i, v); 183 PyTuple_SET_ITEM(r, i, v);
479 } 184 }
480 return r; 185 return r;
481 error: 186 error:
482 Py_XDECREF(r); 187 Py_XDECREF(r);
483 return NULL; 188 return NULL;
484 } 189 }
485 190
191 static char _mysql_ResultObject_field_flags__doc__[] =
192 "Returns a tuple of field flags, one for each column in the result.\n\
193 " ;
194
195 static PyObject *
196 _mysql_ResultObject_field_flags(
197 _mysql_ResultObject *self,
198 PyObject *unused)
199 {
200 PyObject *d;
201 MYSQL_FIELD *fields;
202 unsigned int i, n;
203
204 check_result_connection(self);
205 n = mysql_num_fields(self->result);
206 fields = mysql_fetch_fields(self->result);
207 if (!(d = PyTuple_New(n))) return NULL;
208 for (i=0; i<n; i++) {
209 PyObject *f;
210 if (!(f = PyInt_FromLong((long)fields[i].flags))) goto error;
211 PyTuple_SET_ITEM(d, i, f);
212 }
213 return d;
214 error:
215 Py_XDECREF(d);
216 return NULL;
217 }
218
219 typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
220
221 static char _mysql_ResultObject_clear__doc__[] =
222 "clear()\n\
223 Reads to the end of the result set, discarding all the rows.\n\
224 ";
225
226 static PyObject *
227 _mysql_ResultObject_clear(
228 _mysql_ResultObject *self,
229 PyObject *unused)
230 {
231 if (self->result) {
232 if (self->use) {
233 Py_BEGIN_ALLOW_THREADS;
234 while (mysql_fetch_row(self->result));
235 Py_END_ALLOW_THREADS;
236
237 if (mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
238 _mysql_Exception((_mysql_ConnectionObject *)self->conn);
239 return NULL;
240 }
241 }
242 }
243 Py_XDECREF(self->fields);
244 self->fields = NULL;
245 Py_XDECREF(self->conn);
246 self->conn = NULL;
247 if (self->result) {
248 mysql_free_result(self->result);
249 self->result = NULL;
250 }
251 Py_INCREF(Py_None);
252 return Py_None;
253 }
254
486 static PyObject * 255 static PyObject *
487 _mysql_ResultObject__iter__( 256 _mysql_ResultObject__iter__(
488 _mysql_ResultObject *self, 257 _mysql_ResultObject *self,
489 PyObject *unused) 258 PyObject *unused)
490 { 259 {
498 _mysql_ResultObject *self, 267 _mysql_ResultObject *self,
499 PyObject *unused) 268 PyObject *unused)
500 { 269 {
501 PyObject *row; 270 PyObject *row;
502 check_result_connection(self); 271 check_result_connection(self);
503 row = _mysql_ResultObject_simple_fetch_row(self, NULL); 272 row = _mysql_ResultObject_fetch_row(self, NULL);
504 if (row == Py_None) { 273 if (row == Py_None) {
505 Py_DECREF(row); 274 Py_DECREF(row);
506 PyErr_SetString(PyExc_StopIteration, ""); 275 PyErr_SetString(PyExc_StopIteration, "");
507 return NULL; 276 return NULL;
508 } 277 }
596 static void 365 static void
597 _mysql_ResultObject_dealloc( 366 _mysql_ResultObject_dealloc(
598 _mysql_ResultObject *self) 367 _mysql_ResultObject *self)
599 { 368 {
600 PyObject_GC_UnTrack((PyObject *)self); 369 PyObject_GC_UnTrack((PyObject *)self);
370 _mysql_ResultObject_clear(self, NULL);
601 mysql_free_result(self->result); 371 mysql_free_result(self->result);
602 _mysql_ResultObject_clear(self);
603 MyFree(self); 372 MyFree(self);
604 } 373 }
605 374
606 static PyObject * 375 static PyObject *
607 _mysql_ResultObject_repr( 376 _mysql_ResultObject_repr(
631 (PyCFunction)_mysql_ResultObject_row_tell, 400 (PyCFunction)_mysql_ResultObject_row_tell,
632 METH_NOARGS, 401 METH_NOARGS,
633 _mysql_ResultObject_row_tell__doc__ 402 _mysql_ResultObject_row_tell__doc__
634 }, 403 },
635 { 404 {
405 "clear",
406 (PyCFunction)_mysql_ResultObject_clear,
407 METH_NOARGS,
408 _mysql_ResultObject_clear__doc__
409 },
410 {
636 "describe", 411 "describe",
637 (PyCFunction)_mysql_ResultObject_describe, 412 (PyCFunction)_mysql_ResultObject_describe,
638 METH_NOARGS, 413 METH_NOARGS,
639 _mysql_ResultObject_describe__doc__ 414 _mysql_ResultObject_describe__doc__
640 }, 415 },
641 { 416 {
642 "fetch_row", 417 "fetch_row",
643 (PyCFunction)_mysql_ResultObject_fetch_row, 418 (PyCFunction)_mysql_ResultObject_fetch_row,
644 METH_VARARGS | METH_KEYWORDS, 419 METH_VARARGS | METH_KEYWORDS,
645 _mysql_ResultObject_fetch_row__doc__ 420 _mysql_ResultObject_fetch_row__doc__
646 },
647 {
648 "simple_fetch_row",
649 (PyCFunction)_mysql_ResultObject_simple_fetch_row,
650 METH_VARARGS | METH_KEYWORDS,
651 _mysql_ResultObject_simple_fetch_row__doc__
652 }, 421 },
653 422
654 { 423 {
655 "field_flags", 424 "field_flags",
656 (PyCFunction)_mysql_ResultObject_field_flags, 425 (PyCFunction)_mysql_ResultObject_field_flags,
677 "connection", 446 "connection",
678 T_OBJECT, 447 T_OBJECT,
679 offsetof(_mysql_ConnectionObject, connection), 448 offsetof(_mysql_ConnectionObject, connection),
680 RO, 449 RO,
681 "Connection associated with result" 450 "Connection associated with result"
682 },
683 {
684 "decoders",
685 T_OBJECT,
686 offsetof(_mysql_ResultObject, decoders),
687 RO,
688 "Field decoders for result set"
689 }, 451 },
690 { 452 {
691 "fields", 453 "fields",
692 T_OBJECT, 454 T_OBJECT,
693 offsetof(_mysql_ResultObject, fields), 455 offsetof(_mysql_ResultObject, fields),