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