comparison src/mysqlmod.c @ 55:e606fd52e866 MySQLdb

make things a little cleaner by moving to a src directory for the C code
author kylev
date Fri, 27 Feb 2009 19:14:09 +0000
parents _mysql.c@e80676c3505f
children 98d968f5af11
comparison
equal deleted inserted replaced
54:6e31278d3433 55:e606fd52e866
1 /* -*- mode: C; indent-tabs-mode: t; c-basic-offset: 8; -*- */
2
3 #include "mysqlmod.h"
4
5 PyObject *_mysql_MySQLError;
6 PyObject *_mysql_Warning;
7 PyObject *_mysql_Error;
8 PyObject *_mysql_DatabaseError;
9 PyObject *_mysql_InterfaceError;
10 PyObject *_mysql_DataError;
11 PyObject *_mysql_OperationalError;
12 PyObject *_mysql_IntegrityError;
13 PyObject *_mysql_InternalError;
14 PyObject *_mysql_ProgrammingError;
15 PyObject *_mysql_NotSupportedError;
16 PyObject *_mysql_error_map;
17
18 int _mysql_server_init_done = 0;
19
20 PyObject *
21 _mysql_Exception(_mysql_ConnectionObject *c)
22 {
23 PyObject *t, *e;
24 int merr;
25
26 if (!(t = PyTuple_New(2))) return NULL;
27 if (!_mysql_server_init_done) {
28 e = _mysql_InternalError;
29 PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L));
30 PyTuple_SET_ITEM(t, 1, PyString_FromString("server not initialized"));
31 PyErr_SetObject(e, t);
32 Py_DECREF(t);
33 return NULL;
34 }
35 merr = mysql_errno(&(c->connection));
36 if (!merr)
37 e = _mysql_InterfaceError;
38 else if (merr > CR_MAX_ERROR) {
39 PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L));
40 PyTuple_SET_ITEM(t, 1, PyString_FromString("error totally whack"));
41 PyErr_SetObject(_mysql_InterfaceError, t);
42 Py_DECREF(t);
43 return NULL;
44 }
45 else {
46 PyObject *py_merr = PyInt_FromLong(merr);
47 e = PyDict_GetItem(_mysql_error_map, py_merr);
48 Py_DECREF(py_merr);
49 if (!e) {
50 if (merr < 1000) e = _mysql_InternalError;
51 else e = _mysql_OperationalError;
52 }
53 }
54 PyTuple_SET_ITEM(t, 0, PyInt_FromLong((long)merr));
55 PyTuple_SET_ITEM(t, 1, PyString_FromString(mysql_error(&(c->connection))));
56 PyErr_SetObject(e, t);
57 Py_DECREF(t);
58 return NULL;
59 }
60
61 static char _mysql_server_init__doc__[] =
62 "Initialize embedded server. If this client is not linked against\n\
63 the embedded server library, this function does nothing.\n\
64 \n\
65 args -- sequence of command-line arguments\n\
66 groups -- sequence of groups to use in defaults files\n\
67 ";
68
69 static PyObject *_mysql_server_init(
70 PyObject *self,
71 PyObject *args,
72 PyObject *kwargs) {
73 static char *kwlist[] = {"args", "groups", NULL};
74 char **cmd_args_c=NULL, **groups_c=NULL, *s;
75 Py_ssize_t cmd_argc=0, i, groupc;
76 PyObject *cmd_args=NULL, *groups=NULL, *ret=NULL, *item;
77
78 if (_mysql_server_init_done) {
79 PyErr_SetString(_mysql_ProgrammingError,
80 "already initialized");
81 return NULL;
82 }
83
84 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", kwlist,
85 &cmd_args, &groups))
86 return NULL;
87
88 #if MYSQL_VERSION_ID >= 40000
89 if (cmd_args) {
90 if (!PySequence_Check(cmd_args)) {
91 PyErr_SetString(PyExc_TypeError,
92 "args must be a sequence");
93 goto finish;
94 }
95 cmd_argc = PySequence_Size(cmd_args);
96 if (cmd_argc == -1) {
97 PyErr_SetString(PyExc_TypeError,
98 "args could not be sized");
99 goto finish;
100 }
101 cmd_args_c = (char **) PyMem_Malloc(cmd_argc*sizeof(char *));
102 for (i=0; i< cmd_argc; i++) {
103 item = PySequence_GetItem(cmd_args, i);
104 s = PyString_AsString(item);
105 Py_DECREF(item);
106 if (!s) {
107 PyErr_SetString(PyExc_TypeError,
108 "args must contain strings");
109 goto finish;
110 }
111 cmd_args_c[i] = s;
112 }
113 }
114 if (groups) {
115 if (!PySequence_Check(groups)) {
116 PyErr_SetString(PyExc_TypeError,
117 "groups must be a sequence");
118 goto finish;
119 }
120 groupc = PySequence_Size(groups);
121 if (groupc == -1) {
122 PyErr_SetString(PyExc_TypeError,
123 "groups could not be sized");
124 goto finish;
125 }
126 groups_c = (char **) PyMem_Malloc((1+groupc)*sizeof(char *));
127 for (i=0; i< groupc; i++) {
128 item = PySequence_GetItem(groups, i);
129 s = PyString_AsString(item);
130 Py_DECREF(item);
131 if (!s) {
132 PyErr_SetString(PyExc_TypeError,
133 "groups must contain strings");
134 goto finish;
135 }
136 groups_c[i] = s;
137 }
138 groups_c[groupc] = (char *)NULL;
139 }
140 /* even though this may block, don't give up the interpreter lock
141 so that the server can't be initialized multiple times. */
142 if (mysql_server_init(cmd_argc, cmd_args_c, groups_c)) {
143 _mysql_Exception(NULL);
144 goto finish;
145 }
146 #endif
147 ret = Py_None;
148 Py_INCREF(Py_None);
149 _mysql_server_init_done = 1;
150 finish:
151 PyMem_Free(groups_c);
152 PyMem_Free(cmd_args_c);
153 return ret;
154 }
155
156 static char _mysql_server_end__doc__[] =
157 "Shut down embedded server. If not using an embedded server, this\n\
158 does nothing.";
159
160 static PyObject *_mysql_server_end(
161 PyObject *self,
162 PyObject *unused) {
163 if (_mysql_server_init_done) {
164 #if MYSQL_VERSION_ID >= 40000
165 mysql_server_end();
166 #endif
167 _mysql_server_init_done = 0;
168 Py_INCREF(Py_None);
169 return Py_None;
170 }
171 return _mysql_Exception(NULL);
172 }
173
174 #if MYSQL_VERSION_ID >= 32314
175 static char _mysql_thread_safe__doc__[] =
176 "Indicates whether the client is compiled as thread-safe.";
177
178 static PyObject *_mysql_thread_safe(
179 PyObject *self,
180 PyObject *unused) {
181
182 check_server_init(NULL);
183 return PyInt_FromLong((long)mysql_thread_safe());
184 }
185 #endif
186
187 extern char _mysql_connect__doc__[];
188 PyObject *
189 _mysql_connect(
190 PyObject *self,
191 PyObject *args,
192 PyObject *kwargs);
193
194 static char _mysql_debug__doc__[] =
195 "Does a DBUG_PUSH with the given string.\n\
196 mysql_debug() uses the Fred Fish debug library.\n\
197 To use this function, you must compile the client library to\n\
198 support debugging.\n\
199 ";
200 static PyObject *
201 _mysql_debug(
202 PyObject *self,
203 PyObject *args)
204 {
205 char *debug;
206 if (!PyArg_ParseTuple(args, "s", &debug)) return NULL;
207 mysql_debug(debug);
208 Py_INCREF(Py_None);
209 return Py_None;
210 }
211
212 extern char _mysql_escape_string__doc__[];
213 PyObject *
214 _mysql_escape_string(
215 _mysql_ConnectionObject *self,
216 PyObject *args);
217
218 extern char _mysql_string_literal__doc__[];
219 PyObject *
220 _mysql_string_literal(
221 _mysql_ConnectionObject *self,
222 PyObject *args);
223
224 static PyObject *_mysql_NULL;
225
226 PyObject *
227 _escape_item(
228 PyObject *item,
229 PyObject *d)
230 {
231 PyObject *quoted=NULL, *itemtype, *itemconv;
232 if (!(itemtype = PyObject_Type(item)))
233 goto error;
234 itemconv = PyObject_GetItem(d, itemtype);
235 Py_DECREF(itemtype);
236 if (!itemconv) {
237 PyErr_Clear();
238 itemconv = PyObject_GetItem(d,
239 (PyObject *) &PyString_Type);
240 }
241 if (!itemconv) {
242 PyErr_SetString(PyExc_TypeError,
243 "no default type converter defined");
244 goto error;
245 }
246 quoted = PyObject_CallFunction(itemconv, "OO", item, d);
247 Py_DECREF(itemconv);
248 error:
249 return quoted;
250 }
251
252 extern char _mysql_escape__doc__[];
253 PyObject *
254 _mysql_escape(
255 PyObject *self,
256 PyObject *args);
257
258 static char _mysql_escape_sequence__doc__[] =
259 "escape_sequence(seq, dict) -- escape any special characters in sequence\n\
260 seq using mapping dict to provide quoting functions for each type.\n\
261 Returns a tuple of escaped items.";
262 static PyObject *
263 _mysql_escape_sequence(
264 PyObject *self,
265 PyObject *args)
266 {
267 PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted;
268 int i, n;
269 if (!PyArg_ParseTuple(args, "OO:escape_sequence", &o, &d))
270 goto error;
271 if (!PyMapping_Check(d)) {
272 PyErr_SetString(PyExc_TypeError,
273 "argument 2 must be a mapping");
274 return NULL;
275 }
276 if ((n = PyObject_Length(o)) == -1) goto error;
277 if (!(r = PyTuple_New(n))) goto error;
278 for (i=0; i<n; i++) {
279 item = PySequence_GetItem(o, i);
280 if (!item) goto error;
281 quoted = _escape_item(item, d);
282 Py_DECREF(item);
283 if (!quoted) goto error;
284 PyTuple_SET_ITEM(r, i, quoted);
285 }
286 return r;
287 error:
288 Py_XDECREF(r);
289 return NULL;
290 }
291
292 static char _mysql_escape_dict__doc__[] =
293 "escape_sequence(d, dict) -- escape any special characters in\n\
294 dictionary d using mapping dict to provide quoting functions for each type.\n\
295 Returns a dictionary of escaped items.";
296 static PyObject *
297 _mysql_escape_dict(
298 PyObject *self,
299 PyObject *args)
300 {
301 PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted, *pkey;
302 Py_ssize_t ppos = 0;
303 if (!PyArg_ParseTuple(args, "O!O:escape_dict", &PyDict_Type, &o, &d))
304 goto error;
305 if (!PyMapping_Check(d)) {
306 PyErr_SetString(PyExc_TypeError,
307 "argument 2 must be a mapping");
308 return NULL;
309 }
310 if (!(r = PyDict_New())) goto error;
311 while (PyDict_Next(o, &ppos, &pkey, &item)) {
312 quoted = _escape_item(item, d);
313 if (!quoted) goto error;
314 if (PyDict_SetItem(r, pkey, quoted)==-1) goto error;
315 Py_DECREF(quoted);
316 }
317 return r;
318 error:
319 Py_XDECREF(r);
320 return NULL;
321 }
322
323 static char _mysql_get_client_info__doc__[] =
324 "get_client_info() -- Returns a string that represents\n\
325 the client library version.";
326 static PyObject *
327 _mysql_get_client_info(
328 PyObject *self,
329 PyObject *unused)
330 {
331 check_server_init(NULL);
332 return PyString_FromString(mysql_get_client_info());
333 }
334
335 extern PyTypeObject _mysql_ConnectionObject_Type;
336 extern PyTypeObject _mysql_ResultObject_Type;
337
338 static PyMethodDef
339 _mysql_methods[] = {
340 {
341 "connect",
342 (PyCFunction)_mysql_connect,
343 METH_VARARGS | METH_KEYWORDS,
344 _mysql_connect__doc__
345 },
346 {
347 "debug",
348 (PyCFunction)_mysql_debug,
349 METH_VARARGS,
350 _mysql_debug__doc__
351 },
352 {
353 "escape",
354 (PyCFunction)_mysql_escape,
355 METH_VARARGS,
356 _mysql_escape__doc__
357 },
358 {
359 "escape_sequence",
360 (PyCFunction)_mysql_escape_sequence,
361 METH_VARARGS,
362 _mysql_escape_sequence__doc__
363 },
364 {
365 "escape_dict",
366 (PyCFunction)_mysql_escape_dict,
367 METH_VARARGS,
368 _mysql_escape_dict__doc__
369 },
370 {
371 "escape_string",
372 (PyCFunction)_mysql_escape_string,
373 METH_VARARGS,
374 _mysql_escape_string__doc__
375 },
376 {
377 "string_literal",
378 (PyCFunction)_mysql_string_literal,
379 METH_VARARGS,
380 _mysql_string_literal__doc__
381 },
382 {
383 "get_client_info",
384 (PyCFunction)_mysql_get_client_info,
385 METH_NOARGS,
386 _mysql_get_client_info__doc__
387 },
388 #if MYSQL_VERSION_ID >= 32314
389 {
390 "thread_safe",
391 (PyCFunction)_mysql_thread_safe,
392 METH_NOARGS,
393 _mysql_thread_safe__doc__
394 },
395 #endif
396 {
397 "server_init",
398 (PyCFunction)_mysql_server_init,
399 METH_VARARGS | METH_KEYWORDS,
400 _mysql_server_init__doc__
401 },
402 {
403 "server_end",
404 (PyCFunction)_mysql_server_end,
405 METH_NOARGS,
406 _mysql_server_end__doc__
407 },
408 {NULL, NULL} /* sentinel */
409 };
410
411 static PyObject *
412 _mysql_NewException(
413 PyObject *dict,
414 PyObject *edict,
415 char *name)
416 {
417 PyObject *e;
418
419 if (!(e = PyDict_GetItemString(edict, name)))
420 return NULL;
421 if (PyDict_SetItemString(dict, name, e)) return NULL;
422 return e;
423 }
424
425 #define QUOTE(X) _QUOTE(X)
426 #define _QUOTE(X) #X
427
428 static char _mysql___doc__[] =
429 "an adaptation of the MySQL C API (mostly)\n\
430 \n\
431 You probably are better off using MySQLdb instead of using this\n\
432 module directly.\n\
433 \n\
434 In general, renaming goes from mysql_* to _mysql.*. _mysql.connect()\n\
435 returns a connection object (MYSQL). Functions which expect MYSQL * as\n\
436 an argument are now methods of the connection object. A number of things\n\
437 return result objects (MYSQL_RES). Functions which expect MYSQL_RES * as\n\
438 an argument are now methods of the result object. Deprecated functions\n\
439 (as of 3.23) are NOT implemented.\n\
440 ";
441
442 PyMODINIT_FUNC
443 init_mysql(void)
444 {
445 PyObject *dict, *module, *emod, *edict, *version_tuple;
446
447 module = Py_InitModule3("_mysql", _mysql_methods, _mysql___doc__);
448 if (!module)
449 return; /* this really should never happen */
450
451 /* Populate final object settings */
452 _mysql_ConnectionObject_Type.ob_type = &PyType_Type;
453 _mysql_ResultObject_Type.ob_type = &PyType_Type;
454 _mysql_FieldObject_Type.ob_type = &PyType_Type;
455 _mysql_ConnectionObject_Type.tp_alloc = PyType_GenericAlloc;
456 _mysql_ConnectionObject_Type.tp_new = PyType_GenericNew;
457 _mysql_ConnectionObject_Type.tp_free = _PyObject_GC_Del;
458 _mysql_ResultObject_Type.tp_alloc = PyType_GenericAlloc;
459 _mysql_ResultObject_Type.tp_new = PyType_GenericNew;
460 _mysql_ResultObject_Type.tp_free = _PyObject_GC_Del;
461 _mysql_FieldObject_Type.tp_alloc = PyType_GenericAlloc;
462 _mysql_FieldObject_Type.tp_new = PyType_GenericNew;
463 _mysql_FieldObject_Type.tp_free = _PyObject_GC_Del;
464
465 if (!(dict = PyModule_GetDict(module)))
466 goto error;
467
468 /* Module constants */
469 version_tuple = PyRun_String(QUOTE(version_info), Py_eval_input,
470 dict, dict);
471 if (PyModule_AddObject(module, "version_info", version_tuple) < 0)
472 goto error;
473 if (PyModule_AddStringConstant(module, "__version__",
474 QUOTE(__version__)) < 0)
475 goto error;
476 if (PyModule_AddStringConstant(module, "NULL", "NULL") < 0)
477 goto error;
478
479
480 /* Register types */
481 if (PyDict_SetItemString(dict, "connection",
482 (PyObject *)&_mysql_ConnectionObject_Type))
483 goto error;
484 Py_INCREF(&_mysql_ConnectionObject_Type);
485 if (PyDict_SetItemString(dict, "result",
486 (PyObject *)&_mysql_ResultObject_Type))
487 goto error;
488 Py_INCREF(&_mysql_ResultObject_Type);
489 if (PyDict_SetItemString(dict, "field",
490 (PyObject *)&_mysql_FieldObject_Type))
491 goto error;
492 Py_INCREF(&_mysql_FieldObject_Type);
493
494 /* Reach into the exceptions module. */
495 if (!(emod = PyImport_ImportModule("MySQLdb.exceptions")))
496 goto error;
497 if (!(edict = PyModule_GetDict(emod))) goto error;
498 if (!(_mysql_MySQLError =
499 _mysql_NewException(dict, edict, "MySQLError")))
500 goto error;
501 if (!(_mysql_Warning =
502 _mysql_NewException(dict, edict, "Warning")))
503 goto error;
504 if (!(_mysql_Error =
505 _mysql_NewException(dict, edict, "Error")))
506 goto error;
507 if (!(_mysql_InterfaceError =
508 _mysql_NewException(dict, edict, "InterfaceError")))
509 goto error;
510 if (!(_mysql_DatabaseError =
511 _mysql_NewException(dict, edict, "DatabaseError")))
512 goto error;
513 if (!(_mysql_DataError =
514 _mysql_NewException(dict, edict, "DataError")))
515 goto error;
516 if (!(_mysql_OperationalError =
517 _mysql_NewException(dict, edict, "OperationalError")))
518 goto error;
519 if (!(_mysql_IntegrityError =
520 _mysql_NewException(dict, edict, "IntegrityError")))
521 goto error;
522 if (!(_mysql_InternalError =
523 _mysql_NewException(dict, edict, "InternalError")))
524 goto error;
525 if (!(_mysql_ProgrammingError =
526 _mysql_NewException(dict, edict, "ProgrammingError")))
527 goto error;
528 if (!(_mysql_NotSupportedError =
529 _mysql_NewException(dict, edict, "NotSupportedError")))
530 goto error;
531 if (!(_mysql_error_map = PyDict_GetItemString(edict, "error_map")))
532 goto error;
533 Py_DECREF(emod);
534
535 error:
536 if (PyErr_Occurred())
537 PyErr_SetString(PyExc_ImportError,
538 "_mysql: init failed");
539 return;
540 }
541
542