comparison src/connections.c @ 67:98d968f5af11 MySQLdb

Reimplement MySQL->Python type conversion in C; much simpler and easier to deal with now. Hey, all my tests pass, so I guess that means I need to write some more tests.
author adustman
date Mon, 30 Mar 2009 20:21:24 +0000
parents e606fd52e866
children 18e5892a5aed
comparison
equal deleted inserted replaced
66:5a7c30cd9de2 67:98d968f5af11
7 _mysql_ConnectionObject *self, 7 _mysql_ConnectionObject *self,
8 PyObject *args, 8 PyObject *args,
9 PyObject *kwargs) 9 PyObject *kwargs)
10 { 10 {
11 MYSQL *conn = NULL; 11 MYSQL *conn = NULL;
12 PyObject *conv = NULL; 12 PyObject *decoder_stack = NULL;
13 PyObject *ssl = NULL; 13 PyObject *ssl = NULL;
14 #if HAVE_OPENSSL 14 #if HAVE_OPENSSL
15 char *key = NULL, *cert = NULL, *ca = NULL, 15 char *key = NULL, *cert = NULL, *ca = NULL,
16 *capath = NULL, *cipher = NULL; 16 *capath = NULL, *cipher = NULL;
17 #endif 17 #endif
18 char *host = NULL, *user = NULL, *passwd = NULL, 18 char *host = NULL, *user = NULL, *passwd = NULL,
19 *db = NULL, *unix_socket = NULL; 19 *db = NULL, *unix_socket = NULL;
20 unsigned int port = 0; 20 unsigned int port = 0;
21 unsigned int client_flag = 0; 21 unsigned int client_flag = 0;
22 static char *kwlist[] = { "host", "user", "passwd", "db", "port", 22 static char *kwlist[] = { "host", "user", "passwd", "db", "port",
23 "unix_socket", "conv", 23 "unix_socket", "decoder_stack",
24 "connect_timeout", "compress", 24 "connect_timeout", "compress",
25 "named_pipe", "init_command", 25 "named_pipe", "init_command",
26 "read_default_file", "read_default_group", 26 "read_default_file", "read_default_group",
27 "client_flag", "ssl", 27 "client_flag", "ssl",
28 "local_infile", 28 "local_infile",
31 int compress = -1, named_pipe = -1, local_infile = -1; 31 int compress = -1, named_pipe = -1, local_infile = -1;
32 char *init_command=NULL, 32 char *init_command=NULL,
33 *read_default_file=NULL, 33 *read_default_file=NULL,
34 *read_default_group=NULL; 34 *read_default_group=NULL;
35 35
36 self->converter = NULL; 36 self->decoder_stack = NULL;
37 self->open = 0; 37 self->open = 0;
38 check_server_init(-1); 38 check_server_init(-1);
39 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssssisOiiisssiOi:connect", 39 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssssisOiiisssiOi:connect",
40 kwlist, 40 kwlist,
41 &host, &user, &passwd, &db, 41 &host, &user, &passwd, &db,
42 &port, &unix_socket, &conv, 42 &port, &unix_socket, &decoder_stack,
43 &connect_timeout, 43 &connect_timeout,
44 &compress, &named_pipe, 44 &compress, &named_pipe,
45 &init_command, &read_default_file, 45 &init_command, &read_default_file,
46 &read_default_group, 46 &read_default_group,
47 &client_flag, &ssl, 47 &client_flag, &ssl,
48 &local_infile 48 &local_infile
49 )) 49 ))
50 return -1; 50 return -1;
51 51
52 /* Keep the converter mapping or a blank mapping dict */ 52 if (!decoder_stack)
53 if (!conv) 53 decoder_stack = PyList_New(0);
54 conv = PyDict_New();
55 else 54 else
56 Py_INCREF(conv); 55 Py_INCREF(decoder_stack);
57 if (!conv) 56 self->decoder_stack = decoder_stack;
58 return -1; 57
59 self->converter = conv;
60
61 #define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\ 58 #define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\
62 if(t){d=PyString_AsString(t);Py_DECREF(t);}\ 59 if(t){d=PyString_AsString(t);Py_DECREF(t);}\
63 PyErr_Clear();} 60 PyErr_Clear();}
64 61
65 if (ssl) { 62 if (ssl) {
146 integer, TCP/IP port to connect to\n\ 143 integer, TCP/IP port to connect to\n\
147 \n\ 144 \n\
148 unix_socket\n\ 145 unix_socket\n\
149 string, location of unix_socket (UNIX-ish only)\n\ 146 string, location of unix_socket (UNIX-ish only)\n\
150 \n\ 147 \n\
151 conv\n\
152 mapping, maps MySQL FIELD_TYPE.* to Python functions which\n\
153 convert a string to the appropriate Python type\n\
154 \n\
155 connect_timeout\n\ 148 connect_timeout\n\
156 number of seconds to wait before the connection\n\ 149 number of seconds to wait before the connection\n\
157 attempt fails.\n\ 150 attempt fails.\n\
158 \n\ 151 \n\
159 compress\n\ 152 compress\n\
199 static int _mysql_ConnectionObject_traverse( 192 static int _mysql_ConnectionObject_traverse(
200 _mysql_ConnectionObject *self, 193 _mysql_ConnectionObject *self,
201 visitproc visit, 194 visitproc visit,
202 void *arg) 195 void *arg)
203 { 196 {
204 if (self->converter) 197 if (self->decoder_stack)
205 return visit(self->converter, arg); 198 return visit(self->decoder_stack, arg);
206 return 0; 199 return 0;
207 } 200 }
208 201
209 static int _mysql_ConnectionObject_clear( 202 static int _mysql_ConnectionObject_clear(
210 _mysql_ConnectionObject *self) 203 _mysql_ConnectionObject *self)
211 { 204 {
212 Py_XDECREF(self->converter); 205 Py_XDECREF(self->decoder_stack);
213 self->converter = NULL; 206 self->decoder_stack = NULL;
214 return 0; 207 return 0;
215 } 208 }
216 209
217 extern PyObject * 210 extern PyObject *
218 _escape_item( 211 _escape_item(
219 PyObject *item, 212 PyObject *item,
220 PyObject *d); 213 PyObject *d);
221
222 char _mysql_escape__doc__[] =
223 "escape(obj, dict) -- escape any special characters in object obj\n\
224 using mapping dict to provide quoting functions for each type.\n\
225 Returns a SQL literal string.";
226 PyObject *
227 _mysql_escape(
228 PyObject *self,
229 PyObject *args)
230 {
231 PyObject *o=NULL, *d=NULL;
232 if (!PyArg_ParseTuple(args, "O|O:escape", &o, &d))
233 return NULL;
234 if (d) {
235 if (!PyMapping_Check(d)) {
236 PyErr_SetString(PyExc_TypeError,
237 "argument 2 must be a mapping");
238 return NULL;
239 }
240 return _escape_item(o, d);
241 } else {
242 if (!self) {
243 PyErr_SetString(PyExc_TypeError,
244 "argument 2 must be a mapping");
245 return NULL;
246 }
247 return _escape_item(o,
248 ((_mysql_ConnectionObject *) self)->converter);
249 }
250 }
251 214
252 char _mysql_escape_string__doc__[] = 215 char _mysql_escape_string__doc__[] =
253 "escape_string(s) -- quote any SQL-interpreted characters in string s.\n\ 216 "escape_string(s) -- quote any SQL-interpreted characters in string s.\n\
254 \n\ 217 If you want quotes around your value, use string_literal(s) instead.\n\
255 Use connection.escape_string(s), if you use it at all.\n\ 218 ";
256 _mysql.escape_string(s) cannot handle character sets. You are\n\
257 probably better off using connection.escape(o) instead, since\n\
258 it will escape entire sequences as well as strings.";
259 219
260 PyObject * 220 PyObject *
261 _mysql_escape_string( 221 _mysql_escape_string(
262 _mysql_ConnectionObject *self, 222 _mysql_ConnectionObject *self,
263 PyObject *args) 223 PyObject *args)
267 int len, size; 227 int len, size;
268 if (!PyArg_ParseTuple(args, "s#:escape_string", &in, &size)) return NULL; 228 if (!PyArg_ParseTuple(args, "s#:escape_string", &in, &size)) return NULL;
269 str = PyString_FromStringAndSize((char *) NULL, size*2+1); 229 str = PyString_FromStringAndSize((char *) NULL, size*2+1);
270 if (!str) return PyErr_NoMemory(); 230 if (!str) return PyErr_NoMemory();
271 out = PyString_AS_STRING(str); 231 out = PyString_AS_STRING(str);
272 #if MYSQL_VERSION_ID < 32321 232 len = mysql_real_escape_string(&(self->connection), out, in, size);
273 len = mysql_escape_string(out, in, size);
274 #else
275 check_server_init(NULL);
276 if (self && self->open)
277 len = mysql_real_escape_string(&(self->connection), out, in, size);
278 else
279 len = mysql_escape_string(out, in, size);
280 #endif
281 if (_PyString_Resize(&str, len) < 0) return NULL; 233 if (_PyString_Resize(&str, len) < 0) return NULL;
282 return (str); 234 return (str);
283 } 235 }
284 236
285 char _mysql_string_literal__doc__[] = 237 char _mysql_string_literal__doc__[] =
286 "string_literal(obj) -- converts object obj into a SQL string literal.\n\ 238 "string_literal(s) -- converts string s into a SQL string literal.\n\
287 This means, any special SQL characters are escaped, and it is enclosed\n\ 239 This means, any special SQL characters are escaped, and it is enclosed\n\
288 within single quotes. In other words, it performs:\n\ 240 within single quotes. In other words, it performs:\n\
289 \n\ 241 \n\
290 \"'%s'\" % escape_string(str(obj))\n\ 242 \"'%s'\" % escape_string(s)\n\
291 \n\ 243 ";
292 Use connection.string_literal(obj), if you use it at all.\n\
293 _mysql.string_literal(obj) cannot handle character sets.";
294 244
295 PyObject * 245 PyObject *
296 _mysql_string_literal( 246 _mysql_string_literal(
297 _mysql_ConnectionObject *self, 247 _mysql_ConnectionObject *self,
298 PyObject *args) 248 PyObject *args)
299 { 249 {
300 PyObject *str, *s, *o, *d; 250 PyObject *str;
301 char *in, *out; 251 char *in, *out;
302 int len, size; 252 int len, size;
303 if (!PyArg_ParseTuple(args, "O|O:string_literal", &o, &d)) return NULL; 253 if (!PyArg_ParseTuple(args, "s#:string_literal", &in, &size)) return NULL;
304 s = PyObject_Str(o);
305 if (!s) return NULL;
306 in = PyString_AsString(s);
307 size = PyString_GET_SIZE(s);
308 str = PyString_FromStringAndSize((char *) NULL, size*2+3); 254 str = PyString_FromStringAndSize((char *) NULL, size*2+3);
309 if (!str) return PyErr_NoMemory(); 255 if (!str) return PyErr_NoMemory();
310 out = PyString_AS_STRING(str); 256 out = PyString_AS_STRING(str);
311 #if MYSQL_VERSION_ID < 32321 257 len = mysql_real_escape_string(&(self->connection), out+1, in, size);
312 len = mysql_escape_string(out+1, in, size);
313 #else
314 check_server_init(NULL);
315 if (self && self->open)
316 len = mysql_real_escape_string(&(self->connection), out+1, in, size);
317 else
318 len = mysql_escape_string(out+1, in, size);
319 #endif
320 *out = *(out+len+1) = '\''; 258 *out = *(out+len+1) = '\'';
321 if (_PyString_Resize(&str, len+2) < 0) return NULL; 259 if (_PyString_Resize(&str, len+2) < 0) return NULL;
322 Py_DECREF(s);
323 return (str); 260 return (str);
324 } 261 }
325 262
326 static char _mysql_ConnectionObject_close__doc__[] = 263 static char _mysql_ConnectionObject_close__doc__[] =
327 "Close the connection. No further activity possible."; 264 "Close the connection. No further activity possible.";
992 { 929 {
993 PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL; 930 PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL;
994 _mysql_ResultObject *r=NULL; 931 _mysql_ResultObject *r=NULL;
995 932
996 check_connection(self); 933 check_connection(self);
997 arglist = Py_BuildValue("(OiO)", self, 0, self->converter); 934 arglist = Py_BuildValue("(OiO)", self, 0, self->decoder_stack);
998 if (!arglist) goto error; 935 if (!arglist) goto error;
999 kwarglist = PyDict_New(); 936 kwarglist = PyDict_New();
1000 if (!kwarglist) goto error; 937 if (!kwarglist) goto error;
1001 r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type); 938 r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type);
1002 if (!r) goto error; 939 if (!r) goto error;
1052 { 989 {
1053 PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL; 990 PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL;
1054 _mysql_ResultObject *r=NULL; 991 _mysql_ResultObject *r=NULL;
1055 992
1056 check_connection(self); 993 check_connection(self);
1057 arglist = Py_BuildValue("(OiO)", self, 1, self->converter); 994 arglist = Py_BuildValue("(OiO)", self, 1, self->decoder_stack);
1058 if (!arglist) return NULL; 995 if (!arglist) return NULL;
1059 kwarglist = PyDict_New(); 996 kwarglist = PyDict_New();
1060 if (!kwarglist) goto error; 997 if (!kwarglist) goto error;
1061 r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type); 998 r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type);
1062 if (!r) goto error; 999 if (!r) goto error;
1195 (PyCFunction)_mysql_ConnectionObject_dump_debug_info, 1132 (PyCFunction)_mysql_ConnectionObject_dump_debug_info,
1196 METH_NOARGS, 1133 METH_NOARGS,
1197 _mysql_ConnectionObject_dump_debug_info__doc__ 1134 _mysql_ConnectionObject_dump_debug_info__doc__
1198 }, 1135 },
1199 { 1136 {
1200 "escape",
1201 (PyCFunction)_mysql_escape,
1202 METH_VARARGS,
1203 _mysql_escape__doc__
1204 },
1205 {
1206 "escape_string", 1137 "escape_string",
1207 (PyCFunction)_mysql_escape_string, 1138 (PyCFunction)_mysql_escape_string,
1208 METH_VARARGS, 1139 METH_VARARGS,
1209 _mysql_escape_string__doc__ 1140 _mysql_escape_string__doc__
1210 }, 1141 },
1325 offsetof(_mysql_ConnectionObject, open), 1256 offsetof(_mysql_ConnectionObject, open),
1326 RO, 1257 RO,
1327 "True if connection is open" 1258 "True if connection is open"
1328 }, 1259 },
1329 { 1260 {
1330 "converter", 1261 "decoder_stack",
1331 T_OBJECT, 1262 T_OBJECT,
1332 offsetof(_mysql_ConnectionObject, converter), 1263 offsetof(_mysql_ConnectionObject, decoder_stack),
1333 0, 1264 0,
1334 "Type conversion mapping" 1265 "Type decoder stack"
1335 }, 1266 },
1336 { 1267 {
1337 "server_capabilities", 1268 "server_capabilities",
1338 T_UINT, 1269 T_UINT,
1339 offsetof(_mysql_ConnectionObject, connection.server_capabilities), 1270 offsetof(_mysql_ConnectionObject, connection.server_capabilities),