Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
singlestore-labs
GitHub Repository: singlestore-labs/singlestoredb-python
Path: blob/main/accel.c
464 views
1
2
#include <math.h>
3
#include <stdint.h>
4
#include <stdlib.h>
5
#include <Python.h>
6
7
#ifndef Py_LIMITED_API
8
#include <datetime.h>
9
#endif
10
11
#ifndef PyBUF_WRITE
12
#define PyBUF_WRITE 0x200
13
#endif
14
15
#define ACCEL_OUT_TUPLES 0
16
#define ACCEL_OUT_STRUCTSEQUENCES 1
17
#define ACCEL_OUT_DICTS 2
18
#define ACCEL_OUT_NAMEDTUPLES 3
19
#define ACCEL_OUT_NUMPY 4
20
#define ACCEL_OUT_PANDAS 5
21
#define ACCEL_OUT_POLARS 6
22
#define ACCEL_OUT_ARROW 7
23
24
#define NUMPY_BOOL 1
25
#define NUMPY_INT8 2
26
#define NUMPY_INT16 3
27
#define NUMPY_INT32 4
28
#define NUMPY_INT64 5
29
#define NUMPY_UINT8 6
30
#define NUMPY_UINT16 7
31
#define NUMPY_UINT32 8
32
#define NUMPY_UINT64 9
33
#define NUMPY_FLOAT32 10
34
#define NUMPY_FLOAT64 11
35
#define NUMPY_TIMEDELTA 12
36
#define NUMPY_DATETIME 13
37
#define NUMPY_OBJECT 14
38
#define NUMPY_BYTES 15
39
#define NUMPY_FIXED_STRING 16
40
41
#define MYSQL_FLAG_NOT_NULL 1
42
#define MYSQL_FLAG_PRI_KEY 2
43
#define MYSQL_FLAG_UNIQUE_KEY 4
44
#define MYSQL_FLAG_MULTIPLE_KEY 8
45
#define MYSQL_FLAG_BLOB 16
46
#define MYSQL_FLAG_UNSIGNED 32
47
#define MYSQL_FLAG_ZEROFILL 64
48
#define MYSQL_FLAG_BINARY 128
49
#define MYSQL_FLAG_ENUM 256
50
#define MYSQL_FLAG_AUTO_INCREMENT 512
51
#define MYSQL_FLAG_TIMESTAMP 1024
52
#define MYSQL_FLAG_SET 2048
53
#define MYSQL_FLAG_PART_KEY 16384
54
#define MYSQL_FLAG_GROUP 32767
55
#define MYSQL_FLAG_UNIQUE 65536
56
57
#define MYSQL_TYPE_DECIMAL 0
58
#define MYSQL_TYPE_TINY 1
59
#define MYSQL_TYPE_SHORT 2
60
#define MYSQL_TYPE_LONG 3
61
#define MYSQL_TYPE_FLOAT 4
62
#define MYSQL_TYPE_DOUBLE 5
63
#define MYSQL_TYPE_NULL 6
64
#define MYSQL_TYPE_TIMESTAMP 7
65
#define MYSQL_TYPE_LONGLONG 8
66
#define MYSQL_TYPE_INT24 9
67
#define MYSQL_TYPE_DATE 10
68
#define MYSQL_TYPE_TIME 11
69
#define MYSQL_TYPE_DATETIME 12
70
#define MYSQL_TYPE_YEAR 13
71
#define MYSQL_TYPE_NEWDATE 14
72
#define MYSQL_TYPE_VARCHAR 15
73
#define MYSQL_TYPE_BIT 16
74
#define MYSQL_TYPE_JSON 245
75
#define MYSQL_TYPE_NEWDECIMAL 246
76
#define MYSQL_TYPE_ENUM 247
77
#define MYSQL_TYPE_SET 248
78
#define MYSQL_TYPE_TINY_BLOB 249
79
#define MYSQL_TYPE_MEDIUM_BLOB 250
80
#define MYSQL_TYPE_LONG_BLOB 251
81
#define MYSQL_TYPE_BLOB 252
82
#define MYSQL_TYPE_VAR_STRING 253
83
#define MYSQL_TYPE_STRING 254
84
#define MYSQL_TYPE_GEOMETRY 255
85
86
// SingleStoreDB extended types
87
#define MYSQL_TYPE_BSON 1001
88
#define MYSQL_TYPE_FLOAT32_VECTOR_JSON 2001
89
#define MYSQL_TYPE_FLOAT64_VECTOR_JSON 2002
90
#define MYSQL_TYPE_INT8_VECTOR_JSON 2003
91
#define MYSQL_TYPE_INT16_VECTOR_JSON 2004
92
#define MYSQL_TYPE_INT32_VECTOR_JSON 2005
93
#define MYSQL_TYPE_INT64_VECTOR_JSON 2006
94
#define MYSQL_TYPE_FLOAT32_VECTOR 3001
95
#define MYSQL_TYPE_FLOAT64_VECTOR 3002
96
#define MYSQL_TYPE_INT8_VECTOR 3003
97
#define MYSQL_TYPE_INT16_VECTOR 3004
98
#define MYSQL_TYPE_INT32_VECTOR 3005
99
#define MYSQL_TYPE_INT64_VECTOR 3006
100
101
#define MYSQL_TYPE_CHAR MYSQL_TYPE_TINY
102
#define MYSQL_TYPE_INTERVAL MYSQL_TYPE_ENUM
103
104
#define MYSQL_COLUMN_NULL 251
105
#define MYSQL_COLUMN_UNSIGNED_CHAR 251
106
#define MYSQL_COLUMN_UNSIGNED_SHORT 252
107
#define MYSQL_COLUMN_UNSIGNED_INT24 253
108
#define MYSQL_COLUMN_UNSIGNED_INT64 254
109
110
#define MYSQL_SERVER_MORE_RESULTS_EXISTS 8
111
112
// 2**24 - 1
113
#define MYSQL_MAX_PACKET_LEN 16777215
114
115
#define ACCEL_OPTION_TIME_TYPE_TIMEDELTA 0
116
#define ACCEL_OPTION_TIME_TYPE_TIME 1
117
#define ACCEL_OPTION_JSON_TYPE_STRING 0
118
#define ACCEL_OPTION_JSON_TYPE_OBJ 1
119
#define ACCEL_OPTION_BIT_TYPE_BYTES 0
120
#define ACCEL_OPTION_BIT_TYPE_INT 1
121
122
#define CHR2INT1(x) ((x)[1] - '0')
123
#define CHR2INT2(x) ((((x)[0] - '0') * 10) + ((x)[1] - '0'))
124
#define CHR2INT3(x) ((((x)[0] - '0') * 1e2) + (((x)[1] - '0') * 10) + ((x)[2] - '0'))
125
#define CHR2INT4(x) ((((x)[0] - '0') * 1e3) + (((x)[1] - '0') * 1e2) + (((x)[2] - '0') * 10) + ((x)[3] - '0'))
126
#define CHR2INT6(x) ((((x)[0] - '0') * 1e5) + (((x)[1] - '0') * 1e4) + (((x)[2] - '0') * 1e3) + (((x)[3] - '0') * 1e2) + (((x)[4] - '0') * 10) + (((x)[5] - '0')))
127
128
#define CHECK_DATE_STR(s, s_l) \
129
((s_l) == 10 && \
130
(s)[0] >= '0' && (s)[0] <= '9' && \
131
(s)[1] >= '0' && (s)[1] <= '9' && \
132
(s)[2] >= '0' && (s)[2] <= '9' && \
133
(s)[3] >= '0' && (s)[3] <= '9' && \
134
(s)[4] == '-' && \
135
(((s)[5] == '1' && ((s)[6] >= '0' && (s)[6] <= '2')) || \
136
((s)[5] == '0' && ((s)[6] >= '1' && (s)[6] <= '9'))) && \
137
(s)[7] == '-' && \
138
((((s)[8] >= '0' && (s)[8] <= '2') && ((s)[9] >= '0' && (s)[9] <= '9')) || \
139
((s)[8] == '3' && ((s)[9] >= '0' && (s)[9] <= '1'))) && \
140
!((s)[0] == '0' && (s)[1] == '0' && (s)[2] == '0' && (s)[3] == '0') && \
141
!((s)[5] == '0' && (s)[6] == '0') && \
142
!((s)[8] == '0' && (s)[9] == '0'))
143
144
#define CHECK_TIME_STR(s, s_l) \
145
((s_l) == 8 && \
146
((((s)[0] >= '0' && (s)[0] <= '1') && ((s)[1] >= '0' && (s)[1] <= '9')) || \
147
((s)[0] == '2' && ((s)[1] >= '0' && (s)[1] <= '3'))) && \
148
(s)[2] == ':' && \
149
(((s)[3] >= '0' && (s)[3] <= '5') && ((s)[4] >= '0' && (s)[4] <= '9')) && \
150
(s)[5] == ':' && \
151
(((s)[6] >= '0' && (s)[6] <= '5') && ((s)[7] >= '0' && (s)[7] <= '9')))
152
153
#define CHECK_MICROSECONDS_STR(s, s_l) \
154
((s_l) == 7 && \
155
(s)[0] == '.' && \
156
(s)[1] >= '0' && (s)[1] <= '9' && \
157
(s)[2] >= '0' && (s)[2] <= '9' && \
158
(s)[3] >= '0' && (s)[3] <= '9' && \
159
(s)[4] >= '0' && (s)[4] <= '9' && \
160
(s)[5] >= '0' && (s)[5] <= '9' && \
161
(s)[6] >= '0' && (s)[6] <= '9')
162
163
#define CHECK_MILLISECONDS_STR(s, s_l) \
164
((s_l) == 4 && \
165
(s)[0] == '.' && \
166
(s)[1] >= '0' && (s)[1] <= '9' && \
167
(s)[2] >= '0' && (s)[2] <= '9' && \
168
(s)[3] >= '0' && (s)[3] <= '9')
169
170
#define CHECK_MICRO_TIME_STR(s, s_l) \
171
((s_l) == 15 && CHECK_TIME_STR(s, 8) && CHECK_MICROSECONDS_STR((s)+8, 7))
172
173
#define CHECK_MILLI_TIME_STR(s, s_l) \
174
((s_l) == 12 && CHECK_TIME_STR(s, 8) && CHECK_MILLISECONDS_STR((s)+8, 4))
175
176
#define CHECK_DATETIME_STR(s, s_l) \
177
((s_l) == 19 && \
178
CHECK_DATE_STR(s, 10) && \
179
((s)[10] == ' ' || (s)[10] == 'T') && \
180
CHECK_TIME_STR((s)+11, 8))
181
182
#define CHECK_MICRO_DATETIME_STR(s, s_l) \
183
((s_l) == 26 && \
184
CHECK_DATE_STR(s, 10) && \
185
((s)[10] == ' ' || (s)[10] == 'T') && \
186
CHECK_MICRO_TIME_STR((s)+11, 15))
187
188
#define CHECK_MILLI_DATETIME_STR(s, s_l) \
189
((s_l) == 23 && \
190
CHECK_DATE_STR(s, 10) && \
191
((s)[10] == ' ' || (s)[10] == 'T') && \
192
CHECK_MICRO_TIME_STR((s)+11, 12))
193
194
#define CHECK_ANY_DATETIME_STR(s, s_l) \
195
(((s_l) == 19 && CHECK_DATETIME_STR(s, s_l)) || \
196
((s_l) == 23 && CHECK_MILLI_DATETIME_STR(s, s_l)) || \
197
((s_l) == 26 && CHECK_MICRO_DATETIME_STR(s, s_l)))
198
199
#define DATETIME_SIZE (19)
200
#define DATETIME_MILLI_SIZE (23)
201
#define DATETIME_MICRO_SIZE (26)
202
203
#define IS_DATETIME_MILLI(s, s_l) ((s_l) == 23)
204
#define IS_DATETIME_MICRO(s, s_l) ((s_l) == 26)
205
206
#define CHECK_ANY_TIME_STR(s, s_l) \
207
(((s_l) == 8 && CHECK_TIME_STR(s, s_l)) || \
208
((s_l) == 12 && CHECK_MILLI_TIME_STR(s, s_l)) || \
209
((s_l) == 15 && CHECK_MICRO_TIME_STR(s, s_l)))
210
211
#define TIME_SIZE (8)
212
#define TIME_MILLI_SIZE (12)
213
#define TIME_MICRO_SIZE (15)
214
215
#define IS_TIME_MILLI(s, s_l) ((s_l) == 12)
216
#define IS_TIME_MICRO(s, s_l) ((s_l) == 15)
217
218
219
// 0000-00-00 00:00:00
220
// 0000-00-00 00:00:00.000
221
// 0000-00-00 00:00:00.000000
222
#define CHECK_ANY_ZERO_DATETIME_STR(s, s_l) \
223
(((s_l) == 19 && CHECK_ZERO_DATETIME_STR(s, s_l)) || \
224
((s_l) == 23 && CHECK_ZERO_MILLI_DATETIME_STR(s, s_l)) || \
225
((s_l) == 26 && CHECK_ZERO_MICRO_DATETIME_STR(s, s_l)))
226
227
#define CHECK_ZERO_DATETIME_STR(s, s_l) \
228
(s_l == 19 && \
229
CHECK_ZERO_DATE_STR(s, 10) && \
230
((s)[10] == ' ' || (s)[10] == 'T') && \
231
CHECK_ZERO_TIME_STR((s)+11, 8))
232
233
#define CHECK_ZERO_MILLI_DATETIME_STR(s, s_l) \
234
(s_l == 23 && \
235
CHECK_ZERO_DATE_STR(s, 10) && \
236
((s)[10] == ' ' || (s)[10] == 'T') && \
237
CHECK_ZERO_MILLI_TIME_STR((s)+11, 12))
238
239
#define CHECK_ZERO_MICRO_DATETIME_STR(s, s_l) \
240
(s_l == 26 && \
241
CHECK_ZERO_DATE_STR(s, 10) && \
242
((s)[10] == ' ' || (s)[10] == 'T') && \
243
CHECK_ZERO_MICRO_TIME_STR((s)+11, 15))
244
245
#define CHECK_ZERO_DATE_STR(s, s_l) \
246
(s_l == 10 && ((s)[0] == '0' && (s)[1] == '0' && (s)[2] == '0' && (s)[3] == '0' && \
247
(s)[4] == '-' && (s)[5] == '0' && (s)[6] == '0' && (s)[7] == '-' && \
248
(s)[8] == '0' && (s)[9] == '0'))
249
250
#define CHECK_ZERO_TIME_STR(s, s_l) \
251
(s_l == 8 && ((s)[0] == '0' && (s)[1] == '0' && (s)[2] == ':' && \
252
(s)[3] == '0' && (s)[4] == '0' && (s)[5] == ':' && \
253
(s)[6] == '0' && (s)[7] == '0'))
254
255
#define CHECK_ZERO_MILLI_TIME_STR(s, s_l) \
256
(s_l == 12 && CHECK_ZERO_TIME_STR(s, 8) && \
257
(s)[8] == '.' && (s)[9] == '0' && (s)[10] == '0' && (s)[11] == '0')
258
259
#define CHECK_ZERO_MICRO_TIME_STR(s, s_l) \
260
(s_l == 15 && CHECK_ZERO_TIME_STR(s, 8) && \
261
(s)[8] == '.' && (s)[9] == '0' && (s)[10] == '0' && (s)[11] == '0' && \
262
(s)[12] == '0' && (s)[13] == '0' && (s)[14] == '0')
263
264
265
#define CHECK_TIMEDELTA1_STR(s, s_l) \
266
((s_l) == 7 && \
267
(s)[0] >= '0' && (s)[0] <= '9' && \
268
(s)[1] == ':' && \
269
(s)[2] >= '0' && (s)[2] <= '5' && \
270
(s)[3] >= '0' && (s)[3] <= '9' && \
271
(s)[4] == ':' && \
272
(s)[5] >= '0' && (s)[5] <= '5' && \
273
(s)[6] >= '0' && (s)[6] <= '9')
274
275
#define CHECK_TIMEDELTA1_MILLI_STR(s, s_l) \
276
((s_l) == 11 && CHECK_TIMEDELTA1_STR(s, 7) && CHECK_MILLISECONDS_STR((s)+7, 4))
277
278
#define CHECK_TIMEDELTA1_MICRO_STR(s, s_l) \
279
((s_l) == 14 && CHECK_TIMEDELTA1_STR(s, 7) && CHECK_MICROSECONDS_STR((s)+7, 7))
280
281
#define CHECK_TIMEDELTA2_STR(s, s_l) \
282
((s_l) == 8 && \
283
(s)[0] >= '0' && (s)[0] <= '9' && \
284
CHECK_TIMEDELTA1_STR((s)+1, 7))
285
286
#define CHECK_TIMEDELTA2_MILLI_STR(s, s_l) \
287
((s_l) == 12 && CHECK_TIMEDELTA2_STR(s, 8) && CHECK_MILLISECONDS_STR((s)+8, 4))
288
289
#define CHECK_TIMEDELTA2_MICRO_STR(s, s_l) \
290
((s_l) == 15 && CHECK_TIMEDELTA2_STR(s, 8) && CHECK_MICROSECONDS_STR((s)+8, 7))
291
292
#define CHECK_TIMEDELTA3_STR(s, s_l) \
293
((s_l) == 9 && \
294
(s)[0] >= '0' && (s)[0] <= '9' && \
295
(s)[1] >= '0' && (s)[1] <= '9' && \
296
CHECK_TIMEDELTA1_STR((s)+2, 7))
297
298
#define CHECK_TIMEDELTA3_MILLI_STR(s, s_l) \
299
((s_l) == 13 && CHECK_TIMEDELTA3_STR(s, 9) && CHECK_MILLISECONDS_STR((s)+9, 4))
300
301
#define CHECK_TIMEDELTA3_MICRO_STR(s, s_l) \
302
((s_l) == 16 && CHECK_TIMEDELTA3_STR(s, 9) && CHECK_MICROSECONDS_STR((s)+9, 7))
303
304
//
305
// 0:00:00 / 0:00:00.000 / 0:00:00.000000
306
// 00:00:00 / 00:00:00.000 / 00:00:00.000000
307
// 000:00:00 / 000:00:00.000 / 000:00:00.000000
308
//
309
#define CHECK_ANY_TIMEDELTA_STR(s, s_l) \
310
(((s_l) > 0 && (s)[0] == '-') ? \
311
(-1 * (_CHECK_ANY_TIMEDELTA_STR((s)+1, (s_l)-1))) : \
312
(_CHECK_ANY_TIMEDELTA_STR((s), (s_l))))
313
314
#define _CHECK_ANY_TIMEDELTA_STR(s, s_l) \
315
(CHECK_TIMEDELTA1_STR(s, s_l) || \
316
CHECK_TIMEDELTA2_STR(s, s_l) || \
317
CHECK_TIMEDELTA3_STR(s, s_l) || \
318
CHECK_TIMEDELTA1_MILLI_STR(s, s_l) || \
319
CHECK_TIMEDELTA2_MILLI_STR(s, s_l) || \
320
CHECK_TIMEDELTA3_MILLI_STR(s, s_l) || \
321
CHECK_TIMEDELTA1_MICRO_STR(s, s_l) || \
322
CHECK_TIMEDELTA2_MICRO_STR(s, s_l) || \
323
CHECK_TIMEDELTA3_MICRO_STR(s, s_l))
324
325
#define TIMEDELTA1_SIZE (7)
326
#define TIMEDELTA2_SIZE (8)
327
#define TIMEDELTA3_SIZE (9)
328
#define TIMEDELTA1_MILLI_SIZE (11)
329
#define TIMEDELTA2_MILLI_SIZE (12)
330
#define TIMEDELTA3_MILLI_SIZE (13)
331
#define TIMEDELTA1_MICRO_SIZE (14)
332
#define TIMEDELTA2_MICRO_SIZE (15)
333
#define TIMEDELTA3_MICRO_SIZE (16)
334
335
#define IS_TIMEDELTA1(s, s_l) ((s_l) == 7 || (s_l) == 11 || (s_l) == 14)
336
#define IS_TIMEDELTA2(s, s_l) ((s_l) == 8 || (s_l) == 12 || (s_l) == 15)
337
#define IS_TIMEDELTA3(s, s_l) ((s_l) == 9 || (s_l) == 13 || (s_l) == 16)
338
339
#define IS_TIMEDELTA_MILLI(s, s_l) ((s_l) == 11 || (s_l) == 12 || (s_l) == 13)
340
#define IS_TIMEDELTA_MICRO(s, s_l) ((s_l) == 14 || (s_l) == 15 || (s_l) == 16)
341
342
#define CHECKRC(x) if ((x) < 0) goto error;
343
344
typedef struct {
345
int type;
346
Py_ssize_t length;
347
} NumpyColType;
348
349
typedef struct {
350
int results_type;
351
int parse_json;
352
PyObject *invalid_values;
353
} MySQLAccelOptions;
354
355
inline int IMAX(int a, int b) { return((a) > (b) ? a : b); }
356
inline int IMIN(int a, int b) { return((a) < (b) ? a : b); }
357
358
static PyObject *create_numpy_array(PyObject *py_memview, char *data_format, int data_type, PyObject *py_objs);
359
360
char *_PyUnicode_AsUTF8(PyObject *unicode) {
361
PyObject *bytes = PyUnicode_AsEncodedString(unicode, "utf-8", "strict");
362
if (!bytes) return NULL;
363
364
char *str = NULL;
365
Py_ssize_t str_l = 0;
366
if (PyBytes_AsStringAndSize(bytes, &str, &str_l) < 0) {
367
return NULL;
368
}
369
370
char *out = calloc(str_l + 1, 1);
371
memcpy(out, str, str_l);
372
return out;
373
}
374
375
// Function to convert a UCS-4 string to a UTF-8 string
376
// Returns the length of the resulting UTF-8 string, or -1 on error
377
int ucs4_to_utf8(const uint32_t *ucs4_str, size_t ucs4_len, char **utf8_str) {
378
if (!ucs4_str || !utf8_str) {
379
return -1; // Invalid input
380
}
381
382
// Allocate a buffer for the UTF-8 string (worst-case: 4 bytes per UCS-4 character)
383
size_t utf8_max_len = ucs4_len * 4 + 1; // +1 for null terminator
384
*utf8_str = malloc(utf8_max_len);
385
if (!*utf8_str) {
386
return -1; // Memory allocation failed
387
}
388
389
char *utf8_ptr = *utf8_str;
390
size_t utf8_len = 0;
391
392
for (size_t i = 0; i < ucs4_len; i++) {
393
uint32_t codepoint = ucs4_str[i];
394
395
if (codepoint <= 0x7F) {
396
// 1-byte UTF-8
397
if (utf8_len + 1 > utf8_max_len) goto error; // Buffer overflow
398
*utf8_ptr++ = (char)codepoint;
399
utf8_len += 1;
400
} else if (codepoint <= 0x7FF) {
401
// 2-byte UTF-8
402
if (utf8_len + 2 > utf8_max_len) goto error; // Buffer overflow
403
*utf8_ptr++ = (char)(0xC0 | (codepoint >> 6));
404
*utf8_ptr++ = (char)(0x80 | (codepoint & 0x3F));
405
utf8_len += 2;
406
} else if (codepoint <= 0xFFFF) {
407
// 3-byte UTF-8
408
if (utf8_len + 3 > utf8_max_len) goto error; // Buffer overflow
409
*utf8_ptr++ = (char)(0xE0 | (codepoint >> 12));
410
*utf8_ptr++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
411
*utf8_ptr++ = (char)(0x80 | (codepoint & 0x3F));
412
utf8_len += 3;
413
} else if (codepoint <= 0x10FFFF) {
414
// 4-byte UTF-8
415
if (utf8_len + 4 > utf8_max_len) goto error; // Buffer overflow
416
*utf8_ptr++ = (char)(0xF0 | (codepoint >> 18));
417
*utf8_ptr++ = (char)(0x80 | ((codepoint >> 12) & 0x3F));
418
*utf8_ptr++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
419
*utf8_ptr++ = (char)(0x80 | (codepoint & 0x3F));
420
utf8_len += 4;
421
} else {
422
// Invalid codepoint
423
goto error;
424
}
425
}
426
427
// Null-terminate the UTF-8 string
428
if (utf8_len + 1 > utf8_max_len) goto error; // Buffer overflow
429
*utf8_ptr = '\0';
430
431
return (int)utf8_len;
432
433
error:
434
free(*utf8_str);
435
*utf8_str = NULL;
436
return -1;
437
}
438
439
size_t length_without_trailing_nulls(const char *str, size_t len) {
440
if (!str || len == 0) {
441
return 0; // Handle null or empty input
442
}
443
444
// Start from the end of the string and move backward
445
while (len > 0 && str[len - 1] == '\0') {
446
len--;
447
}
448
449
return len;
450
}
451
452
//
453
// Cached int values for date/time components
454
//
455
static PyObject *PyInts[62] = {0};
456
457
//
458
// Cached string values
459
//
460
typedef struct {
461
PyObject *unbuffered_active;
462
PyObject *active_idx;
463
PyObject *_state;
464
PyObject *affected_rows;
465
PyObject *warning_count;
466
PyObject *connection;
467
PyObject *has_next;
468
PyObject *options;
469
PyObject *Decimal;
470
PyObject *date;
471
PyObject *timedelta;
472
PyObject *time;
473
PyObject *datetime;
474
PyObject *loads;
475
PyObject *field_count;
476
PyObject *converters;
477
PyObject *fields;
478
PyObject *flags;
479
PyObject *scale;
480
PyObject *type_code;
481
PyObject *name;
482
PyObject *table_name;
483
PyObject *_sock;
484
PyObject *settimeout;
485
PyObject *_rfile;
486
PyObject *read;
487
PyObject *x_errno;
488
PyObject *_result;
489
PyObject *_read_timeout;
490
PyObject *_next_seq_id;
491
PyObject *rows;
492
PyObject *namedtuple;
493
PyObject *Row;
494
PyObject *Series;
495
PyObject *array;
496
PyObject *vectorize;
497
PyObject *DataFrame;
498
PyObject *Table;
499
PyObject *from_pylist;
500
PyObject *int8;
501
PyObject *int16;
502
PyObject *int32;
503
PyObject *int64;
504
PyObject *float32;
505
PyObject *float64;
506
PyObject *unpack;
507
PyObject *decode;
508
PyObject *frombuffer;
509
} PyStrings;
510
511
static PyStrings PyStr = {0};
512
513
//
514
// Cached Python functions
515
//
516
typedef struct {
517
PyObject *json_loads;
518
PyObject *decimal_Decimal;
519
PyObject *datetime_date;
520
PyObject *datetime_time;
521
PyObject *datetime_timedelta;
522
PyObject *datetime_datetime;
523
PyObject *collections_namedtuple;
524
PyObject *numpy_array;
525
PyObject *numpy_frombuffer;
526
PyObject *numpy_vectorize;
527
PyObject *pandas_DataFrame;
528
PyObject *polars_DataFrame;
529
PyObject *pyarrow_Table;
530
PyObject *pyarrow_Table_from_pylist;
531
PyObject *struct_unpack;
532
PyObject *bson_decode;
533
} PyFunctions;
534
535
static PyFunctions PyFunc = {0};
536
537
//
538
// Cached Python objects
539
//
540
typedef struct {
541
PyObject *namedtuple_kwargs;
542
PyObject *create_numpy_array_args;
543
PyObject *create_numpy_array_kwargs;
544
PyObject *create_numpy_array_kwargs_vector[7];
545
PyObject *struct_unpack_args;
546
PyObject *bson_decode_args;
547
} PyObjects;
548
549
static PyObjects PyObj = {0};
550
551
//
552
// State
553
//
554
555
static PyTypeObject *StateType = NULL;
556
557
typedef struct {
558
PyObject_HEAD
559
PyObject *py_conn; // Database connection
560
PyObject *py_fields; // List of table fields
561
PyObject *py_rows; // Output object
562
PyObject *py_rfile; // Socket file I/O
563
PyObject *py_read; // File I/O read method
564
PyObject *py_sock; // Socket
565
PyObject *py_read_timeout; // Socket read timeout value
566
PyObject *py_settimeout; // Socket settimeout method
567
PyObject **py_converters; // List of converter functions
568
PyObject **py_names; // Column names
569
PyObject *py_names_list; // Python list of column names
570
PyObject *py_default_converters; // Dict of default converters
571
PyObject *py_namedtuple; // Generated namedtuple type
572
PyObject *py_namedtuple_args; // Pre-allocated tuple for namedtuple args
573
PyTypeObject *structsequence; // StructSequence type (like C namedtuple)
574
PyStructSequence_Desc structsequence_desc;
575
PyObject **py_encodings; // Encoding for each column as Python string
576
PyObject **py_invalid_values; // Values to use when invalid data exists in a cell
577
const char **encodings; // Encoding for each column
578
unsigned long long n_cols; // Total number of columns
579
unsigned long long n_rows; // Total number of rows read
580
unsigned long long n_rows_in_batch; // Number of rows in current batch (fetchmany size)
581
unsigned long *type_codes; // Type code for each column
582
unsigned long *flags; // Column flags
583
unsigned long *scales; // Column scales
584
unsigned long *offsets; // Column offsets in buffer
585
unsigned long long next_seq_id; // MySQL packet sequence number
586
MySQLAccelOptions options; // Packet reader options
587
int unbuffered; // Are we running in unbuffered mode?
588
int is_eof; // Have we hit the eof packet yet?
589
struct {
590
PyObject *_next_seq_id;
591
PyObject *rows;
592
} py_str;
593
char *encoding_errors;
594
} StateObject;
595
596
static int read_options(MySQLAccelOptions *options, PyObject *dict);
597
598
#define DESTROY(x) do { if (x) { free((void*)x); (x) = NULL; } } while (0)
599
600
int ensure_numpy() {
601
if (PyFunc.numpy_array && PyFunc.numpy_vectorize) goto exit;
602
603
// Import numpy if it exists
604
PyObject *numpy_mod = PyImport_ImportModule("numpy");
605
if (!numpy_mod) goto error;
606
607
PyFunc.numpy_array = PyObject_GetAttr(numpy_mod, PyStr.array);
608
if (!PyFunc.numpy_array) goto error;
609
610
PyFunc.numpy_frombuffer = PyObject_GetAttr(numpy_mod, PyStr.frombuffer);
611
if (!PyFunc.numpy_frombuffer) goto error;
612
613
PyFunc.numpy_vectorize = PyObject_GetAttr(numpy_mod, PyStr.vectorize);
614
if (!PyFunc.numpy_vectorize) goto error;
615
616
exit:
617
return 0;
618
619
error:
620
PyErr_Clear();
621
return -1;
622
}
623
624
625
int ensure_pandas() {
626
if (PyFunc.pandas_DataFrame) goto exit;
627
628
// Import pandas if it exists
629
PyObject *pandas_mod = PyImport_ImportModule("pandas");
630
if (!pandas_mod) goto error;
631
632
PyFunc.pandas_DataFrame = PyObject_GetAttr(pandas_mod, PyStr.DataFrame);
633
if (!PyFunc.pandas_DataFrame) goto error;
634
635
exit:
636
return 0;
637
638
error:
639
PyErr_Clear();
640
return -1;
641
}
642
643
644
int ensure_polars() {
645
if (PyFunc.polars_DataFrame) goto exit;
646
647
// Import polars if it exists
648
PyObject *polars_mod = PyImport_ImportModule("polars");
649
if (!polars_mod) goto error;
650
651
PyFunc.polars_DataFrame = PyObject_GetAttr(polars_mod, PyStr.DataFrame);
652
if (!PyFunc.polars_DataFrame) goto error;
653
654
exit:
655
return 0;
656
657
error:
658
PyErr_Clear();
659
return -1;
660
}
661
662
663
int ensure_pyarrow() {
664
if (PyFunc.pyarrow_Table_from_pylist) goto exit;
665
666
// Import pyarrow if it exists
667
PyObject *pyarrow_mod = PyImport_ImportModule("pyarrow");
668
if (!pyarrow_mod) goto error;
669
670
PyFunc.pyarrow_Table = PyObject_GetAttr(pyarrow_mod, PyStr.Table);
671
if (!PyFunc.pyarrow_Table) goto error;
672
673
PyFunc.pyarrow_Table_from_pylist = PyObject_GetAttr(PyFunc.pyarrow_Table, PyStr.from_pylist);
674
if (!PyFunc.pyarrow_Table_from_pylist) goto error;
675
676
exit:
677
return 0;
678
679
error:
680
PyErr_Clear();
681
return -1;
682
}
683
684
685
int ensure_bson() {
686
if (PyFunc.bson_decode) goto exit;
687
688
// Import bson if it exists
689
PyObject *bson_mod = PyImport_ImportModule("bson");
690
if (!bson_mod) goto error;
691
692
PyFunc.bson_decode = PyObject_GetAttr(bson_mod, PyStr.decode);
693
if (!PyFunc.bson_decode) goto error;
694
695
exit:
696
return 0;
697
698
error:
699
PyErr_Clear();
700
return -1;
701
}
702
703
704
static void State_clear_fields(StateObject *self) {
705
if (!self) return;
706
DESTROY(self->offsets);
707
DESTROY(self->scales);
708
DESTROY(self->flags);
709
DESTROY(self->type_codes);
710
DESTROY(self->encodings);
711
DESTROY(self->structsequence_desc.fields);
712
DESTROY(self->encoding_errors);
713
if (self->py_converters) {
714
for (unsigned long i = 0; i < self->n_cols; i++) {
715
Py_CLEAR(self->py_converters[i]);
716
}
717
DESTROY(self->py_converters);
718
}
719
if (self->py_names) {
720
for (unsigned long i = 0; i < self->n_cols; i++) {
721
Py_CLEAR(self->py_names[i]);
722
}
723
DESTROY(self->py_names);
724
}
725
if (self->py_encodings) {
726
for (unsigned long i = 0; i < self->n_cols; i++) {
727
Py_CLEAR(self->py_encodings[i]);
728
}
729
DESTROY(self->py_encodings);
730
}
731
if (self->py_invalid_values) {
732
for (unsigned long i = 0; i < self->n_cols; i++) {
733
Py_CLEAR(self->py_invalid_values[i]);
734
}
735
DESTROY(self->py_invalid_values);
736
}
737
Py_CLEAR(self->structsequence);
738
Py_CLEAR(self->py_namedtuple);
739
Py_CLEAR(self->py_namedtuple_args);
740
Py_CLEAR(self->py_names_list);
741
Py_CLEAR(self->py_default_converters);
742
Py_CLEAR(self->py_settimeout);
743
Py_CLEAR(self->py_read_timeout);
744
Py_CLEAR(self->py_sock);
745
Py_CLEAR(self->py_read);
746
Py_CLEAR(self->py_rfile);
747
Py_CLEAR(self->py_rows);
748
Py_CLEAR(self->py_fields);
749
Py_CLEAR(self->py_conn);
750
}
751
752
static void State_dealloc(StateObject *self) {
753
State_clear_fields(self);
754
PyObject_Del(self);
755
}
756
757
static int State_init(StateObject *self, PyObject *args, PyObject *kwds) {
758
int rc = 0;
759
PyObject *py_res = NULL;
760
PyObject *py_converters = NULL;
761
PyObject *py_options = NULL;
762
PyObject *py_args = NULL;
763
unsigned long long requested_n_rows = 0;
764
765
if (!PyArg_ParseTuple(args, "OK", &py_res, &requested_n_rows)) {
766
return -1;
767
}
768
769
py_options = PyObject_GetAttr(py_res, PyStr.options);
770
if (!py_options) {
771
Py_INCREF(Py_None);
772
py_options = Py_None;
773
}
774
775
if (PyDict_Check(py_options)) {
776
self->py_default_converters = PyDict_GetItemString(py_options, "default_converters");
777
if (self->py_default_converters && !PyDict_Check(self->py_default_converters)) {
778
self->py_default_converters = NULL;
779
}
780
Py_XINCREF(self->py_default_converters);
781
PyObject *py_unbuffered = PyDict_GetItemString(py_options, "unbuffered");
782
if (py_unbuffered && PyObject_IsTrue(py_unbuffered)) {
783
self->unbuffered = 1;
784
}
785
PyObject *py_encoding_errors = PyDict_GetItemString(py_options, "encoding_errors");
786
if (py_encoding_errors) {
787
self->encoding_errors = _PyUnicode_AsUTF8(py_encoding_errors);
788
if (!self->encoding_errors) goto error;
789
}
790
}
791
792
if (!self->encoding_errors) {
793
self->encoding_errors = calloc(7, 1);
794
if (!self->encoding_errors) goto error;
795
memcpy(self->encoding_errors, "strict", 6);
796
}
797
798
if (self->unbuffered) {
799
PyObject *unbuffered_active = PyObject_GetAttr(py_res, PyStr.unbuffered_active);
800
if (!unbuffered_active || !PyObject_IsTrue(unbuffered_active)) {
801
Py_XDECREF(unbuffered_active);
802
goto error;
803
}
804
Py_XDECREF(unbuffered_active);
805
}
806
807
// Retrieve type codes for each column.
808
PyObject *py_field_count = PyObject_GetAttr(py_res, PyStr.field_count);
809
if (!py_field_count) goto error;
810
self->n_cols = PyLong_AsUnsignedLong(py_field_count);
811
Py_XDECREF(py_field_count);
812
813
py_converters = PyObject_GetAttr(py_res, PyStr.converters);
814
if (!py_converters) goto error;
815
816
self->py_converters = calloc(self->n_cols, sizeof(PyObject*));
817
if (!self->py_converters) goto error;
818
819
self->type_codes = calloc(self->n_cols, sizeof(unsigned long));
820
if (!self->type_codes) goto error;
821
822
self->flags = calloc(self->n_cols, sizeof(unsigned long));
823
if (!self->flags) goto error;
824
825
self->scales = calloc(self->n_cols, sizeof(unsigned long));
826
if (!self->scales) goto error;
827
828
self->encodings = calloc(self->n_cols, sizeof(char*));
829
if (!self->encodings) goto error;
830
831
self->py_encodings = calloc(self->n_cols, sizeof(char*));
832
if (!self->py_encodings) goto error;
833
834
self->py_invalid_values = calloc(self->n_cols, sizeof(char*));
835
if (!self->py_invalid_values) goto error;
836
837
self->py_names = calloc(self->n_cols, sizeof(PyObject*));
838
if (!self->py_names) goto error;
839
840
self->py_fields = PyObject_GetAttr(py_res, PyStr.fields);
841
if (!self->py_fields) goto error;
842
843
self->py_names_list = PyList_New(self->n_cols);
844
if (!self->py_names_list) goto error;
845
846
for (unsigned long i = 0; i < self->n_cols; i++) {
847
// Get type codes.
848
PyObject *py_field = PyList_GetItem(self->py_fields, i);
849
if (!py_field) goto error;
850
851
PyObject *py_flags = PyObject_GetAttr(py_field, PyStr.flags);
852
if (!py_flags) goto error;
853
self->flags[i] = PyLong_AsUnsignedLong(py_flags);
854
Py_XDECREF(py_flags);
855
856
PyObject *py_scale = PyObject_GetAttr(py_field, PyStr.scale);
857
if (!py_scale) goto error;
858
self->scales[i] = PyLong_AsUnsignedLong(py_scale);
859
Py_XDECREF(py_scale);
860
861
PyObject *py_field_type = PyObject_GetAttr(py_field, PyStr.type_code);
862
if (!py_field_type) goto error;
863
self->type_codes[i] = PyLong_AsUnsignedLong(py_field_type);
864
PyObject *py_default_converter = (self->py_default_converters) ?
865
PyDict_GetItem(self->py_default_converters, py_field_type) : NULL;
866
PyObject *py_invalid_value = (self->options.invalid_values) ?
867
PyDict_GetItem(self->options.invalid_values, py_field_type) : NULL;
868
Py_XDECREF(py_field_type);
869
870
// Get field name.
871
PyObject *py_field_name = PyObject_GetAttr(py_field, PyStr.name);
872
if (!py_field_name) goto error;
873
874
// Make sure field name is not a duplicate.
875
int dup_found = 0;
876
for (unsigned long j = 0; j < i; j++) {
877
if (PyUnicode_Compare(self->py_names[j], py_field_name) == 0) {
878
dup_found = 1;
879
break;
880
}
881
}
882
if (dup_found) {
883
PyObject *py_table_name = PyObject_GetAttr(py_field, PyStr.table_name);
884
self->py_names[i] = PyUnicode_FromFormat("%U.%U", py_table_name, py_field_name);
885
Py_XDECREF(py_table_name);
886
if (!self->py_names[i]) goto error;
887
} else {
888
self->py_names[i] = py_field_name;
889
}
890
891
Py_INCREF(self->py_names[i]); // Extra ref since SetItem steals one
892
rc = PyList_SetItem(self->py_names_list, i, self->py_names[i]);
893
if (rc) goto error;
894
895
// Get field encodings (NULL means binary) and default converters.
896
PyObject *py_tmp = PyList_GetItem(py_converters, i);
897
if (!py_tmp) goto error;
898
PyObject *py_encoding = PyTuple_GetItem(py_tmp, 0);
899
if (!py_encoding) goto error;
900
PyObject *py_converter = PyTuple_GetItem(py_tmp, 1);
901
if (!py_converter) goto error;
902
903
self->py_encodings[i] = (py_encoding == Py_None) ? NULL : py_encoding;
904
Py_XINCREF(self->py_encodings[i]);
905
906
self->encodings[i] = (!py_encoding || py_encoding == Py_None) ?
907
NULL : _PyUnicode_AsUTF8(py_encoding);
908
909
self->py_invalid_values[i] = (!py_invalid_value || py_invalid_value == Py_None) ?
910
NULL : py_converter;
911
Py_XINCREF(self->py_invalid_values[i]);
912
913
self->py_converters[i] = ((!py_converter || py_converter == py_default_converter)
914
// TODO: Need C accelerated converters for extended types
915
// && self->type_codes[i] < 256
916
) ?
917
NULL : py_converter;
918
Py_XINCREF(self->py_converters[i]);
919
}
920
921
// Loop over all data packets.
922
self->py_conn = PyObject_GetAttr(py_res, PyStr.connection);
923
if (!self->py_conn) goto error;
924
925
// Cache socket timeout and read methods.
926
self->py_sock = PyObject_GetAttr(self->py_conn, PyStr._sock);
927
if (!self->py_sock) goto error;
928
self->py_settimeout = PyObject_GetAttr(self->py_sock, PyStr.settimeout);
929
if (!self->py_settimeout) goto error;
930
self->py_read_timeout = PyObject_GetAttr(self->py_conn, PyStr._read_timeout);
931
if (!self->py_read_timeout) goto error;
932
933
self->py_rfile = PyObject_GetAttr(self->py_conn, PyStr._rfile);
934
if (!self->py_rfile) goto error;
935
self->py_read = PyObject_GetAttr(self->py_rfile, PyStr.read);
936
if (!self->py_read) goto error;
937
938
PyObject *py_next_seq_id = PyObject_GetAttr(self->py_conn, PyStr._next_seq_id);
939
if (!py_next_seq_id) goto error;
940
self->next_seq_id = PyLong_AsUnsignedLongLong(py_next_seq_id);
941
Py_XDECREF(py_next_seq_id);
942
943
if (py_options && PyDict_Check(py_options)) {
944
rc = read_options(&self->options, py_options);
945
if (rc) goto error;
946
}
947
948
switch (self->options.results_type) {
949
case ACCEL_OUT_NAMEDTUPLES:
950
case ACCEL_OUT_STRUCTSEQUENCES:
951
if (self->options.results_type == ACCEL_OUT_NAMEDTUPLES)
952
{
953
py_args = PyTuple_New(2);
954
if (!py_args) goto error;
955
956
rc = PyTuple_SetItem(py_args, 0, PyStr.Row);
957
if (rc) goto error;
958
Py_INCREF(PyStr.Row);
959
960
rc = PyTuple_SetItem(py_args, 1, self->py_names_list);
961
if (rc) goto error;
962
Py_INCREF(self->py_names_list);
963
964
self->py_namedtuple = PyObject_Call(
965
PyFunc.collections_namedtuple,
966
py_args, PyObj.namedtuple_kwargs);
967
if (!self->py_namedtuple) goto error;
968
969
self->py_namedtuple_args = PyTuple_New(self->n_cols);
970
if (!self->py_namedtuple_args) goto error;
971
}
972
else
973
{
974
self->structsequence_desc.name = "singlestoredb.Row";
975
self->structsequence_desc.doc = "Row of data values";
976
self->structsequence_desc.n_in_sequence = (int)self->n_cols;
977
self->structsequence_desc.fields = calloc(self->n_cols + 1, sizeof(PyStructSequence_Field));
978
if (!self->structsequence_desc.fields) goto error;
979
for (unsigned long i = 0; i < self->n_cols; i++) {
980
self->structsequence_desc.fields[i].name = _PyUnicode_AsUTF8(self->py_names[i]);
981
self->structsequence_desc.fields[i].doc = NULL;
982
}
983
self->structsequence = PyStructSequence_NewType(&self->structsequence_desc);
984
if (!self->structsequence) goto error;
985
}
986
987
// Fall through
988
989
default:
990
// For fetchone, reuse the same list every time.
991
//if (requested_n_rows == 1) {
992
// self->py_rows = PyList_New(1);
993
// PyList_SetItem(self->py_rows, 0, Py_None);
994
//} else {
995
self->py_rows = PyList_New(0);
996
//}
997
if (!self->py_rows) goto error;
998
999
PyObject_SetAttr(py_res, PyStr.rows, self->py_rows);
1000
}
1001
1002
exit:
1003
Py_XDECREF(py_args);
1004
Py_XDECREF(py_converters);
1005
Py_XDECREF(py_options);
1006
if (PyErr_Occurred()) {
1007
PyErr_Print();
1008
}
1009
return rc;
1010
1011
error:
1012
State_clear_fields(self);
1013
rc = -1;
1014
goto exit;
1015
}
1016
1017
static int State_reset_batch(
1018
StateObject *self,
1019
PyObject *py_res,
1020
unsigned long long requested_n_rows
1021
) {
1022
int rc = 0;
1023
PyObject *py_tmp = NULL;
1024
1025
self->n_rows_in_batch = 0;
1026
1027
//if (requested_n_rows != 1) {
1028
py_tmp = self->py_rows;
1029
self->py_rows = PyList_New(0);
1030
Py_XDECREF(py_tmp);
1031
if (!self->py_rows) { rc = -1; goto error; }
1032
rc = PyObject_SetAttr(py_res, PyStr.rows, self->py_rows);
1033
//}
1034
1035
exit:
1036
return rc;
1037
1038
error:
1039
goto exit;
1040
}
1041
1042
static PyType_Slot StateType_slots[] = {
1043
{Py_tp_init, (initproc)State_init},
1044
{Py_tp_dealloc, (destructor)State_dealloc},
1045
{Py_tp_doc, "PyMySQL accelerator"},
1046
{0, NULL},
1047
};
1048
1049
static PyType_Spec StateType_spec = {
1050
.name = "_singlestoredb_accel.State",
1051
.basicsize = sizeof(StateObject),
1052
.itemsize = 0,
1053
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1054
.slots = StateType_slots,
1055
};
1056
1057
//
1058
// End State
1059
//
1060
1061
static int read_options(MySQLAccelOptions *options, PyObject *dict) {
1062
if (!options || !dict) return 0;
1063
1064
PyObject *key = NULL;
1065
PyObject *value = NULL;
1066
Py_ssize_t pos = 0;
1067
int rc = 0;
1068
1069
while (PyDict_Next(dict, &pos, &key, &value)) {
1070
if (PyUnicode_CompareWithASCIIString(key, "results_type") == 0) {
1071
if (PyUnicode_CompareWithASCIIString(value, "dict") == 0 ||
1072
PyUnicode_CompareWithASCIIString(value, "dicts") == 0 ) {
1073
options->results_type = ACCEL_OUT_DICTS;
1074
}
1075
else if (PyUnicode_CompareWithASCIIString(value, "namedtuple") == 0 ||
1076
PyUnicode_CompareWithASCIIString(value, "namedtuples") == 0) {
1077
options->results_type = ACCEL_OUT_NAMEDTUPLES;
1078
}
1079
else if (PyUnicode_CompareWithASCIIString(value, "structsequence") == 0 ||
1080
PyUnicode_CompareWithASCIIString(value, "structsequences") == 0) {
1081
options->results_type = ACCEL_OUT_STRUCTSEQUENCES;
1082
}
1083
else if (PyUnicode_CompareWithASCIIString(value, "numpy") == 0) {
1084
options->results_type = ACCEL_OUT_NUMPY;
1085
rc = ensure_numpy();
1086
}
1087
else if (PyUnicode_CompareWithASCIIString(value, "pandas") == 0) {
1088
options->results_type = ACCEL_OUT_PANDAS;
1089
rc = ensure_pandas();
1090
}
1091
else if (PyUnicode_CompareWithASCIIString(value, "polars") == 0) {
1092
options->results_type = ACCEL_OUT_POLARS;
1093
rc = ensure_polars();
1094
}
1095
else if (PyUnicode_CompareWithASCIIString(value, "arrow") == 0 ||
1096
PyUnicode_CompareWithASCIIString(value, "pyarrow") == 0) {
1097
options->results_type = ACCEL_OUT_ARROW;
1098
rc = ensure_pyarrow();
1099
}
1100
else {
1101
options->results_type = ACCEL_OUT_TUPLES;
1102
}
1103
} else if (PyUnicode_CompareWithASCIIString(key, "parse_json") == 0) {
1104
options->parse_json = PyObject_IsTrue(value);
1105
} else if (PyUnicode_CompareWithASCIIString(key, "invalid_values") == 0) {
1106
if (PyDict_Check(value)) {
1107
options->invalid_values = value;
1108
}
1109
}
1110
}
1111
1112
return rc;
1113
}
1114
1115
static void raise_exception(
1116
PyObject *self,
1117
char *err_type,
1118
unsigned long long err_code,
1119
char *err_str
1120
) {
1121
PyObject *py_exc = NULL;
1122
PyObject *py_val = NULL;
1123
1124
py_exc = PyObject_GetAttrString(self, err_type);
1125
if (!py_exc) goto error;
1126
1127
py_val = Py_BuildValue("(Ks)", err_code, err_str);
1128
if (!py_val) goto error;
1129
1130
PyErr_SetObject(py_exc, py_val);
1131
1132
exit:
1133
if (py_exc) { Py_DECREF(py_exc); }
1134
if (py_val) { Py_DECREF(py_val); }
1135
return;
1136
1137
error:
1138
goto exit;
1139
}
1140
1141
static int is_error_packet(char *buff_bytes) {
1142
return buff_bytes && *(uint8_t*)buff_bytes == 0xFF;
1143
}
1144
1145
static void force_close(PyObject *py_conn) {
1146
PyObject *py_sock = NULL;
1147
1148
py_sock = PyObject_GetAttr(py_conn, PyStr._sock);
1149
if (!py_sock) goto error;
1150
1151
Py_XDECREF(PyObject_CallMethod(py_sock, "close", NULL));
1152
PyErr_Clear();
1153
1154
PyObject_SetAttr(py_conn, PyStr._sock, Py_None);
1155
PyObject_SetAttr(py_conn, PyStr._rfile, Py_None);
1156
1157
exit:
1158
Py_XDECREF(py_sock);
1159
return;
1160
1161
error:
1162
goto exit;
1163
}
1164
1165
static PyObject *read_bytes(StateObject *py_state, unsigned long long num_bytes) {
1166
PyObject *py_num_bytes = NULL;
1167
PyObject *py_data = NULL;
1168
PyObject *py_exc = NULL;
1169
1170
if (py_state->py_read_timeout && py_state->py_read_timeout != Py_None) {
1171
Py_XDECREF(PyObject_CallFunctionObjArgs(py_state->py_settimeout,
1172
py_state->py_read_timeout, NULL));
1173
if (PyErr_Occurred()) goto error;
1174
}
1175
1176
py_num_bytes = PyLong_FromUnsignedLongLong(num_bytes);
1177
if (!py_num_bytes) goto error;
1178
1179
while (1) {
1180
py_data = PyObject_CallFunctionObjArgs(py_state->py_read, py_num_bytes, NULL);
1181
1182
if ((py_exc = PyErr_Occurred())) {
1183
if (PyErr_ExceptionMatches(PyExc_IOError) || PyErr_ExceptionMatches(PyExc_OSError)) {
1184
PyObject *py_errno = PyObject_GetAttr(py_exc, PyStr.x_errno);
1185
if (!py_errno) goto error;
1186
1187
unsigned long long err = PyLong_AsUnsignedLongLong(py_errno);
1188
Py_DECREF(py_errno);
1189
1190
if (err == 4 /* errno.EINTER */) {
1191
continue;
1192
}
1193
1194
force_close(py_state->py_conn);
1195
raise_exception(py_state->py_conn, "OperationalError", 0,
1196
"Lost connection to SingleStoreDB server during query");
1197
goto error;
1198
}
1199
else if (PyErr_ExceptionMatches(PyExc_BaseException)) {
1200
// Don't convert unknown exception to MySQLError.
1201
force_close(py_state->py_conn);
1202
goto error;
1203
}
1204
}
1205
1206
if (py_data) {
1207
break;
1208
}
1209
}
1210
1211
if (PyBytes_Size(py_data) < (long int)num_bytes) {
1212
force_close(py_state->py_conn);
1213
raise_exception(py_state->py_conn, "OperationalError", 0,
1214
"Lost connection to SingleStoreDB server during query");
1215
goto error;
1216
}
1217
1218
exit:
1219
Py_XDECREF(py_num_bytes);
1220
return py_data;
1221
1222
error:
1223
Py_CLEAR(py_data);
1224
goto exit;
1225
}
1226
1227
static PyObject *read_packet(StateObject *py_state) {
1228
PyObject *py_buff = NULL;
1229
PyObject *py_new_buff = NULL;
1230
PyObject *py_packet_header = NULL;
1231
PyObject *py_bytes_to_read = NULL;
1232
PyObject *py_recv_data = NULL;
1233
unsigned long long bytes_to_read = 0;
1234
char *buff = NULL;
1235
uint64_t btrl = 0;
1236
uint8_t btrh = 0;
1237
uint8_t packet_number = 0;
1238
1239
py_buff = PyByteArray_FromStringAndSize(NULL, 0);
1240
if (!py_buff) goto error;
1241
1242
while (1) {
1243
py_packet_header = read_bytes(py_state, 4);
1244
if (!py_packet_header) goto error;
1245
1246
buff = PyBytes_AsString(py_packet_header);
1247
1248
btrl = *(uint16_t*)buff;
1249
btrh = *(uint8_t*)(buff+2);
1250
packet_number = *(uint8_t*)(buff+3);
1251
bytes_to_read = btrl + (btrh << 16);
1252
1253
Py_CLEAR(py_packet_header);
1254
1255
if (packet_number != py_state->next_seq_id) {
1256
force_close(py_state->py_conn);
1257
if (packet_number == 0) {
1258
raise_exception(py_state->py_conn, "OperationalError", 0,
1259
"Lost connection to SingleStoreDB server during query");
1260
1261
goto error;
1262
}
1263
raise_exception(py_state->py_conn, "InternalError", 0,
1264
"Packet sequence number wrong");
1265
goto error;
1266
}
1267
1268
py_state->next_seq_id = (py_state->next_seq_id + 1) % 256;
1269
1270
py_recv_data = read_bytes(py_state, bytes_to_read);
1271
if (!py_recv_data) goto error;
1272
1273
py_new_buff = PyByteArray_Concat(py_buff, py_recv_data);
1274
Py_CLEAR(py_recv_data);
1275
Py_CLEAR(py_buff);
1276
if (!py_new_buff) goto error;
1277
1278
py_buff = py_new_buff;
1279
py_new_buff = NULL;
1280
1281
if (bytes_to_read == 0xFFFFFF) {
1282
continue;
1283
}
1284
1285
if (bytes_to_read < MYSQL_MAX_PACKET_LEN) {
1286
break;
1287
}
1288
}
1289
1290
if (is_error_packet(PyByteArray_AsString(py_buff))) {
1291
PyObject *py_result = PyObject_GetAttr(py_state->py_conn, PyStr._result);
1292
if (py_result && py_result != Py_None) {
1293
PyObject *py_unbuffered_active = PyObject_GetAttr(py_result, PyStr.unbuffered_active);
1294
if (py_unbuffered_active == Py_True) {
1295
PyObject_SetAttr(py_result, PyStr.unbuffered_active, Py_False);
1296
}
1297
Py_XDECREF(py_unbuffered_active);
1298
}
1299
Py_XDECREF(py_result);
1300
Py_XDECREF(PyObject_CallMethod(py_state->py_conn, "_raise_mysql_exception",
1301
"O", py_buff, NULL));
1302
goto error;
1303
}
1304
1305
exit:
1306
Py_XDECREF(py_new_buff);
1307
Py_XDECREF(py_bytes_to_read);
1308
Py_XDECREF(py_recv_data);
1309
Py_XDECREF(py_packet_header);
1310
return py_buff;
1311
1312
error:
1313
Py_CLEAR(py_buff);
1314
goto exit;
1315
}
1316
1317
static int is_eof_packet(char *data, unsigned long long data_l) {
1318
return data && (uint8_t)*(uint8_t*)data == 0xFE && data_l < 9;
1319
}
1320
1321
static int check_packet_is_eof(
1322
char **data,
1323
unsigned long long *data_l,
1324
unsigned long long *warning_count,
1325
int *has_next
1326
) {
1327
uint16_t server_status = 0;
1328
if (!data || !data_l) {
1329
if (has_next) *has_next = 0;
1330
if (warning_count) *warning_count = 0;
1331
return 0;
1332
}
1333
if (!is_eof_packet(*data, *data_l)) {
1334
return 0;
1335
}
1336
*data += 1; *data_l -= 1;
1337
if (warning_count) *warning_count = **(uint16_t**)data;
1338
*data += 2; *data_l -= 2;
1339
server_status = **(uint16_t**)data;
1340
*data += 2; *data_l -= 2;
1341
if (has_next) *has_next = server_status & MYSQL_SERVER_MORE_RESULTS_EXISTS;
1342
return 1;
1343
}
1344
1345
static unsigned long long read_length_encoded_integer(
1346
char **data,
1347
unsigned long long *data_l,
1348
int *is_null
1349
) {
1350
if (is_null) *is_null = 0;
1351
1352
if (!data || !data_l || *data_l == 0) {
1353
if (is_null) *is_null = 1;
1354
return 0;
1355
}
1356
1357
uint8_t c = **(uint8_t**)data;
1358
*data += 1; *data_l -= 1;
1359
1360
if (c == MYSQL_COLUMN_NULL) {
1361
if (is_null) *is_null = 1;
1362
return 0;
1363
}
1364
1365
if (c < MYSQL_COLUMN_UNSIGNED_CHAR) {
1366
return c;
1367
}
1368
1369
if (c == MYSQL_COLUMN_UNSIGNED_SHORT) {
1370
if (*data_l < 2) {
1371
if (is_null) *is_null = 1;
1372
return 0;
1373
}
1374
uint16_t out = **(uint16_t**)data;
1375
*data += 2; *data_l -= 2;
1376
return out;
1377
}
1378
1379
if (c == MYSQL_COLUMN_UNSIGNED_INT24) {
1380
if (*data_l < 3) {
1381
if (is_null) *is_null = 1;
1382
return 0;
1383
}
1384
uint16_t low = **(uint16_t**)data;
1385
*data += 2; *data_l -= 2;
1386
uint8_t high = **(uint8_t**)data;
1387
*data += 1; *data_l -= 1;
1388
return low + (high << 16);
1389
}
1390
1391
if (c == MYSQL_COLUMN_UNSIGNED_INT64) {
1392
if (*data_l < 8) {
1393
if (is_null) *is_null = 1;
1394
return 0;
1395
}
1396
uint64_t out = **(uint64_t**)data;
1397
*data += 8; *data_l -= 8;
1398
return out;
1399
}
1400
1401
if (is_null) *is_null = 1;
1402
return 0;
1403
}
1404
1405
static void read_length_coded_string(
1406
char **data,
1407
unsigned long long *data_l,
1408
char **out,
1409
unsigned long long *out_l,
1410
int *is_null
1411
) {
1412
if (is_null) *is_null = 0;
1413
1414
if (!data || !data_l || !out || !out_l) {
1415
if (is_null) *is_null = 1;
1416
return;
1417
}
1418
1419
unsigned long long length = read_length_encoded_integer(data, data_l, is_null);
1420
1421
if (is_null && *is_null) {
1422
return;
1423
}
1424
1425
length = (length > *data_l) ? *data_l : length;
1426
1427
*out = *data;
1428
*out_l = length;
1429
1430
*data += length;
1431
*data_l -= length;
1432
1433
return;
1434
}
1435
1436
#ifdef Py_LIMITED_API
1437
1438
static PyObject *PyDate_FromDate(
1439
StateObject *py_state,
1440
int year,
1441
int month,
1442
int day
1443
) {
1444
PyObject *out = NULL;
1445
PyObject *py_year = NULL;
1446
int free_year = 0;
1447
1448
if (year >= 0 && year <= 60) {
1449
py_year = PyInts[year];
1450
} else {
1451
free_year = 1;
1452
py_year = PyLong_FromLong(year);
1453
}
1454
1455
out = PyObject_CallFunctionObjArgs(
1456
PyFunc.datetime_date, py_year, PyInts[month], PyInts[day], NULL
1457
);
1458
1459
if (free_year) Py_XDECREF(py_year);
1460
1461
return out;
1462
}
1463
1464
static PyObject *PyDelta_FromDSU(
1465
StateObject *py_state,
1466
int days,
1467
int seconds,
1468
int microseconds
1469
) {
1470
PyObject *out = NULL;
1471
PyObject *py_days = NULL;
1472
PyObject *py_seconds = NULL;
1473
PyObject *py_microseconds = NULL;
1474
int free_days = 0;
1475
int free_seconds = 0;
1476
int free_microseconds = 0;
1477
1478
if (days >= 0 && days <= 60) {
1479
py_days = PyInts[days];
1480
} else {
1481
free_days = 1;
1482
py_days = PyLong_FromLong(days);
1483
}
1484
1485
if (seconds >= 0 && seconds <= 60) {
1486
py_seconds = PyInts[seconds];
1487
} else {
1488
free_seconds = 1;
1489
py_seconds = PyLong_FromLong(seconds);
1490
}
1491
1492
if (microseconds >= 0 && microseconds <= 60) {
1493
py_microseconds = PyInts[microseconds];
1494
} else {
1495
free_microseconds = 1;
1496
py_microseconds = PyLong_FromLong(microseconds);
1497
}
1498
1499
out = PyObject_CallFunctionObjArgs(
1500
PyFunc.datetime_timedelta, py_days, py_seconds, py_microseconds, NULL
1501
);
1502
1503
if (free_days) Py_XDECREF(py_days);
1504
if (free_seconds) Py_XDECREF(py_seconds);
1505
if (free_microseconds) Py_XDECREF(py_microseconds);
1506
1507
return out;
1508
}
1509
1510
static PyObject *PyDateTime_FromDateAndTime(
1511
StateObject *py_state,
1512
int year,
1513
int month,
1514
int day,
1515
int hour,
1516
int minute,
1517
int second,
1518
int microsecond
1519
) {
1520
PyObject *out = NULL;
1521
PyObject *py_year = NULL;
1522
PyObject *py_microsecond = NULL;
1523
int free_year = 0;
1524
int free_microsecond = 0;
1525
1526
if (year >= 0 && year <= 60) {
1527
py_year = PyInts[year];
1528
} else {
1529
free_year = 1;
1530
py_year = PyLong_FromLong(year);
1531
}
1532
1533
if (microsecond >= 0 && microsecond <= 60) {
1534
py_microsecond = PyInts[microsecond];
1535
} else {
1536
free_microsecond = 1;
1537
py_microsecond = PyLong_FromLong(microsecond);
1538
}
1539
1540
out = PyObject_CallFunctionObjArgs(
1541
PyFunc.datetime_datetime, py_year, PyInts[month], PyInts[day],
1542
PyInts[hour], PyInts[minute], PyInts[second], py_microsecond, NULL
1543
);
1544
1545
if (free_microsecond) Py_XDECREF(py_microsecond);
1546
if (free_year) Py_XDECREF(py_year);
1547
1548
return out;
1549
}
1550
1551
#endif
1552
1553
static PyObject *read_row_from_packet(
1554
StateObject *py_state,
1555
char *data,
1556
unsigned long long data_l
1557
) {
1558
char *out = NULL;
1559
char *orig_out = NULL;
1560
unsigned long long out_l = 0;
1561
unsigned long long orig_out_l = 0;
1562
int is_null = 0;
1563
PyObject *py_result = NULL;
1564
PyObject *py_item = NULL;
1565
PyObject *py_str = NULL;
1566
PyObject *py_memview = NULL;
1567
char end = '\0';
1568
char *cast_type_codes[] = {"", "f", "d", "b", "h", "i", "q"};
1569
int item_type_lengths[] = {0, 4, 8, 1, 2, 4, 8};
1570
1571
int sign = 1;
1572
int year = 0;
1573
int month = 0;
1574
int day = 0;
1575
int hour = 0;
1576
int minute = 0;
1577
int second = 0;
1578
int microsecond = 0;
1579
1580
switch (py_state->options.results_type) {
1581
case ACCEL_OUT_DICTS:
1582
case ACCEL_OUT_ARROW:
1583
py_result = PyDict_New();
1584
break;
1585
case ACCEL_OUT_STRUCTSEQUENCES: {
1586
if (!py_state->structsequence) goto error;
1587
py_result = PyStructSequence_New(py_state->structsequence);
1588
break;
1589
}
1590
case ACCEL_OUT_NAMEDTUPLES:
1591
if (!py_state->py_namedtuple) goto error;
1592
if (!py_state->py_namedtuple_args) goto error;
1593
py_result = py_state->py_namedtuple_args;
1594
break;
1595
default:
1596
py_result = PyTuple_New(py_state->n_cols);
1597
}
1598
1599
for (unsigned long i = 0; i < py_state->n_cols; i++) {
1600
1601
read_length_coded_string(&data, &data_l, &out, &out_l, &is_null);
1602
end = out[out_l];
1603
1604
orig_out = out;
1605
orig_out_l = out_l;
1606
1607
py_item = Py_None;
1608
1609
// Don't convert if it's a NULL.
1610
if (!is_null) {
1611
1612
// If a converter was passed in, use it.
1613
if (py_state->py_converters[i]) {
1614
py_str = NULL;
1615
if (py_state->encodings[i] == NULL) {
1616
py_str = PyBytes_FromStringAndSize(out, out_l);
1617
if (!py_str) goto error;
1618
} else {
1619
py_str = PyUnicode_Decode(out, out_l, py_state->encodings[i], py_state->encoding_errors);
1620
if (PyErr_Occurred()) {
1621
PyErr_Clear();
1622
PyErr_Format(
1623
PyExc_UnicodeDecodeError,
1624
"failed to decode string value in column '%S' using encoding '%s'; "
1625
"use the 'encoding_errors' option on the connection to specify how to handle this error",
1626
py_state->py_names[i], py_state->encodings[i]
1627
);
1628
}
1629
if (!py_str) goto error;
1630
}
1631
if (py_state->py_converters[i] == Py_None) {
1632
py_item = py_str;
1633
} else {
1634
py_item = PyObject_CallFunctionObjArgs(py_state->py_converters[i], py_str, NULL);
1635
Py_CLEAR(py_str);
1636
}
1637
if (!py_item) goto error;
1638
}
1639
1640
// If no converter was passed in, do the default processing.
1641
else {
1642
switch (py_state->type_codes[i]) {
1643
case MYSQL_TYPE_NEWDECIMAL:
1644
case MYSQL_TYPE_DECIMAL:
1645
py_str = PyUnicode_Decode(out, out_l, py_state->encodings[i], py_state->encoding_errors);
1646
if (!py_str) goto error;
1647
1648
py_item = PyObject_CallFunctionObjArgs(PyFunc.decimal_Decimal, py_str, NULL);
1649
Py_CLEAR(py_str);
1650
if (!py_item) goto error;
1651
break;
1652
1653
case MYSQL_TYPE_TINY:
1654
case MYSQL_TYPE_SHORT:
1655
case MYSQL_TYPE_LONG:
1656
case MYSQL_TYPE_LONGLONG:
1657
case MYSQL_TYPE_INT24:
1658
if (data_l) out[out_l] = '\0';
1659
if (py_state->flags[i] & MYSQL_FLAG_UNSIGNED) {
1660
py_item = PyLong_FromUnsignedLongLong(strtoull(out, NULL, 10));
1661
} else {
1662
py_item = PyLong_FromLongLong(strtoll(out, NULL, 10));
1663
}
1664
if (data_l) out[out_l] = end;
1665
if (!py_item) goto error;
1666
break;
1667
1668
case MYSQL_TYPE_FLOAT:
1669
case MYSQL_TYPE_DOUBLE:
1670
if (data_l) out[out_l] = '\0';
1671
py_item = PyFloat_FromDouble(strtod(out, NULL));
1672
if (data_l) out[out_l] = end;
1673
if (!py_item) goto error;
1674
break;
1675
1676
case MYSQL_TYPE_NULL:
1677
py_item = Py_None;
1678
break;
1679
1680
case MYSQL_TYPE_DATETIME:
1681
case MYSQL_TYPE_TIMESTAMP:
1682
if (CHECK_ANY_ZERO_DATETIME_STR(out, out_l)) {
1683
py_item = Py_None;
1684
Py_INCREF(Py_None);
1685
break;
1686
}
1687
else if (!CHECK_ANY_DATETIME_STR(out, out_l)) {
1688
if (py_state->py_invalid_values[i]) {
1689
py_item = py_state->py_invalid_values[i];
1690
Py_INCREF(py_item);
1691
} else {
1692
py_item = PyUnicode_Decode(orig_out, orig_out_l, "ascii", py_state->encoding_errors);
1693
if (!py_item) goto error;
1694
}
1695
break;
1696
}
1697
year = CHR2INT4(out); out += 5;
1698
month = CHR2INT2(out); out += 3;
1699
day = CHR2INT2(out); out += 3;
1700
hour = CHR2INT2(out); out += 3;
1701
minute = CHR2INT2(out); out += 3;
1702
second = CHR2INT2(out); out += 3;
1703
microsecond = (IS_DATETIME_MICRO(out, out_l)) ? CHR2INT6(out) :
1704
(IS_DATETIME_MILLI(out, out_l)) ? CHR2INT3(out) * 1e3 : 0;
1705
py_item = PyDateTime_FromDateAndTime(
1706
#ifdef Py_LIMITED_API
1707
py_state,
1708
#endif
1709
year, month, day, hour, minute, second, microsecond);
1710
if (!py_item) {
1711
PyErr_Clear();
1712
py_item = PyUnicode_Decode(orig_out, orig_out_l, "ascii", py_state->encoding_errors);
1713
}
1714
if (!py_item) goto error;
1715
break;
1716
1717
case MYSQL_TYPE_NEWDATE:
1718
case MYSQL_TYPE_DATE:
1719
if (CHECK_ZERO_DATE_STR(out, out_l)) {
1720
py_item = Py_None;
1721
Py_INCREF(Py_None);
1722
break;
1723
}
1724
else if (!CHECK_DATE_STR(out, out_l)) {
1725
if (py_state->py_invalid_values[i]) {
1726
py_item = py_state->py_invalid_values[i];
1727
Py_INCREF(py_item);
1728
} else {
1729
py_item = PyUnicode_Decode(orig_out, orig_out_l, "ascii", py_state->encoding_errors);
1730
if (!py_item) goto error;
1731
}
1732
break;
1733
}
1734
year = CHR2INT4(out); out += 5;
1735
month = CHR2INT2(out); out += 3;
1736
day = CHR2INT2(out); out += 3;
1737
py_item = PyDate_FromDate(
1738
#ifdef Py_LIMITED_API
1739
py_state,
1740
#endif
1741
year, month, day);
1742
if (!py_item) {
1743
PyErr_Clear();
1744
py_item = PyUnicode_Decode(orig_out, orig_out_l, "ascii", py_state->encoding_errors);
1745
}
1746
if (!py_item) goto error;
1747
break;
1748
1749
case MYSQL_TYPE_TIME:
1750
sign = CHECK_ANY_TIMEDELTA_STR(out, out_l);
1751
if (!sign) {
1752
if (py_state->py_invalid_values[i]) {
1753
py_item = py_state->py_invalid_values[i];
1754
Py_INCREF(py_item);
1755
} else {
1756
py_item = PyUnicode_Decode(orig_out, orig_out_l, "ascii", py_state->encoding_errors);
1757
if (!py_item) goto error;
1758
}
1759
break;
1760
} else if (sign < 0) {
1761
out += 1; out_l -= 1;
1762
}
1763
if (IS_TIMEDELTA1(out, out_l)) {
1764
hour = CHR2INT1(out); out += 2;
1765
minute = CHR2INT2(out); out += 3;
1766
second = CHR2INT2(out); out += 3;
1767
microsecond = (IS_TIMEDELTA_MICRO(out, out_l)) ? CHR2INT6(out) :
1768
(IS_TIMEDELTA_MILLI(out, out_l)) ? CHR2INT3(out) * 1e3 : 0;
1769
}
1770
else if (IS_TIMEDELTA2(out, out_l)) {
1771
hour = CHR2INT2(out); out += 3;
1772
minute = CHR2INT2(out); out += 3;
1773
second = CHR2INT2(out); out += 3;
1774
microsecond = (IS_TIMEDELTA_MICRO(out, out_l)) ? CHR2INT6(out) :
1775
(IS_TIMEDELTA_MILLI(out, out_l)) ? CHR2INT3(out) * 1e3 : 0;
1776
}
1777
else if (IS_TIMEDELTA3(out, out_l)) {
1778
hour = CHR2INT3(out); out += 4;
1779
minute = CHR2INT2(out); out += 3;
1780
second = CHR2INT2(out); out += 3;
1781
microsecond = (IS_TIMEDELTA_MICRO(out, out_l)) ? CHR2INT6(out) :
1782
(IS_TIMEDELTA_MILLI(out, out_l)) ? CHR2INT3(out) * 1e3 : 0;
1783
}
1784
py_item = PyDelta_FromDSU(
1785
#ifdef Py_LIMITED_API
1786
py_state,
1787
#endif
1788
0, sign * hour * 60 * 60 +
1789
sign * minute * 60 +
1790
sign * second,
1791
sign * microsecond);
1792
if (!py_item) {
1793
PyErr_Clear();
1794
py_item = PyUnicode_Decode(orig_out, orig_out_l, "ascii", py_state->encoding_errors);
1795
}
1796
if (!py_item) goto error;
1797
break;
1798
1799
case MYSQL_TYPE_YEAR:
1800
if (out_l == 0) {
1801
goto error;
1802
break;
1803
}
1804
if (data_l) out[out_l] = '\0';
1805
year = strtoul(out, NULL, 10);
1806
py_item = PyLong_FromLong(year);
1807
if (data_l) out[out_l] = end;
1808
if (!py_item) goto error;
1809
break;
1810
1811
case MYSQL_TYPE_BIT:
1812
case MYSQL_TYPE_JSON:
1813
case MYSQL_TYPE_TINY_BLOB:
1814
case MYSQL_TYPE_MEDIUM_BLOB:
1815
case MYSQL_TYPE_LONG_BLOB:
1816
case MYSQL_TYPE_BLOB:
1817
case MYSQL_TYPE_GEOMETRY:
1818
case MYSQL_TYPE_ENUM:
1819
case MYSQL_TYPE_SET:
1820
case MYSQL_TYPE_VARCHAR:
1821
case MYSQL_TYPE_VAR_STRING:
1822
case MYSQL_TYPE_STRING:
1823
case MYSQL_TYPE_FLOAT32_VECTOR_JSON:
1824
case MYSQL_TYPE_FLOAT64_VECTOR_JSON:
1825
case MYSQL_TYPE_INT8_VECTOR_JSON:
1826
case MYSQL_TYPE_INT16_VECTOR_JSON:
1827
case MYSQL_TYPE_INT32_VECTOR_JSON:
1828
case MYSQL_TYPE_INT64_VECTOR_JSON:
1829
if (!py_state->encodings[i]) {
1830
py_item = PyBytes_FromStringAndSize(out, out_l);
1831
if (!py_item) goto error;
1832
break;
1833
}
1834
1835
py_item = PyUnicode_Decode(out, out_l, py_state->encodings[i], py_state->encoding_errors);
1836
if (PyErr_Occurred()) {
1837
PyErr_Clear();
1838
PyErr_Format(
1839
PyExc_UnicodeDecodeError,
1840
"failed to decode string value in column '%S' using encoding '%s'; "
1841
"use the 'encoding_errors' option on the connection to specify how to handle this error",
1842
py_state->py_names[i], py_state->encodings[i]
1843
);
1844
}
1845
if (!py_item) goto error;
1846
1847
// Parse JSON string.
1848
if ((py_state->type_codes[i] == MYSQL_TYPE_JSON && py_state->options.parse_json)
1849
|| (py_state->type_codes[i] >= MYSQL_TYPE_FLOAT32_VECTOR_JSON
1850
&& py_state->type_codes[i] <= MYSQL_TYPE_INT64_VECTOR_JSON)) {
1851
py_str = py_item;
1852
py_item = PyObject_CallFunctionObjArgs(PyFunc.json_loads, py_str, NULL);
1853
Py_CLEAR(py_str);
1854
if (!py_item) goto error;
1855
}
1856
1857
if (ensure_numpy() == 0) {
1858
switch (py_state->type_codes[i]) {
1859
case MYSQL_TYPE_FLOAT32_VECTOR_JSON:
1860
case MYSQL_TYPE_FLOAT64_VECTOR_JSON:
1861
case MYSQL_TYPE_INT8_VECTOR_JSON:
1862
case MYSQL_TYPE_INT16_VECTOR_JSON:
1863
case MYSQL_TYPE_INT32_VECTOR_JSON:
1864
case MYSQL_TYPE_INT64_VECTOR_JSON:
1865
CHECKRC(PyTuple_SetItem(PyObj.create_numpy_array_args, 0, py_item));
1866
py_item = PyObject_Call(
1867
PyFunc.numpy_array,
1868
PyObj.create_numpy_array_args,
1869
PyObj.create_numpy_array_kwargs_vector[py_state->type_codes[i] % 1000]
1870
);
1871
if (!py_item) goto error;
1872
}
1873
}
1874
1875
break;
1876
1877
case MYSQL_TYPE_FLOAT32_VECTOR:
1878
case MYSQL_TYPE_FLOAT64_VECTOR:
1879
case MYSQL_TYPE_INT8_VECTOR:
1880
case MYSQL_TYPE_INT16_VECTOR:
1881
case MYSQL_TYPE_INT32_VECTOR:
1882
case MYSQL_TYPE_INT64_VECTOR:
1883
{
1884
int type_idx = py_state->type_codes[i] % 1000;
1885
1886
if (ensure_numpy() == 0) {
1887
py_memview = PyBytes_FromStringAndSize(out, out_l);
1888
if (!py_memview) goto error;
1889
1890
CHECKRC(PyTuple_SetItem(PyObj.create_numpy_array_args, 0, py_memview));
1891
1892
py_item = PyObject_Call(
1893
PyFunc.numpy_frombuffer,
1894
PyObj.create_numpy_array_args,
1895
PyObj.create_numpy_array_kwargs_vector[type_idx]
1896
);
1897
if (!py_item) goto error;
1898
1899
} else {
1900
py_memview = PyBytes_FromStringAndSize(out, out_l);
1901
if (!py_memview) goto error;
1902
1903
CHECKRC(PyTuple_SetItem(PyObj.struct_unpack_args, 0,
1904
PyUnicode_FromFormat("<%ld%s", out_l / item_type_lengths[type_idx], cast_type_codes[type_idx])));
1905
CHECKRC(PyTuple_SetItem(PyObj.struct_unpack_args, 1, py_memview));
1906
1907
py_item = PyObject_Call(
1908
PyFunc.struct_unpack,
1909
PyObj.struct_unpack_args,
1910
NULL
1911
);
1912
if (!py_item) goto error;
1913
}
1914
1915
break;
1916
}
1917
1918
case MYSQL_TYPE_BSON:
1919
py_item = PyBytes_FromStringAndSize(out, out_l);
1920
if (!py_item) goto error;
1921
1922
if (ensure_bson() == 0) {
1923
CHECKRC(PyTuple_SetItem(PyObj.bson_decode_args, 0, py_item));
1924
py_item = PyObject_Call(
1925
PyFunc.bson_decode,
1926
PyObj.bson_decode_args,
1927
NULL
1928
);
1929
if (!py_item) goto error;
1930
}
1931
1932
break;
1933
1934
default:
1935
PyErr_Format(PyExc_TypeError, "unknown type code: %ld",
1936
py_state->type_codes[i], NULL);
1937
goto error;
1938
}
1939
}
1940
}
1941
1942
if (py_item == Py_None) {
1943
Py_INCREF(Py_None);
1944
}
1945
1946
switch (py_state->options.results_type) {
1947
case ACCEL_OUT_STRUCTSEQUENCES:
1948
PyStructSequence_SetItem(py_result, i, py_item);
1949
break;
1950
case ACCEL_OUT_DICTS:
1951
case ACCEL_OUT_ARROW:
1952
PyDict_SetItem(py_result, py_state->py_names[i], py_item);
1953
Py_DECREF(py_item);
1954
break;
1955
default:
1956
PyTuple_SetItem(py_result, i, py_item);
1957
}
1958
}
1959
1960
if (py_state->options.results_type == ACCEL_OUT_NAMEDTUPLES) {
1961
// We just use py_result above as storage for the parameters to
1962
// the namedtuple constructor. It gets deleted at the end of the
1963
// fetch operation.
1964
py_result = PyObject_CallObject(py_state->py_namedtuple, py_result);
1965
if (!py_result) goto error;
1966
}
1967
1968
exit:
1969
return py_result;
1970
1971
error:
1972
Py_CLEAR(py_result);
1973
goto exit;
1974
}
1975
1976
static PyObject *read_rowdata_packet(PyObject *self, PyObject *args, PyObject *kwargs) {
1977
int rc = 0;
1978
StateObject *py_state = NULL;
1979
PyObject *py_res = NULL;
1980
PyObject *py_unbuffered = NULL;
1981
PyObject *py_out = NULL;
1982
PyObject *py_next_seq_id = NULL;
1983
PyObject *py_zero = PyLong_FromUnsignedLong(0);
1984
PyObject *py_err_type = NULL;
1985
PyObject *py_err_value = NULL;
1986
PyObject *py_err_tb = NULL;
1987
unsigned long long requested_n_rows = 0;
1988
unsigned long long row_idx = 0;
1989
char *keywords[] = {"result", "unbuffered", "size", NULL};
1990
1991
// Parse function args.
1992
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|K", keywords, &py_res, &py_unbuffered, &requested_n_rows)) {
1993
goto error;
1994
}
1995
1996
if (py_unbuffered && PyObject_IsTrue(py_unbuffered)) {
1997
PyObject *unbuffered_active = PyObject_GetAttr(py_res, PyStr.unbuffered_active);
1998
if (!unbuffered_active || !PyObject_IsTrue(unbuffered_active)) {
1999
Py_XDECREF(unbuffered_active);
2000
Py_XDECREF(py_zero);
2001
Py_INCREF(Py_None);
2002
return Py_None;
2003
}
2004
Py_XDECREF(unbuffered_active);
2005
}
2006
2007
// Get the rowdata state.
2008
py_state = (StateObject*)PyObject_GetAttr(py_res, PyStr._state);
2009
if (!py_state) {
2010
PyErr_Clear();
2011
2012
PyObject *py_requested_n_rows = PyLong_FromUnsignedLongLong(requested_n_rows);
2013
if (!py_requested_n_rows) goto error;
2014
2015
PyObject *py_args = PyTuple_New(2);
2016
if (!py_args) goto error;
2017
PyTuple_SetItem(py_args, 0, py_res);
2018
PyTuple_SetItem(py_args, 1, py_requested_n_rows);
2019
Py_INCREF(py_res);
2020
Py_INCREF(py_requested_n_rows);
2021
2022
py_state = (StateObject*)PyObject_CallObject((PyObject*)StateType, py_args);
2023
if (!py_state) { Py_DECREF(py_args); goto error; }
2024
Py_DECREF(py_args);
2025
2026
PyObject_SetAttr(py_res, PyStr._state, (PyObject*)py_state);
2027
}
2028
else if (requested_n_rows > 0) {
2029
State_reset_batch(py_state, py_res, requested_n_rows);
2030
}
2031
2032
if (requested_n_rows == 0) {
2033
requested_n_rows = UINTMAX_MAX;
2034
}
2035
2036
if (py_state->is_eof) {
2037
goto exit;
2038
}
2039
2040
while (row_idx < requested_n_rows) {
2041
PyObject *py_buff = read_packet(py_state);
2042
if (!py_buff) goto error;
2043
2044
PyObject *py_row = NULL;
2045
char *data = PyByteArray_AsString(py_buff);
2046
unsigned long long data_l = PyByteArray_Size(py_buff);
2047
unsigned long long warning_count = 0;
2048
int has_next = 0;
2049
2050
if (check_packet_is_eof(&data, &data_l, &warning_count, &has_next)) {
2051
Py_CLEAR(py_buff);
2052
2053
py_state->is_eof = 1;
2054
2055
PyObject *py_long = NULL;
2056
2057
py_long = PyLong_FromUnsignedLongLong(warning_count);
2058
PyObject_SetAttr(py_res, PyStr.warning_count, py_long ? py_long : 0);
2059
Py_CLEAR(py_long);
2060
2061
py_long = PyLong_FromLong(has_next);
2062
PyObject_SetAttr(py_res, PyStr.has_next, py_long ? py_long : 0);
2063
Py_CLEAR(py_long);
2064
2065
PyObject_SetAttr(py_res, PyStr.connection, Py_None);
2066
PyObject_SetAttr(py_res, PyStr.unbuffered_active, Py_False);
2067
2068
break;
2069
}
2070
2071
py_state->n_rows++;
2072
py_state->n_rows_in_batch++;
2073
2074
py_row = read_row_from_packet(py_state, data, data_l);
2075
if (!py_row) { Py_CLEAR(py_buff); goto error; }
2076
2077
//if (requested_n_rows == 1) {
2078
// rc = PyList_SetItem(py_state->py_rows, 0, py_row);
2079
//} else {
2080
rc = PyList_Append(py_state->py_rows, py_row);
2081
Py_DECREF(py_row);
2082
//}
2083
if (rc != 0) { Py_CLEAR(py_buff); goto error; }
2084
2085
row_idx++;
2086
2087
Py_CLEAR(py_buff);
2088
}
2089
2090
exit:
2091
if (!py_state) return NULL;
2092
2093
py_next_seq_id = PyLong_FromUnsignedLongLong(py_state->next_seq_id);
2094
if (!py_next_seq_id) goto error;
2095
PyObject_SetAttr(py_state->py_conn, PyStr._next_seq_id, py_next_seq_id);
2096
Py_DECREF(py_next_seq_id);
2097
2098
py_out = NULL;
2099
2100
if (py_state->unbuffered) {
2101
if (py_state->is_eof && row_idx == 0) {
2102
Py_INCREF(Py_None);
2103
py_out = Py_None;
2104
PyObject_SetAttr(py_res, PyStr.rows, Py_None);
2105
PyObject *py_n_rows = PyLong_FromSsize_t(py_state->n_rows);
2106
PyObject_SetAttr(py_res, PyStr.affected_rows, (py_n_rows) ? py_n_rows : Py_None);
2107
Py_XDECREF(py_n_rows);
2108
PyObject_DelAttr(py_res, PyStr._state);
2109
Py_CLEAR(py_state);
2110
}
2111
else {
2112
py_out = (requested_n_rows == 1) ?
2113
PyList_GetItem(py_state->py_rows, 0) : py_state->py_rows;
2114
Py_XINCREF(py_out);
2115
}
2116
}
2117
else {
2118
py_out = py_state->py_rows;
2119
Py_INCREF(py_out);
2120
PyObject *py_n_rows = PyLong_FromSsize_t(py_state->n_rows);
2121
PyObject_SetAttr(py_res, PyStr.affected_rows, (py_n_rows) ? py_n_rows : Py_None);
2122
Py_XDECREF(py_n_rows);
2123
if (py_state->is_eof) {
2124
PyObject_DelAttr(py_res, PyStr._state);
2125
Py_CLEAR(py_state);
2126
}
2127
}
2128
2129
Py_XDECREF(py_zero);
2130
2131
if (PyErr_Occurred()) {
2132
Py_CLEAR(py_out);
2133
}
2134
else if (py_err_type) {
2135
Py_CLEAR(py_out);
2136
PyErr_Restore(py_err_type, py_err_value, py_err_tb);
2137
}
2138
2139
return py_out;
2140
2141
error:
2142
if (PyErr_Occurred()) {
2143
PyErr_Fetch(&py_err_type, &py_err_value, &py_err_tb);
2144
}
2145
goto exit;
2146
}
2147
2148
2149
static PyObject *create_numpy_array(PyObject *py_memview, char *data_format, int data_type, PyObject *py_objs) {
2150
PyObject *py_memviewc = NULL;
2151
PyObject *py_in = NULL;
2152
PyObject *py_out = NULL;
2153
PyObject *py_vec_func = NULL;
2154
2155
py_memviewc = PyObject_CallMethod(py_memview, "cast", "s", data_format);
2156
if (!py_memviewc) goto error;
2157
2158
CHECKRC(PyTuple_SetItem(PyObj.create_numpy_array_args, 0, py_memviewc));
2159
Py_INCREF(py_memviewc);
2160
2161
py_out = PyObject_Call(PyFunc.numpy_array, PyObj.create_numpy_array_args, PyObj.create_numpy_array_kwargs);
2162
if (!py_out) goto error;
2163
2164
// Add series to the output, remapping string values as needed
2165
if (py_objs) {
2166
switch(data_type) {
2167
case MYSQL_TYPE_VARCHAR:
2168
case MYSQL_TYPE_JSON:
2169
case MYSQL_TYPE_SET:
2170
case MYSQL_TYPE_ENUM:
2171
case MYSQL_TYPE_VAR_STRING:
2172
case MYSQL_TYPE_STRING:
2173
case MYSQL_TYPE_GEOMETRY:
2174
case MYSQL_TYPE_TINY_BLOB:
2175
case MYSQL_TYPE_MEDIUM_BLOB:
2176
case MYSQL_TYPE_LONG_BLOB:
2177
case MYSQL_TYPE_BLOB:
2178
case -MYSQL_TYPE_VARCHAR:
2179
case -MYSQL_TYPE_JSON:
2180
case -MYSQL_TYPE_SET:
2181
case -MYSQL_TYPE_ENUM:
2182
case -MYSQL_TYPE_VAR_STRING:
2183
case -MYSQL_TYPE_STRING:
2184
case -MYSQL_TYPE_GEOMETRY:
2185
case -MYSQL_TYPE_TINY_BLOB:
2186
case -MYSQL_TYPE_MEDIUM_BLOB:
2187
case -MYSQL_TYPE_LONG_BLOB:
2188
case -MYSQL_TYPE_BLOB:
2189
py_vec_func = PyObject_CallFunction(PyFunc.numpy_vectorize, "Os", PyObject_GetAttrString(py_objs, "get"), "O");
2190
py_in = py_out;
2191
py_out = PyObject_CallFunction(py_vec_func, "O", py_in);
2192
if (!py_out) goto error;
2193
break;
2194
}
2195
}
2196
2197
exit:
2198
Py_XDECREF(py_in);
2199
Py_XDECREF(py_vec_func);
2200
Py_XDECREF(py_memviewc);
2201
2202
return py_out;
2203
2204
error:
2205
Py_XDECREF(py_out);
2206
py_out = NULL;
2207
2208
goto exit;
2209
}
2210
2211
2212
static PyObject *load_rowdat_1_numpy(PyObject *self, PyObject *args, PyObject *kwargs) {
2213
PyObject *py_data = NULL;
2214
PyObject *py_out = NULL;
2215
PyObject *py_colspec = NULL;
2216
PyObject *py_str = NULL;
2217
PyObject *py_blob = NULL;
2218
PyObject *py_memview = NULL;
2219
PyObject *py_arr = NULL;
2220
PyObject *py_out_pairs = NULL;
2221
PyObject *py_index = NULL;
2222
PyObject *py_objs = NULL;
2223
PyObject *py_mask = NULL;
2224
PyObject *py_pair = NULL;
2225
Py_ssize_t length = 0;
2226
uint8_t is_null = 0;
2227
int8_t i8 = 0;
2228
int16_t i16 = 0;
2229
int32_t i32 = 0;
2230
int64_t i64 = 0;
2231
uint8_t u8 = 0;
2232
uint16_t u16 = 0;
2233
uint32_t u32 = 0;
2234
uint64_t u64 = 0;
2235
float flt = 0;
2236
double dbl = 0;
2237
int *ctypes = NULL;
2238
char *data = NULL;
2239
char *orig_data = NULL;
2240
char *end = NULL;
2241
unsigned long long n_cols = 0;
2242
unsigned long long i = 0;
2243
unsigned long long j = 0;
2244
char *keywords[] = {"colspec", "data", NULL};
2245
uint64_t n_rows = 0;
2246
int *item_sizes = NULL;
2247
char **data_formats = NULL;
2248
char **out_cols = NULL;
2249
char **mask_cols = NULL;
2250
int64_t *out_row_ids = NULL;
2251
2252
if (ensure_numpy() < 0) goto error;
2253
2254
// Parse function args.
2255
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", keywords, &py_colspec, &py_data)) {
2256
goto error;
2257
}
2258
2259
CHECKRC(PyBytes_AsStringAndSize(py_data, &data, &length));
2260
end = data + (unsigned long long)length;
2261
orig_data = data;
2262
2263
// Get number of columns
2264
n_cols = PyObject_Length(py_colspec);
2265
2266
// Determine column types
2267
ctypes = calloc(sizeof(int), n_cols);
2268
if (!ctypes) goto error;
2269
for (i = 0; i < n_cols; i++) {
2270
PyObject *py_cspec = PySequence_GetItem(py_colspec, i);
2271
if (!py_cspec) goto error;
2272
PyObject *py_ctype = PySequence_GetItem(py_cspec, 1);
2273
if (!py_ctype) { Py_DECREF(py_cspec); goto error; }
2274
ctypes[i] = (int)PyLong_AsLong(py_ctype);
2275
Py_DECREF(py_ctype);
2276
Py_DECREF(py_cspec);
2277
if (PyErr_Occurred()) { goto error; }
2278
}
2279
2280
#define CHECKSIZE(x) \
2281
if ((data + x) > end) { \
2282
PyErr_SetString(PyExc_ValueError, "data length does not align with specified column values"); \
2283
goto error; \
2284
}
2285
2286
// Determine number of rows
2287
item_sizes = malloc(sizeof(int) * n_cols);
2288
if (!item_sizes) goto error;
2289
data_formats = malloc(sizeof(char*) * n_cols);
2290
if (!data_formats) goto error;
2291
while (end > data) {
2292
// Row ID
2293
CHECKSIZE(8);
2294
data += 8;
2295
2296
for (i = 0; i < n_cols; i++) {
2297
// Null slot
2298
CHECKSIZE(1);
2299
data += 1;
2300
2301
// Data row
2302
switch (ctypes[i]) {
2303
case MYSQL_TYPE_NULL:
2304
PyErr_SetString(PyExc_TypeError, "unsupported data type: NULL");
2305
goto error;
2306
break;
2307
2308
case MYSQL_TYPE_BIT:
2309
PyErr_SetString(PyExc_TypeError, "unsupported data type: BIT");
2310
goto error;
2311
break;
2312
2313
case MYSQL_TYPE_TINY:
2314
case -MYSQL_TYPE_TINY:
2315
CHECKSIZE(1);
2316
item_sizes[i] = 1;
2317
data_formats[i] = (ctypes[i] < 0) ? "B" : "b";
2318
data += 1;
2319
break;
2320
2321
case MYSQL_TYPE_SHORT:
2322
case -MYSQL_TYPE_SHORT:
2323
CHECKSIZE(2);
2324
item_sizes[i] = 2;
2325
data_formats[i] = (ctypes[i] < 0) ? "H" : "h";
2326
data += 2;
2327
break;
2328
2329
case MYSQL_TYPE_LONG:
2330
case -MYSQL_TYPE_LONG:
2331
case MYSQL_TYPE_INT24:
2332
case -MYSQL_TYPE_INT24:
2333
CHECKSIZE(4);
2334
item_sizes[i] = 4;
2335
data_formats[i] = (ctypes[i] < 0) ? "I" : "i";
2336
data += 4;
2337
break;
2338
2339
case MYSQL_TYPE_LONGLONG:
2340
case -MYSQL_TYPE_LONGLONG:
2341
CHECKSIZE(8);
2342
item_sizes[i] = 8;
2343
data_formats[i] = (ctypes[i] < 0) ? "Q" : "q";
2344
data += 8;
2345
break;
2346
2347
case MYSQL_TYPE_FLOAT:
2348
CHECKSIZE(4);
2349
item_sizes[i] = 4;
2350
data_formats[i] = "f";
2351
data += 4;
2352
break;
2353
2354
case MYSQL_TYPE_DOUBLE:
2355
CHECKSIZE(8);
2356
item_sizes[i] = 8;
2357
data_formats[i] = "d";
2358
data += 8;
2359
break;
2360
2361
case MYSQL_TYPE_DECIMAL:
2362
case MYSQL_TYPE_NEWDECIMAL:
2363
PyErr_SetString(PyExc_TypeError, "unsupported data type: DECIMAL");
2364
goto error;
2365
break;
2366
2367
case MYSQL_TYPE_DATE:
2368
case MYSQL_TYPE_NEWDATE:
2369
PyErr_SetString(PyExc_TypeError, "unsupported data type: DATE");
2370
goto error;
2371
break;
2372
2373
case MYSQL_TYPE_TIME:
2374
PyErr_SetString(PyExc_TypeError, "unsupported data type: TIME");
2375
goto error;
2376
break;
2377
2378
case MYSQL_TYPE_DATETIME:
2379
PyErr_SetString(PyExc_TypeError, "unsupported data type: DATETIME");
2380
goto error;
2381
break;
2382
2383
case MYSQL_TYPE_TIMESTAMP:
2384
PyErr_SetString(PyExc_TypeError, "unsupported data type: TIMESTAMP");
2385
goto error;
2386
break;
2387
2388
case MYSQL_TYPE_YEAR:
2389
CHECKSIZE(2);
2390
data += 2;
2391
break;
2392
2393
case MYSQL_TYPE_VARCHAR:
2394
case MYSQL_TYPE_JSON:
2395
case MYSQL_TYPE_SET:
2396
case MYSQL_TYPE_ENUM:
2397
case MYSQL_TYPE_VAR_STRING:
2398
case MYSQL_TYPE_STRING:
2399
case MYSQL_TYPE_GEOMETRY:
2400
case MYSQL_TYPE_TINY_BLOB:
2401
case MYSQL_TYPE_MEDIUM_BLOB:
2402
case MYSQL_TYPE_LONG_BLOB:
2403
case MYSQL_TYPE_BLOB:
2404
CHECKSIZE(8);
2405
item_sizes[i] = 8;
2406
data_formats[i] = "Q";
2407
i64 = *(int64_t*)data;
2408
data += 8;
2409
CHECKSIZE(i64);
2410
data += i64;
2411
break;
2412
2413
// Use negative to indicate binary
2414
case -MYSQL_TYPE_VARCHAR:
2415
case -MYSQL_TYPE_JSON:
2416
case -MYSQL_TYPE_SET:
2417
case -MYSQL_TYPE_ENUM:
2418
case -MYSQL_TYPE_VAR_STRING:
2419
case -MYSQL_TYPE_STRING:
2420
case -MYSQL_TYPE_GEOMETRY:
2421
case -MYSQL_TYPE_TINY_BLOB:
2422
case -MYSQL_TYPE_MEDIUM_BLOB:
2423
case -MYSQL_TYPE_LONG_BLOB:
2424
CHECKSIZE(8);
2425
item_sizes[i] = 8;
2426
data_formats[i] = "Q";
2427
i64 = *(int64_t*)data;
2428
data += 8;
2429
CHECKSIZE(i64);
2430
data += i64;
2431
break;
2432
}
2433
}
2434
2435
n_rows += 1;
2436
}
2437
2438
// Reset data pointer
2439
data = orig_data;
2440
2441
// Allocate data columns
2442
out_cols = malloc(n_cols * sizeof(char*));
2443
if (!out_cols) goto error;
2444
mask_cols = malloc(n_cols * sizeof(char*));
2445
if (!mask_cols) goto error;
2446
for (i = 0; i < n_cols; i++) {
2447
out_cols[i] = malloc(item_sizes[i] * n_rows);
2448
if (!out_cols[i]) goto error;
2449
mask_cols[i] = malloc(1 * n_rows);
2450
if (!mask_cols[i]) goto error;
2451
}
2452
2453
// Allocate row ID array
2454
out_row_ids = malloc(sizeof(int64_t) * n_rows);
2455
if (!out_row_ids) goto error;
2456
2457
// Create dict for strings/blobs
2458
py_objs = PyDict_New();
2459
if (!py_objs) goto error;
2460
CHECKRC(PyDict_SetItem(py_objs, PyLong_FromUnsignedLongLong(0), Py_None));
2461
2462
// Build output arrays
2463
j = 0;
2464
while (end > data) {
2465
if (j >= n_rows) goto error;
2466
2467
out_row_ids[j] = *(int64_t*)data; data += 8;
2468
2469
for (i = 0; i < n_cols; i++) {
2470
is_null = (data[0] == '\x01');
2471
data += 1;
2472
2473
((char*)mask_cols[i])[j] = (is_null) ? '\x01' : '\x00';
2474
2475
switch (ctypes[i]) {
2476
case MYSQL_TYPE_NULL:
2477
i8 = 0; data += 1;
2478
memcpy(out_cols[i] + j * 1, &i8, 1);
2479
break;
2480
2481
case MYSQL_TYPE_BIT:
2482
// TODO
2483
break;
2484
2485
case MYSQL_TYPE_TINY:
2486
i8 = (is_null) ? 0 : *(int8_t*)data; data += 1;
2487
memcpy(out_cols[i] + j * 1, &i8, 1);
2488
break;
2489
2490
// Use negative to indicate unsigned
2491
case -MYSQL_TYPE_TINY:
2492
u8 = (is_null) ? 0 : *(uint8_t*)data; data += 1;
2493
memcpy(out_cols[i] + j * 1, &u8, 1);
2494
break;
2495
2496
case MYSQL_TYPE_SHORT:
2497
i16 = (is_null) ? 0 : *(int16_t*)data; data += 2;
2498
memcpy(out_cols[i] + j * 2, &i16, 2);
2499
break;
2500
2501
// Use negative to indicate unsigned
2502
case -MYSQL_TYPE_SHORT:
2503
u16 = (is_null) ? 0 : *(uint16_t*)data; data += 2;
2504
memcpy(out_cols[i] + j * 2, &u16, 2);
2505
break;
2506
2507
case MYSQL_TYPE_LONG:
2508
case MYSQL_TYPE_INT24:
2509
i32 = (is_null) ? 0 : *(int32_t*)data; data += 4;
2510
memcpy(out_cols[i] + j * 4, &i32, 4);
2511
break;
2512
2513
// Use negative to indicate unsigned
2514
case -MYSQL_TYPE_LONG:
2515
case -MYSQL_TYPE_INT24:
2516
u32 = (is_null) ? 0 : *(uint32_t*)data; data += 4;
2517
memcpy(out_cols[i] + j * 4, &u32, 4);
2518
break;
2519
2520
case MYSQL_TYPE_LONGLONG:
2521
i64 = (is_null) ? 0 : *(int64_t*)data; data += 8;
2522
memcpy(out_cols[i] + j * 8, &i64, 8);
2523
break;
2524
2525
// Use negative to indicate unsigned
2526
case -MYSQL_TYPE_LONGLONG:
2527
u64 = (is_null) ? 0 : *(uint64_t*)data; data += 8;
2528
memcpy(out_cols[i] + j * 8, &u64, 8);
2529
break;
2530
2531
case MYSQL_TYPE_FLOAT:
2532
flt = (is_null) ? NAN : *(float*)data; data += 4;
2533
memcpy(out_cols[i] + j * 4, &flt, 4);
2534
break;
2535
2536
case MYSQL_TYPE_DOUBLE:
2537
dbl = (is_null) ? NAN : *(double*)data; data += 8;
2538
memcpy(out_cols[i] + j * 8, &dbl, 8);
2539
break;
2540
2541
case MYSQL_TYPE_DECIMAL:
2542
case MYSQL_TYPE_NEWDECIMAL:
2543
// TODO
2544
break;
2545
2546
case MYSQL_TYPE_DATE:
2547
case MYSQL_TYPE_NEWDATE:
2548
// TODO
2549
break;
2550
2551
case MYSQL_TYPE_TIME:
2552
// TODO
2553
break;
2554
2555
case MYSQL_TYPE_DATETIME:
2556
// TODO
2557
break;
2558
2559
case MYSQL_TYPE_TIMESTAMP:
2560
// TODO
2561
break;
2562
2563
case MYSQL_TYPE_YEAR:
2564
u16 = (is_null) ? 0 : *(uint16_t*)data; data += 2;
2565
memcpy(out_cols[i] + j * 2, &u16, 2);
2566
break;
2567
2568
case MYSQL_TYPE_VARCHAR:
2569
case MYSQL_TYPE_JSON:
2570
case MYSQL_TYPE_SET:
2571
case MYSQL_TYPE_ENUM:
2572
case MYSQL_TYPE_VAR_STRING:
2573
case MYSQL_TYPE_STRING:
2574
case MYSQL_TYPE_GEOMETRY:
2575
case MYSQL_TYPE_TINY_BLOB:
2576
case MYSQL_TYPE_MEDIUM_BLOB:
2577
case MYSQL_TYPE_LONG_BLOB:
2578
case MYSQL_TYPE_BLOB:
2579
i64 = *(int64_t*)data; data += 8;
2580
if (is_null) {
2581
u64 = 0;
2582
memcpy(out_cols[i] + j * 8, &u64, 8);
2583
} else {
2584
py_str = PyUnicode_FromStringAndSize(data, (Py_ssize_t)i64);
2585
data += i64;
2586
if (!py_str) goto error;
2587
u64 = (uint64_t)py_str;
2588
memcpy(out_cols[i] + j * 8, &u64, 8);
2589
CHECKRC(PyDict_SetItem(py_objs, PyLong_FromUnsignedLongLong(u64), py_str));
2590
Py_CLEAR(py_str);
2591
}
2592
break;
2593
2594
// Use negative to indicate binary
2595
case -MYSQL_TYPE_VARCHAR:
2596
case -MYSQL_TYPE_JSON:
2597
case -MYSQL_TYPE_SET:
2598
case -MYSQL_TYPE_ENUM:
2599
case -MYSQL_TYPE_VAR_STRING:
2600
case -MYSQL_TYPE_STRING:
2601
case -MYSQL_TYPE_GEOMETRY:
2602
case -MYSQL_TYPE_TINY_BLOB:
2603
case -MYSQL_TYPE_MEDIUM_BLOB:
2604
case -MYSQL_TYPE_LONG_BLOB:
2605
case -MYSQL_TYPE_BLOB:
2606
i64 = *(int64_t*)data; data += 8;
2607
if (is_null) {
2608
u64 = 0;
2609
memcpy(out_cols[i] + j * 8, &u64, 8);
2610
} else {
2611
py_blob = PyBytes_FromStringAndSize(data, (Py_ssize_t)i64);
2612
data += i64;
2613
if (!py_blob) goto error;
2614
u64 = (uint64_t)py_blob;
2615
memcpy(out_cols[i] + j * 8, &u64, 8);
2616
CHECKRC(PyDict_SetItem(py_objs, PyLong_FromUnsignedLongLong(u64), py_blob));
2617
Py_CLEAR(py_blob);
2618
}
2619
break;
2620
2621
default:
2622
goto error;
2623
}
2624
}
2625
2626
j += 1;
2627
}
2628
2629
py_out = PyTuple_New(2);
2630
if (!py_out) goto error;
2631
2632
py_out_pairs = PyList_New(n_cols);
2633
if (!py_out_pairs) goto error;
2634
2635
// Create Series of row IDs
2636
py_memview = PyMemoryView_FromMemory((char*)out_row_ids, n_rows * 8, PyBUF_WRITE);
2637
if (!py_memview) goto error;
2638
2639
py_index = create_numpy_array(py_memview, "Q", 0, NULL);
2640
Py_CLEAR(py_memview);
2641
if (!py_index) goto error;
2642
2643
CHECKRC(PyTuple_SetItem(py_out, 0, py_index));
2644
CHECKRC(PyTuple_SetItem(py_out, 1, py_out_pairs));
2645
2646
// Convert C buffers to numpy arrays and masks
2647
for (i = 0; i < n_cols; i++) {
2648
py_pair = PyTuple_New(2);
2649
if (!py_pair) goto error;
2650
2651
py_memview = PyMemoryView_FromMemory(out_cols[i], n_rows * item_sizes[i], PyBUF_WRITE);
2652
if (!py_memview) goto error;
2653
2654
py_arr = create_numpy_array(py_memview, data_formats[i], ctypes[i], py_objs);
2655
Py_CLEAR(py_memview);
2656
if (!py_arr) goto error;
2657
2658
py_memview = PyMemoryView_FromMemory(mask_cols[i], n_rows * 1, PyBUF_WRITE);
2659
if (!py_memview) goto error;
2660
2661
py_mask = create_numpy_array(py_memview, "?", 0, NULL);
2662
Py_CLEAR(py_memview);
2663
if (!py_mask) goto error;
2664
2665
if (!py_arr) goto error;
2666
if (!py_mask) goto error;
2667
2668
CHECKRC(PyTuple_SetItem(py_pair, 0, py_arr));
2669
py_arr = NULL;
2670
2671
CHECKRC(PyTuple_SetItem(py_pair, 1, py_mask));
2672
py_mask = NULL;
2673
2674
CHECKRC(PyList_SetItem(py_out_pairs, i, py_pair));
2675
py_pair = NULL;
2676
}
2677
2678
exit:
2679
if (ctypes) free(ctypes);
2680
if (out_cols) {
2681
for (i = 0; i < n_cols; i++) {
2682
if (out_cols[i]) free(out_cols[i]);
2683
}
2684
free(out_cols);
2685
}
2686
if (mask_cols) {
2687
for (i = 0; i < n_cols; i++) {
2688
if (mask_cols[i]) free(mask_cols[i]);
2689
}
2690
free(mask_cols);
2691
}
2692
if (out_row_ids) free(out_row_ids);
2693
if (data_formats) free(data_formats);
2694
if (item_sizes) free(item_sizes);
2695
2696
Py_XDECREF(py_str);
2697
Py_XDECREF(py_arr);
2698
Py_XDECREF(py_mask);
2699
Py_XDECREF(py_pair);
2700
Py_XDECREF(py_blob);
2701
Py_XDECREF(py_objs);
2702
Py_XDECREF(py_memview);
2703
2704
return py_out;
2705
2706
error:
2707
Py_XDECREF(py_out);
2708
py_out = NULL;
2709
2710
goto exit;
2711
}
2712
2713
2714
static char *get_array_base_address(PyObject *py_array) {
2715
char *out = NULL;
2716
PyObject *py_array_interface = NULL;
2717
PyObject *py_data = NULL;
2718
PyObject *py_address = NULL;
2719
2720
if (py_array == Py_None) goto exit;
2721
2722
py_array_interface = PyObject_GetAttrString(py_array, "__array_interface__");
2723
if (!py_array_interface) goto error;
2724
2725
py_data = PyDict_GetItemString(py_array_interface, "data");
2726
if (!py_data) goto error;
2727
2728
py_address = PyTuple_GetItem(py_data, 0);
2729
if (!py_address) goto error;
2730
2731
out = (char*)PyLong_AsUnsignedLongLong(py_address);
2732
2733
exit:
2734
Py_XDECREF(py_array_interface);
2735
2736
return out;
2737
2738
error:
2739
goto exit;
2740
}
2741
2742
2743
static NumpyColType get_numpy_col_type(PyObject *py_array) {
2744
NumpyColType out = {0};
2745
char *str = NULL;
2746
PyObject *py_array_interface = NULL;
2747
PyObject *py_typestr = NULL;
2748
2749
if (py_array == Py_None) goto error;
2750
2751
py_array_interface = PyObject_GetAttrString(py_array, "__array_interface__");
2752
if (!py_array_interface) goto error;
2753
2754
py_typestr = PyDict_GetItemString(py_array_interface, "typestr");
2755
if (!py_typestr) goto error;
2756
2757
str = _PyUnicode_AsUTF8(py_typestr);
2758
if (!str) goto error;
2759
2760
switch (str[1]) {
2761
case 'b':
2762
out.type = NUMPY_BOOL;
2763
out.length = 1;
2764
break;
2765
case 'i':
2766
switch (str[2]) {
2767
case '1':
2768
out.type = NUMPY_INT8;
2769
out.length = 1;
2770
break;
2771
case '2':
2772
out.type = NUMPY_INT16;
2773
out.length = 2;
2774
break;
2775
case '4':
2776
out.type = NUMPY_INT32;
2777
out.length = 4;
2778
break;
2779
case '8':
2780
out.type = NUMPY_INT64;
2781
out.length = 8;
2782
break;
2783
}
2784
break;
2785
case 'u':
2786
switch (str[2]) {
2787
case '1':
2788
out.type = NUMPY_UINT8;
2789
out.length = 1;
2790
break;
2791
case '2':
2792
out.type = NUMPY_UINT16;
2793
out.length = 2;
2794
break;
2795
case '4':
2796
out.type = NUMPY_UINT32;
2797
out.length = 4;
2798
break;
2799
case '8':
2800
out.type = NUMPY_UINT64;
2801
out.length = 8;
2802
break;
2803
}
2804
break;
2805
case 'f':
2806
switch (str[2]) {
2807
case '4':
2808
out.type = NUMPY_FLOAT32;
2809
out.length = 4;
2810
break;
2811
case '8':
2812
out.type = NUMPY_FLOAT64;
2813
out.length = 8;
2814
break;
2815
}
2816
break;
2817
case 'O':
2818
out.type = NUMPY_OBJECT;
2819
out.length = 8;
2820
break;
2821
case 'm':
2822
out.type = NUMPY_TIMEDELTA;
2823
out.length = 8;
2824
break;
2825
case 'M':
2826
out.type = NUMPY_DATETIME;
2827
out.length = 8;
2828
break;
2829
case 'S':
2830
out.type = NUMPY_BYTES;
2831
out.length = (Py_ssize_t)strtol(str + 2, NULL, 10);
2832
if (out.length < 0) {
2833
goto error;
2834
}
2835
break;
2836
case 'U':
2837
out.type = NUMPY_FIXED_STRING;
2838
out.length = (Py_ssize_t)strtol(str + 2, NULL, 10);
2839
if (out.length < 0) {
2840
goto error;
2841
}
2842
break;
2843
default:
2844
goto error;
2845
}
2846
2847
exit:
2848
Py_XDECREF(py_array_interface);
2849
2850
if (str) free(str);
2851
2852
return out;
2853
2854
error:
2855
out.type = 0;
2856
out.length = 0;
2857
goto exit;
2858
}
2859
2860
2861
//
2862
// Convert Python objects to rowdat_1 format
2863
//
2864
// The inputs must look like:
2865
//
2866
// [mysql-type-1, mysql-type-2, ...], row-id-array, [(array-1, mask-1), (array-2, mask-2), ...]
2867
//
2868
// The number of elements in the first argument must be the same as the number
2869
// of elements in the last parameter. The number of elements in the second
2870
// parameter must equal the number of elements in each of the array-1 and mask-1
2871
// parameters. The mask parameters may be Py_None.
2872
//
2873
static PyObject *dump_rowdat_1_numpy(PyObject *self, PyObject *args, PyObject *kwargs) {
2874
PyObject *py_returns = NULL;
2875
PyObject *py_row_ids = NULL;
2876
PyObject *py_cols = NULL;
2877
PyObject *py_out = NULL;
2878
unsigned long long n_cols = 0;
2879
unsigned long long n_rows = 0;
2880
uint8_t is_null = 0;
2881
int8_t i8 = 0;
2882
int16_t i16 = 0;
2883
int32_t i32 = 0;
2884
int64_t i64 = 0;
2885
uint8_t u8 = 0;
2886
uint16_t u16 = 0;
2887
uint32_t u32 = 0;
2888
uint64_t u64 = 0;
2889
float flt = 0;
2890
double dbl = 0;
2891
char *out = NULL;
2892
unsigned long long out_l = 0;
2893
unsigned long long out_idx = 0;
2894
int *returns = NULL;
2895
char *keywords[] = {"returns", "row_ids", "cols", NULL};
2896
unsigned long long i = 0;
2897
unsigned long long j = 0;
2898
char **cols = NULL;
2899
char **masks = NULL;
2900
NumpyColType *col_types = NULL;
2901
int64_t *row_ids = NULL;
2902
2903
// Parse function args.
2904
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO", keywords, &py_returns, &py_row_ids, &py_cols)) {
2905
goto error;
2906
}
2907
2908
if (PyObject_Length(py_returns) != PyObject_Length(py_cols)) {
2909
PyErr_SetString(PyExc_ValueError, "number of return values does not match number of returned columns");
2910
goto error;
2911
}
2912
2913
n_rows = (unsigned long long)PyObject_Length(py_row_ids);
2914
if (n_rows == 0) {
2915
py_out = PyBytes_FromStringAndSize("", 0);
2916
goto exit;
2917
}
2918
2919
// Verify all data lengths agree
2920
n_cols = (unsigned long long)PyObject_Length(py_returns);
2921
if (n_cols == 0) {
2922
py_out = PyBytes_FromStringAndSize("", 0);
2923
goto exit;
2924
}
2925
for (i = 0; i < n_cols; i++) {
2926
PyObject *py_item = PyList_GetItem(py_cols, i);
2927
if (!py_item) goto error;
2928
2929
PyObject *py_data = PyTuple_GetItem(py_item, 0);
2930
if (!py_data) goto error;
2931
2932
if ((unsigned long long)PyObject_Length(py_data) != n_rows) {
2933
PyErr_SetString(PyExc_ValueError, "mismatched lengths of column values");
2934
goto error;
2935
}
2936
2937
PyObject *py_mask = PyTuple_GetItem(py_item, 1);
2938
if (!py_mask) goto error;
2939
2940
if (py_mask != Py_None && (unsigned long long)PyObject_Length(py_mask) != n_rows) {
2941
PyErr_SetString(PyExc_ValueError, "length of mask values does not match the length of data rows");
2942
goto error;
2943
}
2944
}
2945
2946
row_ids = (int64_t*)get_array_base_address(py_row_ids);
2947
if (!row_ids) {
2948
PyErr_SetString(PyExc_ValueError, "unable to get base address of row IDs");
2949
goto error;
2950
}
2951
2952
// Starting size, it will be resized later
2953
out_l = 256 * n_cols;
2954
out_idx = 0;
2955
out = malloc(out_l);
2956
if (!out) {
2957
PyErr_SetString(PyExc_MemoryError, "failed to allocate output buffer");
2958
goto error;
2959
}
2960
2961
// Get return types
2962
returns = malloc(sizeof(int) * n_cols);
2963
if (!returns) {
2964
PyErr_SetString(PyExc_MemoryError, "failed to allocate returns array");
2965
goto error;
2966
}
2967
2968
for (i = 0; i < n_cols; i++) {
2969
PyObject *py_item = PySequence_GetItem(py_returns, i);
2970
if (!py_item) goto error;
2971
returns[i] = (int)PyLong_AsLong(py_item);
2972
Py_DECREF(py_item);
2973
if (PyErr_Occurred()) { goto error; }
2974
}
2975
2976
// Get column array memory
2977
cols = calloc(sizeof(char*), n_cols);
2978
if (!cols) {
2979
PyErr_SetString(PyExc_MemoryError, "failed to allocate cols array");
2980
goto error;
2981
}
2982
col_types = calloc(sizeof(NumpyColType), n_cols);
2983
if (!col_types) {
2984
PyErr_SetString(PyExc_MemoryError, "failed to allocate col_types array");
2985
goto error;
2986
}
2987
masks = calloc(sizeof(char*), n_cols);
2988
if (!masks) {
2989
PyErr_SetString(PyExc_MemoryError, "failed to allocate masks array");
2990
goto error;
2991
}
2992
for (i = 0; i < n_cols; i++) {
2993
PyObject *py_item = PyList_GetItem(py_cols, i);
2994
if (!py_item) goto error;
2995
2996
PyObject *py_data = PyTuple_GetItem(py_item, 0);
2997
if (!py_data) goto error;
2998
2999
cols[i] = get_array_base_address(py_data);
3000
if (!cols[i]) {
3001
PyErr_SetString(PyExc_ValueError, "unable to get base address of data column");
3002
goto error;
3003
}
3004
3005
col_types[i] = get_numpy_col_type(py_data);
3006
if (!col_types[i].type) {
3007
PyErr_SetString(PyExc_ValueError, "unable to get column type of data column");
3008
goto error;
3009
}
3010
3011
PyObject *py_mask = PyTuple_GetItem(py_item, 1);
3012
if (!py_mask) goto error;
3013
3014
masks[i] = get_array_base_address(py_mask);
3015
if (masks[i] && get_numpy_col_type(py_mask).type != NUMPY_BOOL) {
3016
PyErr_SetString(PyExc_ValueError, "mask must only contain boolean values");
3017
goto error;
3018
}
3019
}
3020
3021
#define CHECKMEM(x) \
3022
if ((out_idx + x) > out_l) { \
3023
out_l = out_l * 2 + x; \
3024
char *new_out = realloc(out, out_l); \
3025
if (!new_out) { \
3026
PyErr_SetString(PyExc_MemoryError, "failed to reallocate output buffer"); \
3027
goto error; \
3028
} \
3029
out = new_out; \
3030
}
3031
3032
for (j = 0; j < n_rows; j++) {
3033
3034
CHECKMEM(8);
3035
memcpy(out+out_idx, &row_ids[j], 8);
3036
out_idx += 8;
3037
3038
for (i = 0; i < n_cols; i++) {
3039
3040
if (masks[i]) {
3041
is_null = *(masks[i] + j) != '\x00';
3042
} else {
3043
is_null = 0;
3044
}
3045
3046
CHECKMEM(1);
3047
memcpy(out+out_idx, &is_null, 1);
3048
out_idx += 1;
3049
3050
#define CHECK_TINYINT(x, unsigned_input) if ((x) < ((unsigned_input) ? 0 : -128) || (x) > 127) { \
3051
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for TINYINT"); \
3052
goto error; \
3053
}
3054
#define CHECK_UNSIGNED_TINYINT(x, unsigned_input) if ((x) < 0 || (x) > 255) { \
3055
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for UNSIGNED TINYINT"); \
3056
goto error; \
3057
}
3058
#define CHECK_SMALLINT(x, unsigned_input) if ((x) < ((unsigned_input) ? 0 : -32768) || (x) > 32767) { \
3059
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for SMALLINT"); \
3060
goto error; \
3061
}
3062
#define CHECK_UNSIGNED_SMALLINT(x, unsigned_input) if ((x) < 0 || (x) > 65535) { \
3063
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for UNSIGNED SMALLINT"); \
3064
goto error; \
3065
}
3066
#define CHECK_MEDIUMINT(x, unsigned_input) if ((x) < ((unsigned_input) ? 0 : -8388608) || (x) > 8388607) { \
3067
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for MEDIUMINT"); \
3068
goto error; \
3069
}
3070
#define CHECK_UNSIGNED_MEDIUMINT(x, unsigned_input) if ((x) < 0 || (x) > 16777215) { \
3071
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for UNSIGNED MEDIUMINT"); \
3072
goto error; \
3073
}
3074
#define CHECK_INT(x, unsigned_input) if ((x) < ((unsigned_input) ? 0 : -2147483648) || (x) > 2147483647) { \
3075
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for INT"); \
3076
goto error; \
3077
}
3078
#define CHECK_UNSIGNED_INT(x, unsigned_input) if ((x) < 0 || (x) > 4294967295) { \
3079
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for UNSIGNED INT"); \
3080
goto error; \
3081
}
3082
#define CHECK_BIGINT(x, unsigned_input) if ((x) < ((unsigned_input) ? 0 : -9223372036854775808) || (x) > 9223372036854775807) { \
3083
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for BIGINT"); \
3084
goto error; \
3085
}
3086
#define CHECK_UNSIGNED_BIGINT(x, unsigned_input) if ((x) < 0 || (x) > 18446744073709551615) { \
3087
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for UNSIGNED BIGINT"); \
3088
goto error; \
3089
}
3090
#define CHECK_YEAR(x) if (!(((x) >= 0 && (x) <= 99) || ((x) >= 1901 && (x) <= 2155))) { \
3091
PyErr_SetString(PyExc_ValueError, "value is outside the valid range for YEAR"); \
3092
goto error; \
3093
}
3094
3095
switch (returns[i]) {
3096
case MYSQL_TYPE_BIT:
3097
PyErr_SetString(PyExc_ValueError, "unsupported data type: BIT");
3098
goto error;
3099
break;
3100
3101
case MYSQL_TYPE_TINY:
3102
CHECKMEM(1);
3103
switch (col_types[i].type) {
3104
case NUMPY_BOOL:
3105
i8 = *(int8_t*)(cols[i] + j * 1);
3106
CHECK_TINYINT(i8, 0);
3107
i8 = (int8_t)((is_null) ? 0 : i8);
3108
break;
3109
case NUMPY_INT8:
3110
i8 = *(int8_t*)(cols[i] + j * 1);
3111
CHECK_TINYINT(i8, 0);
3112
i8 = (int8_t)((is_null) ? 0 : i8);
3113
break;
3114
case NUMPY_INT16:
3115
i16 = *(int16_t*)(cols[i] + j * 2);
3116
CHECK_TINYINT(i16, 0);
3117
i8 = (int8_t)((is_null) ? 0 : i16);
3118
break;
3119
case NUMPY_INT32:
3120
i32 = *(int32_t*)(cols[i] + j * 4);
3121
CHECK_TINYINT(i32, 0);
3122
i8 = (int8_t)((is_null) ? 0 : i32);
3123
break;
3124
case NUMPY_INT64:
3125
i64 = *(int64_t*)(cols[i] + j * 8);
3126
CHECK_TINYINT(i64, 0);
3127
i8 = (int8_t)((is_null) ? 0 : i64);
3128
break;
3129
case NUMPY_UINT8:
3130
u8 = *(uint8_t*)(cols[i] + j * 1);
3131
CHECK_TINYINT(u8, 1);
3132
i8 = (int8_t)((is_null) ? 0 : u8);
3133
break;
3134
case NUMPY_UINT16:
3135
u16 = *(uint16_t*)(cols[i] + j * 2);
3136
CHECK_TINYINT(u16, 1);
3137
i8 = (int8_t)((is_null) ? 0 : u16);
3138
break;
3139
case NUMPY_UINT32:
3140
u32 = *(uint32_t*)(cols[i] + j * 4);
3141
CHECK_TINYINT(u32, 1);
3142
i8 = (int8_t)((is_null) ? 0 : u32);
3143
break;
3144
case NUMPY_UINT64:
3145
u64 = *(uint64_t*)(cols[i] + j * 8);
3146
CHECK_TINYINT(u64, 1);
3147
i8 = (int8_t)((is_null) ? 0 : u64);
3148
break;
3149
case NUMPY_FLOAT32:
3150
flt = *(float*)(cols[i] + j * 4);
3151
CHECK_TINYINT(flt, 0);
3152
i8 = (int8_t)((is_null) ? 0 : flt);
3153
break;
3154
case NUMPY_FLOAT64:
3155
dbl = *(double*)(cols[i] + j * 8);
3156
CHECK_TINYINT(dbl, 0);
3157
i8 = (int8_t)((is_null) ? 0 : dbl);
3158
break;
3159
default:
3160
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type TINYINT");
3161
goto error;
3162
}
3163
memcpy(out+out_idx, &i8, 1);
3164
out_idx += 1;
3165
break;
3166
3167
// Use negative to indicate unsigned
3168
case -MYSQL_TYPE_TINY:
3169
CHECKMEM(1);
3170
switch (col_types[i].type) {
3171
case NUMPY_BOOL:
3172
i8 = *(int8_t*)(cols[i] + j * 1);
3173
CHECK_UNSIGNED_TINYINT(i8, 0);
3174
u8 = (uint8_t)((is_null) ? 0 : i8);
3175
break;
3176
case NUMPY_INT8:
3177
i8 = *(int8_t*)(cols[i] + j * 1);
3178
CHECK_UNSIGNED_TINYINT(i8, 0);
3179
u8 = (uint8_t)((is_null) ? 0 : i8);
3180
break;
3181
case NUMPY_INT16:
3182
i16 = *(int16_t*)(cols[i] + j * 2);
3183
CHECK_UNSIGNED_TINYINT(i16, 0);
3184
u8 = (uint8_t)((is_null) ? 0 : i16);
3185
break;
3186
case NUMPY_INT32:
3187
i32 = *(int32_t*)(cols[i] + j * 4);
3188
CHECK_UNSIGNED_TINYINT(i32, 0);
3189
u8 = (uint8_t)((is_null) ? 0 : i32);
3190
break;
3191
case NUMPY_INT64:
3192
i64 = *(int64_t*)(cols[i] + j * 8);
3193
CHECK_UNSIGNED_TINYINT(i64, 0);
3194
u8 = (uint8_t)((is_null) ? 0 : i64);
3195
break;
3196
case NUMPY_UINT8:
3197
u8 = *(uint8_t*)(cols[i] + j * 1);
3198
CHECK_UNSIGNED_TINYINT(u8, 1);
3199
u8 = (uint8_t)((is_null) ? 0 : u8);
3200
break;
3201
case NUMPY_UINT16:
3202
u16 = *(uint16_t*)(cols[i] + j * 2);
3203
CHECK_UNSIGNED_TINYINT(u16, 1);
3204
u8 = (uint8_t)((is_null) ? 0 : u16);
3205
break;
3206
case NUMPY_UINT32:
3207
u32 = *(uint32_t*)(cols[i] + j * 4);
3208
CHECK_UNSIGNED_TINYINT(u32, 1);
3209
u8 = (uint8_t)((is_null) ? 0 : u32);
3210
break;
3211
case NUMPY_UINT64:
3212
u64 = *(uint64_t*)(cols[i] + j * 8);
3213
CHECK_UNSIGNED_TINYINT(u64, 1);
3214
u8 = (uint8_t)((is_null) ? 0 : u64);
3215
break;
3216
case NUMPY_FLOAT32:
3217
flt = *(float*)(cols[i] + j * 4);
3218
CHECK_UNSIGNED_TINYINT(flt, 0);
3219
u8 = (uint8_t)((is_null) ? 0 : flt);
3220
break;
3221
case NUMPY_FLOAT64:
3222
dbl = *(double*)(cols[i] + j * 8);
3223
CHECK_UNSIGNED_TINYINT(dbl, 0);
3224
u8 = (uint8_t)((is_null) ? 0 : dbl);
3225
break;
3226
default:
3227
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type UNSIGNED TINYINT");
3228
goto error;
3229
}
3230
memcpy(out+out_idx, &u8, 1);
3231
out_idx += 1;
3232
break;
3233
3234
case MYSQL_TYPE_SHORT:
3235
CHECKMEM(2);
3236
switch (col_types[i].type) {
3237
case NUMPY_BOOL:
3238
i8 = *(int8_t*)(cols[i] + j * 1);
3239
CHECK_SMALLINT(i8, 0);
3240
i16 = (int16_t)((is_null) ? 0 : i8);
3241
break;
3242
case NUMPY_INT8:
3243
i8 = *(int8_t*)(cols[i] + j * 1);
3244
CHECK_SMALLINT(i8, 0);
3245
i16 = (int16_t)((is_null) ? 0 : i8);
3246
break;
3247
case NUMPY_INT16:
3248
i16 = *(int16_t*)(cols[i] + j * 2);
3249
CHECK_SMALLINT(i16, 0);
3250
i16 = (int16_t)((is_null) ? 0 : i16);
3251
break;
3252
case NUMPY_INT32:
3253
i32 = *(int32_t*)(cols[i] + j * 4);
3254
CHECK_SMALLINT(i32, 0);
3255
i16 = (int16_t)((is_null) ? 0 : i32);
3256
break;
3257
case NUMPY_INT64:
3258
i64 = *(int64_t*)(cols[i] + j * 8);
3259
CHECK_SMALLINT(i64, 0);
3260
i16 = (int16_t)((is_null) ? 0 : i64);
3261
break;
3262
case NUMPY_UINT8:
3263
u8 = *(uint8_t*)(cols[i] + j * 1);
3264
CHECK_SMALLINT(u8, 1);
3265
i16 = (int16_t)((is_null) ? 0 : u8);
3266
break;
3267
case NUMPY_UINT16:
3268
u16 = *(uint16_t*)(cols[i] + j * 2);
3269
CHECK_SMALLINT(u16, 1);
3270
i16 = (int16_t)((is_null) ? 0 : u16);
3271
break;
3272
case NUMPY_UINT32:
3273
u32 = *(uint32_t*)(cols[i] + j * 4);
3274
CHECK_SMALLINT(u32, 1);
3275
i16 = (int16_t)((is_null) ? 0 : u32);
3276
break;
3277
case NUMPY_UINT64:
3278
u64 = *(uint64_t*)(cols[i] + j * 8);
3279
CHECK_SMALLINT(u64, 1);
3280
i16 = (int16_t)((is_null) ? 0 : u64);
3281
break;
3282
case NUMPY_FLOAT32:
3283
flt = *(float*)(cols[i] + j * 4);
3284
CHECK_SMALLINT(flt, 0);
3285
i16 = (int16_t)((is_null) ? 0 : flt);
3286
break;
3287
case NUMPY_FLOAT64:
3288
dbl = *(double*)(cols[i] + j * 8);
3289
CHECK_SMALLINT(dbl, 0);
3290
i16 = (int16_t)((is_null) ? 0 : dbl);
3291
break;
3292
default:
3293
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type SMALLINT");
3294
goto error;
3295
}
3296
memcpy(out+out_idx, &i16, 2);
3297
out_idx += 2;
3298
break;
3299
3300
// Use negative to indicate unsigned
3301
case -MYSQL_TYPE_SHORT:
3302
CHECKMEM(2);
3303
switch (col_types[i].type) {
3304
case NUMPY_BOOL:
3305
i8 = *(int8_t*)(cols[i] + j * 1);
3306
CHECK_UNSIGNED_SMALLINT(i8, 0);
3307
u16 = (uint16_t)((is_null) ? 0 : i8);
3308
break;
3309
case NUMPY_INT8:
3310
i8 = *(int8_t*)(cols[i] + j * 1);
3311
CHECK_UNSIGNED_SMALLINT(i8, 0);
3312
u16 = (uint16_t)((is_null) ? 0 : i8);
3313
break;
3314
case NUMPY_INT16:
3315
i16 = *(int16_t*)(cols[i] + j * 2);
3316
CHECK_UNSIGNED_SMALLINT(i16, 0);
3317
u16 = (uint16_t)((is_null) ? 0 : i16);
3318
break;
3319
case NUMPY_INT32:
3320
i32 = *(int32_t*)(cols[i] + j * 4);
3321
CHECK_UNSIGNED_SMALLINT(i32, 0);
3322
u16 = (uint16_t)((is_null) ? 0 : i32);
3323
break;
3324
case NUMPY_INT64:
3325
i64 = *(int64_t*)(cols[i] + j * 8);
3326
CHECK_UNSIGNED_SMALLINT(i64, 0);
3327
u16 = (uint16_t)((is_null) ? 0 : i64);
3328
break;
3329
case NUMPY_UINT8:
3330
u8 = *(uint8_t*)(cols[i] + j * 1);
3331
CHECK_UNSIGNED_SMALLINT(u8, 1);
3332
u16 = (uint16_t)((is_null) ? 0 : u8);
3333
break;
3334
case NUMPY_UINT16:
3335
u16 = *(uint16_t*)(cols[i] + j * 2);
3336
CHECK_UNSIGNED_SMALLINT(u16, 1);
3337
u16 = (uint16_t)((is_null) ? 0 : u16);
3338
break;
3339
case NUMPY_UINT32:
3340
u32 = *(uint32_t*)(cols[i] + j * 4);
3341
CHECK_UNSIGNED_SMALLINT(u32, 1);
3342
u16 = (uint16_t)((is_null) ? 0 : u32);
3343
break;
3344
case NUMPY_UINT64:
3345
u64 = *(uint64_t*)(cols[i] + j * 8);
3346
CHECK_UNSIGNED_SMALLINT(u64, 1);
3347
u16 = (uint16_t)((is_null) ? 0 : u64);
3348
break;
3349
case NUMPY_FLOAT32:
3350
flt = *(float*)(cols[i] + j * 4);
3351
CHECK_UNSIGNED_SMALLINT(flt, 0);
3352
u16 = (uint16_t)((is_null) ? 0 : flt);
3353
break;
3354
case NUMPY_FLOAT64:
3355
dbl = *(double*)(cols[i] + j * 8);
3356
CHECK_UNSIGNED_SMALLINT(dbl, 0);
3357
u16 = (uint16_t)((is_null) ? 0 : dbl);
3358
break;
3359
default:
3360
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type UNSIGNED MEDIUMINT");
3361
goto error;
3362
}
3363
memcpy(out+out_idx, &u16, 2);
3364
out_idx += 2;
3365
break;
3366
3367
case MYSQL_TYPE_INT24:
3368
CHECKMEM(4);
3369
switch (col_types[i].type) {
3370
case NUMPY_BOOL:
3371
i8 = *(int8_t*)(cols[i] + j * 1);
3372
CHECK_MEDIUMINT(i8, 0);
3373
i32 = (int32_t)((is_null) ? 0 : i8);
3374
break;
3375
case NUMPY_INT8:
3376
i8 = *(int8_t*)(cols[i] + j * 1);
3377
CHECK_MEDIUMINT(i8, 0);
3378
i32 = (int32_t)((is_null) ? 0 : i8);
3379
break;
3380
case NUMPY_INT16:
3381
i16 = *(int16_t*)(cols[i] + j * 2);
3382
CHECK_MEDIUMINT(i16, 0);
3383
i32 = (int32_t)((is_null) ? 0 : i16);
3384
break;
3385
case NUMPY_INT32:
3386
i32 = *(int32_t*)(cols[i] + j * 4);
3387
CHECK_MEDIUMINT(i32, 0);
3388
i32 = (int32_t)((is_null) ? 0 : i32);
3389
break;
3390
case NUMPY_INT64:
3391
i64 = *(int64_t*)(cols[i] + j * 8);
3392
CHECK_MEDIUMINT(i64, 0);
3393
i32 = (int32_t)((is_null) ? 0 : i64);
3394
break;
3395
case NUMPY_UINT8:
3396
u8 = *(uint8_t*)(cols[i] + j * 1);
3397
CHECK_MEDIUMINT(u8, 1);
3398
i32 = (int32_t)((is_null) ? 0 : u8);
3399
break;
3400
case NUMPY_UINT16:
3401
u16 = *(uint16_t*)(cols[i] + j * 2);
3402
CHECK_MEDIUMINT(u16, 1);
3403
i32 = (int32_t)((is_null) ? 0 : u16);
3404
break;
3405
case NUMPY_UINT32:
3406
u32 = *(uint32_t*)(cols[i] + j * 4);
3407
CHECK_MEDIUMINT(u32, 1);
3408
i32 = (int32_t)((is_null) ? 0 : u32);
3409
break;
3410
case NUMPY_UINT64:
3411
u64 = *(uint64_t*)(cols[i] + j * 8);
3412
CHECK_MEDIUMINT(u64, 1);
3413
i32 = (int32_t)((is_null) ? 0 : u64);
3414
break;
3415
case NUMPY_FLOAT32:
3416
flt = *(float*)(cols[i] + j * 4);
3417
CHECK_MEDIUMINT(flt, 0);
3418
i32 = (int32_t)((is_null) ? 0 : flt);
3419
break;
3420
case NUMPY_FLOAT64:
3421
dbl = *(double*)(cols[i] + j * 8);
3422
CHECK_MEDIUMINT(dbl, 0);
3423
i32 = (int32_t)((is_null) ? 0 : dbl);
3424
break;
3425
default:
3426
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type MEDIUMINT");
3427
goto error;
3428
}
3429
memcpy(out+out_idx, &i32, 4);
3430
out_idx += 4;
3431
break;
3432
3433
case MYSQL_TYPE_LONG:
3434
CHECKMEM(4);
3435
switch (col_types[i].type) {
3436
case NUMPY_BOOL:
3437
i8 = *(int8_t*)(cols[i] + j * 1);
3438
CHECK_INT(i8, 0);
3439
i32 = (int32_t)((is_null) ? 0 : i8);
3440
break;
3441
case NUMPY_INT8:
3442
i8 = *(int8_t*)(cols[i] + j * 1);
3443
CHECK_INT(i8, 0);
3444
i32 = (int32_t)((is_null) ? 0 : i8);
3445
break;
3446
case NUMPY_INT16:
3447
i16 = *(int16_t*)(cols[i] + j * 2);
3448
CHECK_INT(i16, 0);
3449
i32 = (int32_t)((is_null) ? 0 : i16);
3450
break;
3451
case NUMPY_INT32:
3452
i32 = *(int32_t*)(cols[i] + j * 4);
3453
CHECK_INT(i32, 0);
3454
i32 = (int32_t)((is_null) ? 0 : i32);
3455
break;
3456
case NUMPY_INT64:
3457
i64 = *(int64_t*)(cols[i] + j * 8);
3458
CHECK_INT(i64, 0);
3459
i32 = (int32_t)((is_null) ? 0 : i64);
3460
break;
3461
case NUMPY_UINT8:
3462
u8 = *(uint8_t*)(cols[i] + j * 1);
3463
CHECK_INT(u8, 1);
3464
i32 = (int32_t)((is_null) ? 0 : u8);
3465
break;
3466
case NUMPY_UINT16:
3467
u16 = *(uint16_t*)(cols[i] + j * 2);
3468
CHECK_INT(u16, 1);
3469
i32 = (int32_t)((is_null) ? 0 : u16);
3470
break;
3471
case NUMPY_UINT32:
3472
u32 = *(uint32_t*)(cols[i] + j * 4);
3473
CHECK_INT(u32, 1);
3474
i32 = (int32_t)((is_null) ? 0 : u32);
3475
break;
3476
case NUMPY_UINT64:
3477
u64 = *(uint64_t*)(cols[i] + j * 8);
3478
CHECK_INT(u64, 1);
3479
i32 = (int32_t)((is_null) ? 0 : u64);
3480
break;
3481
case NUMPY_FLOAT32:
3482
flt = *(float*)(cols[i] + j * 4);
3483
CHECK_INT(flt, 0);
3484
i32 = (int32_t)((is_null) ? 0 : flt);
3485
break;
3486
case NUMPY_FLOAT64:
3487
dbl = *(double*)(cols[i] + j * 8);
3488
CHECK_INT(dbl, 0);
3489
i32 = (int32_t)((is_null) ? 0 : dbl);
3490
break;
3491
default:
3492
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type INT");
3493
goto error;
3494
}
3495
memcpy(out+out_idx, &i32, 4);
3496
out_idx += 4;
3497
break;
3498
3499
// Use negative to indicate unsigned
3500
case -MYSQL_TYPE_INT24:
3501
CHECKMEM(4);
3502
switch (col_types[i].type) {
3503
case NUMPY_BOOL:
3504
i8 = *(int8_t*)(cols[i] + j * 1);
3505
CHECK_UNSIGNED_MEDIUMINT(i8, 0);
3506
u32 = (uint32_t)((is_null) ? 0 : i8);
3507
break;
3508
case NUMPY_INT8:
3509
i8 = *(int8_t*)(cols[i] + j * 1);
3510
CHECK_UNSIGNED_MEDIUMINT(i8, 0);
3511
u32 = (uint32_t)((is_null) ? 0 : i8);
3512
break;
3513
case NUMPY_INT16:
3514
i16 = *(int16_t*)(cols[i] + j * 2);
3515
CHECK_UNSIGNED_MEDIUMINT(i16, 0);
3516
u32 = (uint32_t)((is_null) ? 0 : i16);
3517
break;
3518
case NUMPY_INT32:
3519
i32 = *(int32_t*)(cols[i] + j * 4);
3520
CHECK_UNSIGNED_MEDIUMINT(i32, 0);
3521
u32 = (uint32_t)((is_null) ? 0 : i32);
3522
break;
3523
case NUMPY_INT64:
3524
i64 = *(int64_t*)(cols[i] + j * 8);
3525
CHECK_UNSIGNED_MEDIUMINT(i64, 0);
3526
u32 = (uint32_t)((is_null) ? 0 : i64);
3527
break;
3528
case NUMPY_UINT8:
3529
u8 = *(uint8_t*)(cols[i] + j * 1);
3530
CHECK_UNSIGNED_MEDIUMINT(u8, 1);
3531
u32 = (uint32_t)((is_null) ? 0 : u8);
3532
break;
3533
case NUMPY_UINT16:
3534
u16 = *(uint16_t*)(cols[i] + j * 2);
3535
CHECK_UNSIGNED_MEDIUMINT(u16, 1);
3536
u32 = (uint32_t)((is_null) ? 0 : u16);
3537
break;
3538
case NUMPY_UINT32:
3539
u32 = *(uint32_t*)(cols[i] + j * 4);
3540
CHECK_UNSIGNED_MEDIUMINT(u32, 1);
3541
u32 = (uint32_t)((is_null) ? 0 : u32);
3542
break;
3543
case NUMPY_UINT64:
3544
u64 = *(uint64_t*)(cols[i] + j * 8);
3545
CHECK_UNSIGNED_MEDIUMINT(u64, 1);
3546
u32 = (uint32_t)((is_null) ? 0 : u64);
3547
break;
3548
case NUMPY_FLOAT32:
3549
flt = *(float*)(cols[i] + j * 4);
3550
CHECK_UNSIGNED_MEDIUMINT(flt, 0);
3551
u32 = (uint32_t)((is_null) ? 0 : flt);
3552
break;
3553
case NUMPY_FLOAT64:
3554
dbl = *(double*)(cols[i] + j * 8);
3555
CHECK_UNSIGNED_MEDIUMINT(dbl, 0);
3556
u32 = (uint32_t)((is_null) ? 0 : dbl);
3557
break;
3558
default:
3559
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type UNSIGNED MEDIUMINT");
3560
goto error;
3561
}
3562
memcpy(out+out_idx, &u32, 4);
3563
out_idx += 4;
3564
break;
3565
3566
// Use negative to indicate unsigned
3567
case -MYSQL_TYPE_LONG:
3568
CHECKMEM(4);
3569
switch (col_types[i].type) {
3570
case NUMPY_BOOL:
3571
i8 = *(int8_t*)(cols[i] + j * 1);
3572
CHECK_UNSIGNED_INT(i8, 0);
3573
u32 = (uint32_t)((is_null) ? 0 : i8);
3574
break;
3575
case NUMPY_INT8:
3576
i8 = *(int8_t*)(cols[i] + j * 1);
3577
CHECK_UNSIGNED_INT(i8, 0);
3578
u32 = (uint32_t)((is_null) ? 0 : i8);
3579
break;
3580
case NUMPY_INT16:
3581
i16 = *(int16_t*)(cols[i] + j * 2);
3582
CHECK_UNSIGNED_INT(i16, 0);
3583
u32 = (uint32_t)((is_null) ? 0 : i16);
3584
break;
3585
case NUMPY_INT32:
3586
i32 = *(int32_t*)(cols[i] + j * 4);
3587
CHECK_UNSIGNED_INT(i32, 0);
3588
u32 = (uint32_t)((is_null) ? 0 : i32);
3589
break;
3590
case NUMPY_INT64:
3591
i64 = *(int64_t*)(cols[i] + j * 8);
3592
CHECK_UNSIGNED_INT(i64, 0);
3593
u32 = (uint32_t)((is_null) ? 0 : i64);
3594
break;
3595
case NUMPY_UINT8:
3596
u8 = *(uint8_t*)(cols[i] + j * 1);
3597
CHECK_UNSIGNED_INT(u8, 1);
3598
u32 = (uint32_t)((is_null) ? 0 : u8);
3599
break;
3600
case NUMPY_UINT16:
3601
u16 = *(uint16_t*)(cols[i] + j * 2);
3602
CHECK_UNSIGNED_INT(u16, 1);
3603
u32 = (uint32_t)((is_null) ? 0 : u16);
3604
break;
3605
case NUMPY_UINT32:
3606
u32 = *(uint32_t*)(cols[i] + j * 4);
3607
CHECK_UNSIGNED_INT(u32, 1);
3608
u32 = (uint32_t)((is_null) ? 0 : u32);
3609
break;
3610
case NUMPY_UINT64:
3611
u64 = *(uint64_t*)(cols[i] + j * 8);
3612
CHECK_UNSIGNED_INT(u64, 1);
3613
u32 = (uint32_t)((is_null) ? 0 : u64);
3614
break;
3615
case NUMPY_FLOAT32:
3616
flt = *(float*)(cols[i] + j * 4);
3617
CHECK_UNSIGNED_INT(flt, 0);
3618
u32 = (uint32_t)((is_null) ? 0 : flt);
3619
break;
3620
case NUMPY_FLOAT64:
3621
dbl = *(double*)(cols[i] + j * 8);
3622
CHECK_UNSIGNED_INT(dbl, 0);
3623
u32 = (uint32_t)((is_null) ? 0 : dbl);
3624
break;
3625
default:
3626
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type UNSIGNED INT");
3627
goto error;
3628
}
3629
memcpy(out+out_idx, &u32, 4);
3630
out_idx += 4;
3631
break;
3632
3633
case MYSQL_TYPE_LONGLONG:
3634
CHECKMEM(8);
3635
switch (col_types[i].type) {
3636
case NUMPY_BOOL:
3637
i8 = *(int8_t*)(cols[i] + j * 1);
3638
CHECK_BIGINT(i8, 0);
3639
i64 = (int64_t)((is_null) ? 0 : i8);
3640
break;
3641
case NUMPY_INT8:
3642
i8 = *(int8_t*)(cols[i] + j * 1);
3643
CHECK_BIGINT(i8, 0);
3644
i64 = (int64_t)((is_null) ? 0 : i8);
3645
break;
3646
case NUMPY_INT16:
3647
i16 = *(int16_t*)(cols[i] + j * 2);
3648
CHECK_BIGINT(i16, 0);
3649
i64 = (int64_t)((is_null) ? 0 : i16);
3650
break;
3651
case NUMPY_INT32:
3652
i32 = *(int32_t*)(cols[i] + j * 4);
3653
CHECK_BIGINT(i32, 0);
3654
i64 = (int64_t)((is_null) ? 0 : i32);
3655
break;
3656
case NUMPY_INT64:
3657
i64 = *(int64_t*)(cols[i] + j * 8);
3658
CHECK_BIGINT(i64, 0);
3659
i64 = (int64_t)((is_null) ? 0 : i64);
3660
break;
3661
case NUMPY_UINT8:
3662
u8 = *(uint8_t*)(cols[i] + j * 1);
3663
CHECK_BIGINT(u8, 1);
3664
i64 = (int64_t)((is_null) ? 0 : u8);
3665
break;
3666
case NUMPY_UINT16:
3667
u16 = *(uint16_t*)(cols[i] + j * 2);
3668
CHECK_BIGINT(u16, 1);
3669
i64 = (int64_t)((is_null) ? 0 : u16);
3670
break;
3671
case NUMPY_UINT32:
3672
u32 = *(uint32_t*)(cols[i] + j * 4);
3673
CHECK_BIGINT(u32, 1);
3674
i64 = (int64_t)((is_null) ? 0 : u32);
3675
break;
3676
case NUMPY_UINT64:
3677
u64 = *(uint64_t*)(cols[i] + j * 8);
3678
CHECK_BIGINT(u64, 1);
3679
i64 = (int64_t)((is_null) ? 0 : u64);
3680
break;
3681
case NUMPY_FLOAT32:
3682
flt = *(float*)(cols[i] + j * 4);
3683
CHECK_BIGINT(flt, 0);
3684
i64 = (int64_t)((is_null) ? 0 : flt);
3685
break;
3686
case NUMPY_FLOAT64:
3687
dbl = *(double*)(cols[i] + j * 8);
3688
CHECK_BIGINT(dbl, 0);
3689
i64 = (int64_t)((is_null) ? 0 : dbl);
3690
break;
3691
default:
3692
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type BIGINT");
3693
goto error;
3694
}
3695
memcpy(out+out_idx, &i64, 8);
3696
out_idx += 8;
3697
break;
3698
3699
// Use negative to indicate unsigned
3700
case -MYSQL_TYPE_LONGLONG:
3701
CHECKMEM(8);
3702
switch (col_types[i].type) {
3703
case NUMPY_BOOL:
3704
i8 = *(int8_t*)(cols[i] + j * 1);
3705
CHECK_UNSIGNED_BIGINT(i8, 0);
3706
u64 = (uint64_t)((is_null) ? 0 : i8);
3707
break;
3708
case NUMPY_INT8:
3709
i8 = *(int8_t*)(cols[i] + j * 1);
3710
CHECK_UNSIGNED_BIGINT(i8, 0);
3711
u64 = (uint64_t)((is_null) ? 0 : i8);
3712
break;
3713
case NUMPY_INT16:
3714
i16 = *(int16_t*)(cols[i] + j * 2);
3715
CHECK_UNSIGNED_BIGINT(i16, 0);
3716
u64 = (uint64_t)((is_null) ? 0 : i16);
3717
break;
3718
case NUMPY_INT32:
3719
i32 = *(int32_t*)(cols[i] + j * 4);
3720
CHECK_UNSIGNED_BIGINT(i32, 0);
3721
u64 = (uint64_t)((is_null) ? 0 : i32);
3722
break;
3723
case NUMPY_INT64:
3724
i64 = *(int64_t*)(cols[i] + j * 8);
3725
CHECK_UNSIGNED_BIGINT(i64, 0);
3726
u64 = (uint64_t)((is_null) ? 0 : i64);
3727
break;
3728
case NUMPY_UINT8:
3729
u8 = *(uint8_t*)(cols[i] + j * 1);
3730
CHECK_UNSIGNED_BIGINT(u8, 1);
3731
u64 = (uint64_t)((is_null) ? 0 : u8);
3732
break;
3733
case NUMPY_UINT16:
3734
u16 = *(uint16_t*)(cols[i] + j * 2);
3735
CHECK_UNSIGNED_BIGINT(u16, 1);
3736
u64 = (uint64_t)((is_null) ? 0 : u16);
3737
break;
3738
case NUMPY_UINT32:
3739
u32 = *(uint32_t*)(cols[i] + j * 4);
3740
CHECK_UNSIGNED_BIGINT(u32, 1);
3741
u64 = (uint64_t)((is_null) ? 0 : u32);
3742
break;
3743
case NUMPY_UINT64:
3744
u64 = *(uint64_t*)(cols[i] + j * 8);
3745
CHECK_UNSIGNED_BIGINT(u64, 1);
3746
u64 = (uint64_t)((is_null) ? 0 : u64);
3747
break;
3748
case NUMPY_FLOAT32:
3749
flt = *(float*)(cols[i] + j * 4);
3750
CHECK_UNSIGNED_BIGINT(flt, 0);
3751
u64 = (uint64_t)((is_null) ? 0 : flt);
3752
break;
3753
case NUMPY_FLOAT64:
3754
dbl = *(double*)(cols[i] + j * 8);
3755
CHECK_UNSIGNED_BIGINT(dbl, 0);
3756
u64 = (uint64_t)((is_null) ? 0 : dbl);
3757
break;
3758
default:
3759
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type UNSIGNED BIGINT");
3760
goto error;
3761
}
3762
memcpy(out+out_idx, &u64, 8);
3763
out_idx += 8;
3764
break;
3765
3766
case MYSQL_TYPE_FLOAT:
3767
CHECKMEM(4);
3768
switch (col_types[i].type) {
3769
case NUMPY_BOOL:
3770
flt = (float)((is_null) ? 0 : *(int8_t*)(cols[i] + j * 1));
3771
break;
3772
case NUMPY_INT8:
3773
flt = (float)((is_null) ? 0 : *(int8_t*)(cols[i] + j * 1));
3774
break;
3775
case NUMPY_INT16:
3776
flt = (float)((is_null) ? 0 : *(int16_t*)(cols[i] + j * 2));
3777
break;
3778
case NUMPY_INT32:
3779
flt = (float)((is_null) ? 0 : *(int32_t*)(cols[i] + j * 4));
3780
break;
3781
case NUMPY_INT64:
3782
flt = (float)((is_null) ? 0 : *(int64_t*)(cols[i] + j * 8));
3783
break;
3784
case NUMPY_UINT8:
3785
flt = (float)((is_null) ? 0 : *(uint8_t*)(cols[i] + j * 1));
3786
break;
3787
case NUMPY_UINT16:
3788
flt = (float)((is_null) ? 0 : *(uint16_t*)(cols[i] + j * 2));
3789
break;
3790
case NUMPY_UINT32:
3791
flt = (float)((is_null) ? 0 : *(uint32_t*)(cols[i] + j * 4));
3792
break;
3793
case NUMPY_UINT64:
3794
flt = (float)((is_null) ? 0 : *(uint64_t*)(cols[i] + j * 8));
3795
break;
3796
case NUMPY_FLOAT32:
3797
flt = (float)((is_null) ? 0 : *(float*)(cols[i] + j * 4));
3798
break;
3799
case NUMPY_FLOAT64:
3800
flt = (float)((is_null) ? 0 : *(double*)(cols[i] + j * 8));
3801
break;
3802
default:
3803
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type FLOAT");
3804
goto error;
3805
}
3806
memcpy(out+out_idx, &flt, 4);
3807
out_idx += 4;
3808
break;
3809
3810
case MYSQL_TYPE_DOUBLE:
3811
CHECKMEM(8);
3812
switch (col_types[i].type) {
3813
case NUMPY_BOOL:
3814
dbl = (double)((is_null) ? 0 : *(int8_t*)(cols[i] + j * 1));
3815
break;
3816
case NUMPY_INT8:
3817
dbl = (double)((is_null) ? 0 : *(int8_t*)(cols[i] + j * 1));
3818
break;
3819
case NUMPY_INT16:
3820
dbl = (double)((is_null) ? 0 : *(int16_t*)(cols[i] + j * 2));
3821
break;
3822
case NUMPY_INT32:
3823
dbl = (double)((is_null) ? 0 : *(int32_t*)(cols[i] + j * 4));
3824
break;
3825
case NUMPY_INT64:
3826
dbl = (double)((is_null) ? 0 : *(int64_t*)(cols[i] + j * 8));
3827
break;
3828
case NUMPY_UINT8:
3829
dbl = (double)((is_null) ? 0 : *(uint8_t*)(cols[i] + j * 1));
3830
break;
3831
case NUMPY_UINT16:
3832
dbl = (double)((is_null) ? 0 : *(uint16_t*)(cols[i] + j * 2));
3833
break;
3834
case NUMPY_UINT32:
3835
dbl = (double)((is_null) ? 0 : *(uint32_t*)(cols[i] + j * 4));
3836
break;
3837
case NUMPY_UINT64:
3838
dbl = (double)((is_null) ? 0 : *(uint64_t*)(cols[i] + j * 8));
3839
break;
3840
case NUMPY_FLOAT32:
3841
dbl = (double)((is_null) ? 0 : *(float*)(cols[i] + j * 4));
3842
break;
3843
case NUMPY_FLOAT64:
3844
dbl = (double)((is_null) ? 0 : *(double*)(cols[i] + j * 8));
3845
break;
3846
default:
3847
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type FLOAT");
3848
goto error;
3849
}
3850
memcpy(out+out_idx, &dbl, 8);
3851
out_idx += 8;
3852
break;
3853
3854
case MYSQL_TYPE_DECIMAL:
3855
// TODO
3856
PyErr_SetString(PyExc_ValueError, "unsupported data type: DECIMAL");
3857
goto error;
3858
break;
3859
3860
case MYSQL_TYPE_DATE:
3861
case MYSQL_TYPE_NEWDATE:
3862
// TODO
3863
PyErr_SetString(PyExc_ValueError, "unsupported data type: DATE");
3864
goto error;
3865
break;
3866
3867
case MYSQL_TYPE_TIME:
3868
// TODO
3869
PyErr_SetString(PyExc_ValueError, "unsupported data type: TIME");
3870
goto error;
3871
break;
3872
3873
case MYSQL_TYPE_DATETIME:
3874
// TODO
3875
PyErr_SetString(PyExc_ValueError, "unsupported data type: DATETIME");
3876
goto error;
3877
break;
3878
3879
case MYSQL_TYPE_TIMESTAMP:
3880
// TODO
3881
PyErr_SetString(PyExc_ValueError, "unsupported data type: TIMESTAMP");
3882
goto error;
3883
break;
3884
3885
case MYSQL_TYPE_YEAR:
3886
CHECKMEM(2);
3887
switch (col_types[i].type) {
3888
case NUMPY_BOOL:
3889
i8 = *(int8_t*)(cols[i] + j * 1);
3890
CHECK_YEAR(i8);
3891
i16 = (int16_t)((is_null) ? 0 : i8);
3892
break;
3893
case NUMPY_INT8:
3894
i8 = *(int8_t*)(cols[i] + j * 1);
3895
CHECK_YEAR(i8);
3896
i16 = (int16_t)((is_null) ? 0 : i8);
3897
break;
3898
case NUMPY_INT16:
3899
i16 = *(int16_t*)(cols[i] + j * 2);
3900
CHECK_YEAR(i16);
3901
i16 = (int16_t)((is_null) ? 0 : i16);
3902
break;
3903
case NUMPY_INT32:
3904
i32 = *(int32_t*)(cols[i] + j * 4);
3905
CHECK_YEAR(i32);
3906
i16 = (int16_t)((is_null) ? 0 : i32);
3907
break;
3908
case NUMPY_INT64:
3909
i64 = *(int64_t*)(cols[i] + j * 8);
3910
CHECK_YEAR(i64);
3911
i16 = (int16_t)((is_null) ? 0 : i64);
3912
break;
3913
case NUMPY_UINT8:
3914
u8 = *(uint8_t*)(cols[i] + j * 1);
3915
CHECK_YEAR(u8);
3916
i16 = (int16_t)((is_null) ? 0 : u8);
3917
break;
3918
case NUMPY_UINT16:
3919
u16 = *(uint16_t*)(cols[i] + j * 2);
3920
CHECK_YEAR(u16);
3921
i16 = (int16_t)((is_null) ? 0 : u16);
3922
break;
3923
case NUMPY_UINT32:
3924
u32 = *(uint32_t*)(cols[i] + j * 4);
3925
CHECK_YEAR(u32);
3926
i16 = (int16_t)((is_null) ? 0 : u32);
3927
break;
3928
case NUMPY_UINT64:
3929
u64 = *(uint64_t*)(cols[i] + j * 8);
3930
CHECK_YEAR(u64);
3931
i16 = (int16_t)((is_null) ? 0 : u64);
3932
break;
3933
case NUMPY_FLOAT32:
3934
flt = *(float*)(cols[i] + j * 4);
3935
CHECK_YEAR(flt);
3936
i16 = (int16_t)((is_null) ? 0 : flt);
3937
break;
3938
case NUMPY_FLOAT64:
3939
dbl = *(double*)(cols[i] + j * 8);
3940
CHECK_YEAR(dbl);
3941
i16 = (int16_t)((is_null) ? 0 : dbl);
3942
break;
3943
default:
3944
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for output type YEAR");
3945
goto error;
3946
}
3947
memcpy(out+out_idx, &i16, 2);
3948
out_idx += 2;
3949
break;
3950
3951
case MYSQL_TYPE_VARCHAR:
3952
case MYSQL_TYPE_JSON:
3953
case MYSQL_TYPE_SET:
3954
case MYSQL_TYPE_ENUM:
3955
case MYSQL_TYPE_VAR_STRING:
3956
case MYSQL_TYPE_STRING:
3957
case MYSQL_TYPE_GEOMETRY:
3958
case MYSQL_TYPE_TINY_BLOB:
3959
case MYSQL_TYPE_MEDIUM_BLOB:
3960
case MYSQL_TYPE_LONG_BLOB:
3961
case MYSQL_TYPE_BLOB:
3962
if (col_types[i].type != NUMPY_OBJECT && col_types[i].type != NUMPY_FIXED_STRING) {
3963
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for character output types");
3964
goto error;
3965
}
3966
3967
if (is_null) {
3968
CHECKMEM(8);
3969
i64 = 0;
3970
memcpy(out+out_idx, &i64, 8);
3971
out_idx += 8;
3972
3973
} else if (col_types[i].type == NUMPY_FIXED_STRING) {
3974
// Jump to col_types[i].length * 4 for UCS4 fixed length string
3975
void *bytes = (void*)(cols[i] + j * col_types[i].length * 4);
3976
3977
if (bytes == NULL) {
3978
CHECKMEM(8);
3979
i64 = 0;
3980
memcpy(out+out_idx, &i64, 8);
3981
out_idx += 8;
3982
} else {
3983
char *utf8_str = NULL;
3984
Py_ssize_t str_l = ucs4_to_utf8(bytes, col_types[i].length, &utf8_str);
3985
if (str_l < 0) {
3986
PyErr_SetString(PyExc_ValueError, "invalid UCS4 string");
3987
if (utf8_str) free(utf8_str);
3988
goto error;
3989
}
3990
str_l = strnlen(utf8_str, str_l);
3991
CHECKMEM(8+str_l);
3992
i64 = str_l;
3993
memcpy(out+out_idx, &i64, 8);
3994
out_idx += 8;
3995
memcpy(out+out_idx, utf8_str, str_l);
3996
out_idx += str_l;
3997
free(utf8_str);
3998
}
3999
4000
} else {
4001
u64 = *(uint64_t*)(cols[i] + j * 8);
4002
4003
PyObject *py_str = (PyObject*)u64;
4004
if (!py_str) goto error;
4005
4006
if (py_str == Py_None) {
4007
CHECKMEM(8);
4008
i64 = 0;
4009
memcpy(out+out_idx, &i64, 8);
4010
out_idx += 8;
4011
} else {
4012
PyObject *py_bytes = PyUnicode_AsEncodedString(py_str, "utf-8", "strict");
4013
if (!py_bytes) goto error;
4014
4015
char *str = NULL;
4016
Py_ssize_t str_l = 0;
4017
if (PyBytes_AsStringAndSize(py_bytes, &str, &str_l) < 0) {
4018
Py_DECREF(py_bytes);
4019
goto error;
4020
}
4021
4022
CHECKMEM(8+str_l);
4023
i64 = str_l;
4024
memcpy(out+out_idx, &i64, 8);
4025
out_idx += 8;
4026
memcpy(out+out_idx, str, str_l);
4027
out_idx += str_l;
4028
Py_DECREF(py_bytes);
4029
}
4030
}
4031
break;
4032
4033
// Use negative to indicate binary
4034
case -MYSQL_TYPE_VARCHAR:
4035
case -MYSQL_TYPE_JSON:
4036
case -MYSQL_TYPE_SET:
4037
case -MYSQL_TYPE_ENUM:
4038
case -MYSQL_TYPE_VAR_STRING:
4039
case -MYSQL_TYPE_STRING:
4040
case -MYSQL_TYPE_GEOMETRY:
4041
case -MYSQL_TYPE_TINY_BLOB:
4042
case -MYSQL_TYPE_MEDIUM_BLOB:
4043
case -MYSQL_TYPE_LONG_BLOB:
4044
case -MYSQL_TYPE_BLOB:
4045
if (col_types[i].type != NUMPY_OBJECT && col_types[i].type != NUMPY_BYTES) {
4046
PyErr_SetString(PyExc_ValueError, "unsupported numpy data type for binary output types");
4047
goto error;
4048
}
4049
4050
if (is_null) {
4051
CHECKMEM(8);
4052
i64 = 0;
4053
memcpy(out+out_idx, &i64, 8);
4054
out_idx += 8;
4055
4056
} else if (col_types[i].type == NUMPY_BYTES) {
4057
void *bytes = (void*)(cols[i] + j * col_types[i].length);
4058
4059
if (bytes == NULL) {
4060
CHECKMEM(8);
4061
i64 = 0;
4062
memcpy(out+out_idx, &i64, 8);
4063
out_idx += 8;
4064
} else {
4065
Py_ssize_t str_l = col_types[i].length;
4066
CHECKMEM(8+str_l);
4067
4068
str_l = length_without_trailing_nulls(bytes, str_l);
4069
4070
i64 = str_l;
4071
memcpy(out+out_idx, &i64, 8);
4072
out_idx += 8;
4073
memcpy(out+out_idx, bytes, str_l);
4074
out_idx += str_l;
4075
}
4076
4077
} else {
4078
u64 = *(uint64_t*)(cols[i] + j * 8);
4079
4080
PyObject *py_bytes = (PyObject*)u64;
4081
4082
if (py_bytes == Py_None) {
4083
CHECKMEM(8);
4084
i64 = 0;
4085
memcpy(out+out_idx, &i64, 8);
4086
out_idx += 8;
4087
} else {
4088
char *str = NULL;
4089
Py_ssize_t str_l = 0;
4090
if (PyBytes_AsStringAndSize(py_bytes, &str, &str_l) < 0) {
4091
goto error;
4092
}
4093
4094
CHECKMEM(8+str_l);
4095
i64 = str_l;
4096
memcpy(out+out_idx, &i64, 8);
4097
out_idx += 8;
4098
memcpy(out+out_idx, str, str_l);
4099
out_idx += str_l;
4100
}
4101
}
4102
break;
4103
4104
default:
4105
PyErr_Format(PyExc_ValueError, "unrecognized database data type: %d", returns[i]);
4106
goto error;
4107
}
4108
}
4109
}
4110
4111
py_out = PyBytes_FromStringAndSize(out, out_idx);
4112
4113
exit:
4114
if (out) free(out);
4115
if (returns) free(returns);
4116
if (masks) free(masks);
4117
if (cols) free(cols);
4118
if (col_types) free(col_types);
4119
4120
return py_out;
4121
4122
error:
4123
Py_XDECREF(py_out);
4124
py_out = NULL;
4125
4126
goto exit;
4127
}
4128
4129
4130
static PyObject *load_rowdat_1(PyObject *self, PyObject *args, PyObject *kwargs) {
4131
PyObject *py_data = NULL;
4132
PyObject *py_out = NULL;
4133
PyObject *py_out_row_ids = NULL;
4134
PyObject *py_out_rows = NULL;
4135
PyObject *py_row = NULL;
4136
PyObject *py_colspec = NULL;
4137
PyObject *py_str = NULL;
4138
PyObject *py_blob = NULL;
4139
Py_ssize_t length = 0;
4140
uint64_t row_id = 0;
4141
uint8_t is_null = 0;
4142
int8_t i8 = 0;
4143
int16_t i16 = 0;
4144
int32_t i32 = 0;
4145
int64_t i64 = 0;
4146
uint8_t u8 = 0;
4147
uint16_t u16 = 0;
4148
uint32_t u32 = 0;
4149
uint64_t u64 = 0;
4150
float flt = 0;
4151
double dbl = 0;
4152
int *ctypes = NULL;
4153
char *data = NULL;
4154
char *end = NULL;
4155
unsigned long long colspec_l = 0;
4156
unsigned long long i = 0;
4157
char *keywords[] = {"colspec", "data", NULL};
4158
4159
// Parse function args.
4160
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", keywords, &py_colspec, &py_data)) {
4161
goto error;
4162
}
4163
4164
CHECKRC(PyBytes_AsStringAndSize(py_data, &data, &length));
4165
end = data + (unsigned long long)length;
4166
4167
colspec_l = PyObject_Length(py_colspec);
4168
ctypes = malloc(sizeof(int) * colspec_l);
4169
4170
for (i = 0; i < colspec_l; i++) {
4171
PyObject *py_cspec = PySequence_GetItem(py_colspec, i);
4172
if (!py_cspec) goto error;
4173
PyObject *py_ctype = PySequence_GetItem(py_cspec, 1);
4174
if (!py_ctype) { Py_DECREF(py_cspec); goto error; }
4175
ctypes[i] = (int)PyLong_AsLong(py_ctype);
4176
Py_DECREF(py_ctype);
4177
Py_DECREF(py_cspec);
4178
if (PyErr_Occurred()) { goto error; }
4179
}
4180
4181
py_out_row_ids = PyList_New(0);
4182
if (!py_out_row_ids) goto error;
4183
4184
py_out_rows = PyList_New(0);
4185
if (!py_out_rows) { Py_DECREF(py_out_row_ids); goto error; }
4186
4187
py_out = PyTuple_New(2);
4188
if (!py_out) { Py_DECREF(py_out_row_ids); Py_DECREF(py_out_rows); goto error; }
4189
4190
if (PyTuple_SetItem(py_out, 0, py_out_row_ids) < 0) {
4191
Py_DECREF(py_out_row_ids);
4192
Py_DECREF(py_out_rows);
4193
goto error;
4194
}
4195
4196
if (PyTuple_SetItem(py_out, 1, py_out_rows) < 0) {
4197
Py_DECREF(py_out_rows);
4198
goto error;
4199
}
4200
4201
while (end > data) {
4202
py_row = PyTuple_New(colspec_l);
4203
if (!py_row) goto error;
4204
4205
row_id = *(int64_t*)data; data += 8;
4206
CHECKRC(PyList_Append(py_out_row_ids, PyLong_FromLongLong(row_id)));
4207
4208
for (unsigned long long i = 0; i < colspec_l; i++) {
4209
is_null = data[0] == '\x01'; data += 1;
4210
if (is_null) Py_INCREF(Py_None);
4211
4212
switch (ctypes[i]) {
4213
case MYSQL_TYPE_NULL:
4214
data += 1;
4215
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4216
Py_INCREF(Py_None);
4217
break;
4218
4219
case MYSQL_TYPE_BIT:
4220
// TODO
4221
break;
4222
4223
case MYSQL_TYPE_TINY:
4224
i8 = *(int8_t*)data; data += 1;
4225
if (is_null) {
4226
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4227
Py_INCREF(Py_None);
4228
} else {
4229
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromLong((long)i8)));
4230
}
4231
break;
4232
4233
// Use negative to indicate unsigned
4234
case -MYSQL_TYPE_TINY:
4235
u8 = *(uint8_t*)data; data += 1;
4236
if (is_null) {
4237
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4238
Py_INCREF(Py_None);
4239
} else {
4240
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromUnsignedLong((unsigned long)u8)));
4241
}
4242
break;
4243
4244
case MYSQL_TYPE_SHORT:
4245
i16 = *(int16_t*)data; data += 2;
4246
if (is_null) {
4247
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4248
Py_INCREF(Py_None);
4249
} else {
4250
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromLong((long)i16)));
4251
}
4252
break;
4253
4254
// Use negative to indicate unsigned
4255
case -MYSQL_TYPE_SHORT:
4256
u16 = *(uint16_t*)data; data += 2;
4257
if (is_null) {
4258
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4259
Py_INCREF(Py_None);
4260
} else {
4261
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromUnsignedLong((unsigned long)u16)));
4262
}
4263
break;
4264
4265
case MYSQL_TYPE_LONG:
4266
case MYSQL_TYPE_INT24:
4267
i32 = *(int32_t*)data; data += 4;
4268
if (is_null) {
4269
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4270
Py_INCREF(Py_None);
4271
} else {
4272
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromLong((long)i32)));
4273
}
4274
break;
4275
4276
// Use negative to indicate unsigned
4277
case -MYSQL_TYPE_LONG:
4278
case -MYSQL_TYPE_INT24:
4279
u32 = *(uint32_t*)data; data += 4;
4280
if (is_null) {
4281
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4282
Py_INCREF(Py_None);
4283
} else {
4284
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromUnsignedLong((unsigned long)u32)));
4285
}
4286
break;
4287
4288
case MYSQL_TYPE_LONGLONG:
4289
i64 = *(int64_t*)data; data += 8;
4290
if (is_null) {
4291
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4292
Py_INCREF(Py_None);
4293
} else {
4294
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromLongLong((long long)i64)));
4295
}
4296
break;
4297
4298
// Use negative to indicate unsigned
4299
case -MYSQL_TYPE_LONGLONG:
4300
u64 = *(uint64_t*)data; data += 8;
4301
if (is_null) {
4302
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4303
Py_INCREF(Py_None);
4304
} else {
4305
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromUnsignedLongLong((unsigned long long)u64)));
4306
}
4307
break;
4308
4309
case MYSQL_TYPE_FLOAT:
4310
flt = *(float*)data; data += 4;
4311
if (is_null) {
4312
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4313
Py_INCREF(Py_None);
4314
} else {
4315
CHECKRC(PyTuple_SetItem(py_row, i, PyFloat_FromDouble((double)flt)));
4316
}
4317
break;
4318
4319
case MYSQL_TYPE_DOUBLE:
4320
dbl = *(double*)data; data += 8;
4321
if (is_null) {
4322
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4323
Py_INCREF(Py_None);
4324
} else {
4325
CHECKRC(PyTuple_SetItem(py_row, i, PyFloat_FromDouble((double)dbl)));
4326
}
4327
break;
4328
4329
case MYSQL_TYPE_DECIMAL:
4330
case MYSQL_TYPE_NEWDECIMAL:
4331
// TODO
4332
break;
4333
4334
case MYSQL_TYPE_DATE:
4335
case MYSQL_TYPE_NEWDATE:
4336
// TODO
4337
break;
4338
4339
case MYSQL_TYPE_TIME:
4340
// TODO
4341
break;
4342
4343
case MYSQL_TYPE_DATETIME:
4344
// TODO
4345
break;
4346
4347
case MYSQL_TYPE_TIMESTAMP:
4348
// TODO
4349
break;
4350
4351
case MYSQL_TYPE_YEAR:
4352
u16 = *(uint16_t*)data; data += 2;
4353
if (is_null) {
4354
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4355
Py_INCREF(Py_None);
4356
} else {
4357
CHECKRC(PyTuple_SetItem(py_row, i, PyLong_FromUnsignedLong((unsigned long)u16)));
4358
}
4359
break;
4360
4361
case MYSQL_TYPE_VARCHAR:
4362
case MYSQL_TYPE_JSON:
4363
case MYSQL_TYPE_SET:
4364
case MYSQL_TYPE_ENUM:
4365
case MYSQL_TYPE_VAR_STRING:
4366
case MYSQL_TYPE_STRING:
4367
case MYSQL_TYPE_GEOMETRY:
4368
case MYSQL_TYPE_TINY_BLOB:
4369
case MYSQL_TYPE_MEDIUM_BLOB:
4370
case MYSQL_TYPE_LONG_BLOB:
4371
case MYSQL_TYPE_BLOB:
4372
i64 = *(int64_t*)data; data += 8;
4373
if (is_null) {
4374
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4375
Py_INCREF(Py_None);
4376
} else {
4377
py_str = PyUnicode_FromStringAndSize(data, (Py_ssize_t)i64);
4378
data += i64;
4379
if (!py_str) goto error;
4380
CHECKRC(PyTuple_SetItem(py_row, i, py_str));
4381
}
4382
break;
4383
4384
// Use negative to indicate binary
4385
case -MYSQL_TYPE_VARCHAR:
4386
case -MYSQL_TYPE_JSON:
4387
case -MYSQL_TYPE_SET:
4388
case -MYSQL_TYPE_ENUM:
4389
case -MYSQL_TYPE_VAR_STRING:
4390
case -MYSQL_TYPE_STRING:
4391
case -MYSQL_TYPE_GEOMETRY:
4392
case -MYSQL_TYPE_TINY_BLOB:
4393
case -MYSQL_TYPE_MEDIUM_BLOB:
4394
case -MYSQL_TYPE_LONG_BLOB:
4395
case -MYSQL_TYPE_BLOB:
4396
i64 = *(int64_t*)data; data += 8;
4397
if (is_null) {
4398
CHECKRC(PyTuple_SetItem(py_row, i, Py_None));
4399
Py_INCREF(Py_None);
4400
} else {
4401
py_blob = PyBytes_FromStringAndSize(data, (Py_ssize_t)i64);
4402
data += i64;
4403
if (!py_blob) goto error;
4404
CHECKRC(PyTuple_SetItem(py_row, i, py_blob));
4405
}
4406
break;
4407
4408
default:
4409
goto error;
4410
}
4411
}
4412
4413
CHECKRC(PyList_Append(py_out_rows, py_row));
4414
Py_DECREF(py_row);
4415
py_row = NULL;
4416
}
4417
4418
exit:
4419
if (ctypes) free(ctypes);
4420
4421
Py_XDECREF(py_row);
4422
4423
return py_out;
4424
4425
error:
4426
Py_XDECREF(py_out);
4427
py_out = NULL;
4428
4429
goto exit;
4430
}
4431
4432
4433
static PyObject *dump_rowdat_1(PyObject *self, PyObject *args, PyObject *kwargs) {
4434
PyObject *py_returns = NULL;
4435
PyObject *py_rows = NULL;
4436
PyObject *py_out = NULL;
4437
PyObject *py_rows_iter = NULL;
4438
PyObject *py_row = NULL;
4439
PyObject *py_row_iter = NULL;
4440
PyObject *py_row_ids = NULL;
4441
PyObject *py_row_ids_iter = NULL;
4442
PyObject *py_item = NULL;
4443
uint64_t row_id = 0;
4444
uint8_t is_null = 0;
4445
int8_t i8 = 0;
4446
int16_t i16 = 0;
4447
int32_t i32 = 0;
4448
int64_t i64 = 0;
4449
uint8_t u8 = 0;
4450
uint16_t u16 = 0;
4451
uint32_t u32 = 0;
4452
uint64_t u64 = 0;
4453
float flt = 0;
4454
double dbl = 0;
4455
char *out = NULL;
4456
unsigned long long out_l = 0;
4457
unsigned long long out_idx = 0;
4458
int *returns = NULL;
4459
char *keywords[] = {"returns", "row_ids", "data", NULL};
4460
unsigned long long i = 0;
4461
unsigned long long n_cols = 0;
4462
unsigned long long n_rows = 0;
4463
4464
// Parse function args.
4465
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO", keywords, &py_returns, &py_row_ids, &py_rows)) {
4466
goto error;
4467
}
4468
4469
n_rows = (unsigned long long)PyObject_Length(py_rows);
4470
if (n_rows == 0) {
4471
py_out = PyBytes_FromStringAndSize("", 0);
4472
goto exit;
4473
}
4474
4475
// Starting size, it will be resized later
4476
out_l = 256 * n_rows;
4477
out_idx = 0;
4478
out = malloc(out_l);
4479
if (!out) goto error;
4480
4481
// Get return types
4482
n_cols = (unsigned long long)PyObject_Length(py_returns);
4483
if (n_cols == 0) {
4484
PyErr_SetString(PyExc_ValueError, "no return values specified");
4485
goto error;
4486
}
4487
4488
returns = malloc(sizeof(int) * n_cols);
4489
if (!returns) goto error;
4490
4491
for (i = 0; i < n_cols; i++) {
4492
PyObject *py_item = PySequence_GetItem(py_returns, i);
4493
if (!py_item) goto error;
4494
returns[i] = (int)PyLong_AsLong(py_item);
4495
Py_DECREF(py_item);
4496
if (PyErr_Occurred()) { goto error; }
4497
}
4498
4499
#define CHECKMEM(x) \
4500
if ((out_idx + x) > out_l) { \
4501
out_l = out_l * 2 + x; \
4502
char *new_out = realloc(out, out_l); \
4503
if (!new_out) { \
4504
PyErr_SetString(PyExc_MemoryError, "failed to reallocate output buffer"); \
4505
goto error; \
4506
} \
4507
out = new_out; \
4508
}
4509
4510
py_rows_iter = PyObject_GetIter(py_rows);
4511
if (!py_rows_iter) goto error;
4512
4513
py_row_ids_iter = PyObject_GetIter(py_row_ids);
4514
if (!py_row_ids_iter) goto error;
4515
4516
while ((py_row = PyIter_Next(py_rows_iter))) {
4517
py_row_iter = PyObject_GetIter(py_row);
4518
if (!py_row_iter) {
4519
Py_DECREF(py_row);
4520
goto error;
4521
}
4522
4523
// First item is always a row ID
4524
py_item = PyIter_Next(py_row_ids_iter);
4525
if (!py_item) {
4526
Py_DECREF(py_row_iter);
4527
Py_DECREF(py_row);
4528
goto error;
4529
}
4530
row_id = (int64_t)PyLong_AsLongLong(py_item);
4531
Py_DECREF(py_item);
4532
4533
CHECKMEM(8);
4534
memcpy(out+out_idx, &row_id, 8);
4535
out_idx += 8;
4536
4537
i = 0;
4538
4539
while ((py_item = PyIter_Next(py_row_iter))) {
4540
4541
is_null = (uint8_t)(py_item == Py_None);
4542
4543
CHECKMEM(1);
4544
memcpy(out+out_idx, &is_null, 1);
4545
out_idx += 1;
4546
4547
switch (returns[i]) {
4548
case MYSQL_TYPE_BIT:
4549
// TODO
4550
break;
4551
4552
case MYSQL_TYPE_TINY:
4553
CHECKMEM(1);
4554
i8 = (is_null) ? 0 : (int8_t)PyLong_AsLong(py_item);
4555
memcpy(out+out_idx, &i8, 1);
4556
out_idx += 1;
4557
break;
4558
4559
// Use negative to indicate unsigned
4560
case -MYSQL_TYPE_TINY:
4561
CHECKMEM(1);
4562
u8 = (is_null) ? 0 : (uint8_t)PyLong_AsUnsignedLong(py_item);
4563
memcpy(out+out_idx, &u8, 1);
4564
out_idx += 1;
4565
break;
4566
4567
case MYSQL_TYPE_SHORT:
4568
CHECKMEM(2);
4569
i16 = (is_null) ? 0 : (int16_t)PyLong_AsLong(py_item);
4570
memcpy(out+out_idx, &i16, 2);
4571
out_idx += 2;
4572
break;
4573
4574
// Use negative to indicate unsigned
4575
case -MYSQL_TYPE_SHORT:
4576
CHECKMEM(2);
4577
u16 = (is_null) ? 0 : (uint16_t)PyLong_AsUnsignedLong(py_item);
4578
memcpy(out+out_idx, &u16, 2);
4579
out_idx += 2;
4580
break;
4581
4582
case MYSQL_TYPE_LONG:
4583
case MYSQL_TYPE_INT24:
4584
CHECKMEM(4);
4585
i32 = (is_null) ? 0 : (int32_t)PyLong_AsLong(py_item);
4586
memcpy(out+out_idx, &i32, 4);
4587
out_idx += 4;
4588
break;
4589
4590
// Use negative to indicate unsigned
4591
case -MYSQL_TYPE_LONG:
4592
case -MYSQL_TYPE_INT24:
4593
CHECKMEM(4);
4594
u32 = (is_null) ? 0 : (uint32_t)PyLong_AsUnsignedLong(py_item);
4595
memcpy(out+out_idx, &u32, 4);
4596
out_idx += 4;
4597
break;
4598
4599
case MYSQL_TYPE_LONGLONG:
4600
CHECKMEM(8);
4601
i64 = (is_null) ? 0 : (int64_t)PyLong_AsLongLong(py_item);
4602
memcpy(out+out_idx, &i64, 8);
4603
out_idx += 8;
4604
break;
4605
4606
// Use negative to indicate unsigned
4607
case -MYSQL_TYPE_LONGLONG:
4608
CHECKMEM(8);
4609
u64 = (is_null) ? 0 : (uint64_t)PyLong_AsUnsignedLongLong(py_item);
4610
memcpy(out+out_idx, &u64, 8);
4611
out_idx += 8;
4612
break;
4613
4614
case MYSQL_TYPE_FLOAT:
4615
CHECKMEM(4);
4616
flt = (is_null) ? 0 : (float)PyFloat_AsDouble(py_item);
4617
memcpy(out+out_idx, &flt, 4);
4618
out_idx += 4;
4619
break;
4620
4621
case MYSQL_TYPE_DOUBLE:
4622
CHECKMEM(8);
4623
dbl = (is_null) ? 0 : (double)PyFloat_AsDouble(py_item);
4624
memcpy(out+out_idx, &dbl, 8);
4625
out_idx += 8;
4626
break;
4627
4628
case MYSQL_TYPE_DECIMAL:
4629
// TODO
4630
break;
4631
4632
case MYSQL_TYPE_DATE:
4633
case MYSQL_TYPE_NEWDATE:
4634
// TODO
4635
break;
4636
4637
case MYSQL_TYPE_TIME:
4638
// TODO
4639
break;
4640
4641
case MYSQL_TYPE_DATETIME:
4642
// TODO
4643
break;
4644
4645
case MYSQL_TYPE_TIMESTAMP:
4646
// TODO
4647
break;
4648
4649
case MYSQL_TYPE_YEAR:
4650
CHECKMEM(2);
4651
i16 = (is_null) ? 0 : (int16_t)PyLong_AsLong(py_item);
4652
memcpy(out+out_idx, &i16, 2);
4653
out_idx += 2;
4654
break;
4655
4656
case MYSQL_TYPE_VARCHAR:
4657
case MYSQL_TYPE_JSON:
4658
case MYSQL_TYPE_SET:
4659
case MYSQL_TYPE_ENUM:
4660
case MYSQL_TYPE_VAR_STRING:
4661
case MYSQL_TYPE_STRING:
4662
case MYSQL_TYPE_GEOMETRY:
4663
case MYSQL_TYPE_TINY_BLOB:
4664
case MYSQL_TYPE_MEDIUM_BLOB:
4665
case MYSQL_TYPE_LONG_BLOB:
4666
case MYSQL_TYPE_BLOB:
4667
if (is_null) {
4668
CHECKMEM(8);
4669
i64 = 0;
4670
memcpy(out+out_idx, &i64, 8);
4671
out_idx += 8;
4672
} else {
4673
PyObject *py_bytes = PyUnicode_AsEncodedString(py_item, "utf-8", "strict");
4674
if (!py_bytes) {
4675
Py_DECREF(py_item);
4676
goto error;
4677
}
4678
4679
char *str = NULL;
4680
Py_ssize_t str_l = 0;
4681
if (PyBytes_AsStringAndSize(py_bytes, &str, &str_l) < 0) {
4682
Py_DECREF(py_bytes);
4683
Py_DECREF(py_item);
4684
goto error;
4685
}
4686
4687
CHECKMEM(8+str_l);
4688
i64 = str_l;
4689
memcpy(out+out_idx, &i64, 8);
4690
out_idx += 8;
4691
memcpy(out+out_idx, str, str_l);
4692
out_idx += str_l;
4693
Py_DECREF(py_bytes);
4694
}
4695
break;
4696
4697
// Use negative to indicate binary
4698
case -MYSQL_TYPE_VARCHAR:
4699
case -MYSQL_TYPE_JSON:
4700
case -MYSQL_TYPE_SET:
4701
case -MYSQL_TYPE_ENUM:
4702
case -MYSQL_TYPE_VAR_STRING:
4703
case -MYSQL_TYPE_STRING:
4704
case -MYSQL_TYPE_GEOMETRY:
4705
case -MYSQL_TYPE_TINY_BLOB:
4706
case -MYSQL_TYPE_MEDIUM_BLOB:
4707
case -MYSQL_TYPE_LONG_BLOB:
4708
case -MYSQL_TYPE_BLOB:
4709
if (is_null) {
4710
CHECKMEM(8);
4711
i64 = 0;
4712
memcpy(out+out_idx, &i64, 8);
4713
out_idx += 8;
4714
} else {
4715
char *str = NULL;
4716
Py_ssize_t str_l = 0;
4717
if (PyBytes_AsStringAndSize(py_item, &str, &str_l) < 0) {
4718
Py_DECREF(py_item);
4719
goto error;
4720
}
4721
4722
CHECKMEM(8+str_l);
4723
i64 = str_l;
4724
memcpy(out+out_idx, &i64, 8);
4725
out_idx += 8;
4726
memcpy(out+out_idx, str, str_l);
4727
out_idx += str_l;
4728
}
4729
break;
4730
4731
default:
4732
Py_DECREF(py_item);
4733
goto error;
4734
}
4735
4736
Py_DECREF(py_item);
4737
py_item = NULL;
4738
4739
i++;
4740
}
4741
4742
Py_DECREF(py_row_iter);
4743
Py_DECREF(py_row);
4744
py_row_iter = NULL;
4745
py_row = NULL;
4746
}
4747
4748
// Convert the output buffer to a Python bytes object and free the buffer
4749
py_out = PyBytes_FromStringAndSize(out, out_idx);
4750
4751
exit:
4752
if (out) free(out);
4753
if (returns) free(returns);
4754
4755
Py_XDECREF(py_item);
4756
Py_XDECREF(py_row_iter);
4757
Py_XDECREF(py_row_ids_iter);
4758
Py_XDECREF(py_row);
4759
Py_XDECREF(py_rows_iter);
4760
4761
return py_out;
4762
4763
error:
4764
Py_XDECREF(py_out);
4765
py_out = NULL;
4766
4767
goto exit;
4768
}
4769
4770
4771
static PyMethodDef PyMySQLAccelMethods[] = {
4772
{"read_rowdata_packet", (PyCFunction)read_rowdata_packet, METH_VARARGS | METH_KEYWORDS, "PyMySQL row data packet reader"},
4773
{"dump_rowdat_1", (PyCFunction)dump_rowdat_1, METH_VARARGS | METH_KEYWORDS, "ROWDAT_1 formatter for external functions"},
4774
{"load_rowdat_1", (PyCFunction)load_rowdat_1, METH_VARARGS | METH_KEYWORDS, "ROWDAT_1 parser for external functions"},
4775
{"dump_rowdat_1_numpy", (PyCFunction)dump_rowdat_1_numpy, METH_VARARGS | METH_KEYWORDS, "ROWDAT_1 formatter for external functions which takes numpy.arrays"},
4776
{"load_rowdat_1_numpy", (PyCFunction)load_rowdat_1_numpy, METH_VARARGS | METH_KEYWORDS, "ROWDAT_1 parser for external functions which creates numpy.arrays"},
4777
{NULL, NULL, 0, NULL}
4778
};
4779
4780
static struct PyModuleDef _singlestoredb_accelmodule = {
4781
PyModuleDef_HEAD_INIT,
4782
"_singlestoredb_accel",
4783
"PyMySQL row data packet reader accelerator",
4784
-1,
4785
PyMySQLAccelMethods
4786
};
4787
4788
PyMODINIT_FUNC PyInit__singlestoredb_accel(void) {
4789
#ifndef Py_LIMITED_API
4790
PyDateTime_IMPORT;
4791
#endif
4792
4793
StateType = (PyTypeObject*)PyType_FromSpec(&StateType_spec);
4794
if (StateType == NULL || PyType_Ready(StateType) < 0) {
4795
return NULL;
4796
}
4797
4798
// Populate ints
4799
for (int i = 0; i < 62; i++) {
4800
PyInts[i] = PyLong_FromLong(i);
4801
}
4802
4803
PyStr.unbuffered_active = PyUnicode_FromString("unbuffered_active");
4804
PyStr._state = PyUnicode_FromString("_state");
4805
PyStr.affected_rows = PyUnicode_FromString("affected_rows");
4806
PyStr.warning_count = PyUnicode_FromString("warning_count");
4807
PyStr.connection = PyUnicode_FromString("connection");
4808
PyStr.has_next = PyUnicode_FromString("has_next");
4809
PyStr.options = PyUnicode_FromString("options");
4810
PyStr.Decimal = PyUnicode_FromString("Decimal");
4811
PyStr.date = PyUnicode_FromString("date");
4812
PyStr.time = PyUnicode_FromString("time");
4813
PyStr.timedelta = PyUnicode_FromString("timedelta");
4814
PyStr.datetime = PyUnicode_FromString("datetime");
4815
PyStr.loads = PyUnicode_FromString("loads");
4816
PyStr.field_count = PyUnicode_FromString("field_count");
4817
PyStr.converters = PyUnicode_FromString("converters");
4818
PyStr.fields = PyUnicode_FromString("fields");
4819
PyStr.flags = PyUnicode_FromString("flags");
4820
PyStr.scale = PyUnicode_FromString("scale");
4821
PyStr.type_code = PyUnicode_FromString("type_code");
4822
PyStr.name = PyUnicode_FromString("name");
4823
PyStr.table_name = PyUnicode_FromString("table_name");
4824
PyStr._sock = PyUnicode_FromString("_sock");
4825
PyStr.settimeout = PyUnicode_FromString("settimeout");
4826
PyStr._read_timeout = PyUnicode_FromString("_read_timeout");
4827
PyStr._rfile = PyUnicode_FromString("_rfile");
4828
PyStr.read = PyUnicode_FromString("read");
4829
PyStr.x_errno = PyUnicode_FromString("errno");
4830
PyStr._result = PyUnicode_FromString("_result");
4831
PyStr._next_seq_id = PyUnicode_FromString("_next_seq_id");
4832
PyStr.rows = PyUnicode_FromString("rows");
4833
PyStr.namedtuple = PyUnicode_FromString("namedtuple");
4834
PyStr.Row = PyUnicode_FromString("Row");
4835
PyStr.Series = PyUnicode_FromString("Series");
4836
PyStr.array = PyUnicode_FromString("array");
4837
PyStr.vectorize = PyUnicode_FromString("vectorize");
4838
PyStr.DataFrame = PyUnicode_FromString("DataFrame");
4839
PyStr.Table = PyUnicode_FromString("Table");
4840
PyStr.from_pylist = PyUnicode_FromString("from_pylist");
4841
PyStr.int8 = PyUnicode_FromString("int8");
4842
PyStr.int16 = PyUnicode_FromString("int16");
4843
PyStr.int32 = PyUnicode_FromString("int32");
4844
PyStr.int64 = PyUnicode_FromString("int64");
4845
PyStr.float32 = PyUnicode_FromString("float32");
4846
PyStr.float64 = PyUnicode_FromString("float64");
4847
PyStr.unpack = PyUnicode_FromString("unpack");
4848
PyStr.decode = PyUnicode_FromString("decode");
4849
PyStr.frombuffer = PyUnicode_FromString("frombuffer");
4850
4851
PyObject *decimal_mod = PyImport_ImportModule("decimal");
4852
if (!decimal_mod) goto error;
4853
PyObject *datetime_mod = PyImport_ImportModule("datetime");
4854
if (!datetime_mod) goto error;
4855
PyObject *json_mod = PyImport_ImportModule("json");
4856
if (!json_mod) goto error;
4857
PyObject *collections_mod = PyImport_ImportModule("collections");
4858
if (!collections_mod) goto error;
4859
PyObject *struct_mod = PyImport_ImportModule("struct");
4860
if (!struct_mod) goto error;
4861
4862
PyFunc.decimal_Decimal = PyObject_GetAttr(decimal_mod, PyStr.Decimal);
4863
if (!PyFunc.decimal_Decimal) goto error;
4864
PyFunc.datetime_date = PyObject_GetAttr(datetime_mod, PyStr.date);
4865
if (!PyFunc.datetime_date) goto error;
4866
PyFunc.datetime_timedelta = PyObject_GetAttr(datetime_mod, PyStr.timedelta);
4867
if (!PyFunc.datetime_timedelta) goto error;
4868
PyFunc.datetime_time = PyObject_GetAttr(datetime_mod, PyStr.time);
4869
if (!PyFunc.datetime_time) goto error;
4870
PyFunc.datetime_datetime = PyObject_GetAttr(datetime_mod, PyStr.datetime);
4871
if (!PyFunc.datetime_datetime) goto error;
4872
PyFunc.json_loads = PyObject_GetAttr(json_mod, PyStr.loads);
4873
if (!PyFunc.json_loads) goto error;
4874
PyFunc.collections_namedtuple = PyObject_GetAttr(collections_mod, PyStr.namedtuple);
4875
if (!PyFunc.collections_namedtuple) goto error;
4876
PyFunc.struct_unpack = PyObject_GetAttr(struct_mod, PyStr.unpack);
4877
if (!PyFunc.struct_unpack) goto error;
4878
4879
PyObj.namedtuple_kwargs = PyDict_New();
4880
if (!PyObj.namedtuple_kwargs) goto error;
4881
if (PyDict_SetItemString(PyObj.namedtuple_kwargs, "rename", Py_True)) {
4882
goto error;
4883
}
4884
4885
PyObj.create_numpy_array_args = PyTuple_New(1);
4886
if (!PyObj.create_numpy_array_args) goto error;
4887
4888
PyObj.create_numpy_array_kwargs = PyDict_New();
4889
if (!PyObj.create_numpy_array_kwargs) goto error;
4890
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs, "copy", Py_True)) {
4891
goto error;
4892
}
4893
4894
PyObj.create_numpy_array_kwargs_vector[1] = PyDict_New();
4895
if (!PyObj.create_numpy_array_kwargs_vector[1]) goto error;
4896
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs_vector[1], "dtype", PyStr.float32)) {
4897
goto error;
4898
}
4899
PyObj.create_numpy_array_kwargs_vector[2] = PyDict_New();
4900
if (!PyObj.create_numpy_array_kwargs_vector[2]) goto error;
4901
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs_vector[2], "dtype", PyStr.float64)) {
4902
goto error;
4903
}
4904
PyObj.create_numpy_array_kwargs_vector[3] = PyDict_New();
4905
if (!PyObj.create_numpy_array_kwargs_vector[3]) goto error;
4906
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs_vector[3], "dtype", PyStr.int8)) {
4907
goto error;
4908
}
4909
PyObj.create_numpy_array_kwargs_vector[4] = PyDict_New();
4910
if (!PyObj.create_numpy_array_kwargs_vector[4]) goto error;
4911
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs_vector[4], "dtype", PyStr.int16)) {
4912
goto error;
4913
}
4914
PyObj.create_numpy_array_kwargs_vector[5] = PyDict_New();
4915
if (!PyObj.create_numpy_array_kwargs_vector[5]) goto error;
4916
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs_vector[5], "dtype", PyStr.int32)) {
4917
goto error;
4918
}
4919
PyObj.create_numpy_array_kwargs_vector[6] = PyDict_New();
4920
if (!PyObj.create_numpy_array_kwargs_vector[6]) goto error;
4921
if (PyDict_SetItemString(PyObj.create_numpy_array_kwargs_vector[6], "dtype", PyStr.int64)) {
4922
goto error;
4923
}
4924
4925
PyObj.struct_unpack_args = PyTuple_New(2);
4926
if (!PyObj.struct_unpack_args) goto error;
4927
4928
PyObj.bson_decode_args = PyTuple_New(1);
4929
if (!PyObj.bson_decode_args) goto error;
4930
4931
return PyModule_Create(&_singlestoredb_accelmodule);
4932
4933
error:
4934
return NULL;
4935
}
4936
4937