~vcs-imports/python-mysqldb/old-svn-trunk

« back to all changes in this revision

Viewing changes to src/results.c

  • Committer: adustman
  • Date: 2010-02-22 03:56:44 UTC
  • Revision ID: vcs-imports@canonical.com-20100222035644-szng2yqz2g8gncor
More serious restructuring and cleaning, especially in the handling
of result sets. All tests pass.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
}
38
38
 
39
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
41
\n\
42
42
Creating instances of this class directly is an excellent way to\n\
43
43
shoot yourself in the foot. If using _mysql.connection directly,\n\
51
51
        PyObject *args,
52
52
        PyObject *kwargs)
53
53
{
54
 
        static char *kwlist[] = {"connection", "use", "decoder_stack", NULL};
 
54
        static char *kwlist[] = {"connection", "use", NULL};
55
55
        MYSQL_RES *result;
56
56
        _mysql_ConnectionObject *conn = NULL;
57
57
        int use = 0;
58
 
        PyObject *decoder_stack = NULL;
59
 
        int n, ns, i, j;
 
58
        int n;
60
59
 
61
 
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iO", kwlist,
62
 
                                          &conn, &use, &decoder_stack))
 
60
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", kwlist,
 
61
                                          &conn, &use))
63
62
                return -1;
64
 
        if (!decoder_stack) decoder_stack = PyList_New(0);
65
 
        if (!decoder_stack) return -1;
 
63
 
66
64
        self->conn = (PyObject *) conn;
67
65
        Py_INCREF(conn);
68
66
        self->use = use;
74
72
        self->result = result;
75
73
        Py_END_ALLOW_THREADS ;
76
74
        if (!result) {
77
 
                self->decoders = PyTuple_New(0);
78
75
                return 0;
79
76
        }
80
77
        n = mysql_num_fields(result);
81
 
        ns = PySequence_Length(decoder_stack);
82
78
        self->nfields = n;
83
 
        if (!(self->decoders = PyTuple_New(n))) return -1;
84
79
        self->fields = _mysql_ResultObject_get_fields(self, NULL);
85
 
        for (i=0; i<n; i++) {
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
 
        }
 
80
 
100
81
        return 0;
101
 
        error:
102
 
        return -1;
103
82
}
104
83
 
105
84
static int
109
88
        void *arg)
110
89
{
111
90
        int r;
112
 
        if (self->decoders) {
113
 
                if (!(r = visit(self->decoders, arg))) return r;
 
91
        if (self->fields) {
 
92
                if (!(r = visit(self->fields, arg))) return r;
114
93
        }
115
94
        if (self->conn)
116
95
                return visit(self->conn, arg);
117
96
        return 0;
118
97
}
119
98
 
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;
129
 
}
130
 
 
131
99
static char _mysql_ResultObject_describe__doc__[] =
132
100
"Returns the sequence of 7-tuples required by the DB-API for\n\
133
101
the Cursor.description attribute.\n\
165
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
136
static char _mysql_ResultObject_fetch_row__doc__[] =
364
 
"fetch_row([maxrows, how]) -- Fetches up to maxrows as a tuple.\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\
 
137
"fetchrow()\n\
434
138
  Fetches one row as a tuple of strings.\n\
435
139
  NULL is returned as None.\n\
 
140
  A single None indicates the end of the result set.\n\
436
141
";
437
142
 
438
143
static PyObject *
439
 
_mysql_ResultObject_simple_fetch_row(
 
144
_mysql_ResultObject_fetch_row(
440
145
        _mysql_ResultObject *self,
441
 
        PyObject *unused)
442
 
{
 
146
        PyObject *unused)
 
147
 {
443
148
        unsigned int n, i;
444
149
        unsigned long *length;
445
150
        PyObject *r=NULL;
446
151
        MYSQL_ROW row;
447
152
        
448
 
        check_result_connection(self);
449
 
        
 
153
        check_result_connection(self);
 
154
        
450
155
        if (!self->use)
451
156
                row = mysql_fetch_row(self->result);
452
157
        else {
453
 
                Py_BEGIN_ALLOW_THREADS;
 
158
                Py_BEGIN_ALLOW_THREADS;
454
159
                row = mysql_fetch_row(self->result);
455
 
                Py_END_ALLOW_THREADS;
 
160
                Py_END_ALLOW_THREADS;
456
161
        }
457
162
        if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
458
163
                _mysql_Exception((_mysql_ConnectionObject *)self->conn);
474
179
                } else /* NULL */ {
475
180
                        v = Py_None;
476
181
                        Py_INCREF(v);
477
 
                }
 
182
                }
478
183
                PyTuple_SET_ITEM(r, i, v);
479
 
        }
 
184
        }
480
185
        return r;
481
186
  error:
482
187
        Py_XDECREF(r);
483
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
255
static PyObject *
487
256
_mysql_ResultObject__iter__(
488
257
        _mysql_ResultObject *self,
500
269
{
501
270
        PyObject *row;
502
271
        check_result_connection(self);
503
 
        row = _mysql_ResultObject_simple_fetch_row(self, NULL);
 
272
        row = _mysql_ResultObject_fetch_row(self, NULL);
504
273
        if (row == Py_None) {
505
274
                Py_DECREF(row);
506
275
                PyErr_SetString(PyExc_StopIteration, "");
598
367
        _mysql_ResultObject *self)
599
368
{
600
369
        PyObject_GC_UnTrack((PyObject *)self);
 
370
        _mysql_ResultObject_clear(self, NULL);
601
371
        mysql_free_result(self->result);
602
 
        _mysql_ResultObject_clear(self);
603
372
        MyFree(self);
604
373
}
605
374
 
633
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
411
                "describe",
637
412
                (PyCFunction)_mysql_ResultObject_describe,
638
413
                METH_NOARGS,
644
419
                METH_VARARGS | METH_KEYWORDS,
645
420
                _mysql_ResultObject_fetch_row__doc__
646
421
        },
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
 
        },
653
422
 
654
423
        {
655
424
                "field_flags",
681
450
                "Connection associated with result"
682
451
        },
683
452
        {
684
 
                "decoders",
685
 
                T_OBJECT,
686
 
                offsetof(_mysql_ResultObject, decoders),
687
 
                RO,
688
 
                "Field decoders for result set"
689
 
        },
690
 
        {
691
453
                "fields",
692
454
                T_OBJECT,
693
455
                offsetof(_mysql_ResultObject, fields),