1 | /**************************************************************************** |
2 | Copyright (C) 2012 Monty Program AB |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public |
15 | License along with this library; if not see <http://www.gnu.org/licenses> |
16 | or write to the Free Software Foundation, Inc., |
17 | 51 Franklin St., Fifth Floor, Boston, MA 02110, USA |
18 | |
19 | Part of this code includes code from the PHP project which |
20 | is freely available from http://www.php.net |
21 | *****************************************************************************/ |
22 | |
23 | /* The implementation for prepared statements was ported from PHP's mysqlnd |
24 | extension, written by Andrey Hristov, Georg Richter and Ulf Wendel |
25 | |
26 | Original file header: |
27 | +----------------------------------------------------------------------+ |
28 | | PHP Version 5 | |
29 | +----------------------------------------------------------------------+ |
30 | | Copyright (c) 2006-2011 The PHP Group | |
31 | +----------------------------------------------------------------------+ |
32 | | This source file is subject to version 3.01 of the PHP license, | |
33 | | that is bundled with this package in the file LICENSE, and is | |
34 | | available through the world-wide-web at the following url: | |
35 | | http://www.php.net/license/3_01.txt | |
36 | | If you did not receive a copy of the PHP license and are unable to | |
37 | | obtain it through the world-wide-web, please send a note to | |
38 | | license@php.net so we can mail you a copy immediately. | |
39 | +----------------------------------------------------------------------+ |
40 | | Authors: Georg Richter <georg@mysql.com> | |
41 | | Andrey Hristov <andrey@mysql.com> | |
42 | | Ulf Wendel <uwendel@mysql.com> | |
43 | +----------------------------------------------------------------------+ |
44 | */ |
45 | |
46 | #include "ma_global.h" |
47 | #include <ma_sys.h> |
48 | #include <ma_string.h> |
49 | #include <mariadb_ctype.h> |
50 | #include "mysql.h" |
51 | #include <math.h> /* ceil() */ |
52 | |
53 | #ifdef WIN32 |
54 | #include <malloc.h> |
55 | #endif |
56 | |
57 | #define MYSQL_SILENT |
58 | |
59 | /* ranges for C-binding */ |
60 | #define UINT_MAX32 0xFFFFFFFFL |
61 | #define UINT_MAX24 0x00FFFFFF |
62 | #define UINT_MAX16 0xFFFF |
63 | #ifndef INT_MIN8 |
64 | #define INT_MIN8 (~0x7F) |
65 | #define INT_MAX8 0x7F |
66 | #endif |
67 | #define UINT_MAX8 0xFF |
68 | |
69 | #define MAX_DOUBLE_STRING_REP_LENGTH 300 |
70 | #if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) |
71 | #define LONGLONG_MIN ((long long) 0x8000000000000000LL) |
72 | #define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) |
73 | #endif |
74 | |
75 | #if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) |
76 | /* First check for ANSI C99 definition: */ |
77 | #ifdef ULLONG_MAX |
78 | #define ULONGLONG_MAX ULLONG_MAX |
79 | #else |
80 | #define ULONGLONG_MAX ((unsigned long long)(~0ULL)) |
81 | #endif |
82 | #endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ |
83 | |
84 | #define YY_PART_YEAR 70 |
85 | |
86 | MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1]; |
87 | my_bool mysql_ps_subsystem_initialized= 0; |
88 | |
89 | |
90 | #define NUMERIC_TRUNCATION(val,min_range, max_range)\ |
91 | ((((val) > (max_range)) || ((val) < (min_range)) ? 1 : 0)) |
92 | |
93 | |
94 | void ma_bmove_upp(register char *dst, register const char *src, register size_t len) |
95 | { |
96 | while (len-- != 0) *--dst = *--src; |
97 | } |
98 | |
99 | /* {{{ ps_fetch_from_1_to_8_bytes */ |
100 | void ps_fetch_from_1_to_8_bytes(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, |
101 | unsigned char **row, unsigned int byte_count) |
102 | { |
103 | my_bool is_unsigned= test(field->flags & UNSIGNED_FLAG); |
104 | r_param->buffer_length= byte_count; |
105 | switch (byte_count) { |
106 | case 1: |
107 | *(uchar *)r_param->buffer= **row; |
108 | *r_param->error= is_unsigned != r_param->is_unsigned && *(uchar *)r_param->buffer > INT_MAX8; |
109 | break; |
110 | case 2: |
111 | shortstore(r_param->buffer, ((ushort) sint2korr(*row))); |
112 | *r_param->error= is_unsigned != r_param->is_unsigned && *(ushort *)r_param->buffer > INT_MAX16; |
113 | break; |
114 | case 4: |
115 | { |
116 | longstore(r_param->buffer, ((uint32)sint4korr(*row))); |
117 | *r_param->error= is_unsigned != r_param->is_unsigned && *(uint32 *)r_param->buffer > INT_MAX32; |
118 | } |
119 | break; |
120 | case 8: |
121 | { |
122 | ulonglong val= (ulonglong)sint8korr(*row); |
123 | longlongstore(r_param->buffer, val); |
124 | *r_param->error= is_unsigned != r_param->is_unsigned && val > LONGLONG_MAX ; |
125 | } |
126 | break; |
127 | default: |
128 | r_param->buffer_length= 0; |
129 | break; |
130 | } |
131 | (*row)+= byte_count; |
132 | } |
133 | /* }}} */ |
134 | |
135 | static longlong my_atoll(const char *number, const char *end, int *error) |
136 | { |
137 | char buffer[255]; |
138 | longlong llval= 0; |
139 | size_t i; |
140 | *error= 0; |
141 | /* set error at the following conditions: |
142 | - string contains invalid character(s) |
143 | - length > 254 |
144 | - strtoll returns invalid range |
145 | */ |
146 | |
147 | memcpy(buffer, number, MIN((uint)(end - number), 254)); |
148 | buffer[(uint)(end - number)]= 0; |
149 | |
150 | errno= 0; |
151 | #ifdef _MSC_VER |
152 | llval = _strtoi64(buffer, NULL, 10); |
153 | #else |
154 | llval= strtoll(buffer, NULL, 10); |
155 | #endif |
156 | |
157 | /* check size */ |
158 | if ((uint)(end - number) > 254) |
159 | { |
160 | *error= 1; |
161 | return llval; |
162 | } |
163 | |
164 | /* check characters */ |
165 | for (i=0; i < strlen(buffer); i++) |
166 | { |
167 | if ((buffer[i] < '0' || buffer[i] > '9') && !isspace(buffer[i])) |
168 | { |
169 | *error= 1; |
170 | return llval; |
171 | } |
172 | } |
173 | |
174 | /* check strtoll result */ |
175 | if (errno == ERANGE) |
176 | *error= errno; |
177 | return llval; |
178 | } |
179 | |
180 | double my_atod(const char *number, const char *end, int *error) |
181 | { |
182 | double val= 0.0; |
183 | char buffer[255]; |
184 | int len= (int)(end - number); |
185 | |
186 | if (len > 254) |
187 | *error= 1; |
188 | |
189 | len= MIN(len, 254); |
190 | memcpy(&buffer, number, len); |
191 | buffer[len]= '\0'; |
192 | |
193 | val= strtod(buffer, NULL); |
194 | /* if (!*error) |
195 | *error= errno; */ |
196 | return val; |
197 | } |
198 | |
199 | my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm) |
200 | { |
201 | my_bool is_time=0, is_date=0, has_time_frac=0; |
202 | char *p= (char *)str; |
203 | |
204 | if ((p= strchr(str, '-')) && p <= str + length) |
205 | is_date= 1; |
206 | if ((p= strchr(str, ':')) && p <= str + length) |
207 | is_time= 1; |
208 | if ((p= strchr(str, '.')) && p <= str + length) |
209 | has_time_frac= 1; |
210 | |
211 | p= (char *)str; |
212 | |
213 | memset(tm, 0, sizeof(MYSQL_TIME)); |
214 | |
215 | if (is_date) |
216 | { |
217 | sscanf(str, "%d-%d-%d" , &tm->year, &tm->month, &tm->day); |
218 | p= strchr(str, ' '); |
219 | if (!p) |
220 | { |
221 | tm->time_type= MYSQL_TIMESTAMP_DATE; |
222 | return 0; |
223 | } |
224 | } |
225 | if (has_time_frac) |
226 | { |
227 | sscanf(p, "%d:%d:%d.%ld" , &tm->hour, &tm->minute, &tm->second, &tm->second_part); |
228 | tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME; |
229 | return 0; |
230 | } |
231 | if (is_time) |
232 | { |
233 | sscanf(p, "%d:%d:%d" , &tm->hour, &tm->minute, &tm->second); |
234 | tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME; |
235 | return 0; |
236 | } |
237 | return 1; |
238 | } |
239 | |
240 | |
241 | static void convert_froma_string(MYSQL_BIND *r_param, char *buffer, size_t len) |
242 | { |
243 | int error= 0; |
244 | switch (r_param->buffer_type) |
245 | { |
246 | case MYSQL_TYPE_TINY: |
247 | { |
248 | longlong val= my_atoll(buffer, buffer + len, &error); |
249 | *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8) || error > 0; |
250 | int1store(r_param->buffer, (uchar) val); |
251 | r_param->buffer_length= sizeof(uchar); |
252 | } |
253 | break; |
254 | case MYSQL_TYPE_YEAR: |
255 | case MYSQL_TYPE_SHORT: |
256 | { |
257 | longlong val= my_atoll(buffer, buffer + len, &error); |
258 | *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16) || error > 0; |
259 | shortstore(r_param->buffer, (short)val); |
260 | r_param->buffer_length= sizeof(short); |
261 | } |
262 | break; |
263 | case MYSQL_TYPE_LONG: |
264 | { |
265 | longlong val= my_atoll(buffer, buffer + len, &error); |
266 | *r_param->error=error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32) || error > 0; |
267 | longstore(r_param->buffer, (int32)val); |
268 | r_param->buffer_length= sizeof(uint32); |
269 | } |
270 | break; |
271 | case MYSQL_TYPE_LONGLONG: |
272 | { |
273 | longlong val= my_atoll(buffer, buffer + len, &error); |
274 | *r_param->error= error > 0; /* no need to check for truncation */ |
275 | longlongstore(r_param->buffer, val); |
276 | r_param->buffer_length= sizeof(longlong); |
277 | } |
278 | break; |
279 | case MYSQL_TYPE_DOUBLE: |
280 | { |
281 | double val= my_atod(buffer, buffer + len, &error); |
282 | *r_param->error= error > 0; /* no need to check for truncation */ |
283 | doublestore((uchar *)r_param->buffer, val); |
284 | r_param->buffer_length= sizeof(double); |
285 | } |
286 | break; |
287 | case MYSQL_TYPE_FLOAT: |
288 | { |
289 | float val= (float)my_atod(buffer, buffer + len, &error); |
290 | *r_param->error= error > 0; /* no need to check for truncation */ |
291 | floatstore((uchar *)r_param->buffer, val); |
292 | r_param->buffer_length= sizeof(float); |
293 | } |
294 | break; |
295 | case MYSQL_TYPE_TIME: |
296 | case MYSQL_TYPE_DATE: |
297 | case MYSQL_TYPE_DATETIME: |
298 | case MYSQL_TYPE_TIMESTAMP: |
299 | { |
300 | MYSQL_TIME *tm= (MYSQL_TIME *)r_param->buffer; |
301 | str_to_TIME(buffer, len, tm); |
302 | break; |
303 | } |
304 | break; |
305 | case MYSQL_TYPE_TINY_BLOB: |
306 | case MYSQL_TYPE_MEDIUM_BLOB: |
307 | case MYSQL_TYPE_LONG_BLOB: |
308 | case MYSQL_TYPE_BLOB: |
309 | case MYSQL_TYPE_DECIMAL: |
310 | case MYSQL_TYPE_NEWDECIMAL: |
311 | default: |
312 | { |
313 | char *start= buffer + r_param->offset; /* stmt_fetch_column sets offset */ |
314 | char *end= buffer + len; |
315 | size_t copylen= 0; |
316 | |
317 | if (start < end) |
318 | { |
319 | copylen= end - start; |
320 | if (r_param->buffer_length) |
321 | memcpy(r_param->buffer, start, MIN(copylen, r_param->buffer_length)); |
322 | } |
323 | if (copylen < r_param->buffer_length) |
324 | ((char *)r_param->buffer)[copylen]= 0; |
325 | *r_param->error= (copylen > r_param->buffer_length); |
326 | |
327 | *r_param->length= (ulong)len; |
328 | } |
329 | break; |
330 | } |
331 | } |
332 | |
333 | static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, longlong val, my_bool is_unsigned) |
334 | { |
335 | switch (r_param->buffer_type) { |
336 | case MYSQL_TYPE_TINY: |
337 | *(uchar *)r_param->buffer= (uchar)val; |
338 | *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8); |
339 | r_param->buffer_length= 1; |
340 | break; |
341 | case MYSQL_TYPE_SHORT: |
342 | case MYSQL_TYPE_YEAR: |
343 | shortstore(r_param->buffer, (short)val); |
344 | *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16); |
345 | r_param->buffer_length= 2; |
346 | break; |
347 | case MYSQL_TYPE_LONG: |
348 | longstore(r_param->buffer, (int32)val); |
349 | *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32); |
350 | r_param->buffer_length= 4; |
351 | break; |
352 | case MYSQL_TYPE_LONGLONG: |
353 | *r_param->error= (val < 0 && r_param->is_unsigned != is_unsigned); |
354 | longlongstore(r_param->buffer, val); |
355 | r_param->buffer_length= 8; |
356 | break; |
357 | case MYSQL_TYPE_DOUBLE: |
358 | { |
359 | volatile double dbl; |
360 | |
361 | dbl= (is_unsigned) ? ulonglong2double((ulonglong)val) : (double)val; |
362 | doublestore(r_param->buffer, dbl); |
363 | |
364 | *r_param->error = (dbl != ceil(dbl)) || |
365 | (is_unsigned ? (ulonglong )dbl != (ulonglong)val : |
366 | (longlong)dbl != (longlong)val); |
367 | |
368 | r_param->buffer_length= 8; |
369 | break; |
370 | } |
371 | case MYSQL_TYPE_FLOAT: |
372 | { |
373 | float fval; |
374 | fval= is_unsigned ? (float)(ulonglong)(val) : (float)val; |
375 | floatstore((uchar *)r_param->buffer, fval); |
376 | *r_param->error= (fval != ceilf(fval)) || |
377 | (is_unsigned ? (ulonglong)fval != (ulonglong)val : |
378 | (longlong)fval != val); |
379 | r_param->buffer_length= 4; |
380 | } |
381 | break; |
382 | default: |
383 | { |
384 | char *buffer; |
385 | char *endptr; |
386 | uint len; |
387 | |
388 | buffer= alloca(MAX(field->length, 22)); |
389 | endptr= ma_ll2str(val, buffer, is_unsigned ? 10 : -10); |
390 | len= (uint)(endptr - buffer); |
391 | |
392 | /* check if field flag is zerofill */ |
393 | if (field->flags & ZEROFILL_FLAG && |
394 | len < field->length && len < r_param->buffer_length) |
395 | { |
396 | ma_bmove_upp(buffer + field->length, buffer + len, len); |
397 | memset((char*) buffer, '0', field->length - len); |
398 | len= field->length; |
399 | } |
400 | convert_froma_string(r_param, buffer, len); |
401 | } |
402 | break; |
403 | } |
404 | } |
405 | |
406 | |
407 | /* {{{ ps_fetch_null */ |
408 | static |
409 | void ps_fetch_null(MYSQL_BIND *r_param __attribute__((unused)), |
410 | const MYSQL_FIELD * field __attribute__((unused)), |
411 | unsigned char **row __attribute__((unused))) |
412 | { |
413 | /* do nothing */ |
414 | } |
415 | /* }}} */ |
416 | |
417 | #define GET_LVALUE_FROM_ROW(is_unsigned, data, ucast, scast)\ |
418 | (is_unsigned) ? (longlong)(ucast) *(longlong *)(data) : (longlong)(scast) *(longlong *)(data) |
419 | /* {{{ ps_fetch_int8 */ |
420 | static |
421 | void ps_fetch_int8(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, |
422 | unsigned char **row) |
423 | { |
424 | switch(r_param->buffer_type) { |
425 | case MYSQL_TYPE_TINY: |
426 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 1); |
427 | break; |
428 | default: |
429 | { |
430 | uchar val= **row; |
431 | longlong lval= field->flags & UNSIGNED_FLAG ? (longlong) val : (longlong)(signed char)val; |
432 | convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); |
433 | (*row) += 1; |
434 | } |
435 | break; |
436 | } |
437 | } |
438 | /* }}} */ |
439 | |
440 | |
441 | /* {{{ ps_fetch_int16 */ |
442 | static |
443 | void ps_fetch_int16(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, |
444 | unsigned char **row) |
445 | { |
446 | switch (r_param->buffer_type) { |
447 | case MYSQL_TYPE_YEAR: |
448 | case MYSQL_TYPE_SHORT: |
449 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 2); |
450 | break; |
451 | default: |
452 | { |
453 | short sval= sint2korr(*row); |
454 | longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ushort) sval : (longlong)sval; |
455 | convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); |
456 | (*row) += 2; |
457 | } |
458 | break; |
459 | } |
460 | } |
461 | /* }}} */ |
462 | |
463 | |
464 | /* {{{ ps_fetch_int32 */ |
465 | static |
466 | void ps_fetch_int32(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, |
467 | unsigned char **row) |
468 | { |
469 | switch (r_param->buffer_type) { |
470 | /* case MYSQL_TYPE_TINY: |
471 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 1); |
472 | break; |
473 | case MYSQL_TYPE_YEAR: |
474 | case MYSQL_TYPE_SHORT: |
475 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 2); |
476 | break; */ |
477 | case MYSQL_TYPE_INT24: |
478 | case MYSQL_TYPE_LONG: |
479 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 4); |
480 | break; |
481 | default: |
482 | { |
483 | int32 sval= sint4korr(*row); |
484 | longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(uint32) sval : (longlong)sval; |
485 | convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); |
486 | (*row) += 4; |
487 | } |
488 | break; |
489 | } |
490 | } |
491 | /* }}} */ |
492 | |
493 | |
494 | /* {{{ ps_fetch_int64 */ |
495 | static |
496 | void ps_fetch_int64(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, |
497 | unsigned char **row) |
498 | { |
499 | switch(r_param->buffer_type) |
500 | { |
501 | /* case MYSQL_TYPE_TINY: |
502 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 1); |
503 | break; |
504 | case MYSQL_TYPE_YEAR: |
505 | case MYSQL_TYPE_SHORT: |
506 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 2); |
507 | break; |
508 | case MYSQL_TYPE_INT24: |
509 | case MYSQL_TYPE_LONG: |
510 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 4); |
511 | break; */ |
512 | case MYSQL_TYPE_LONGLONG: |
513 | ps_fetch_from_1_to_8_bytes(r_param, field, row, 8); |
514 | break; |
515 | default: |
516 | { |
517 | longlong sval= (longlong)sint8korr(*row); |
518 | longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ulonglong) sval : (longlong)sval; |
519 | convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); |
520 | (*row) += 8; |
521 | } |
522 | break; |
523 | } |
524 | } |
525 | /* }}} */ |
526 | |
527 | static void convert_from_float(MYSQL_BIND *r_param, const MYSQL_FIELD *field, float val, int size __attribute__((unused))) |
528 | { |
529 | double check_trunc_val= (val > 0) ? floor(val) : -floor(-val); |
530 | char *buf= (char *)r_param->buffer; |
531 | switch (r_param->buffer_type) |
532 | { |
533 | case MYSQL_TYPE_TINY: |
534 | *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val; |
535 | *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) : |
536 | (double)((int8)*buf)); |
537 | r_param->buffer_length= 1; |
538 | break; |
539 | case MYSQL_TYPE_SHORT: |
540 | case MYSQL_TYPE_YEAR: |
541 | { |
542 | if (r_param->is_unsigned) |
543 | { |
544 | ushort sval= (ushort)val; |
545 | shortstore(buf, sval); |
546 | *r_param->error= check_trunc_val != (double)sval; |
547 | } else { |
548 | short sval= (short)val; |
549 | shortstore(buf, sval); |
550 | *r_param->error= check_trunc_val != (double)sval; |
551 | } |
552 | r_param->buffer_length= 2; |
553 | } |
554 | break; |
555 | case MYSQL_TYPE_LONG: |
556 | { |
557 | if (r_param->is_unsigned) |
558 | { |
559 | uint32 lval= (uint32)val; |
560 | longstore(buf, lval); |
561 | *r_param->error= (check_trunc_val != (double)lval); |
562 | } else { |
563 | int32 lval= (int32)val; |
564 | longstore(buf, lval); |
565 | *r_param->error= (check_trunc_val != (double)lval); |
566 | } |
567 | r_param->buffer_length= 4; |
568 | } |
569 | break; |
570 | case MYSQL_TYPE_LONGLONG: |
571 | { |
572 | if (r_param->is_unsigned) |
573 | { |
574 | ulonglong llval= (ulonglong)val; |
575 | longlongstore(buf, llval); |
576 | *r_param->error= (check_trunc_val != (double)llval); |
577 | } else { |
578 | longlong llval= (longlong)val; |
579 | longlongstore(buf, llval); |
580 | *r_param->error= (check_trunc_val != (double)llval); |
581 | } |
582 | r_param->buffer_length= 8; |
583 | } |
584 | break; |
585 | case MYSQL_TYPE_DOUBLE: |
586 | { |
587 | double dval= (double)val; |
588 | memcpy(buf, &dval, sizeof(double)); |
589 | r_param->buffer_length= 8; |
590 | } |
591 | break; |
592 | default: |
593 | { |
594 | char buff[MAX_DOUBLE_STRING_REP_LENGTH]; |
595 | size_t length; |
596 | |
597 | length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length); |
598 | |
599 | if (field->decimals >= NOT_FIXED_DEC) |
600 | { |
601 | length= ma_gcvt(val, MY_GCVT_ARG_FLOAT, (int)length, buff, NULL); |
602 | } |
603 | else |
604 | { |
605 | length= ma_fcvt(val, field->decimals, buff, NULL); |
606 | } |
607 | |
608 | /* check if ZEROFILL flag is active */ |
609 | if (field->flags & ZEROFILL_FLAG) |
610 | { |
611 | /* enough space available ? */ |
612 | if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1) |
613 | break; |
614 | ma_bmove_upp(buff + field->length, buff + length, length); |
615 | memset((char*) buff, '0', field->length - length); |
616 | length= field->length; |
617 | } |
618 | |
619 | convert_froma_string(r_param, buff, length); |
620 | } |
621 | break; |
622 | } |
623 | } |
624 | |
625 | static void convert_from_double(MYSQL_BIND *r_param, const MYSQL_FIELD *field, double val, int size __attribute__((unused))) |
626 | { |
627 | double check_trunc_val= (val > 0) ? floor(val) : -floor(-val); |
628 | char *buf= (char *)r_param->buffer; |
629 | switch (r_param->buffer_type) |
630 | { |
631 | case MYSQL_TYPE_TINY: |
632 | *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val; |
633 | *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) : |
634 | (double)((int8)*buf)); |
635 | r_param->buffer_length= 1; |
636 | break; |
637 | case MYSQL_TYPE_SHORT: |
638 | case MYSQL_TYPE_YEAR: |
639 | { |
640 | if (r_param->is_unsigned) |
641 | { |
642 | ushort sval= (ushort)val; |
643 | shortstore(buf, sval); |
644 | *r_param->error= check_trunc_val != (double)sval; |
645 | } else { |
646 | short sval= (short)val; |
647 | shortstore(buf, sval); |
648 | *r_param->error= check_trunc_val != (double)sval; |
649 | } |
650 | r_param->buffer_length= 2; |
651 | } |
652 | break; |
653 | case MYSQL_TYPE_LONG: |
654 | { |
655 | if (r_param->is_unsigned) |
656 | { |
657 | uint32 lval= (uint32)val; |
658 | longstore(buf, lval); |
659 | *r_param->error= (check_trunc_val != (double)lval); |
660 | } else { |
661 | int32 lval= (int32)val; |
662 | longstore(buf, lval); |
663 | *r_param->error= (check_trunc_val != (double)lval); |
664 | } |
665 | r_param->buffer_length= 4; |
666 | } |
667 | break; |
668 | case MYSQL_TYPE_LONGLONG: |
669 | { |
670 | if (r_param->is_unsigned) |
671 | { |
672 | ulonglong llval= (ulonglong)val; |
673 | longlongstore(buf, llval); |
674 | *r_param->error= (check_trunc_val != (double)llval); |
675 | } else { |
676 | longlong llval= (longlong)val; |
677 | longlongstore(buf, llval); |
678 | *r_param->error= (check_trunc_val != (double)llval); |
679 | } |
680 | r_param->buffer_length= 8; |
681 | } |
682 | break; |
683 | case MYSQL_TYPE_FLOAT: |
684 | { |
685 | float fval= (float)val; |
686 | memcpy(buf, &fval, sizeof(float)); |
687 | *r_param->error= (*(float*)buf != fval); |
688 | r_param->buffer_length= 4; |
689 | } |
690 | break; |
691 | default: |
692 | { |
693 | char buff[MAX_DOUBLE_STRING_REP_LENGTH]; |
694 | size_t length; |
695 | |
696 | length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length); |
697 | |
698 | if (field->decimals >= NOT_FIXED_DEC) |
699 | { |
700 | length= ma_gcvt(val, MY_GCVT_ARG_DOUBLE, (int)length, buff, NULL); |
701 | } |
702 | else |
703 | { |
704 | length= ma_fcvt(val, field->decimals, buff, NULL); |
705 | } |
706 | |
707 | /* check if ZEROFILL flag is active */ |
708 | if (field->flags & ZEROFILL_FLAG) |
709 | { |
710 | /* enough space available ? */ |
711 | if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1) |
712 | break; |
713 | ma_bmove_upp(buff + field->length, buff + length, length); |
714 | memset((char*) buff, '0', field->length - length); |
715 | length= field->length; |
716 | } |
717 | convert_froma_string(r_param, buff, length); |
718 | } |
719 | break; |
720 | } |
721 | } |
722 | |
723 | |
724 | /* {{{ ps_fetch_double */ |
725 | static |
726 | void ps_fetch_double(MYSQL_BIND *r_param, const MYSQL_FIELD * field , unsigned char **row) |
727 | { |
728 | switch (r_param->buffer_type) |
729 | { |
730 | case MYSQL_TYPE_DOUBLE: |
731 | { |
732 | double *value= (double *)r_param->buffer; |
733 | float8get(*value, *row); |
734 | r_param->buffer_length= 8; |
735 | } |
736 | break; |
737 | default: |
738 | { |
739 | double value; |
740 | float8get(value, *row); |
741 | convert_from_double(r_param, field, value, sizeof(double)); |
742 | } |
743 | break; |
744 | } |
745 | (*row)+= 8; |
746 | } |
747 | /* }}} */ |
748 | |
749 | /* {{{ ps_fetch_float */ |
750 | static |
751 | void ps_fetch_float(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row) |
752 | { |
753 | switch(r_param->buffer_type) |
754 | { |
755 | case MYSQL_TYPE_FLOAT: |
756 | { |
757 | float *value= (float *)r_param->buffer; |
758 | float4get(*value, *row); |
759 | r_param->buffer_length= 4; |
760 | *r_param->error= 0; |
761 | } |
762 | break; |
763 | default: |
764 | { |
765 | float value; |
766 | memcpy(&value, *row, sizeof(float)); |
767 | float4get(value, (char *)*row); |
768 | convert_from_float(r_param, field, value, sizeof(float)); |
769 | } |
770 | break; |
771 | } |
772 | (*row)+= 4; |
773 | } |
774 | /* }}} */ |
775 | |
776 | static void convert_to_datetime(MYSQL_TIME *t, unsigned char **row, uint len, enum enum_field_types type) |
777 | { |
778 | memset(t, 0, sizeof(MYSQL_TIME)); |
779 | |
780 | /* binary protocol for datetime: |
781 | 4-bytes: DATE |
782 | 7-bytes: DATE + TIME |
783 | >7 bytes: DATE + TIME with second_part |
784 | */ |
785 | if (len) |
786 | { |
787 | unsigned char *to= *row; |
788 | int has_date= 0; |
789 | uint offset= 7; |
790 | |
791 | if (type == MYSQL_TYPE_TIME) |
792 | { |
793 | t->neg= to[0]; |
794 | t->day= (ulong) sint4korr(to + 1); |
795 | t->time_type= MYSQL_TIMESTAMP_TIME; |
796 | offset= 8; |
797 | to++; |
798 | } else |
799 | { |
800 | t->year= (uint) sint2korr(to); |
801 | t->month= (uint) to[2]; |
802 | t->day= (uint) to[3]; |
803 | t->time_type= MYSQL_TIMESTAMP_DATE; |
804 | if (type == MYSQL_TYPE_DATE) |
805 | return; |
806 | has_date= 1; |
807 | } |
808 | |
809 | if (len > 4) |
810 | { |
811 | t->hour= (uint) to[4]; |
812 | if (type == MYSQL_TYPE_TIME) |
813 | t->hour+= t->day * 24; |
814 | t->minute= (uint) to[5]; |
815 | t->second= (uint) to[6]; |
816 | if (has_date) |
817 | t->time_type= MYSQL_TIMESTAMP_DATETIME; |
818 | } |
819 | if (len > offset) |
820 | { |
821 | t->second_part= (ulong)sint4korr(to+7); |
822 | } |
823 | } |
824 | } |
825 | |
826 | |
827 | /* {{{ ps_fetch_datetime */ |
828 | static |
829 | void ps_fetch_datetime(MYSQL_BIND *r_param, const MYSQL_FIELD * field, |
830 | unsigned char **row) |
831 | { |
832 | MYSQL_TIME *t= (MYSQL_TIME *)r_param->buffer; |
833 | unsigned int len= net_field_length(row); |
834 | |
835 | switch (r_param->buffer_type) { |
836 | case MYSQL_TYPE_DATETIME: |
837 | case MYSQL_TYPE_TIMESTAMP: |
838 | convert_to_datetime(t, row, len, field->type); |
839 | break; |
840 | case MYSQL_TYPE_DATE: |
841 | convert_to_datetime(t, row, len, field->type); |
842 | break; |
843 | case MYSQL_TYPE_TIME: |
844 | convert_to_datetime(t, row, len, field->type); |
845 | t->year= t->day= t->month= 0; |
846 | break; |
847 | case MYSQL_TYPE_YEAR: |
848 | { |
849 | MYSQL_TIME tm; |
850 | convert_to_datetime(&tm, row, len, field->type); |
851 | shortstore(r_param->buffer, tm.year); |
852 | break; |
853 | } |
854 | default: |
855 | { |
856 | char dtbuffer[60]; |
857 | MYSQL_TIME tm; |
858 | size_t length; |
859 | convert_to_datetime(&tm, row, len, field->type); |
860 | /* |
861 | if (tm.time_type== MYSQL_TIMESTAMP_TIME && tm.day) |
862 | { |
863 | tm.hour+= tm.day * 24; |
864 | tm.day=0; |
865 | } |
866 | */ |
867 | switch(field->type) { |
868 | case MYSQL_TYPE_DATE: |
869 | length= sprintf(dtbuffer, "%04u-%02u-%02u" , tm.year, tm.month, tm.day); |
870 | break; |
871 | case MYSQL_TYPE_TIME: |
872 | length= sprintf(dtbuffer, "%s%02u:%02u:%02u" , (tm.neg ? "-" : "" ), tm.hour, tm.minute, tm.second); |
873 | if (field->decimals && field->decimals <= 6) |
874 | { |
875 | char ms[8]; |
876 | sprintf(ms, ".%06lu" , tm.second_part); |
877 | if (field->decimals < 6) |
878 | ms[field->decimals + 1]= 0; |
879 | length+= strlen(ms); |
880 | strcat(dtbuffer, ms); |
881 | } |
882 | break; |
883 | case MYSQL_TYPE_DATETIME: |
884 | case MYSQL_TYPE_TIMESTAMP: |
885 | length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u" , tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); |
886 | if (field->decimals && field->decimals <= 6) |
887 | { |
888 | char ms[8]; |
889 | sprintf(ms, ".%06lu" , tm.second_part); |
890 | if (field->decimals < 6) |
891 | ms[field->decimals + 1]= 0; |
892 | length+= strlen(ms); |
893 | strcat(dtbuffer, ms); |
894 | } |
895 | break; |
896 | default: |
897 | dtbuffer[0]= 0; |
898 | length= 0; |
899 | break; |
900 | } |
901 | convert_froma_string(r_param, dtbuffer, length); |
902 | break; |
903 | } |
904 | } |
905 | (*row) += len; |
906 | } |
907 | /* }}} */ |
908 | |
909 | /* {{{ ps_fetch_string */ |
910 | static |
911 | void ps_fetch_string(MYSQL_BIND *r_param, |
912 | const MYSQL_FIELD *field __attribute__((unused)), |
913 | unsigned char **row) |
914 | { |
915 | /* C-API differs from PHP. While PHP just converts string to string, |
916 | C-API needs to convert the string to the defined type with in |
917 | the result bind buffer. |
918 | */ |
919 | ulong field_length= net_field_length(row); |
920 | |
921 | convert_froma_string(r_param, (char *)*row, field_length); |
922 | (*row) += field_length; |
923 | } |
924 | /* }}} */ |
925 | |
926 | /* {{{ ps_fetch_bin */ |
927 | static |
928 | void ps_fetch_bin(MYSQL_BIND *r_param, |
929 | const MYSQL_FIELD *field, |
930 | unsigned char **row) |
931 | { |
932 | if (field->charsetnr == 63) |
933 | { |
934 | ulong field_length= *r_param->length= net_field_length(row); |
935 | uchar *current_pos= (*row) + r_param->offset, |
936 | *end= (*row) + field_length; |
937 | size_t copylen= 0; |
938 | |
939 | if (current_pos < end) |
940 | { |
941 | copylen= end - current_pos; |
942 | if (r_param->buffer_length) |
943 | memcpy(r_param->buffer, current_pos, MIN(copylen, r_param->buffer_length)); |
944 | } |
945 | if (copylen < r_param->buffer_length && |
946 | (r_param->buffer_type == MYSQL_TYPE_STRING || |
947 | r_param->buffer_type == MYSQL_TYPE_JSON)) |
948 | ((char *)r_param->buffer)[copylen]= 0; |
949 | *r_param->error= copylen > r_param->buffer_length; |
950 | (*row)+= field_length; |
951 | } |
952 | else |
953 | ps_fetch_string(r_param, field, row); |
954 | } |
955 | /* }}} */ |
956 | |
957 | /* {{{ _mysqlnd_init_ps_subsystem */ |
958 | void mysql_init_ps_subsystem(void) |
959 | { |
960 | memset(mysql_ps_fetch_functions, 0, sizeof(mysql_ps_fetch_functions)); |
961 | mysql_ps_fetch_functions[MYSQL_TYPE_NULL].func= ps_fetch_null; |
962 | mysql_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0; |
963 | mysql_ps_fetch_functions[MYSQL_TYPE_NULL].max_len = 0; |
964 | |
965 | mysql_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8; |
966 | mysql_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1; |
967 | mysql_ps_fetch_functions[MYSQL_TYPE_TINY].max_len = 4; |
968 | |
969 | mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16; |
970 | mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2; |
971 | mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].max_len = 6; |
972 | |
973 | mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16; |
974 | mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2; |
975 | mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].max_len = 6; |
976 | |
977 | mysql_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32; |
978 | mysql_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4; |
979 | mysql_ps_fetch_functions[MYSQL_TYPE_INT24].max_len = 9; |
980 | |
981 | mysql_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32; |
982 | mysql_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4; |
983 | mysql_ps_fetch_functions[MYSQL_TYPE_LONG].max_len = 11; |
984 | |
985 | mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64; |
986 | mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8; |
987 | mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].max_len = 21; |
988 | |
989 | mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float; |
990 | mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4; |
991 | mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH; |
992 | |
993 | mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double; |
994 | mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8; |
995 | mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].max_len = MAX_DOUBLE_STRING_REP_LENGTH; |
996 | |
997 | mysql_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_datetime; |
998 | mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; |
999 | mysql_ps_fetch_functions[MYSQL_TYPE_TIME].max_len = 17; |
1000 | |
1001 | mysql_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_datetime; |
1002 | mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; |
1003 | mysql_ps_fetch_functions[MYSQL_TYPE_DATE].max_len = 10; |
1004 | |
1005 | mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string; |
1006 | mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; |
1007 | mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].max_len = -1; |
1008 | |
1009 | mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime; |
1010 | mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN; |
1011 | mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].max_len = 30; |
1012 | |
1013 | mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime; |
1014 | mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN; |
1015 | mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].max_len = 30; |
1016 | |
1017 | mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_bin; |
1018 | mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR; |
1019 | mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].max_len = -1; |
1020 | |
1021 | mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_bin; |
1022 | mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1023 | mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].max_len = -1; |
1024 | |
1025 | mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_bin; |
1026 | mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR; |
1027 | mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].max_len = -1; |
1028 | |
1029 | mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_bin; |
1030 | mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1031 | mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].max_len = -1; |
1032 | |
1033 | mysql_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bin; |
1034 | mysql_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1035 | mysql_ps_fetch_functions[MYSQL_TYPE_BIT].max_len = -1; |
1036 | |
1037 | mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string; |
1038 | mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1039 | mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].max_len = -1; |
1040 | |
1041 | mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string; |
1042 | mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1043 | mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].max_len = -1; |
1044 | |
1045 | mysql_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string; |
1046 | mysql_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1047 | mysql_ps_fetch_functions[MYSQL_TYPE_STRING].max_len = -1; |
1048 | |
1049 | mysql_ps_fetch_functions[MYSQL_TYPE_JSON].func = ps_fetch_string; |
1050 | mysql_ps_fetch_functions[MYSQL_TYPE_JSON].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1051 | mysql_ps_fetch_functions[MYSQL_TYPE_JSON].max_len = -1; |
1052 | |
1053 | mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string; |
1054 | mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1055 | mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].max_len = -1; |
1056 | |
1057 | mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string; |
1058 | mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1059 | mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].max_len = -1; |
1060 | |
1061 | mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string; |
1062 | mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1063 | mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].max_len = -1; |
1064 | |
1065 | mysql_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string; |
1066 | mysql_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQL_PS_SKIP_RESULT_STR; |
1067 | mysql_ps_fetch_functions[MYSQL_TYPE_SET].max_len = -1; |
1068 | |
1069 | mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string; |
1070 | mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQL_PS_SKIP_RESULT_STR; |
1071 | mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].max_len = -1; |
1072 | |
1073 | mysql_ps_subsystem_initialized= 1; |
1074 | } |
1075 | /* }}} */ |
1076 | |
1077 | |
1078 | /* |
1079 | * Local variables: |
1080 | * tab-width: 4 |
1081 | * c-basic-offset: 4 |
1082 | * End: |
1083 | * vim600: noet sw=4 ts=4 fdm=marker |
1084 | * vim<600: noet sw=4 ts=4 |
1085 | */ |
1086 | |