├── README.md
├── amysql.c
├── amysql.so
├── setup.py
└── test.py
/README.md:
--------------------------------------------------------------------------------
1 |
Simple and High Performance MySQL Driver(Python).
2 |
3 | -
0. This is community version, supported and tested on Linux x64, Python 2.7;
4 |
-
1. This driver works fine and with very high performance for most company and most scene;
5 |
-
2. Note: not fully compatiable with MySQL offcial protocol;
6 |
-
3. contact the maintainer for License and/or business collaboration.
7 |
8 | Current Supported Functions:
9 |
10 | -
0. MySQL safe handshake(SHA1, MY_SCRAMBLE_LENGTH:20 byte);
11 |
-
1. SQL CRUD;
12 |
-
2. MySQL Store procedure.
13 |
14 | Interface:
15 |
16 | -
0. new connection:
17 |
18 | >>> import amysql;
19 | >>> c=amysql.Con();
20 | >>> c.connect(
21 |
'localhost', # server host
22 |
3306, # server port
23 |
'xweb', # username
24 |
'xweb123', # password
25 |
'xweb') # database
26 |
);
27 | -
1. SQL CRUD:
28 |
29 | >>> c.query("select * from sys_usr")
30 |
31 | -
2. Call MySQL Store Procedure:
32 |
33 | >>> c.query("call sys_usr_list()")
34 | -
3. Query Result:
35 |
36 | >>> c.rows
37 | >>> c.fields
38 | -
4. adapte to Python async socket( c.sock is instance of Python socket class. ):
39 |
40 | >>> c.sock
41 |
42 | Todo:
43 |
46 |
47 |
--------------------------------------------------------------------------------
/amysql.c:
--------------------------------------------------------------------------------
1 | /* Copyright (C) 2012 Abael Heyijun
2 | free for non-commercial use, All rights reserved. */
3 |
4 |
5 | #ifndef __UMY_H__
6 | #define __UMY_H__
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | //////// Python
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | //////// System - Level
22 | #define true 1
23 | #define false 0
24 | #define LOCK(con) con->rwlock =1
25 | #define UNLOCK(con) con->rwlock =0
26 | #ifdef Py_PYTHON_H
27 | #define THROW(...) do{fprintf(stderr,"Exception call: %s (%s:%ld)\n",__FUNCTION__, __FILE__, (long)__LINE__);fprintf(stderr, __VA_ARGS__);fflush(stderr);exit(-1);}while(0)
28 | #define MyMalloc(ptr, size) if((ptr=PyMem_Malloc(size))==NULL){THROW("Exception memory alloction(size:%d) ",(size));}
29 | #define MyCalloc(ptr, n, size) if((ptr=PyMem_Malloc((n) *(size)))==NULL){THROW("Exception memory alloction(size:%d) ",(size));}
30 | #define MyRealloc(ptr, size) if((ptr=PyMem_Realloc((void *)(ptr),size))==NULL){THROW("Exception memory alloction(size:%d) ",(size));}
31 | #define MyFree(p) if(p)PyMem_Free(p)
32 | #else
33 | #define THROW(...) do{fprintf(stderr,"Exception call: %s (%s:%ld)\n",__FUNCTION__, __FILE__, (long)__LINE__);fprintf(stderr, __VA_ARGS__);fflush(stderr);exit(-1);}while(0)
34 | #define MyMalloc(ptr, size) if((ptr=malloc(size)==NULL){THROW("Exception memory alloction(size:%d) ",(size));}
35 | #define MyCalloc(ptr, n, size) if((ptr=calloc(n, (size)))==NULL){THROW("Exception memory alloction(size:%d) ",(size));}
36 | #define MyRealloc(ptr, size) if((ptr=realloc((void *)(ptr), (size)))==NULL){THROW("Exception memory alloction(size:%d) ",(size));}
37 | #define MyFree(p) if(p)free(p)
38 | #endif
39 | #define EXPORTFUNCTION extern "C" __declspec(dllexport)
40 | typedef u_int8_t UINT1;
41 | typedef u_int16_t UINT2;
42 | typedef u_int32_t UINT4;
43 | typedef u_int64_t UINT8;
44 |
45 | typedef int8_t INT1;
46 | typedef int16_t INT2;
47 | typedef int32_t INT4;
48 | typedef int64_t INT8;
49 | typedef unsigned long long ulonglong;
50 | typedef unsigned long ulong;
51 | typedef unsigned char bool;
52 |
53 |
54 | //////// App Level
55 | #define MY_BUFFER_MAX 1073741824 // (1024*1024*1024)
56 | #define MY_PACKET_MAX 16777215 // (1024*1024*16 -1)
57 | #define MY_HANDSHAKE_SIZE 74
58 | #define MY_HEADER_SIZE 4
59 | #define MY_SQLSTATE_LENGTH 5
60 | #define MY_PROTOCOL_VERSION 0xa
61 | #define MY_SHA1_HASH_SIZE 20
62 | #define MY_NULL_LENGTH ((unsigned long) ~0)
63 | #define MY_SCRAMBLE_LENGTH 20
64 | #define MY_SCRAMBLE_LENGTH_323 8
65 | #define MY_PACKET_ERROR 0
66 | #define MY_TX_BUFFER_SIZE 4194304 //(1024*1024*4)
67 | #define MY_BUFFER_SIZE 16777216 // (1024*1024*16)
68 | #define MY_PACKET_MAX 16777215 // (1024*1024*16 -1)
69 | #define SERVER_STATUS_IN_TRANS 1
70 | #define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
71 | #define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */
72 | #define SERVER_QUERY_NO_GOOD_INDEX_USED 16
73 | #define SERVER_QUERY_NO_INDEX_USED 32
74 | #define PVERSION41_CHAR '*'
75 |
76 | #define SHA1CircularShift(bits,word) (((word) << (bits)) | ((word) >> (32-(bits))))
77 | enum sha_result_codes {
78 | SHA_SUCCESS = 0, SHA_NULL, /* Null pointer parameter */
79 | SHA_INPUT_TOO_LONG, /* input data too long */
80 | SHA_STATE_ERROR /* called Input after Result */
81 | };
82 | typedef struct SHA1_CONTEXT {
83 | ulonglong Length; /* Message length in bits */
84 | UINT4 Intermediate_Hash[MY_SHA1_HASH_SIZE / 4]; /* Message Digest */
85 | int Computed; /* Is the digest computed? */
86 | int Corrupted; /* Is the message digest corrupted? */
87 | INT2 Message_Block_Index; /* Index into message block array */
88 | UINT1 Message_Block[64]; /* 512-bit message blocks */
89 | } SHA1_CONTEXT;
90 | static const UINT4 sha_const_key[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,0xC3D2E1F0 };
91 | static const UINT4 SHA1_KEY[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
92 |
93 | static PyObject *sockmodule = NULL;
94 | static PyObject *sockclass = NULL;
95 | static PyTypeObject ConType;
96 | static PyObject *amysql_Error;
97 | static PyObject *amysql_SQLError;
98 |
99 | enum MY_CHARSETS {
100 | MCS_UNDEFINED = 0,
101 | MCS_big5_chinese_ci = 1,
102 | MCS_big5_bin = 84,
103 | MCS_dec8_swedish_ci = 3,
104 | MCS_dec8_bin = 69,
105 | MCS_cp850_general_ci = 4,
106 | MCS_cp850_bin = 80,
107 | MCS_hp8_english_ci = 6,
108 | MCS_hp8_bin = 72,
109 | MCS_koi8r_general_ci = 7,
110 | MCS_koi8r_bin = 74,
111 | MCS_latin1_german1_ci = 5,
112 | MCS_latin1_swedish_ci = 8,
113 | MCS_latin1_danish_ci = 15,
114 | MCS_latin1_german2_ci = 31,
115 | MCS_latin1_bin = 47,
116 | MCS_latin1_general_ci = 48,
117 | MCS_latin1_general_cs = 49,
118 | MCS_latin1_spanish_ci = 94,
119 | MCS_latin2_czech_cs = 2,
120 | MCS_latin2_general_ci = 9,
121 | MCS_latin2_hungarian_ci = 21,
122 | MCS_latin2_croatian_ci = 27,
123 | MCS_latin2_bin = 77,
124 | MCS_swe7_swedish_ci = 10,
125 | MCS_swe7_bin = 82,
126 | MCS_ascii_general_ci = 11,
127 | MCS_ascii_bin = 65,
128 | MCS_ujis_japanese_ci = 12,
129 | MCS_ujis_bin = 91,
130 | MCS_sjis_japanese_ci = 13,
131 | MCS_sjis_bin = 88,
132 | MCS_hebrew_general_ci = 16,
133 | MCS_hebrew_bin = 71,
134 | MCS_tis620_thai_ci = 18,
135 | MCS_tis620_bin = 89,
136 | MCS_euckr_korean_ci = 19,
137 | MCS_euckr_bin = 85,
138 | MCS_koi8u_general_ci = 22,
139 | MCS_koi8u_bin = 75,
140 | MCS_gb2312_chinese_ci = 24,
141 | MCS_gb2312_bin = 86,
142 | MCS_greek_general_ci = 25,
143 | MCS_greek_bin = 70,
144 | MCS_cp1250_general_ci = 26,
145 | MCS_cp1250_czech_cs = 34,
146 | MCS_cp1250_croatian_ci = 44,
147 | MCS_cp1250_bin = 66,
148 | MCS_cp1250_polish_ci = 99,
149 | MCS_gbk_chinese_ci = 28,
150 | MCS_gbk_bin = 87,
151 | MCS_latin5_turkish_ci = 30,
152 | MCS_latin5_bin = 78,
153 | MCS_armscii8_general_ci = 32,
154 | MCS_armscii8_bin = 64,
155 | MCS_utf8_general_ci = 33,
156 | MCS_utf8_bin = 83,
157 | MCS_utf8_unicode_ci = 192,
158 | MCS_utf8_icelandic_ci = 193,
159 | MCS_utf8_latvian_ci = 194,
160 | MCS_utf8_romanian_ci = 195,
161 | MCS_utf8_slovenian_ci = 196,
162 | MCS_utf8_polish_ci = 197,
163 | MCS_utf8_estonian_ci = 198,
164 | MCS_utf8_spanish_ci = 199,
165 | MCS_utf8_swedish_ci = 200,
166 | MCS_utf8_turkish_ci = 201,
167 | MCS_utf8_czech_ci = 202,
168 | MCS_utf8_danish_ci = 203,
169 | MCS_utf8_lithuanian_ci = 204,
170 | MCS_utf8_slovak_ci = 205,
171 | MCS_utf8_spanish2_ci = 206,
172 | MCS_utf8_roman_ci = 207,
173 | MCS_utf8_persian_ci = 208,
174 | MCS_utf8_esperanto_ci = 209,
175 | MCS_utf8_hungarian_ci = 210,
176 | MCS_utf8_sinhala_ci = 211,
177 | MCS_ucs2_general_ci = 35,
178 | MCS_ucs2_bin = 90,
179 | MCS_ucs2_unicode_ci = 128,
180 | MCS_ucs2_icelandic_ci = 129,
181 | MCS_ucs2_latvian_ci = 130,
182 | MCS_ucs2_romanian_ci = 131,
183 | MCS_ucs2_slovenian_ci = 132,
184 | MCS_ucs2_polish_ci = 133,
185 | MCS_ucs2_estonian_ci = 134,
186 | MCS_ucs2_spanish_ci = 135,
187 | MCS_ucs2_swedish_ci = 136,
188 | MCS_ucs2_turkish_ci = 137,
189 | MCS_ucs2_czech_ci = 138,
190 | MCS_ucs2_danish_ci = 139,
191 | MCS_ucs2_lithuanian_ci = 140,
192 | MCS_ucs2_slovak_ci = 141,
193 | MCS_ucs2_spanish2_ci = 142,
194 | MCS_ucs2_roman_ci = 143,
195 | MCS_ucs2_persian_ci = 144,
196 | MCS_ucs2_esperanto_ci = 145,
197 | MCS_ucs2_hungarian_ci = 146,
198 | MCS_ucs2_sinhala_ci = 147,
199 | MCS_cp866_general_ci = 36,
200 | MCS_cp866_bin = 68,
201 | MCS_keybcs2_general_ci = 37,
202 | MCS_keybcs2_bin = 73,
203 | MCS_macce_general_ci = 38,
204 | MCS_macce_bin = 43,
205 | MCS_macroman_general_ci = 39,
206 | MCS_macroman_bin = 53,
207 | MCS_cp852_general_ci = 40,
208 | MCS_cp852_bin = 81,
209 | MCS_latin7_estonian_cs = 20,
210 | MCS_latin7_general_ci = 41,
211 | MCS_latin7_general_cs = 42,
212 | MCS_latin7_bin = 79,
213 | MCS_utf8mb4_general_ci = 45,
214 | MCS_utf8mb4_bin = 46,
215 | MCS_utf8mb4_unicode_ci = 224,
216 | MCS_utf8mb4_icelandic_ci = 225,
217 | MCS_utf8mb4_latvian_ci = 226,
218 | MCS_utf8mb4_romanian_ci = 227,
219 | MCS_utf8mb4_slovenian_ci = 228,
220 | MCS_utf8mb4_polish_ci = 229,
221 | MCS_utf8mb4_estonian_ci = 230,
222 | MCS_utf8mb4_spanish_ci = 231,
223 | MCS_utf8mb4_swedish_ci = 232,
224 | MCS_utf8mb4_turkish_ci = 233,
225 | MCS_utf8mb4_czech_ci = 234,
226 | MCS_utf8mb4_danish_ci = 235,
227 | MCS_utf8mb4_lithuanian_ci = 236,
228 | MCS_utf8mb4_slovak_ci = 237,
229 | MCS_utf8mb4_spanish2_ci = 238,
230 | MCS_utf8mb4_roman_ci = 239,
231 | MCS_utf8mb4_persian_ci = 240,
232 | MCS_utf8mb4_esperanto_ci = 241,
233 | MCS_utf8mb4_hungarian_ci = 242,
234 | MCS_utf8mb4_sinhala_ci = 243,
235 | MCS_cp1251_bulgarian_ci = 14,
236 | MCS_cp1251_ukrainian_ci = 23,
237 | MCS_cp1251_bin = 50,
238 | MCS_cp1251_general_ci = 51,
239 | MCS_cp1251_general_cs = 52,
240 | MCS_utf16_general_ci = 54,
241 | MCS_utf16_bin = 55,
242 | MCS_utf16_unicode_ci = 101,
243 | MCS_utf16_icelandic_ci = 102,
244 | MCS_utf16_latvian_ci = 103,
245 | MCS_utf16_romanian_ci = 104,
246 | MCS_utf16_slovenian_ci = 105,
247 | MCS_utf16_polish_ci = 106,
248 | MCS_utf16_estonian_ci = 107,
249 | MCS_utf16_spanish_ci = 108,
250 | MCS_utf16_swedish_ci = 109,
251 | MCS_utf16_turkish_ci = 110,
252 | MCS_utf16_czech_ci = 111,
253 | MCS_utf16_danish_ci = 112,
254 | MCS_utf16_lithuanian_ci = 113,
255 | MCS_utf16_slovak_ci = 114,
256 | MCS_utf16_spanish2_ci = 115,
257 | MCS_utf16_roman_ci = 116,
258 | MCS_utf16_persian_ci = 117,
259 | MCS_utf16_esperanto_ci = 118,
260 | MCS_utf16_hungarian_ci = 119,
261 | MCS_utf16_sinhala_ci = 120,
262 | MCS_cp1256_general_ci = 57,
263 | MCS_cp1256_bin = 67,
264 | MCS_cp1257_lithuanian_ci = 29,
265 | MCS_cp1257_bin = 58,
266 | MCS_cp1257_general_ci = 59,
267 | MCS_utf32_general_ci = 60,
268 | MCS_utf32_bin = 61,
269 | MCS_utf32_unicode_ci = 160,
270 | MCS_utf32_icelandic_ci = 161,
271 | MCS_utf32_latvian_ci = 162,
272 | MCS_utf32_romanian_ci = 163,
273 | MCS_utf32_slovenian_ci = 164,
274 | MCS_utf32_polish_ci = 165,
275 | MCS_utf32_estonian_ci = 166,
276 | MCS_utf32_spanish_ci = 167,
277 | MCS_utf32_swedish_ci = 168,
278 | MCS_utf32_turkish_ci = 169,
279 | MCS_utf32_czech_ci = 170,
280 | MCS_utf32_danish_ci = 171,
281 | MCS_utf32_lithuanian_ci = 172,
282 | MCS_utf32_slovak_ci = 173,
283 | MCS_utf32_spanish2_ci = 174,
284 | MCS_utf32_roman_ci = 175,
285 | MCS_utf32_persian_ci = 176,
286 | MCS_utf32_esperanto_ci = 177,
287 | MCS_utf32_hungarian_ci = 178,
288 | MCS_utf32_sinhala_ci = 179,
289 | MCS_binary = 63,
290 | MCS_geostd8_general_ci = 92,
291 | MCS_geostd8_bin = 93,
292 | MCS_cp932_japanese_ci = 95,
293 | MCS_cp932_bin = 96,
294 | MCS_eucjpms_japanese_ci = 97,
295 | MCS_eucjpms_bin = 98,
296 | };
297 |
298 | enum MY_CMD {
299 | COM_SLEEP,
300 | COM_QUIT,
301 | COM_INIT_DB,
302 | COM_QUERY,
303 | COM_FIELD_LIST,
304 | COM_CREATE_DB,
305 | COM_DROP_DB,
306 | COM_REFRESH,
307 | COM_SHUTDOWN,
308 | COM_STATISTICS,
309 | COM_PROCESS_INFO,
310 | COM_CONNECT,
311 | COM_PROCESS_KILL,
312 | COM_DEBUG,
313 | COM_PING,
314 | COM_TIME,
315 | COM_DELAYED_INSERT,
316 | COM_CHANGE_USER,
317 | COM_BINLOG_DUMP,
318 | COM_TABLE_DUMP,
319 | COM_CONNECT_OUT,
320 | COM_REGISTER_SLAVE,
321 | COM_STMT_PREPARE,
322 | COM_STMT_EXECUTE,
323 | COM_STMT_SEND_LONG_DATA,
324 | COM_STMT_CLOSE,
325 | COM_STMT_RESET,
326 | COM_SET_OPTION,
327 | COM_STMT_FETCH,
328 | COM_DAEMON,
329 | COM_END
330 | };
331 |
332 | enum MY_FIELDFLAG {
333 | MFFLAG_NOT_NULL_FLAG = 0x0001,
334 | MFFLAG_PRI_KEY_FLAG = 0x0002,
335 | MFFLAG_UNIQUE_KEY_FLAG = 0x0004,
336 | MFFLAG_MULTIPLE_KEY_FLAG = 0x0008,
337 | MFFLAG_BLOB_FLAG = 0x0010,
338 | MFFLAG_UNSIGNED_FLAG = 0x0020,
339 | MFFLAG_ZEROFILL_FLAG = 0x0040,
340 | MFFLAG_BINARY_FLAG = 0x0080,
341 | MFFLAG_ENUM_FLAG = 0x0100,
342 | MFFLAG_AUTO_INCREMENT_FLAG = 0x0200,
343 | MFFLAG_TIMESTAMP_FLAG = 0x0400,
344 | MFFLAG_SET_FLAG = 0x0800,
345 | };
346 |
347 | enum MY_STATUS {
348 | MY_STATUS_READY, MY_STATUS_GET_RESULT, MY_STATUS_USE_RESULT
349 | };
350 |
351 | enum MY_PACKETREAD {
352 | MPR_NONE = 0,
353 | MPR_MORE = 1,
354 | MPR_ERROR = 2,
355 | MPR_TRUE = 4,
356 | MPR_START = 8,
357 | MPR_END = 16,
358 | MPR_EOF = 32,
359 | };
360 |
361 | enum MY_FIELDTYPE {
362 | MFTYPE_DECIMAL = 0x00,
363 | MFTYPE_TINY = 0x01,
364 | MFTYPE_SHORT = 0x02,
365 | MFTYPE_LONG = 0x03,
366 | MFTYPE_FLOAT = 0x04,
367 | MFTYPE_DOUBLE = 0x05,
368 | MFTYPE_NULL = 0x06,
369 | MFTYPE_TIMESTAMP = 0x07,
370 | MFTYPE_LONGLONG = 0x08,
371 | MFTYPE_INT24 = 0x09,
372 | MFTYPE_DATE = 0x0a,
373 | MFTYPE_TIME = 0x0b,
374 | MFTYPE_DATETIME = 0x0c,
375 | MFTYPE_YEAR = 0x0d,
376 | MFTYPE_NEWDATE = 0x0e,
377 | MFTYPE_VARCHAR = 0x0f,
378 | MFTYPE_BIT = 0x10,
379 | MFTYPE_NEWDECIMAL = 0xf6,
380 | MFTYPE_ENUM = 0xf7,
381 | MFTYPE_SET = 0xf8,
382 | MFTYPE_TINY_BLOB = 0xf9,
383 | MFTYPE_MEDIUM_BLOB = 0xfa,
384 | MFTYPE_LONG_BLOB = 0xfb,
385 | MFTYPE_BLOB = 0xfc,
386 | MFTYPE_VAR_STRING = 0xfd,
387 | MFTYPE_STRING = 0xfe,
388 | MFTYPE_GEOMETRY = 0xff,
389 | };
390 |
391 | enum MY_CAPABILITIES {
392 | MCP_LONG_PASSWORD = (1 << 0), // new more secure passwords
393 | MCP_FOUND_ROWS = (1 << 1), //Found instead of affected rows
394 | MCP_LONG_FLAG = (1 << 2), //Get all column flags */
395 | MCP_CONNECT_WITH_DB = (1 << 3), // One can specify db on connect */
396 | MCP_NO_SCHEMA = (1 << 4), // /* Don't allow database.table.column */
397 | MCP_COMPRESS = (1 << 5), // Can use compression protocol */
398 | MCP_ODBC = (1 << 6), // Odbc client */
399 | MCP_LOCAL_FILES = (1 << 7), // Can use LOAD DATA LOCAL */
400 | MCP_IGNORE_SPACE = (1 << 8), // Ignore spaces before '(' */
401 | MCP_PROTOCOL_41 = (1 << 9), // New 4.1 protocol */
402 | MCP_INTERACTIVE = (1 << 10), // This is an interactive client */
403 | MCP_SSL = (1 << 11), //Switch to SSL after handshake */
404 | MCP_IGNORE_SIGPIPE = (1 << 12), // IGNORE sigpipes */
405 | MCP_TRANSACTIONS = (1 << 13), // Client knows about transactions */
406 | MCP_RESERVED = (1 << 14), // Old flag for 4.1 protocol */
407 | MCP_SECURE_CONNECTION = (1 << 15), // New 4.1 authentication */
408 | MCP_MULTI_STATEMENTS = (1 << 16), // Enable/disable multi-stmt support */
409 | MCP_MULTI_RESULTS = (1 << 17), // Enable/disable multi-results */
410 | };
411 |
412 | typedef struct Field {
413 | PyObject *name;
414 | UINT1 type;
415 | UINT2 flags;
416 | UINT2 charset;
417 | UINT2 decimal;
418 | } Field;
419 |
420 | //////// The Core Data Struct
421 | typedef struct {
422 | PyObject_HEAD
423 | PyObject *(*PFN_PyUnicode_Encode)(const Py_UNICODE *data, Py_ssize_t length,
424 | const char *errors);
425 |
426 | PyObject *Error;
427 | PyObject *SQLError;
428 |
429 | /* query-wide random string */
430 | void *sock;
431 | UINT1 *readerStartPtr, *readerReadPtr, *readerWritePtr, *readerEndPtr;
432 | UINT1 *writerStartPtr, *writerReadPtr, *writerWritePtr, *writerEndPtr;
433 | UINT1 *readerPktPtr;
434 | PyObject *fields;
435 | PyObject *rows;
436 | PyObject *curs;
437 | UINT4 nums;
438 | UINT1 columns;
439 | UINT1 nid; // next packet sequence id;
440 | UINT1 sqlstate[MY_SQLSTATE_LENGTH + 1]; //
441 | UINT2 lasterrno; // last errno;
442 | char *errmsg;
443 |
444 | UINT8 affectedRows;
445 | UINT8 insertId; /* id if insert on table with NEXTNR */
446 | UINT8 fieldCount;
447 | UINT4 serverStatus;
448 | UINT4 serverLanguage;
449 | UINT4 warningCount;
450 |
451 | /* session-wide random string */
452 | UINT1 ver;
453 | UINT4 cid; /* Con Id for connection in server */
454 | UINT4 tid; /* thread Id for connection in server */
455 | UINT4 pid;
456 |
457 | UINT1 serverLang;
458 | UINT2 serverCaps;
459 | UINT4 clientFlag;
460 | char scramble[MY_SCRAMBLE_LENGTH + 1];
461 |
462 | UINT4 timeout; /* set to 1 if automatic reconnect */
463 | UINT4 port; //ac: auto Commit
464 | char *host, *user, *pswd, *db, *serverVersion;
465 | bool ac;
466 | enum MY_CHARSETS charset;
467 | } Con;
468 |
469 | // for error and DEBUG
470 | void pbuf(FILE *file, void *_offset, size_t len, int perRow) {
471 | size_t cnt = 0;
472 | int index;
473 |
474 | char *offset = (char *) _offset;
475 | char *end = offset + len;
476 |
477 | int orgPerRow = perRow;
478 |
479 | fprintf(file, "<< %u(0x%x) %p - %p --------------\n", (unsigned int)len, (unsigned int)len, _offset,
480 | _offset + (unsigned int)len);
481 |
482 | while (offset != end) {
483 | fprintf(file, "%08x: ", (unsigned int)cnt);
484 |
485 | if (end - offset < perRow) {
486 | perRow = end - offset;
487 | }
488 |
489 | for (index = 0; index < perRow; index++) {
490 | int chr = (unsigned char) *offset;
491 |
492 | if (isprint(chr)) {
493 | fprintf(file, "%c", chr);
494 | } else {
495 | fprintf(file, ".");
496 | }
497 |
498 | offset++;
499 | }
500 |
501 | offset -= perRow;
502 |
503 | for (index = perRow; index < orgPerRow; index++) {
504 | fprintf(file, " ");
505 | }
506 |
507 | fprintf(file, " ");
508 |
509 | for (index = 0; index < perRow; index++) {
510 | int chr = (unsigned char) *offset;
511 |
512 | fprintf(file, "%02x ", chr);
513 | offset++;
514 | }
515 |
516 | fprintf(file, "\n");
517 |
518 | cnt += perRow;
519 | }
520 | }
521 |
522 | PyObject *API_error(Con *self, const char *msg) {
523 | PyObject *value;
524 |
525 | if (self->sock) {
526 | if (PyErr_Occurred()) {
527 | value = Py_BuildValue("(s,o,i,s)",
528 | "Python exception when local error is set",
529 | PyErr_Occurred(), self->lasterrno, self->errmsg);
530 | PyErr_Clear();
531 | PyErr_SetObject(amysql_Error, value);
532 | Py_DECREF(value);
533 | return NULL;
534 | }
535 |
536 | value = Py_BuildValue("(s,s)", msg, "Should not happen");
537 | PyErr_SetObject(PyExc_RuntimeError, value);
538 | Py_DECREF(value);
539 | return NULL;
540 | }
541 |
542 | if (PyErr_Occurred()) {
543 | return NULL;
544 | }
545 |
546 | value = Py_BuildValue("(s, s)", msg,
547 | "No error or Python error specified");
548 | PyErr_SetObject(PyExc_RuntimeError, value);
549 | if (value)
550 | Py_DECREF(value);
551 | return NULL;
552 | }
553 |
554 | // SHA1
555 | inline void SHA1ProcessMessageBlock(register SHA1_CONTEXT *context) {
556 | register int t, idx; /* Loop counter */
557 | UINT4 temp; /* Temporary word value */
558 | UINT4 W[80]; /* Word sequence */
559 | UINT4 A, B, C, D, E; /* Word buffers */
560 |
561 | for (t = 0; t < 16; t++) {
562 | idx = t * 4;
563 | W[t] = context->Message_Block[idx] << 24;
564 | W[t] |= context->Message_Block[idx + 1] << 16;
565 | W[t] |= context->Message_Block[idx + 2] << 8;
566 | W[t] |= context->Message_Block[idx + 3];
567 | }
568 |
569 | for (t = 16; t < 80; t++) {
570 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
571 | }
572 |
573 | A = context->Intermediate_Hash[0];
574 | B = context->Intermediate_Hash[1];
575 | C = context->Intermediate_Hash[2];
576 | D = context->Intermediate_Hash[3];
577 | E = context->Intermediate_Hash[4];
578 |
579 | for (t = 0; t < 20; t++) {
580 | temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t]
581 | + SHA1_KEY[0];
582 | E = D;
583 | D = C;
584 | C = SHA1CircularShift(30,B);
585 | B = A;
586 | A = temp;
587 | }
588 |
589 | for (t = 20; t < 40; t++) {
590 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + SHA1_KEY[1];
591 | E = D;
592 | D = C;
593 | C = SHA1CircularShift(30,B);
594 | B = A;
595 | A = temp;
596 | }
597 |
598 | for (t = 40; t < 60; t++) {
599 | temp = (SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E
600 | + W[t] + SHA1_KEY[2]);
601 | E = D;
602 | D = C;
603 | C = SHA1CircularShift(30,B);
604 | B = A;
605 | A = temp;
606 | }
607 |
608 | for (t = 60; t < 80; t++) {
609 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + SHA1_KEY[3];
610 | E = D;
611 | D = C;
612 | C = SHA1CircularShift(30,B);
613 | B = A;
614 | A = temp;
615 | }
616 |
617 | context->Intermediate_Hash[0] += A;
618 | context->Intermediate_Hash[1] += B;
619 | context->Intermediate_Hash[2] += C;
620 | context->Intermediate_Hash[3] += D;
621 | context->Intermediate_Hash[4] += E;
622 |
623 | context->Message_Block_Index = 0;
624 | }
625 | inline void SHA1PadMessage(SHA1_CONTEXT *context) {
626 | int i = context->Message_Block_Index;
627 |
628 | if (i > 55) {
629 | context->Message_Block[i++] = 0x80;
630 | bzero((char*) &context->Message_Block[i],
631 | sizeof(context->Message_Block[0]) * (64 - i));
632 | context->Message_Block_Index = 64;
633 |
634 | /* This function sets context->Message_Block_Index to zero */
635 | SHA1ProcessMessageBlock(context);
636 |
637 | bzero((char*) &context->Message_Block[0],
638 | sizeof(context->Message_Block[0]) * 56);
639 | context->Message_Block_Index = 56;
640 | } else {
641 | context->Message_Block[i++] = 0x80;
642 | bzero((char*) &context->Message_Block[i],
643 | sizeof(context->Message_Block[0]) * (56 - i));
644 | context->Message_Block_Index = 56;
645 | }
646 |
647 | context->Message_Block[56] = (UINT1) (context->Length >> 56);
648 | context->Message_Block[57] = (UINT1) (context->Length >> 48);
649 | context->Message_Block[58] = (UINT1) (context->Length >> 40);
650 | context->Message_Block[59] = (UINT1) (context->Length >> 32);
651 | context->Message_Block[60] = (UINT1) (context->Length >> 24);
652 | context->Message_Block[61] = (UINT1) (context->Length >> 16);
653 | context->Message_Block[62] = (UINT1) (context->Length >> 8);
654 | context->Message_Block[63] = (UINT1) (context->Length);
655 |
656 | SHA1ProcessMessageBlock(context);
657 | }
658 | static int sha1_reset(SHA1_CONTEXT *context) {
659 | context->Length = 0;
660 | context->Message_Block_Index = 0;
661 |
662 | context->Intermediate_Hash[0] = sha_const_key[0];
663 | context->Intermediate_Hash[1] = sha_const_key[1];
664 | context->Intermediate_Hash[2] = sha_const_key[2];
665 | context->Intermediate_Hash[3] = sha_const_key[3];
666 | context->Intermediate_Hash[4] = sha_const_key[4];
667 |
668 | context->Computed = 0;
669 | context->Corrupted = 0;
670 |
671 | return SHA_SUCCESS;
672 | }
673 | static int sha1_result(SHA1_CONTEXT *context,
674 | UINT1 Message_Digest[MY_SHA1_HASH_SIZE]) {
675 | UINT4 i;
676 | if (!context->Computed) {
677 | SHA1PadMessage(context);/* message may be sensitive, clear it out */
678 | for (i = 0; i < 64; ++i)
679 | context->Message_Block[i] = 0;
680 | context->Length = 0; /* and clear length */
681 | context->Computed = 1;
682 | }
683 |
684 | for (i = 0; i < MY_SHA1_HASH_SIZE; i++)
685 | Message_Digest[i] = (INT1) (context->Intermediate_Hash[i >> 2]
686 | >> 8 * (3 - (i & 0x03)));
687 | return SHA_SUCCESS;
688 | }
689 | static int sha1_input(SHA1_CONTEXT *context, const UINT1 *message_array,
690 | unsigned length) {
691 | if (!length)
692 | return SHA_SUCCESS;
693 | while (length--) {
694 | context->Message_Block[context->Message_Block_Index++] = (*message_array
695 | & 0xFF);
696 | context->Length += 8; /* Length is in bits */
697 |
698 | if (context->Message_Block_Index == 64) {
699 | SHA1ProcessMessageBlock(context);
700 | }
701 | message_array++;
702 | }
703 | return SHA_SUCCESS;
704 | }
705 | static void scramble_password(UINT1 *to, const UINT1 *message, const UINT1 *password) {
706 | SHA1_CONTEXT sha1_context;
707 | UINT1 hash_stage1[MY_SHA1_HASH_SIZE];
708 | UINT1 hash_stage2[MY_SHA1_HASH_SIZE];
709 | int index = 0;
710 |
711 | sha1_reset(&sha1_context);
712 | sha1_input(&sha1_context, (UINT1 *) password, (UINT4) strlen(password));
713 | sha1_result(&sha1_context, hash_stage1);
714 | sha1_reset(&sha1_context);
715 | sha1_input(&sha1_context, hash_stage1, MY_SHA1_HASH_SIZE);
716 | sha1_result(&sha1_context, hash_stage2);
717 | sha1_reset(&sha1_context);
718 | sha1_input(&sha1_context, (const UINT1 *) message, MY_SCRAMBLE_LENGTH);
719 | sha1_input(&sha1_context, hash_stage2, MY_SHA1_HASH_SIZE);
720 | sha1_result(&sha1_context, to);
721 | for (index = 0; index < MY_SHA1_HASH_SIZE; ++index)to[index] ^= hash_stage1[index];/* xor allows 'from' and 'to' overlap: lets take advantage of it */
722 | }
723 |
724 | //////// Python socket interface
725 | inline void *
726 | API_getSocket() {
727 | PyObject *sockobj;
728 | sockobj = PyObject_Call(sockclass, PyTuple_New(0), NULL);
729 | return sockobj;
730 | }
731 | inline int
732 | API_setTimeout(void *sock, int timeoutSec) {
733 | PyObject *intobj;
734 | PyObject *retobj;
735 | PyObject *methodObj;
736 |
737 | intobj = PyFloat_FromDouble((double) timeoutSec);
738 |
739 | methodObj = PyString_FromString("settimeout");
740 | retobj = PyObject_CallMethodObjArgs((PyObject *) sock, methodObj, intobj,
741 | NULL);
742 | Py_DECREF(intobj);
743 | Py_DECREF(methodObj);
744 | if (retobj == NULL) {
745 | PyErr_Clear();
746 | return 0;
747 | }
748 |
749 | Py_DECREF(retobj);
750 | return 1;
751 |
752 | }
753 | inline bool API_closeSocket(void *sock) {
754 | PyObject *res = PyObject_CallMethod((PyObject *) sock, "close", NULL);
755 |
756 | if (res == NULL)
757 | return 0;
758 |
759 | Py_DECREF(res);
760 | Py_DECREF((PyObject *) sock);
761 | return 1;
762 | }
763 | inline bool API_setblockingSocket(void *sock, bool flag) {
764 | PyObject *res = PyObject_CallMethod((PyObject *) sock, "setblocking", "i",
765 | &flag);
766 |
767 | if (res == NULL)
768 | return 0;
769 |
770 | Py_DECREF(res);
771 | Py_DECREF((PyObject *) sock);
772 | return 1;
773 | }
774 | inline int API_connectSocket(void *sock, const char *host, int port) {
775 | PyObject *res;
776 | PyObject *addrTuple;
777 | PyObject *connectStr;
778 |
779 | addrTuple = PyTuple_New(2);
780 | PyTuple_SET_ITEM(addrTuple, 0, PyString_FromString(host));
781 | PyTuple_SET_ITEM(addrTuple, 1, PyInt_FromLong(port));
782 |
783 | connectStr = PyString_FromString("connect_ex");
784 | res = PyObject_CallMethodObjArgs((PyObject *) sock, connectStr, addrTuple,
785 | NULL);
786 |
787 | Py_DECREF(connectStr);
788 | Py_DECREF(addrTuple);
789 |
790 | if (res == NULL)
791 | return 0;
792 | Py_DECREF(res);
793 | return 1;
794 | }
795 | inline int API_recvSocket(void *sock,UINT1 *buffer, size_t size) {
796 | int ret;
797 | PyObject *res;
798 | if ((res = PyObject_CallMethodObjArgs((PyObject *) sock,
799 | PyString_FromString("recv"), PyInt_FromLong(size), NULL)) == NULL)
800 | return -1;
801 | ret = (long) PyString_GET_SIZE(res);
802 | memcpy(buffer, PyString_AS_STRING(res), ret);
803 | Py_DECREF(res);
804 | return ret;
805 | }
806 | inline int API_sendSocket(void *sock, const char *buffer, int cbBuffer) {
807 | PyObject *res;
808 | PyObject *pybuffer;
809 | PyObject *funcStr;
810 | int ret;
811 |
812 | funcStr = PyString_FromString("send");
813 | pybuffer = PyString_FromStringAndSize(buffer, cbBuffer);
814 | res = PyObject_CallMethodObjArgs((PyObject *) sock, funcStr, pybuffer,
815 | NULL);
816 | Py_DECREF(funcStr);
817 | Py_DECREF(pybuffer);
818 |
819 | if (res == NULL) {
820 | return -1;
821 | }
822 |
823 | ret = (int) PyInt_AsLong(res);
824 | Py_DECREF(res);
825 | return ret;
826 | }
827 |
828 | //////// Con buffers( reader/writer ) interface
829 | inline UINT1 readerUINT1(Con *self) {
830 | assert(self->readerReadPtr + 1 < self->readerPktPtr);
831 | return *self->readerReadPtr++;
832 | }
833 | inline UINT2 readerUINT2(Con *self) {
834 | assert(self->readerReadPtr + 2 <= self->readerPktPtr);
835 | UINT2 ret = *((UINT2 *)self->readerReadPtr);
836 | self->readerReadPtr += 2;
837 | return ret;
838 | }
839 | inline UINT4 readerUINT3(Con *self) {
840 | assert(self->readerReadPtr + 3 < self->readerPktPtr);
841 | UINT4 ret = 0xffffff & *((UINT4 *) self->readerReadPtr);
842 | self->readerReadPtr += 3;
843 | return ret;
844 | }
845 | inline UINT4 readerUINT4(Con *self) {
846 | assert(self->readerReadPtr + 4 <= self->readerPktPtr);
847 | UINT4 ret = *((UINT4 *) self->readerReadPtr);
848 | self->readerReadPtr += 4;
849 | return ret;
850 | }
851 | inline UINT4 Con_WriteUINT4(Con *self) {
852 | assert(self->writerWritePtr + 4 < self->writerEndPtr);
853 | UINT4 ret = *((UINT4 *) self->readerReadPtr);
854 | self->readerReadPtr += 4;
855 | return *self->readerReadPtr++;
856 | return ret;
857 | }
858 | inline UINT8 readerCodedLength(Con *self) {
859 | assert(self->readerReadPtr < self->readerPktPtr);
860 | register UINT1 *pos = self->readerReadPtr;
861 |
862 | switch (*pos) {
863 | case 0xfe:
864 | self->readerReadPtr += 9;
865 | return *((UINT8 *) (pos + 1));
866 | case 0xfd:
867 | self->readerReadPtr += 4;
868 | return pos[1] | pos[2] << 8 | pos[3] << 16;
869 | case 0xfc:
870 | self->readerReadPtr += 3;
871 | return *((UINT2 *) pos);
872 | case 0xfb:
873 | self->readerReadPtr++;
874 | return MY_NULL_LENGTH;
875 | default:
876 | self->readerReadPtr++;
877 | return *pos;
878 | }
879 | }
880 | inline ulong readerFieldLength(Con *self) {
881 | assert(self->readerReadPtr < self->readerPktPtr);
882 | register UINT1 *pos = self->readerReadPtr;
883 | switch (*pos) {
884 | case 0xfe:
885 | self->readerReadPtr += 9;
886 | return *((const UINT4 *) (pos + 1));
887 | case 0xfd:
888 | self->readerReadPtr += 4;
889 | return 0xffffff & *((const UINT4 *) (pos + 1));
890 | case 0xfc:
891 | self->readerReadPtr += 3;
892 | return *((const UINT2 *) (pos + 1));
893 | case 0xfb:
894 | self->readerReadPtr++;
895 | return MY_NULL_LENGTH;
896 | default:
897 | self->readerReadPtr++;
898 | return (ulong) *pos;
899 | }
900 | }
901 | inline UINT1 *readerBytes(Con *self, size_t size) {
902 | assert(
903 | self->readerReadPtr + size < self->readerPktPtr
904 | && self->readerPktPtr <= self->readerWritePtr);
905 | UINT1 *ret = (UINT1 *) self->readerReadPtr;
906 | self->readerReadPtr += size;
907 | return ret;
908 | }
909 | inline char *readerNTString(Con *self) {
910 | assert(
911 | self->readerReadPtr < self->readerPktPtr
912 | && self->readerPktPtr <= self->readerEndPtr);
913 | char *ret = (char *)self->readerReadPtr;
914 | while (self->readerReadPtr < self->readerPktPtr)
915 | if ((*self->readerReadPtr++) == '\0')
916 | return ret;
917 | assert(0);
918 | return NULL;
919 | }
920 | #define readerReset(con) do{if(!con->readerStartPtr || con->readerEndPtr -con->readerStartPtr>MY_BUFFER_SIZE){MyRealloc(con->readerStartPtr, MY_BUFFER_SIZE);con->readerEndPtr= con->readerStartPtr +MY_BUFFER_SIZE;};con->nid=0;con->readerPktPtr=con->readerReadPtr=con->readerWritePtr=con->readerStartPtr;}while(0)
921 | #define writerINT1(con,u) do{*((UINT1*)con->writerWritePtr)=(u);con->writerWritePtr++;}while(0)
922 | #define writerINT4(con,u) do{*((UINT4*)con->writerWritePtr)=(u);con->writerWritePtr+=4;}while(0)
923 | #define writerSize(con) (con->writerEndPtr-con->writerStartPtr)
924 | #define writerIsDone(con) (con->writerReadPtr ==con->writerWritePtr)
925 | #define writerPush(con, ptr, sz) do{assert(con->writeWritePtr +sz>0 && con->writeWritePtr +szwriterEndPtr);memcpy(con->writeWritePtr,p,sz);con->writeWritePtr+=sz;}while(0)
926 | #define writerPull(con,sz) do{assert(con->writeReadPtr+sz>0 && writeReadPtr+sz<=writeWritePtr);writeReadPtr +=sz;}while(0)
927 | inline void writerReset(Con *self) {
928 | if (!self->writerStartPtr
929 | || self->writerEndPtr - self->writerStartPtr <= MY_PACKET_MAX
930 | || self->writerEndPtr - self->writerStartPtr >= MY_BUFFER_MAX) {
931 | MyRealloc(self->writerStartPtr, MY_BUFFER_SIZE);
932 | self->writerWritePtr = self->writerReadPtr = self->writerStartPtr;
933 | self->writerEndPtr = self->writerStartPtr + MY_BUFFER_SIZE;
934 | }
935 | self->writerWritePtr = self->writerReadPtr;
936 | *((UINT4*) self->writerWritePtr) = 0;
937 | self->writerWritePtr += MY_HEADER_SIZE;
938 | }
939 | inline void writerFinalize(Con *self, UINT4 sid) {
940 | *((UINT4 *) self->writerReadPtr) = 0xffffff
941 | & ((UINT4) (self->writerWritePtr - self->writerReadPtr
942 | - MY_HEADER_SIZE));
943 | self->writerReadPtr[3] = (UINT1) sid;
944 | }
945 | inline bool writerNTString(Con *self, char *p) {
946 | if (!p) {
947 | assert(self->writerWritePtr < self->writerEndPtr);
948 | *(self->writerWritePtr++) = '\0';
949 | }
950 | while (*p && self->writerWritePtr < self->writerEndPtr)
951 | *(self->writerWritePtr++) = *p++;
952 | assert(self->writerWritePtr < self->writerEndPtr);
953 | *(self->writerWritePtr)++ = '\0';
954 | return true;
955 | }
956 | inline bool writerBytes(Con *self, char *p, UINT4 sz) {
957 | if (!p || sz == 0 || self->writerEndPtr - self->writerWritePtr < sz)
958 | return false;
959 | while (self->writerWritePtr < self->writerEndPtr && sz-- > 0)
960 | *(self->writerWritePtr++) = *p++;
961 | if (sz != 0)
962 | return false;
963 | return true;
964 | }
965 |
966 | inline INT4 parseINT4(UINT1 *start, UINT1 *end) {
967 | INT4 intValue = 0;
968 | INT4 intNeg = 1;
969 | INT4 chr;
970 |
971 | if (*start == '-') {
972 | start++;
973 | intNeg = -1;
974 | }
975 |
976 | while (start < end) {
977 | chr = (INT4) (unsigned char) *(start++);
978 | switch (chr) {
979 | case '0':
980 | case '1':
981 | case '2':
982 | case '3':
983 | case '4':
984 | case '5':
985 | case '6':
986 | case '7':
987 | case '8':
988 | case '9':
989 | intValue = intValue * 10 + (INT4) (chr - 48);
990 | break;
991 |
992 | default:
993 | break;
994 | }
995 | }
996 |
997 | return intValue * intNeg;
998 | }
999 | inline INT8 parseINT8(UINT1 *start, char *end) {
1000 | INT8 intValue = 0;
1001 | INT8 intNeg = 1;
1002 | INT8 chr;
1003 |
1004 | if (*start == '-') {
1005 | start++;
1006 | intNeg = -1;
1007 | }
1008 |
1009 | while (start < end) {
1010 | chr = (INT4) (unsigned char) *(start++);
1011 |
1012 | switch (chr) {
1013 | case '0':
1014 | case '1':
1015 | case '2':
1016 | case '3':
1017 | case '4':
1018 | case '5':
1019 | case '6':
1020 | case '7':
1021 | case '8':
1022 | case '9':
1023 | intValue = intValue * 10 + (INT8) (chr - 48);
1024 | break;
1025 |
1026 | default:
1027 | break;
1028 | }
1029 | }
1030 |
1031 | return intValue * intNeg;
1032 | }
1033 |
1034 |
1035 |
1036 | static PyObject *Con_Connect(Con *self, PyObject *args);
1037 | int Con_Constructor(Con *self, PyObject *args) {
1038 | self->tid = 0;
1039 | self->sock = NULL;
1040 | self->Error = amysql_Error;
1041 | self->SQLError = amysql_SQLError;
1042 | self->PFN_PyUnicode_Encode = NULL;
1043 | readerReset(self);
1044 | writerReset(self);
1045 | if (PyErr_Occurred()) {
1046 | PyErr_Format(PyExc_RuntimeError, "Exception is set for no error in %s",
1047 | __FUNCTION__);
1048 | return -1;
1049 | }
1050 |
1051 | if (args && PyObject_IsTrue(args))
1052 | Con_Connect(self, args);
1053 | Py_INCREF(self);
1054 | return 0;
1055 | }
1056 | static int Con_Clear(Con *self) {
1057 | Py_CLEAR(self->rows);
1058 | Py_CLEAR(self->fields);
1059 | Py_CLEAR(self->sock);
1060 | return 0;
1061 | }
1062 | static PyObject *
1063 | Con_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
1064 | {
1065 | Con *self;
1066 | self = (Con *)type->tp_alloc(type, 0);
1067 | return (PyObject *)self;
1068 | }
1069 | static void Con_Destructor(Con *self) {
1070 | if (self->sock) {
1071 | self->tid = 0;
1072 | writerReset(self);
1073 | writerINT1(self, 0x1);
1074 | writerFinalize(self, 0);
1075 | API_sendSocket(self->sock, self->writerReadPtr,
1076 | self->writerWritePtr - self->writerReadPtr);
1077 | if(self->readerStartPtr)MyFree(self->readerStartPtr);
1078 | if(self->writerStartPtr)MyFree(self->writerStartPtr);
1079 | API_closeSocket(self->sock);
1080 | Con_Clear(self);
1081 | self->readerStartPtr=self->readerReadPtr=self->readerPktPtr=self->readerWritePtr=self->readerEndPtr \
1082 | =self->writerStartPtr=self->writerReadPtr=self->writerWritePtr=self->writerEndPtr \
1083 | =self->rows =self->fields =self->sock =NULL;
1084 | }
1085 | }
1086 | static int
1087 | Con_Traverse(Con *self, visitproc visit, void *arg)
1088 | {
1089 | if(self->rows)Py_VISIT(self->rows);
1090 | if(self->fields)Py_VISIT(self->fields);
1091 | return 0;
1092 | }
1093 |
1094 | inline static PyObject *Con_PacketRecv(Con *self, bool skipCols) {
1095 | register UINT1 *pos;
1096 | register ulong cols, i, pktlen, remain;
1097 | register long len;
1098 | register Field *fields = NULL, *col = NULL;
1099 | register PyObject *row, *valobj, *sobj;
1100 | static long RSLen, PRLen, WPLen;
1101 | int year;
1102 | int month;
1103 | int day;
1104 | int hour;
1105 | int minute;
1106 | int second;
1107 | char temp[20];
1108 |
1109 | self->serverStatus &= ~SERVER_MORE_RESULTS_EXISTS;
1110 | pos = self->readerReadPtr = self->readerPktPtr;
1111 | if (self->readerWritePtr - self->readerPktPtr < MY_HEADER_SIZE) {
1112 | if (self->readerEndPtr - self->readerPktPtr < MY_HEADER_SIZE) {
1113 | do {
1114 | len = self->readerEndPtr - self->readerStartPtr;
1115 | if (len <= 0) {
1116 | len = MY_BUFFER_SIZE;
1117 | } else
1118 | len <<= 1;
1119 | assert(0 < len && len <= MY_BUFFER_MAX);
1120 | RSLen = self->readerReadPtr - self->readerStartPtr;
1121 | PRLen = self->readerPktPtr - self->readerReadPtr;
1122 | WPLen = self->readerWritePtr - self->readerPktPtr;
1123 | MyRealloc(self->readerStartPtr, len);
1124 | self->readerEndPtr = self->readerStartPtr + len;
1125 | self->readerReadPtr = self->readerStartPtr + RSLen;
1126 | self->readerPktPtr = self->readerReadPtr + PRLen;
1127 | self->readerWritePtr = self->readerPktPtr + WPLen;
1128 | } while (self->readerEndPtr - self->readerPktPtr
1129 | < MY_HEADER_SIZE);
1130 | }
1131 | do {
1132 | len = API_recvSocket(self->sock, self->readerWritePtr,
1133 | self->readerEndPtr - self->readerWritePtr);
1134 | if (len <= 0L) {
1135 | break;
1136 | } else
1137 | self->readerWritePtr += len;
1138 | } while (self->readerWritePtr - self->readerPktPtr < MY_HEADER_SIZE);
1139 | }
1140 | remain = 0xffffff & *((UINT4 *) pos);
1141 | if (self->readerWritePtr - self->readerPktPtr < remain) {
1142 | if (self->readerEndPtr - self->readerPktPtr < remain) {
1143 | do {
1144 | len = self->readerEndPtr - self->readerStartPtr;
1145 | if (len <= 0) {
1146 | len = MY_BUFFER_SIZE;
1147 | } else
1148 | len = len << 1;
1149 | assert(0 < len && len <= MY_BUFFER_MAX);
1150 | RSLen = self->readerReadPtr - self->readerStartPtr;
1151 | PRLen = self->readerPktPtr - self->readerReadPtr;
1152 | WPLen = self->readerWritePtr - self->readerPktPtr;
1153 | MyRealloc(self->readerStartPtr, len);
1154 | self->readerEndPtr = self->readerStartPtr + len;
1155 | self->readerReadPtr = self->readerStartPtr + RSLen;
1156 | self->readerPktPtr = self->readerReadPtr + PRLen;
1157 | self->readerWritePtr = self->readerPktPtr + WPLen;
1158 | } while (self->readerEndPtr - self->readerPktPtr < remain);
1159 | }
1160 | do {
1161 | len = API_recvSocket(self->sock, self->readerWritePtr,
1162 | self->readerEndPtr - self->readerWritePtr);
1163 | if (len <= 0L) {
1164 | break;
1165 | } else
1166 | self->readerWritePtr += len;
1167 | } while (self->readerWritePtr - self->readerPktPtr < remain);
1168 | }
1169 | self->nid = pos[3];
1170 | self->readerReadPtr = pos = pos + MY_HEADER_SIZE;
1171 | self->readerPktPtr = pos + remain;
1172 |
1173 | if (*pos == 0x0) { // OK
1174 | self->readerReadPtr = pos+1;
1175 | self->affectedRows = readerCodedLength(self);
1176 | self->insertId = readerCodedLength(self);
1177 | self->serverStatus = readerUINT2(self);
1178 | self->warningCount = readerUINT2(self);
1179 | self->readerReadPtr=self->readerPktPtr;
1180 | fprintf(stderr, "\nAFFECTED ROWS: %llu INSERT ID: %llu STATUS: %u WARNC: %u \n",
1181 | self->affectedRows, self->insertId, self->serverStatus,
1182 | self->warningCount);
1183 | return self;
1184 | } else if (*pos == 0xff) { // Error
1185 | self->serverStatus &= ~SERVER_MORE_RESULTS_EXISTS;
1186 | if (remain > 3) {
1187 | self->lasterrno =*((UINT2 *) (pos + 1));
1188 | pos += 3;
1189 | if (*(pos++) == '#') {
1190 | self->sqlstate[MY_SQLSTATE_LENGTH] = '\0';
1191 | for (len = 0; len < MY_SQLSTATE_LENGTH; ++len)
1192 | self->sqlstate[len] = *(pos++);
1193 | self->errmsg = pos;
1194 | } else {
1195 | self->sqlstate[0] = 'H';
1196 | self->sqlstate[1] = 'Y';
1197 | self->sqlstate[2] = '0';
1198 | self->sqlstate[3] = '0';
1199 | self->sqlstate[4] = '0';
1200 | self->sqlstate[5] = '\0';
1201 | self->errmsg = pos;
1202 | }
1203 | };
1204 | readerReset(self);
1205 | THROW("Got error: %d/%s (%s)", self->lasterrno, self->sqlstate, self->errmsg);
1206 | return NULL;
1207 | } else if (*pos == 0xfe && remain <8) { // EOF Packet
1208 | self->readerReadPtr= pos+1;
1209 | self->warningCount = readerUINT2(self);
1210 | self->serverStatus = readerUINT2(self);
1211 | self->readerReadPtr= self->readerPktPtr;
1212 | if (self->serverStatus & SERVER_MORE_RESULTS_EXISTS)
1213 | return self;
1214 | THROW("Unexpected EOF when decoding result");
1215 | }
1216 |
1217 | if (!(self->serverStatus & SERVER_STATUS_AUTOCOMMIT))
1218 | self->serverStatus |= SERVER_STATUS_IN_TRANS;
1219 | switch (*pos) {
1220 | case 0xfe:
1221 | cols = *((UINT4 *) (pos + 1));
1222 | pos += 9;
1223 | break;
1224 | case 0xfd:
1225 | cols = 0xffffff & *((UINT4 *) (pos + 1));
1226 | pos += 4;
1227 | break;
1228 | case 0xfc:
1229 | cols = *((UINT2 *) (pos + 1));
1230 | pos += 3;
1231 | break;
1232 | case 0xfb:
1233 | cols = MY_NULL_LENGTH;
1234 | pos++;
1235 | break;
1236 | default:
1237 | cols = *pos++;
1238 | break;
1239 | }
1240 | assert(pos == self->readerPktPtr);
1241 | self->readerReadPtr = pos;
1242 |
1243 | if (self->rows){Py_DECREF(self->rows);self->rows=NULL;}
1244 | if (self->fields){Py_DECREF(self->fields);self->fields=NULL;}
1245 | self->rows = PyList_New(0);
1246 | self->fields = PyTuple_New(cols);
1247 | if (self->rows && self->fields){
1248 | Py_INCREF(self->rows);
1249 | Py_INCREF(self->fields);
1250 | } else if (PyErr_Occurred()) {
1251 | PyErr_Format(PyExc_ValueError, "Parse packet field: %s", pos);
1252 | return 0;
1253 | }
1254 |
1255 | MyRealloc(fields, cols*sizeof(Field));
1256 | for (i = 0; i <= cols; i++) { // Fields
1257 | pos = self->readerReadPtr = self->readerPktPtr;
1258 | if (self->readerWritePtr - self->readerPktPtr < MY_HEADER_SIZE) {
1259 | if (self->readerEndPtr - self->readerPktPtr < MY_HEADER_SIZE) {
1260 | do {
1261 | len = self->readerEndPtr - self->readerStartPtr;
1262 | if (len <= 0) {
1263 | len = MY_BUFFER_SIZE;
1264 | } else
1265 | len <<= 1;
1266 | assert(0 < len && len <= MY_BUFFER_MAX);
1267 | RSLen = self->readerReadPtr - self->readerStartPtr;
1268 | PRLen = self->readerPktPtr - self->readerReadPtr;
1269 | WPLen = self->readerWritePtr - self->readerPktPtr;
1270 | MyRealloc(self->readerStartPtr, len);
1271 | self->readerEndPtr = self->readerStartPtr + len;
1272 | self->readerReadPtr = self->readerStartPtr + RSLen;
1273 | self->readerPktPtr = self->readerReadPtr + PRLen;
1274 | self->readerWritePtr = self->readerPktPtr + WPLen;
1275 | } while (self->readerEndPtr - self->readerPktPtr
1276 | < MY_HEADER_SIZE);
1277 | }
1278 | do {
1279 | len = API_recvSocket(self->sock, self->readerWritePtr,
1280 | self->readerEndPtr - self->readerWritePtr);
1281 | if (len <= 0L) {
1282 | break;
1283 | } else
1284 | self->readerWritePtr += len;
1285 | } while (self->readerWritePtr - self->readerPktPtr < MY_HEADER_SIZE);
1286 | }
1287 | remain = 0xffffff & *((UINT4 *) pos);
1288 | self->nid = pos[3];
1289 | self->readerPktPtr = pos = pos + MY_HEADER_SIZE;
1290 | if (self->readerWritePtr - self->readerPktPtr < remain) {
1291 | if (self->readerEndPtr - self->readerPktPtr < remain) {
1292 | do {
1293 | len = self->readerEndPtr - self->readerStartPtr;
1294 | if (len <= 0) {
1295 | len = MY_BUFFER_SIZE;
1296 | } else
1297 | len = len << 1;
1298 | assert(0 < len && len <= MY_BUFFER_MAX);
1299 | RSLen = self->readerReadPtr - self->readerStartPtr;
1300 | PRLen = self->readerPktPtr - self->readerReadPtr;
1301 | WPLen = self->readerWritePtr - self->readerPktPtr;
1302 | MyRealloc(self->readerStartPtr, len);
1303 | self->readerEndPtr = self->readerStartPtr + len;
1304 | self->readerReadPtr = self->readerStartPtr + RSLen;
1305 | self->readerPktPtr = self->readerReadPtr + PRLen;
1306 | self->readerWritePtr = self->readerPktPtr + WPLen;
1307 | } while (self->readerEndPtr - self->readerPktPtr < remain);
1308 | }
1309 | do {
1310 | len = API_recvSocket(self->sock, self->readerWritePtr,
1311 | self->readerEndPtr - self->readerWritePtr);
1312 | if (len <= 0L) {
1313 | break;
1314 | } else
1315 | self->readerWritePtr += len;
1316 | } while (self->readerWritePtr - self->readerPktPtr < remain);
1317 | }
1318 | self->readerReadPtr =pos;
1319 | self->readerPktPtr = pos + remain;
1320 | if (*pos == 0xfe) { // fields DONE!
1321 | assert(i == cols);
1322 | break;
1323 | }
1324 | switch (*pos) { //UINT1 *catalog
1325 | case 0xfd:
1326 | pos += 4 + 0xffffff & *((const UINT4 *) (pos + 1));
1327 | break;
1328 | case 0xfc:
1329 | pos += 3 + *((const UINT2 *) (pos + 1));
1330 | break;
1331 | case 0xfb:
1332 | pos += 1 + MY_NULL_LENGTH;
1333 | break;
1334 | default:
1335 | pos += 1 + *pos;
1336 | break;
1337 | };
1338 | switch (*pos) { //UINT1 *db : scheme name
1339 | case 0xfe:
1340 | pos += 9 + *((const UINT4 *) (pos + 1));
1341 | break;
1342 | case 0xfd:
1343 | pos += 4 + 0xffffff & *((const UINT4 *) (pos + 1));
1344 | break;
1345 | case 0xfc:
1346 | pos += 3 + *((const UINT2 *) (pos + 1));
1347 | break;
1348 | case 0xfb:
1349 | pos += 1 + MY_NULL_LENGTH;
1350 | break;
1351 | default:
1352 | pos += 1 + *pos;
1353 | break;
1354 | }
1355 | switch (*pos) { //UINT1 *table : virtual table name
1356 | case 0xfe:
1357 | pos += 9 + *((const UINT4 *) (pos + 1));
1358 | break;
1359 | case 0xfd:
1360 | pos += 4 + 0xffffff & *((const UINT4 *) (pos + 1));
1361 | break;
1362 | case 0xfc:
1363 | pos += 3 + *((const UINT2 *) (pos + 1));
1364 | break;
1365 | case 0xfb:
1366 | pos += 1 + MY_NULL_LENGTH;
1367 | break;
1368 | default:
1369 | pos += 1 + *pos;
1370 | break;
1371 | }
1372 | switch (*pos) { //UINT1 *org_table : physical table name
1373 | case 0xfe:
1374 | pos += 9 + *((const UINT4 *) (pos + 1));
1375 | break;
1376 | case 0xfd:
1377 | pos += 4 + 0xffffff & *((const UINT4 *) (pos + 1));
1378 | break;
1379 | case 0xfc:
1380 | pos += 3 + *((const UINT2 *) (pos + 1));
1381 | break;
1382 | case 0xfb:
1383 | pos += 1 + MY_NULL_LENGTH;
1384 | break;
1385 | default:
1386 | pos += 1 + *pos;
1387 | break;
1388 | }
1389 | switch (*pos) { //UINT1 *name
1390 | case 0xfe:
1391 | pos += 9;
1392 | len = *((const UINT4 *) (pos + 1));
1393 | break;
1394 | case 0xfd:
1395 | pos += 4;
1396 | len = 0xffffff & *((const UINT4 *) (pos + 1));
1397 | break;
1398 | case 0xfc:
1399 | pos += 3;
1400 | len = *((const UINT2 *) (pos + 1));
1401 | break;
1402 | case 0xfb:
1403 | pos++;
1404 | len = MY_NULL_LENGTH;
1405 | break;
1406 | default:
1407 | len = *pos++;
1408 | break;
1409 | }
1410 | fields[i].name = PyString_FromStringAndSize(pos, len);
1411 | if (fields[i].name == NULL) {
1412 | if (PyErr_Occurred()) {
1413 | PyErr_Format(PyExc_ValueError, "Parse packet field: %s",
1414 | pos);
1415 | return 0;
1416 | }
1417 | }else pos += len; //
1418 | switch (*pos) { //UINT1 *org_name
1419 | case 0xfe:
1420 | pos += 9 + *((const UINT4 *) (pos + 1));
1421 | break;
1422 | case 0xfd:
1423 | pos += 4 + 0xffffff & *((const UINT4 *) (pos + 1));
1424 | break;
1425 | case 0xfc:
1426 | pos += 3 + *((const UINT2 *) (pos + 1));
1427 | break;
1428 | case 0xfb:
1429 | pos += 1 + MY_NULL_LENGTH;
1430 | break;
1431 | default:
1432 | pos += 1 + *pos;
1433 | break;
1434 | }
1435 | assert(*pos++ == 0xc);
1436 | fields[i].charset = *((UINT2 *) pos);
1437 | pos += 2; //UINT2 charset
1438 | pos += 4; //UINT4 length =
1439 | fields[i].type = *pos++; //UINT1 type =
1440 | fields[i].flags = *((UINT2 *) pos); pos += 2; //UINT1 flags =
1441 | fields[i].decimal = *pos; //UINT2 decimals =;
1442 | self->readerReadPtr = self->readerPktPtr;
1443 |
1444 | PyTuple_SET_ITEM(self->fields, i, fields[i].name);
1445 | }
1446 |
1447 | self->nums =0;
1448 | while (1) { // ROWS
1449 | pos = self->readerReadPtr = self->readerPktPtr;
1450 | if (self->readerWritePtr - self->readerPktPtr < MY_HEADER_SIZE) {
1451 | if (self->readerEndPtr - self->readerPktPtr < MY_HEADER_SIZE) {
1452 | do {
1453 | len = self->readerEndPtr - self->readerStartPtr;
1454 | if (len <= 0) {
1455 | len = MY_BUFFER_SIZE;
1456 | } else
1457 | len = len << 1;
1458 | assert(0 < len && len <= MY_BUFFER_MAX);
1459 | RSLen = self->readerReadPtr - self->readerStartPtr;
1460 | PRLen = self->readerPktPtr - self->readerReadPtr;
1461 | WPLen = self->readerWritePtr - self->readerPktPtr;
1462 | MyRealloc(self->readerStartPtr, len);
1463 | self->readerEndPtr = self->readerStartPtr + len;
1464 | self->readerReadPtr = self->readerStartPtr + RSLen;
1465 | self->readerPktPtr = self->readerReadPtr + PRLen;
1466 | self->readerWritePtr = self->readerPktPtr + WPLen;
1467 | } while (self->readerEndPtr - self->readerPktPtr
1468 | < MY_HEADER_SIZE);
1469 | }
1470 | do {
1471 | len = API_recvSocket(self->sock, self->readerWritePtr,
1472 | self->readerEndPtr - self->readerWritePtr);
1473 | if (len <= 0L) {
1474 | break;
1475 | } else
1476 | self->readerWritePtr += len;
1477 | } while (self->readerWritePtr - self->readerPktPtr
1478 | < MY_HEADER_SIZE);
1479 | }
1480 | remain = 0xffffff & *((UINT4 *) pos);
1481 | self->nid = pos[3];
1482 | self->readerPktPtr = pos = pos + MY_HEADER_SIZE;
1483 | if (self->readerWritePtr - self->readerPktPtr < remain) {
1484 | if (self->readerEndPtr - self->readerPktPtr < remain) {
1485 | do {
1486 | len = self->readerEndPtr - self->readerStartPtr;
1487 | if (len <= 0) {
1488 | len = MY_BUFFER_SIZE;
1489 | } else
1490 | len = len << 1;
1491 | assert(0 < len && len <= MY_BUFFER_MAX);
1492 | RSLen = self->readerReadPtr - self->readerStartPtr;
1493 | PRLen = self->readerPktPtr - self->readerReadPtr;
1494 | WPLen = self->readerWritePtr - self->readerPktPtr;
1495 | MyRealloc(self->readerStartPtr, len);
1496 | self->readerEndPtr = self->readerStartPtr + len;
1497 | self->readerReadPtr = self->readerStartPtr + RSLen;
1498 | self->readerPktPtr = self->readerReadPtr + PRLen;
1499 | self->readerWritePtr = self->readerPktPtr + WPLen;
1500 | } while (self->readerEndPtr - self->readerPktPtr
1501 | < remain);
1502 | }
1503 | do {
1504 | len = API_recvSocket(self->sock, self->readerWritePtr,
1505 | self->readerEndPtr - self->readerWritePtr);
1506 | if (len <= 0L) {
1507 | break;
1508 | } else
1509 | self->readerWritePtr += len;
1510 | } while (self->readerWritePtr - self->readerPktPtr < remain);
1511 | }
1512 | self->readerPktPtr = pos + remain;
1513 | self->readerReadPtr = pos;
1514 | if (*pos == 0xff) { // ERROR packet
1515 | if (self->rows){Py_DECREF(self->rows);self->rows=NULL;}
1516 | if (self->fields){Py_DECREF(self->fields);self->fields=NULL;}
1517 | return self;
1518 | }else if (*pos == 0xfe || remain < 8) {// EOF packet
1519 | if (self->serverStatus & SERVER_MORE_RESULTS_EXISTS) {
1520 | self->warningCount = readerUINT2(self);
1521 | self->serverStatus = readerUINT2(self);
1522 | self->readerReadPtr = self->readerPktPtr;
1523 | return self;
1524 | }
1525 | self->readerReadPtr = self->readerPktPtr;
1526 | break;
1527 | }else if (*pos ==0x0 || *pos == 0xfb){// OK|NULL packet
1528 | self->readerReadPtr = self->readerPktPtr;
1529 | break;
1530 | }
1531 |
1532 | row = PyTuple_New(cols);
1533 | for (i =0; i < cols; i++) {
1534 | col = fields + i;
1535 | if (*pos == 0xfb){ /* null field */
1536 | PyTuple_SET_ITEM(row, i, Py_None);
1537 | pos++;
1538 | continue;
1539 | }
1540 | switch (*pos){
1541 | case 0xfe:
1542 | len = *((const UINT4 *) (pos + 1));
1543 | pos += 9;
1544 | break;
1545 | case 0xfd:
1546 | len = 0xffffff & *((const UINT4 *) (pos + 1));
1547 | pos += 4;
1548 | break;
1549 | case 0xfc:
1550 | len = *((const UINT2 *) (pos + 1));
1551 | pos += 3;
1552 | break;
1553 | default:
1554 | len = *pos;
1555 | pos++;
1556 | break;
1557 | }
1558 | switch (col->type) {
1559 | case MFTYPE_NULL://PyNone:
1560 | valobj = Py_None;
1561 | Py_INCREF(valobj);
1562 | break;
1563 |
1564 | case MFTYPE_TINY://PyInt
1565 | case MFTYPE_SHORT:
1566 | case MFTYPE_LONG:
1567 | case MFTYPE_INT24:
1568 | valobj = PyInt_FromLong(parseINT4(pos, pos + len));
1569 | break;
1570 |
1571 | case MFTYPE_LONGLONG://PyLong
1572 | valobj = PyLong_FromLongLong(
1573 | parseINT8(pos, pos + len));
1574 | break;
1575 |
1576 | case MFTYPE_FLOAT://PyFloat
1577 | case MFTYPE_DOUBLE:
1578 | sobj = PyString_FromStringAndSize(pos, len);//FIXME: Too slow
1579 | valobj = PyFloat_FromString(sobj, NULL);
1580 | Py_DECREF(sobj);
1581 | break;
1582 |
1583 | case MFTYPE_DATE:
1584 | year = parseINT4(pos, pos + 4);
1585 | if (year < 1) {
1586 | valobj = Py_None;
1587 | Py_INCREF(valobj);
1588 | break;
1589 | }
1590 | month = parseINT4(pos + 5, pos + 7);
1591 | day = parseINT4(pos + 8, pos + 10);
1592 | valobj = PyDate_FromDate(year, month, day);
1593 | break;
1594 |
1595 | case MFTYPE_DATETIME:
1596 | //9999-12-31 23:59:59
1597 | memcpy(temp, pos, len);
1598 | temp[len] = '\0';
1599 | year = parseINT4(pos, pos + 4);
1600 | month = parseINT4(pos + 5, pos + 7);
1601 | day = parseINT4(pos + 8, pos + 10);
1602 | hour = parseINT4(pos + 11, pos + 13);
1603 | minute = parseINT4(pos + 14, pos + 16);
1604 | second = parseINT4(pos + 17, pos + 19);
1605 | if (year < 1) {
1606 | valobj = Py_None;
1607 | Py_IncRef(valobj);
1608 | break;
1609 | }
1610 | valobj = PyDateTime_FromDateAndTime(year, month, day,
1611 | hour, minute, second, 0);
1612 | break;
1613 |
1614 | case MFTYPE_TIMESTAMP:// We ignore these
1615 | case MFTYPE_TIME:
1616 | case MFTYPE_YEAR:
1617 | case MFTYPE_NEWDATE:
1618 | // Fall through for string encoding
1619 | //Blob goes as String
1620 | case MFTYPE_TINY_BLOB:
1621 | case MFTYPE_MEDIUM_BLOB:
1622 | case MFTYPE_LONG_BLOB:
1623 | case MFTYPE_BLOB:
1624 | if (col->flags & MFFLAG_BINARY_FLAG) {
1625 | valobj = PyString_FromStringAndSize(pos, len);
1626 | break;
1627 | }
1628 | case MFTYPE_VAR_STRING://PyString family
1629 | case MFTYPE_VARCHAR:
1630 | case MFTYPE_STRING:
1631 | switch (col->charset) {
1632 | case MCS_binary:
1633 | valobj=PyString_FromStringAndSize(pos, len);
1634 | break;
1635 | case MCS_ascii_general_ci: //11,
1636 | case MCS_ascii_bin: //65,
1637 | valobj=PyUnicode_DecodeASCII(pos, len, NULL);
1638 | break;
1639 | case MCS_utf8_general_ci: //33,
1640 | case MCS_utf8_bin: //83,
1641 | case MCS_utf8_unicode_ci: //192,
1642 | valobj=PyUnicode_DecodeUTF8(pos, len, NULL);
1643 | break;
1644 | case MCS_utf16_general_ci: //54,
1645 | case MCS_utf16_bin: //55,
1646 | case MCS_utf16_unicode_ci: //101,
1647 | valobj=PyUnicode_DecodeUTF16(pos, len/2, NULL, NULL);
1648 | break;
1649 | case MCS_utf32_general_ci: //60,
1650 | case MCS_utf32_bin: //61,
1651 | case MCS_utf32_unicode_ci: //160,
1652 | valobj=PyUnicode_DecodeUTF32(pos, len / 4, NULL, NULL);
1653 | break;
1654 | default:
1655 | fprintf(stderr,"Exception call:%s (%s:%l) :\n",(char *)__FUNCTION__, (char *)__FILE__, (long)__LINE__);
1656 | fprintf(stderr,"Error decoding field: TYPE: %02x CHRS: %02x FLAG: %02x NAME: %s\n", col->type, col->charset, col->flags, PyString_AsString(col->name));
1657 | return;
1658 | }
1659 | break;
1660 |
1661 | case MFTYPE_ENUM:
1662 | case MFTYPE_GEOMETRY:
1663 | case MFTYPE_BIT:
1664 | case MFTYPE_NEWDECIMAL:
1665 | case MFTYPE_SET:
1666 | case MFTYPE_DECIMAL:
1667 | // Fall through for string encoding
1668 | valobj = PyString_FromStringAndSize(pos, len);
1669 | break;
1670 | default:
1671 | fprintf(stdout, "COL ERROR: TYPE: %x CHAS:%x NAME: %s\n", col->type, col->charset, col->name);
1672 | }
1673 | pos += len;
1674 | PyTuple_SET_ITEM(row, i, valobj);
1675 | }
1676 | Py_INCREF(row);
1677 | PyList_Append(self->rows, row);
1678 | self->nums ++;
1679 | }
1680 |
1681 | self->readerPktPtr += pktlen;
1682 | self->readerPktPtr = self->readerReadPtr;
1683 | if (PyErr_Occurred()) {
1684 | PyErr_Format(PyExc_ValueError, "Parse packet.");
1685 | return 0;
1686 | }
1687 | return self->readerWritePtr - self->readerReadPtr;
1688 | }
1689 |
1690 | PyObject *Con_isConnected(Con *self, PyObject *args) {
1691 | if (self->sock) {
1692 | Py_RETURN_TRUE;
1693 | }
1694 | self->tid = 0;
1695 | Py_RETURN_FALSE;
1696 | }
1697 |
1698 | static PyObject *Con_Connect(Con *self, PyObject *args) {
1699 | /*
1700 | Args: Con conn, const char *_host, int _port, const char *_username, const char *_password, const char *_database, int _autoCommit, const char *_charset*/
1701 | ulong i, len;
1702 | UINT1 *pos;
1703 | char *pstrCharset = NULL;
1704 |
1705 | if (!PyArg_ParseTuple(args, "sisss|bsb", &self->host, &self->port,
1706 | &self->user, &self->pswd, &self->db, &self->ac, &pstrCharset))
1707 | return -1;
1708 | self->ac = (self->ac) ? 1 : 0;
1709 | self->host = self->host ? self->host : "localhost";
1710 | self->user = self->user ? self->user : "";
1711 | self->pswd = self->pswd ? self->pswd : "";
1712 | self->port = self->port ? self->port : 3306;
1713 | if (pstrCharset) {
1714 | if (strcmp(pstrCharset, "utf8") == 0) {
1715 | self->charset = MCS_utf8_general_ci;
1716 | self->PFN_PyUnicode_Encode = PyUnicode_EncodeUTF8;
1717 | } else if (strcmp(pstrCharset, "latin1") == 0) {
1718 | self->charset = MCS_latin1_general_ci;
1719 | self->PFN_PyUnicode_Encode = PyUnicode_EncodeLatin1;
1720 | } else if (strcmp(pstrCharset, "ascii") == 0) {
1721 | self->charset = MCS_ascii_general_ci;
1722 | self->PFN_PyUnicode_Encode = PyUnicode_EncodeASCII;
1723 | } else if (strcmp(pstrCharset, "utf8bin") == 0) {
1724 | self->charset = MCS_utf8_bin;
1725 | self->PFN_PyUnicode_Encode = PyUnicode_DecodeUTF8;
1726 | } else if (strcmp(pstrCharset, "bin") == 0) {
1727 | self->charset = MCS_binary;
1728 | self->PFN_PyUnicode_Encode = PyString_FromStringAndSize;
1729 | } else {
1730 | return PyErr_Format(PyExc_ValueError,
1731 | "Unsupported character set '%s' specified", pstrCharset);
1732 | }
1733 | } else {
1734 | self->charset = MCS_utf8_general_ci;
1735 | self->PFN_PyUnicode_Encode = PyUnicode_EncodeUTF8;
1736 | }
1737 |
1738 | if (self->sock)
1739 | return PyErr_Format(PyExc_ValueError, "Already connected: TID:%d",
1740 | self->tid);
1741 |
1742 | if (!(self->sock = API_getSocket())
1743 | || !API_connectSocket(self->sock, self->host, self->port)) {
1744 | self->pid--;
1745 | return API_error(self, "connect");
1746 | }
1747 |
1748 | if (!self->readerStartPtr || !self->readerEndPtr
1749 | || self->readerReadPtr == self->readerWritePtr)
1750 | readerReset(self);
1751 |
1752 | self->readerWritePtr = self->readerReadPtr = self->readerPktPtr =self->readerStartPtr;
1753 | while(self->readerEndPtr -self->readerPktPtr readerEndPtr -self->readerStartPtr;
1755 | if(len<=0){
1756 | len=MY_BUFFER_SIZE;
1757 | }else len =len<<1;
1758 | assert(0readerReadPtr -self->readerStartPtr;
1761 | PRLen=self->readerPktPtr -self->readerReadPtr;
1762 | WPLen=self->readerWritePtr-self->readerPktPtr;
1763 | MyRealloc(self->readerStartPtr,len);
1764 | self->readerEndPtr =self->readerStartPtr +len;
1765 | self->readerReadPtr =self->readerStartPtr +RSLen;
1766 | self->readerPktPtr =self->readerReadPtr +PRLen;
1767 | self->readerWritePtr=self->readerPktPtr +WPLen;
1768 | };
1769 | while (self->readerWritePtr -self->readerPktPtr sock, self->readerWritePtr, self->readerEndPtr-self->readerWritePtr);
1771 | if(len<= 0L){
1772 | break;
1773 | }else self->readerWritePtr +=len;
1774 | }assert(self->readerWritePtr -self->readerPktPtr >=MY_HEADER_SIZE);
1775 |
1776 | pos =self->readerPktPtr;
1777 | i=len=pos[0] | pos[1]<<8 | pos[2]<<16;
1778 | self->nid =pos[3];
1779 | self->readerReadPtr=self->readerPktPtr =pos =pos +MY_HEADER_SIZE;
1780 | while(self->readerEndPtr -self->readerPktPtr readerEndPtr -self->readerStartPtr;
1782 | if(len<=0){
1783 | len=MY_BUFFER_SIZE;
1784 | }else len =len<<1;
1785 | assert(0readerReadPtr -self->readerStartPtr;
1788 | PRLen=self->readerPktPtr -self->readerReadPtr;
1789 | WPLen=self->readerWritePtr-self->readerPktPtr;
1790 | MyRealloc(self->readerStartPtr,len);
1791 | self->readerEndPtr =self->readerStartPtr +len;
1792 | self->readerReadPtr =self->readerStartPtr +RSLen;
1793 | self->readerPktPtr =self->readerReadPtr +PRLen;
1794 | self->readerWritePtr=self->readerPktPtr +WPLen;
1795 | };
1796 | while (self->readerWritePtr -self->readerPktPtr sock, self->readerWritePtr, self->readerEndPtr-self->readerWritePtr);
1798 | if(len<= 0L){
1799 | break;
1800 | }else self->readerWritePtr +=len;
1801 | }assert(self->readerWritePtr -self->readerPktPtr>=i);
1802 | self->readerPktPtr =pos +i;
1803 | if(i<64){
1804 | self->pid--;
1805 | return API_error(self, "packet receiving");
1806 | }
1807 |
1808 | len=i;
1809 | self->nid =pos[3];
1810 | self->ver = readerUINT1(self);
1811 | if (self->ver == 0xff) {
1812 | THROW("Too many connections reported by server");
1813 | return false;
1814 | }
1815 | if (self->ver != MY_PROTOCOL_VERSION) {
1816 | THROW(
1817 | "Protocol version expect:%0x, got(%0x)\n", MY_PROTOCOL_VERSION, self->ver);
1818 | return false;
1819 | }
1820 | self->serverVersion = readerNTString(self);
1821 | self->cid = readerUINT4(self);
1822 | for (i = 0; i < MY_SCRAMBLE_LENGTH_323; i++, self->readerReadPtr++)
1823 | self->scramble[i] = *self->readerReadPtr;
1824 | self->scramble[MY_SCRAMBLE_LENGTH_323] = *(self->readerReadPtr++);
1825 |
1826 | i=len;
1827 | self->serverCaps = readerUINT2(self);
1828 | if (!(self->serverCaps & MCP_PROTOCOL_41)) {
1829 | THROW("Authentication < 4.1 not supported");
1830 | return false;
1831 | }
1832 | UINT1 serverLang = readerUINT1(self);
1833 | self->serverStatus = readerUINT2(self);
1834 | self->serverCaps |= readerUINT2(self) << 16;
1835 | len = readerUINT1(self);
1836 | if (len < 13 + MY_SCRAMBLE_LENGTH_323)
1837 | len = 13;
1838 | readerBytes(self, 10);
1839 |
1840 | for (i = MY_SCRAMBLE_LENGTH_323; i <= len; ++i, ++self->readerReadPtr)
1841 | self->scramble[i] = *self->readerReadPtr;
1842 |
1843 | self->readerReadPtr = self->readerPktPtr;
1844 | assert(self->readerPktPtr == self->readerWritePtr);
1845 |
1846 | self->clientFlag = self->serverCaps;
1847 | self->clientFlag &= ~MCP_COMPRESS;
1848 | self->clientFlag &= ~MCP_NO_SCHEMA;
1849 | self->clientFlag &= ~MCP_SSL;
1850 | self->clientFlag |= MCP_MULTI_STATEMENTS;
1851 | self->clientFlag |= MCP_MULTI_RESULTS;
1852 | self->clientFlag |= MCP_CONNECT_WITH_DB;
1853 | /*
1854 | #ifdef DEBUG
1855 | fprintf(stderr,"host: %s:%u user: %s pswd:%s db: %s autocommit: %01u flag: %06x caps: %04x blocking: %u\n\n",
1856 | self->host ? self->host : "(Null)", self->port,
1857 | self->user ? self->user : "(Null)", self->pswd ? self->pswd : "(Null)",
1858 | self->db ? self->db : "(Null)", (UINT4)self->ac, self->clientFlag, self->serverCaps, self->blocking);
1859 | #endif
1860 | */
1861 | writerReset(self);
1862 | writerINT4(self, self->clientFlag);
1863 | writerINT4(self, MY_BUFFER_SIZE);
1864 | if (self->charset != MCS_UNDEFINED) {
1865 | writerINT1(self, (UINT1)self->charset);
1866 | } else {
1867 | writerINT1(self, self->serverLang);
1868 | }
1869 | for (i = 0; i < 23; i++)
1870 | writerINT1(self, 0);
1871 |
1872 | if (self->user) {
1873 | writerNTString(self, self->user);
1874 | } else
1875 | writerINT1(self, 0x0);
1876 |
1877 | if (self->pswd && self->pswd[0]) {
1878 | writerINT1(self, MY_SHA1_HASH_SIZE);
1879 | UINT8 token[MY_SHA1_HASH_SIZE + 1];
1880 | token[MY_SHA1_HASH_SIZE] = 0;
1881 | scramble_password(token, self->scramble, self->pswd);
1882 | writerBytes(self, token, MY_SHA1_HASH_SIZE);
1883 | } else
1884 | writerINT1(self, 0x0);
1885 | if (self->serverCaps & MCP_CONNECT_WITH_DB && self->db) {
1886 | writerNTString(self, self->db);
1887 | } else
1888 | writerINT1(self, 0x0);
1889 | writerFinalize(self, 1);
1890 | API_sendSocket(self->sock, self->writerReadPtr, self->writerWritePtr - self->writerReadPtr);
1891 | self->readerWritePtr = self->readerReadPtr = self->readerPktPtr =self->readerStartPtr;
1892 | while (self->readerWritePtr -self->readerPktPtr sock, self->readerWritePtr, self->readerEndPtr-self->readerWritePtr);
1894 | if(len<= 0L){
1895 | break;
1896 | }else self->readerWritePtr +=len;
1897 | }assert(self->readerWritePtr -self->readerPktPtr >=MY_HEADER_SIZE);
1898 | pos =self->readerPktPtr;
1899 | i=len=pos[0] | pos[1]<<8 | pos[2]<<16;
1900 | self->nid =pos[3];
1901 | if(pos[4] != 0x0){
1902 | self->pid--;
1903 | return API_error(self, "packet receiving");
1904 | }
1905 | self->readerWritePtr = self->readerReadPtr = self->readerPktPtr =self->readerStartPtr;
1906 |
1907 |
1908 | char strTemp[256 + 1];
1909 | if (self->ac) {
1910 | len =snprintf(strTemp, 256,
1911 | "SET AUTOCOMMIT=1,time_zone='+0:00',sql_mode='TRADITIONAL',character_set_client='binary',character_set_results='binary'");
1912 | } else {
1913 | len =snprintf(strTemp, 256,
1914 | "SET AUTOCOMMIT=0,time_zone='+0:00',sql_mode='TRADITIONAL',character_set_client='binary',character_set_results='binary'");
1915 | }
1916 | writerReset(self);
1917 | writerINT1(self, COM_QUERY);
1918 | writerBytes(self, strTemp, len);
1919 | writerFinalize(self, 0);
1920 | API_sendSocket(self->sock, self->writerReadPtr,self->writerWritePtr - self->writerReadPtr);
1921 | self->readerWritePtr = self->readerReadPtr = self->readerPktPtr =self->readerStartPtr;
1922 | while (self->readerWritePtr -self->readerPktPtr sock, self->readerWritePtr, self->readerEndPtr-self->readerWritePtr);
1924 | if(len<= 0L){
1925 | break;
1926 | }else self->readerWritePtr +=len;
1927 | }assert(self->readerWritePtr -self->readerPktPtr >=MY_HEADER_SIZE);
1928 | pos =self->readerPktPtr;
1929 | i=len=pos[0] | pos[1]<<8 | pos[2]<<16;
1930 | self->nid =pos[3];
1931 | if(pos[4] != 0x0){
1932 | self->pid--;
1933 | return API_error(self, "packet receiving");
1934 | }
1935 | self->readerWritePtr = self->readerReadPtr = self->readerPktPtr =self->readerStartPtr;
1936 | self->writerWritePtr = self->writerReadPtr =self->writerStartPtr;
1937 | return self;
1938 | }
1939 |
1940 | int AppendAndEscapeString(char *buffStart, char *buffEnd, const char *strStart,
1941 | const char *strEnd, int quote) {
1942 | //{'\0': '\\0', '\n': '\\n', '\r': '\\r', '\\': '\\\\', "'": "\\'", '"': '\\"', '\x1a': '\\Z'}):
1943 | char *buffOffset = buffStart;
1944 |
1945 | if (quote) {
1946 | (*buffOffset++) = '\'';
1947 | }
1948 |
1949 | while (strStart < strEnd) {
1950 | switch (*strStart) {
1951 | case '\0': // NULL
1952 | (*buffOffset++) = '\\';
1953 | (*buffOffset++) = '0';
1954 | break;
1955 | case '\n': // LF
1956 | (*buffOffset++) = '\\';
1957 | (*buffOffset++) = 'n';
1958 | break;
1959 | case '\r': // CR
1960 | (*buffOffset++) = '\\';
1961 | (*buffOffset++) = 'r';
1962 | break;
1963 | case '\\': // BACKSLASH
1964 | (*buffOffset++) = '\\';
1965 | (*buffOffset++) = '\\';
1966 | break;
1967 | case '\'': // SINGLE QUOTE
1968 | (*buffOffset++) = '\\';
1969 | (*buffOffset++) = '\'';
1970 | break;
1971 | case '\"': // DOUBLE QUOTE
1972 | (*buffOffset++) = '\\';
1973 | (*buffOffset++) = '\"';
1974 | break;
1975 | case '\x1a': // SUBSTITUTE CONTROL CHARACTER
1976 | (*buffOffset++) = '\\';
1977 | (*buffOffset++) = 'Z';
1978 | break;
1979 |
1980 | default:
1981 | (*buffOffset++) = (*strStart);
1982 | break;
1983 | }
1984 |
1985 | strStart++;
1986 | }
1987 |
1988 | if (quote) {
1989 | (*buffOffset++) = '\'';
1990 | }
1991 |
1992 | return (int) (buffOffset - buffStart);
1993 | }
1994 |
1995 | int AppendEscapedArg(Con *self, char *start, char *end, PyObject *obj) {
1996 | int ret;
1997 | PyObject *strobj;
1998 |
1999 | /*
2000 | FIXME: Surround strings with '' could be performed in this function to avoid extra logic in AppendAndEscapeString */
2001 | if (PyString_Check(obj)) {
2002 | return AppendAndEscapeString(start, end, PyString_AS_STRING(obj),
2003 | PyString_AS_STRING(obj) + PyString_GET_SIZE(obj), true);
2004 | } else if (PyUnicode_Check(obj)) {
2005 | strobj = self->PFN_PyUnicode_Encode(PyUnicode_AS_UNICODE(obj),
2006 | PyUnicode_GET_SIZE(obj), NULL);
2007 |
2008 | if (strobj == NULL) {
2009 | if (PyErr_Occurred()) {
2010 | return -1;
2011 | }
2012 |
2013 | PyErr_SetObject(PyExc_ValueError, obj);
2014 | return -1;
2015 | }
2016 |
2017 | ret = AppendAndEscapeString(start, end, PyString_AS_STRING(strobj),
2018 | PyString_AS_STRING(strobj) + PyString_GET_SIZE(strobj), true);
2019 | Py_DECREF(strobj);
2020 |
2021 | return ret;
2022 | } else if (obj == Py_None) {
2023 | (*start++) = 'n';
2024 | (*start++) = 'u';
2025 | (*start++) = 'l';
2026 | (*start++) = 'l';
2027 | return 4;
2028 | } else if (PyDateTime_Check(obj)) {
2029 | int len = sprintf(start, "'%04d-%02d-%02d %02d:%02d:%02d'",
2030 | PyDateTime_GET_YEAR(obj), PyDateTime_GET_MONTH(obj),
2031 | PyDateTime_GET_DAY(obj), PyDateTime_DATE_GET_HOUR(obj),
2032 | PyDateTime_DATE_GET_MINUTE(obj),
2033 | PyDateTime_DATE_GET_SECOND(obj));
2034 |
2035 | return len;
2036 | } else if (PyDate_Check(obj)) {
2037 | int len = sprintf(start, "'%04d:%02d:%02d'", PyDateTime_GET_YEAR(obj),
2038 | PyDateTime_GET_MONTH(obj), PyDateTime_GET_DAY(obj));
2039 |
2040 | return len;
2041 | }
2042 |
2043 | //FIXME: Might possible to avoid this?
2044 | strobj = PyObject_Str(obj);
2045 | ret = AppendAndEscapeString(start, end, PyString_AS_STRING(strobj),
2046 | PyString_AS_STRING(strobj) + PyString_GET_SIZE(strobj), false);
2047 | Py_DECREF(strobj);
2048 | return ret;
2049 | }
2050 |
2051 | PyObject *EscapeQueryArguments(Con *self, PyObject *inQuery, PyObject *iterable) {
2052 | size_t cbOutQuery = 0;
2053 | char *obuffer;
2054 | char *optr;
2055 | char *iptr;
2056 | int heap = 0;
2057 | int appendLen;
2058 | PyObject *retobj;
2059 | PyObject *iterator;
2060 | PyObject *arg;
2061 |
2062 | // Estimate output length
2063 |
2064 | cbOutQuery += PyString_GET_SIZE(inQuery);
2065 |
2066 | iterator = PyObject_GetIter(iterable);
2067 |
2068 | while ((arg = PyIter_Next(iterator))) {
2069 | // Quotes;
2070 | cbOutQuery += 2;
2071 |
2072 | // Worst case escape and utf-8
2073 | if (PyString_Check(arg))
2074 | cbOutQuery += (PyString_GET_SIZE(arg) * 2);
2075 | else if (PyUnicode_Check(arg))
2076 | cbOutQuery += (PyUnicode_GET_SIZE(arg) * 6);
2077 | else
2078 | cbOutQuery += 64;
2079 |
2080 | Py_DECREF(arg);
2081 | }
2082 |
2083 | Py_DECREF(iterator);
2084 |
2085 | if (cbOutQuery > (1024 * 64)) {
2086 | /*
2087 | FIXME: Allocate a PyString and resize it just like the Python code does it */
2088 | obuffer = (char *) PyObject_Malloc(cbOutQuery);
2089 | heap = 1;
2090 | } else {
2091 | obuffer = (char *) alloca(cbOutQuery);
2092 | }
2093 |
2094 | optr = obuffer;
2095 | iptr = PyString_AS_STRING(inQuery);
2096 |
2097 | iterator = PyObject_GetIter(iterable);
2098 |
2099 | while (1) {
2100 | switch (*iptr) {
2101 | case '\0':
2102 | goto END_PARSE;
2103 |
2104 | case '%':
2105 |
2106 | iptr++;
2107 |
2108 | if (*iptr != 's' && *iptr != '%') {
2109 | Py_DECREF(iterator);
2110 | if (heap)
2111 | PyObject_Free(obuffer);
2112 | return PyErr_Format(PyExc_ValueError,
2113 | "Found character %c expected %%", *iptr);
2114 | }
2115 |
2116 | if (*iptr == '%') {
2117 | *(optr++) = *(iptr)++;
2118 | break;
2119 | }
2120 |
2121 | iptr++;
2122 |
2123 | arg = PyIter_Next(iterator);
2124 |
2125 | if (arg == NULL) {
2126 | Py_DECREF(iterator);
2127 | if (heap)
2128 | PyObject_Free(obuffer);
2129 | return PyErr_Format(PyExc_ValueError,
2130 | "Unexpected end of iterator found");
2131 | }
2132 |
2133 | appendLen = AppendEscapedArg(self, optr, obuffer + cbOutQuery, arg);
2134 | Py_DECREF(arg);
2135 |
2136 | if (appendLen == -1) {
2137 | Py_DECREF(iterator);
2138 | if (heap)
2139 | PyObject_Free(obuffer);
2140 | return NULL;
2141 | }
2142 |
2143 | optr += appendLen;
2144 |
2145 | break;
2146 |
2147 | default:
2148 | *(optr++) = *(iptr)++;
2149 | break;
2150 | }
2151 | }
2152 |
2153 | END_PARSE: Py_DECREF(iterator);
2154 |
2155 | retobj = PyString_FromStringAndSize(obuffer, (optr - obuffer));
2156 |
2157 | if (heap) {
2158 | PyObject_Free(obuffer);
2159 | }
2160 |
2161 | return retobj;
2162 | }
2163 |
2164 | PyObject *Con_Query(Con *self, PyObject *args) {
2165 | int retMore = 0;
2166 | PyObject *inQuery = NULL;
2167 | PyObject *iterable = NULL;
2168 | PyObject *escapedQuery = NULL;
2169 | PyObject *query = NULL;
2170 |
2171 | if (!self->sock)
2172 | return PyErr_Format(PyExc_RuntimeError, "Not connected");
2173 | if (!PyArg_ParseTuple(args, "O|O", &inQuery, &iterable)) {
2174 | return NULL;
2175 | }
2176 |
2177 | if (iterable) {
2178 | PyObject *iterator = PyObject_GetIter(iterable);
2179 | if (iterator == NULL) {
2180 | PyErr_Clear();
2181 | return PyErr_Format(PyExc_TypeError, "Expected iterable");
2182 | }
2183 | Py_DECREF(iterator);
2184 | }
2185 | if (!PyString_Check(inQuery)) {
2186 | if (!PyUnicode_Check(inQuery)) {
2187 | return PyErr_Format(PyExc_TypeError,
2188 | "Query argument must be either String or Unicode");
2189 | }
2190 | query = self->PFN_PyUnicode_Encode(PyUnicode_AS_UNICODE(inQuery),
2191 | PyUnicode_GET_SIZE(inQuery), NULL);
2192 | if (query == NULL) {
2193 | if (!PyErr_Occurred()) {
2194 | PyErr_SetObject(PyExc_ValueError, query);
2195 | return NULL;
2196 | }
2197 | return NULL;
2198 | }
2199 | } else {
2200 | query = inQuery;
2201 | Py_INCREF(query);
2202 | }
2203 |
2204 | if (iterable) {
2205 | escapedQuery = EscapeQueryArguments(self, query, iterable);
2206 | Py_DECREF(query);
2207 |
2208 | if (escapedQuery == NULL) {
2209 | if (!PyErr_Occurred()) {
2210 | return PyErr_Format(PyExc_RuntimeError,
2211 | "Exception not set in EscapeQueryArguments chain");
2212 | }
2213 | return NULL;
2214 | }
2215 | } else {
2216 | escapedQuery = query;
2217 | }
2218 |
2219 | writerReset(self);
2220 | writerINT1(self, COM_QUERY);
2221 | writerBytes(self, PyString_AS_STRING(escapedQuery),
2222 | PyString_GET_SIZE(escapedQuery));
2223 | writerFinalize(self, 0);
2224 | API_sendSocket(self->sock, self->writerReadPtr, self->writerWritePtr - self->writerReadPtr);
2225 | /*
2226 | #ifdef DEBUG
2227 | pbuf(stderr, self->writerReadPtr, self->writerWritePtr -self->writerReadPtr, 16);
2228 | fprintf(stderr, "\nS: %p R: %p P: %p W: %p E: %p\n",self->readerStartPtr, self->readerReadPtr,
2229 | self->readerPktPtr, self->readerWritePtr, self->readerEndPtr);
2230 | #endif
2231 | */
2232 | self->writerWritePtr = self->writerReadPtr =self->writerStartPtr;
2233 | self->readerWritePtr = self->readerReadPtr = self->readerPktPtr =self->readerStartPtr;
2234 | Con_PacketRecv(self, 0);
2235 |
2236 | if (PyErr_Occurred()) {
2237 | PyErr_Print();
2238 | Py_INCREF(Py_None);
2239 | return Py_None;
2240 | }
2241 | Py_INCREF(Py_None);
2242 | return Py_None;
2243 |
2244 | /*
2245 | if ((*PyString_AS_STRING(escapedQuery)) == ' ')retMore = 1;
2246 | // ret = Con_Query(self, PyString_AS_STRING(escapedQuery), PyString_GET_SIZE(escapedQuery), retMore);
2247 |
2248 | Py_DECREF(escapedQuery);
2249 |
2250 | if (ret == NULL)
2251 | {
2252 | return API_error(self, "query result");
2253 | }
2254 |
2255 | if(PyTuple_Check(ret))return ret; // it's a OK packet, return (affectedRows, insertID, ... ), see above API_resultOK();
2256 |
2257 | if(retMore){
2258 | PyObject *tuple = PyTuple_New(2);
2259 | PyTuple_SET_ITEM(tuple, 0, ret->fields);
2260 | PyTuple_SET_ITEM(tuple, 1, ret->rows);
2261 | return tuple;
2262 | }else return ret->rows;
2263 | */
2264 | }
2265 |
2266 | static PyMethodDef Con_methods[] =
2267 | {
2268 | { "connect", (PyCFunction) Con_Connect, METH_VARARGS,
2269 | "Connects to database server. Arguments: host, port, username, password, database, autocommit, charset" },
2270 | { "query", (PyCFunction) Con_Query, METH_VARARGS,
2271 | "Performs a query. Arguments: query, arguments to escape" },
2272 | { "close", (PyCFunction) Con_Clear, METH_NOARGS,
2273 | "Closes connection" },
2274 | // {"ping", (PyCFunction) Con_ping, METH_NOARGS, "Check connection status"},
2275 | { "isConnected", (PyCFunction) Con_isConnected, METH_NOARGS,
2276 | "Check connection status" },
2277 | // {"setTimeout", (PyCFunction) Con_setTimeout, METH_VARARGS, "Sets connection timeout in seconds"},
2278 | // {"setTxBufferSize", (PyCFunction) Con_setTxBufferSize, METH_VARARGS, "Sets connection timeout in seconds"},
2279 | // {"setRxBufferSize", (PyCFunction) Con_setRxBufferSize, METH_VARARGS, "Sets connection timeout in seconds"},
2280 | { NULL } };
2281 | static PyMemberDef Con_members[] = {
2282 |
2283 | { "Error", T_OBJECT, offsetof(Con, Error), READONLY },
2284 | { "SQLError", T_OBJECT, offsetof(Con, SQLError), READONLY },
2285 | { "tid", T_INT, offsetof(Con, tid), READONLY, "Server side thread id" },
2286 | { "sock", T_OBJECT, offsetof(Con, sock), 1, "Server side Python Socket" },
2287 | { "rows", T_OBJECT, offsetof(Con, rows), 1, "Query result rows" },
2288 | { "fields",T_OBJECT, offsetof(Con, fields), 1, "Query result fields" },
2289 | { "host", T_STRING, offsetof(Con,host), READONLY, "Server host name" },
2290 | { "username", T_STRING, offsetof(Con, user), READONLY, "user name" },
2291 | { "password", T_STRING, offsetof(Con, pswd), READONLY, "password" },
2292 | {"port", T_INT, offsetof(Con, port), READONLY, "Server side port" },
2293 | { NULL } };
2294 |
2295 | static PyTypeObject ConType = {
2296 | PyObject_HEAD_INIT(NULL)
2297 | 0, /* ob_size */
2298 | "amysql.Con", /* tp_name */
2299 | sizeof(Con), /* tp_basicsize */
2300 | 0, /* tp_itemsize */
2301 | Con_Destructor, /* tp_dealloc */
2302 | 0, /* tp_print */
2303 | 0, /* tp_getattr */
2304 | 0, /* tp_setattr */
2305 | 0, /* tp_compare */
2306 | 0, /* tp_repr */
2307 | 0, /* tp_as_number */
2308 | 0, /* tp_as_sequence */
2309 | 0, /* tp_as_mapping */
2310 | 0, /* tp_hash */
2311 | 0, /* tp_call */
2312 | 0, /* tp_str */
2313 | 0, /* tp_getattro */
2314 | 0, /* tp_setattro */
2315 | 0, /* tp_as_buffer */
2316 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
2317 | "", /* tp_doc */
2318 | Con_Traverse, /* tp_traverse */
2319 | Con_Clear, /* tp_clear */
2320 | 0, /* tp_richcompare */
2321 | 0, /* tp_weaklistoffset */
2322 | 0, /* tp_iter */
2323 | 0, /* tp_iternext */
2324 | Con_methods, /* tp_methods */
2325 | Con_members, /* tp_members */
2326 | 0, /* tp_getset */
2327 | 0, /* tp_base */
2328 | 0, /* tp_dict */
2329 | 0, /* tp_descr_get */
2330 | 0, /* tp_descr_set */
2331 | 0, /* tp_dictoffset */
2332 | (initproc)Con_Constructor, /* tp_init */
2333 | 0, /* tp_alloc */
2334 | Con_New, /* tp_new */
2335 | };
2336 |
2337 | static PyMethodDef methods[] = { { NULL, NULL, 0, NULL } /* Sentinel */
2338 | };
2339 |
2340 | PyMODINIT_FUNC initamysql(void) {
2341 | PyObject* m;
2342 | PyObject *dict;
2343 | PyDateTime_IMPORT;
2344 |
2345 | m = Py_InitModule3("amysql", methods, "");
2346 | if (m == NULL)
2347 | return;
2348 |
2349 | dict = PyModule_GetDict(m);
2350 |
2351 | ConType.tp_new = PyType_GenericNew;
2352 | if (PyType_Ready(&ConType) < 0)
2353 | return;
2354 | Py_INCREF(&ConType);
2355 | PyModule_AddObject(m, "Con", (PyObject *) &ConType);
2356 |
2357 | amysql_Error = PyErr_NewException("amysql.Error", PyExc_Error,
2358 | NULL);
2359 | amysql_SQLError = PyErr_NewException("amysql.SQLError", amysql_Error, NULL);
2360 |
2361 | PyDict_SetItemString(dict, "Error", amysql_Error);
2362 | PyDict_SetItemString(dict, "SQLError", amysql_SQLError);
2363 |
2364 | if (sockclass == NULL) {
2365 | if(sockmodule == NULL){
2366 | sockmodule = PyImport_ImportModule("socket");
2367 | if (sockmodule == NULL){fprintf(stderr, "Error importing Python standard socket module\n");exit(-1);}
2368 | }
2369 | sockclass = PyObject_GetAttrString(sockmodule, "socket");
2370 | if (!sockclass ||!PyType_Check(sockclass) ||!PyCallable_Check(sockclass)){fprintf(stderr, "Error get 'socket.socket' method\n");exit(-1);}
2371 | }
2372 | }
2373 |
2374 |
2375 | #endif
2376 |
2377 |
2378 |
2379 |
2380 |
--------------------------------------------------------------------------------
/amysql.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abaelhe/amysql/9854a459144fda7e0adb2d046a88c40ced4a63c7/amysql.so
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from distutils.core import setup, Extension
2 | import shutil
3 | import sys
4 |
5 | CLASSIFIERS = filter(None, map(str.strip,
6 | """
7 | Intended Audience :: Developers
8 | License :: Private :: All Rights Reserved!
9 | Programming Language :: Python
10 | Topic :: Database
11 | Topic :: Software Development :: Libraries :: Python Modules
12 | """.splitlines()))
13 |
14 | libs = []
15 |
16 | if sys.platform != "win32":
17 | libs.append("stdc++")
18 |
19 | if sys.platform == "win32":
20 | libs.append("ws2_32")
21 |
22 |
23 | module1 = Extension('amysql',
24 | sources = ["./amysql.c" ],
25 | include_dirs = [ "./"],
26 | library_dirs = [ "./"],
27 | libraries=libs,
28 | define_macros=[('WIN32_LEAN_AND_MEAN', None), ('DEBUG', None)])
29 |
30 | setup (name = 'amysql',
31 | version = "2.5",
32 | description = "Async MySQL driver for Python",
33 | ext_modules = [module1],
34 | extra_compile_args=["-O0"],
35 | extra_link_args=["-O0"],
36 | author="Abael Heyijun",
37 | author_email="hyjdyx@gmail.com",
38 | license="BSD License",
39 | platforms=['any'],
40 | url="http://www.abael.com",
41 | classifiers=CLASSIFIERS,
42 | )
43 |
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | import amysql
2 | c=amysql.Con()
3 | c.connect('localhost',3306, 'xweb', 'xweb123', 'xweb')
4 | from time import time
5 | def pf(func, n):
6 | t=time()
7 | for i in xrange(n):
8 | func()
9 | d=time()
10 | return n/(d-t)
11 |
12 | print pf(lambda:c.query("select * from sys_usr"), 10000)
13 |
--------------------------------------------------------------------------------