/**************************************************************************** Copyright (C) 2012 Monty Program AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not see or write to the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110, USA Part of this code includes code from the PHP project which is freely available from http://www.php.net *****************************************************************************/ /* The implementation for prepared statements was ported from PHP's mysqlnd extension, written by Andrey Hristov, Georg Richter and Ulf Wendel Original file header: +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Georg Richter | | Andrey Hristov | | Ulf Wendel | +----------------------------------------------------------------------+ */ #include "my_global.h" #include #include #include #include #include "mysql.h" #define MYSQL_SILENT /* ranges for C-binding */ #define UINT_MAX32 0xFFFFFFFFL #define UINT_MAX24 0x00FFFFFF #define UINT_MAX16 0xFFFF #ifndef INT_MIN8 #define INT_MIN8 (~0x7F) #define INT_MAX8 0x7F #endif #define UINT_MAX8 0xFF #if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) #define LONGLONG_MIN ((long long) 0x8000000000000000LL) #define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) #endif #if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) /* First check for ANSI C99 definition: */ #ifdef ULLONG_MAX #define ULONGLONG_MAX ULLONG_MAX #else #define ULONGLONG_MAX ((unsigned long long)(~0ULL)) #endif #endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ #define YY_PART_YEAR 70 #define MAX_DOUBLE_STRING_REP_LENGTH 300 MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1]; my_bool mysql_ps_subsystem_initialized= 0; #define NUMERIC_TRUNCATION(val,min_range, max_range)\ ((((val) > (max_range)) || ((val) < (min_range)) ? 1 : 0)) /* helper function for zero fill */ void ma_bmove_upp(register char *dst, register const char *src, register size_t len) { while (len-- != 0) *--dst = *--src; } /* {{{ ps_fetch_from_1_to_8_bytes */ void ps_fetch_from_1_to_8_bytes(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, unsigned char **row, unsigned int byte_count) { my_bool is_unsigned= test(field->flags & UNSIGNED_FLAG); r_param->buffer_length= byte_count; switch (byte_count) { case 1: *(uchar *)r_param->buffer= **row; *r_param->error= is_unsigned != r_param->is_unsigned && *(uchar *)r_param->buffer > INT_MAX8; break; case 2: shortstore(r_param->buffer, ((ushort) sint2korr(*row))); *r_param->error= is_unsigned != r_param->is_unsigned && *(ushort *)r_param->buffer > INT_MAX16; break; case 4: { longstore(r_param->buffer, ((uint32)sint4korr(*row))); *r_param->error= is_unsigned != r_param->is_unsigned && *(uint32 *)r_param->buffer > INT_MAX32; } break; case 8: { ulonglong val= (ulonglong)sint8korr(*row); longlongstore(r_param->buffer, val); *r_param->error= is_unsigned != r_param->is_unsigned && val > LONGLONG_MAX ; } break; default: r_param->buffer_length= 0; break; } (*row)+= byte_count; } /* }}} */ static longlong my_atoll(const char *number, const char *end, int *error) { char buffer[255]; longlong llval= 0; size_t i; /* set error at the following conditions: - string contains invalid character(s) - length > 254 - strtoll returns invalid range */ memcpy(buffer, number, MIN((uint)(end - number), 254)); buffer[(uint)(end - number)]= 0; llval= strtoll(buffer, NULL, 10); /* check size */ if ((uint)(end - number) > 254) { *error= 1; return llval; } /* check characters */ for (i=0; i < strlen(buffer); i++) { if (buffer[i] < '0' || buffer[i] > '9') { *error= 1; return llval; } } /* check strtoll result */ if (errno == ERANGE) *error= errno; return llval; } double my_atod(const char *number, const char *end, int *error) { double val= 0.0; char buffer[255]; int len= (int)(end - number); if (len > 254) *error= 1; len= MIN(len, 254); memcpy(&buffer, number, len); buffer[len]= '\0'; val= strtod(buffer, NULL); /* if (!*error) *error= errno; */ return val; } my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm) { my_bool is_time=0, is_date=0, has_time_frac=0; char *p= (char *)str; if ((p= strchr(str, '-')) && p <= str + length) is_date= 1; if ((p= strchr(str, ':')) && p <= str + length) is_time= 1; if ((p= strchr(str, '.')) && p <= str + length) has_time_frac= 1; p= (char *)str; memset(tm, 0, sizeof(MYSQL_TIME)); if (is_date) { sscanf(str, "%d-%d-%d", &tm->year, &tm->month, &tm->day); p= strchr(str, ' '); if (!p) { tm->time_type= MYSQL_TIMESTAMP_DATE; return 0; } } if (has_time_frac) { sscanf(p, "%d:%d:%d.%ld", &tm->hour, &tm->minute, &tm->second, &tm->second_part); tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME; return 0; } if (is_time) { sscanf(p, "%d:%d:%d", &tm->hour, &tm->minute, &tm->second); tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME; return 0; } return 1; } static void convert_from_string(MYSQL_BIND *r_param, char *buffer, size_t len) { int error= 0; switch (r_param->buffer_type) { case MYSQL_TYPE_TINY: { longlong val= my_atoll(buffer, buffer + len, &error); *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8) || error > 0; int1store(r_param->buffer, (uchar) val); r_param->buffer_length= sizeof(uchar); } break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: { longlong val= my_atoll(buffer, buffer + len, &error); *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16) || error > 0; shortstore(r_param->buffer, (short)val); r_param->buffer_length= sizeof(short); } break; case MYSQL_TYPE_LONG: { longlong val= my_atoll(buffer, buffer + len, &error); *r_param->error=error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32) || error > 0; longstore(r_param->buffer, (int32)val); r_param->buffer_length= sizeof(uint32); } break; case MYSQL_TYPE_LONGLONG: { longlong val= my_atoll(buffer, buffer + len, &error); *r_param->error= error > 0; /* no need to check for truncation */ longlongstore(r_param->buffer, val); r_param->buffer_length= sizeof(longlong); } break; case MYSQL_TYPE_DOUBLE: { double val= my_atod(buffer, buffer + len, &error); *r_param->error= error > 0; /* no need to check for truncation */ float8store(r_param->buffer, val); r_param->buffer_length= sizeof(double); } break; case MYSQL_TYPE_FLOAT: { float val= (float)my_atod(buffer, buffer + len, &error); *r_param->error= error > 0; /* no need to check for truncation */ float4store(r_param->buffer, val); r_param->buffer_length= sizeof(float); } break; case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATE: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: { MYSQL_TIME *tm= (MYSQL_TIME *)r_param->buffer; str_to_TIME(buffer, len, tm); break; } break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: default: { char *start= buffer + r_param->offset; /* stmt_fetch_column sets offset */ char *end= buffer + len; size_t copylen= 0; if (start < end) { copylen= end - start; if (r_param->buffer_length) memcpy(r_param->buffer, start, MIN(copylen, r_param->buffer_length)); } if (copylen < r_param->buffer_length) ((char *)r_param->buffer)[copylen]= '\0'; *r_param->error= (copylen > r_param->buffer_length); *r_param->length= (ulong)len; } break; } } static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, longlong val, my_bool is_unsigned) { switch (r_param->buffer_type) { case MYSQL_TYPE_TINY: *(uchar *)r_param->buffer= (uchar)val; *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8); r_param->buffer_length= 1; break; case MYSQL_TYPE_SHORT: case MYSQL_TYPE_YEAR: shortstore(r_param->buffer, (short)val); *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16); r_param->buffer_length= 2; break; case MYSQL_TYPE_LONG: longstore(r_param->buffer, (int32)val); *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32); r_param->buffer_length= 4; break; case MYSQL_TYPE_LONGLONG: *r_param->error= (val < 0 && r_param->is_unsigned != is_unsigned); longlongstore(r_param->buffer, val); r_param->buffer_length= 8; break; case MYSQL_TYPE_DOUBLE: { volatile double dbl; dbl= (is_unsigned) ? ulonglong2double((ulonglong)val) : (double)val; doublestore(r_param->buffer, dbl); *r_param->error= is_unsigned ? (ulonglong )dbl != (ulonglong)val : (longlong)dbl != (longlong)val; r_param->buffer_length= 8; break; } case MYSQL_TYPE_FLOAT: { float fval; fval= is_unsigned ? (float)(ulonglong)(val) : (float)val; float4store(r_param->buffer, fval); *r_param->error= is_unsigned ? (ulonglong)fval != (ulonglong)val : (longlong)fval != val; r_param->buffer_length= 4; } break; default: { char buffer[22]; char *endptr; uint len; endptr= longlong10_to_str(val, buffer, is_unsigned ? 10 : -10); len= (uint)(endptr - buffer); if (field->flags & ZEROFILL_FLAG && len < field->length && len < r_param->buffer_length) { ma_bmove_upp(buffer + field->length, buffer + len, len); memset((char*) buffer, '0', field->length - len); len= field->length; } convert_from_string(r_param, buffer, len); } break; } } /* {{{ ps_fetch_null */ static void ps_fetch_null(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row) { /* do nothing */ } /* }}} */ #define GET_LVALUE_FROM_ROW(is_unsigned, data, ucast, scast)\ (is_unsigned) ? (longlong)(ucast) *(longlong *)(data) : (longlong)(scast) *(longlong *)(data) /* {{{ ps_fetch_int8 */ static void ps_fetch_int8(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, unsigned char **row) { switch(r_param->buffer_type) { case MYSQL_TYPE_TINY: ps_fetch_from_1_to_8_bytes(r_param, field, row, 1); break; default: { uchar val= **row; longlong lval= field->flags & UNSIGNED_FLAG ? (longlong) val : (longlong)(signed char)val; convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); (*row) += 1; } break; } } /* }}} */ /* {{{ ps_fetch_int16 */ static void ps_fetch_int16(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, unsigned char **row) { switch (r_param->buffer_type) { case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: ps_fetch_from_1_to_8_bytes(r_param, field, row, 2); break; default: { short sval= sint2korr(*row); longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ushort) sval : (longlong)sval; convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); (*row) += 2; } break; } } /* }}} */ /* {{{ ps_fetch_int32 */ static void ps_fetch_int32(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, unsigned char **row) { switch (r_param->buffer_type) { /* case MYSQL_TYPE_TINY: ps_fetch_from_1_to_8_bytes(r_param, field, row, 1); break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: ps_fetch_from_1_to_8_bytes(r_param, field, row, 2); break; */ case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONG: ps_fetch_from_1_to_8_bytes(r_param, field, row, 4); break; default: { int32 sval= sint4korr(*row); longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(uint32) sval : (longlong)sval; convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); (*row) += 4; } break; } } /* }}} */ /* {{{ ps_fetch_int64 */ static void ps_fetch_int64(MYSQL_BIND *r_param, const MYSQL_FIELD * const field, unsigned char **row) { switch(r_param->buffer_type) { /* case MYSQL_TYPE_TINY: ps_fetch_from_1_to_8_bytes(r_param, field, row, 1); break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: ps_fetch_from_1_to_8_bytes(r_param, field, row, 2); break; case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONG: ps_fetch_from_1_to_8_bytes(r_param, field, row, 4); break; */ case MYSQL_TYPE_LONGLONG: ps_fetch_from_1_to_8_bytes(r_param, field, row, 8); break; default: { longlong sval= (longlong)sint8korr(*row); longlong lval= field->flags & UNSIGNED_FLAG ? (ulonglong) sval : (longlong)sval; convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG); (*row) += 8; } break; } } /* }}} */ static void convert_from_float(MYSQL_BIND *r_param, const MYSQL_FIELD *field, double val, int size) { double check_trunc_val= (val > 0) ? floor(val) : -floor(-val); char *buf= (char *)r_param->buffer; switch (r_param->buffer_type) { case MYSQL_TYPE_TINY: *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val; *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) : (double)((int8)*buf)); r_param->buffer_length= 1; break; case MYSQL_TYPE_SHORT: case MYSQL_TYPE_YEAR: { if (r_param->is_unsigned) { ushort sval= (ushort)val; shortstore(buf, sval); *r_param->error= check_trunc_val != (double)sval; } else { short sval= (short)val; shortstore(buf, sval); *r_param->error= check_trunc_val != (double)sval; } r_param->buffer_length= 2; } break; case MYSQL_TYPE_LONG: { if (r_param->is_unsigned) { uint32 lval= (uint32)val; longstore(buf, lval); *r_param->error= (check_trunc_val != (double)lval); } else { int32 lval= (int32)val; longstore(buf, lval); *r_param->error= (check_trunc_val != (double)lval); } r_param->buffer_length= 4; } break; case MYSQL_TYPE_LONGLONG: { if (r_param->is_unsigned) { ulonglong llval= (ulonglong)val; longlongstore(buf, llval); *r_param->error= (check_trunc_val != (double)llval); } else { longlong llval= (longlong)val; longlongstore(buf, llval); *r_param->error= (check_trunc_val != (double)llval); } r_param->buffer_length= 8; } break; case MYSQL_TYPE_FLOAT: { float fval= (float)val; memcpy(buf, &fval, sizeof(float)); *r_param->error= (*(float*)buf != fval); r_param->buffer_length= 4; } break; case MYSQL_TYPE_DOUBLE: { memcpy(buf, &val, sizeof(double)); r_param->buffer_length= 8; } break; default: { char buff[MAX_DOUBLE_STRING_REP_LENGTH]; size_t length; length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length); if (field->decimals >= NOT_FIXED_DEC) { length= ma_gcvt(val, MY_GCVT_ARG_FLOAT, length, buff, NULL); } else { length= ma_fcvt(val, field->decimals, buff, NULL); } /* check if ZEROFILL flag is active */ if (field->flags & ZEROFILL_FLAG) { /* enough space available ? */ if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1) break; ma_bmove_upp(buff + field->length, buff + length, length); memset((char*) buff, '0', field->length - length); length= field->length; } convert_from_string(r_param, buff, length); } break; } } static void convert_from_double(MYSQL_BIND *r_param, const MYSQL_FIELD *field, double val, int size) { double check_trunc_val= (val > 0) ? floor(val) : -floor(-val); char *buf= (char *)r_param->buffer; switch (r_param->buffer_type) { case MYSQL_TYPE_TINY: *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val; *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) : (double)((int8)*buf)); r_param->buffer_length= 1; break; case MYSQL_TYPE_SHORT: case MYSQL_TYPE_YEAR: { if (r_param->is_unsigned) { ushort sval= (ushort)val; shortstore(buf, sval); *r_param->error= check_trunc_val != (double)sval; } else { short sval= (short)val; shortstore(buf, sval); *r_param->error= check_trunc_val != (double)sval; } r_param->buffer_length= 2; } break; case MYSQL_TYPE_LONG: { if (r_param->is_unsigned) { uint32 lval= (uint32)val; longstore(buf, lval); *r_param->error= (check_trunc_val != (double)lval); } else { int32 lval= (int32)val; longstore(buf, lval); *r_param->error= (check_trunc_val != (double)lval); } r_param->buffer_length= 4; } break; case MYSQL_TYPE_LONGLONG: { if (r_param->is_unsigned) { ulonglong llval= (ulonglong)val; longlongstore(buf, llval); *r_param->error= (check_trunc_val != (double)llval); } else { longlong llval= (longlong)val; longlongstore(buf, llval); *r_param->error= (check_trunc_val != (double)llval); } r_param->buffer_length= 8; } break; case MYSQL_TYPE_FLOAT: { float fval= (float)val; memcpy(buf, &fval, sizeof(float)); *r_param->error= (*(float*)buf != fval); r_param->buffer_length= 4; } break; default: { char buff[MAX_DOUBLE_STRING_REP_LENGTH]; size_t length; length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length); if (field->decimals >= NOT_FIXED_DEC) { length= ma_gcvt(val, MY_GCVT_ARG_DOUBLE, length, buff, NULL); } else { length= ma_fcvt(val, field->decimals, buff, NULL); } /* check if ZEROFILL flag is active */ if (field->flags & ZEROFILL_FLAG) { /* enough space available ? */ if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1) break; ma_bmove_upp(buff + field->length, buff + length, length); memset((char*) buff, '0', field->length - length); length= field->length; } convert_from_string(r_param, buff, length); } break; } } /* {{{ ps_fetch_float */ static void ps_fetch_float(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row) { switch(r_param->buffer_type) { case MYSQL_TYPE_FLOAT: { float *value= (float *)r_param->buffer; float4get(*value, *row); r_param->buffer_length= 4; *r_param->error= 0; } break; default: { float value; memcpy(&value, *row, sizeof(float)); float4get(value, (char *)*row); convert_from_float(r_param, field, value, sizeof(float)); } break; } (*row)+= 4; } /* }}} */ /* {{{ ps_fetch_double */ static void ps_fetch_double(MYSQL_BIND *r_param, const MYSQL_FIELD * field , unsigned char **row) { switch (r_param->buffer_type) { case MYSQL_TYPE_DOUBLE: { double *value= (double *)r_param->buffer; float8get(*value, *row); r_param->buffer_length= 8; } break; default: { double value; float8get(value, *row); convert_from_double(r_param, field, value, sizeof(double)); } break; } (*row)+= 8; } /* }}} */ static void convert_to_datetime(MYSQL_TIME *t, unsigned char **row, uint len, enum enum_field_types type) { memset(t, 0, sizeof(MYSQL_TIME)); /* binary protocol for datetime: 4-bytes: DATE 7-bytes: DATE + TIME >7 bytes: DATE + TIME with second_part */ if (len) { unsigned char *to= *row; int has_date= 0; uint offset= 7; if (type == MYSQL_TYPE_TIME) { t->neg= to[0]; t->day= (ulong) sint4korr(to + 1); t->time_type= MYSQL_TIMESTAMP_TIME; offset= 8; to++; } else { t->year= (uint) sint2korr(to); t->month= (uint) to[2]; t->day= (uint) to[3]; t->time_type= MYSQL_TIMESTAMP_DATE; if (type == MYSQL_TYPE_DATE) return; has_date= 1; } if (len > 4) { t->hour= (uint) to[4]; t->minute= (uint) to[5]; t->second= (uint) to[6]; if (has_date) t->time_type= MYSQL_TIMESTAMP_DATETIME; } if (len > offset) { t->second_part= (ulong)sint4korr(to+7); } } } /* {{{ ps_fetch_datetime */ static void ps_fetch_datetime(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row) { MYSQL_TIME *t= (MYSQL_TIME *)r_param->buffer; unsigned int len= net_field_length(row); switch (r_param->buffer_type) { case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: convert_to_datetime(t, row, len, field->type); break; case MYSQL_TYPE_DATE: convert_to_datetime(t, row, len, field->type); break; case MYSQL_TYPE_TIME: convert_to_datetime(t, row, len, field->type); if (t->day) { t->hour+= t->day * 24; t->day= 0; } t->year= t->day= t->month= 0; break; case MYSQL_TYPE_YEAR: { MYSQL_TIME tm; convert_to_datetime(&tm, row, len, field->type); shortstore(r_param->buffer, tm.year); break; } default: { char dtbuffer[60]; MYSQL_TIME tm; unsigned int length; convert_to_datetime(&tm, row, len, field->type); if (tm.time_type== MYSQL_TIMESTAMP_TIME && tm.day) { tm.hour+= tm.day * 24; tm.day=0; } switch(field->type) { case MYSQL_TYPE_DATE: length= sprintf(dtbuffer, "%04u-%02u-%02u", tm.year, tm.month, tm.day); break; case MYSQL_TYPE_TIME: length= sprintf(dtbuffer, "%s%02u:%02u:%02u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second); if (field->decimals) { char ms[8]; sprintf(ms, ".%06lu", tm.second_part); if (field->decimals < 6) ms[field->decimals + 1]= 0; length+= strlen(ms); strcat(dtbuffer, ms); } break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); if (field->decimals) { char ms[8]; sprintf(ms, ".%06lu", tm.second_part); if (field->decimals < 6) ms[field->decimals + 1]= 0; length+= strlen(ms); strcat(dtbuffer, ms); } break; default: dtbuffer[0]= 0; length= 0; break; } convert_from_string(r_param, dtbuffer, length); break; } } (*row) += len; } /* }}} */ /* {{{ ps_fetch_string */ static void ps_fetch_string(MYSQL_BIND *r_param, const MYSQL_FIELD *field, unsigned char **row) { /* C-API differs from PHP. While PHP just converts string to string, C-API needs to convert the string to the defined type with in the result bind buffer. */ ulong field_length= net_field_length(row); convert_from_string(r_param, (char *)*row, field_length); (*row) += field_length; } /* }}} */ /* {{{ ps_fetch_bin */ static void ps_fetch_bin(MYSQL_BIND *r_param, const MYSQL_FIELD *field, unsigned char **row) { ulong field_length= *r_param->length= net_field_length(row); uchar *current_pos= (*row) + r_param->offset, *end= (*row) + field_length; size_t copylen= 0; if (current_pos < end) { copylen= end - current_pos; if (r_param->buffer_length) { memcpy(r_param->buffer, current_pos, MIN(copylen, r_param->buffer_length)); if (copylen < r_param->buffer_length && r_param->buffer_type == MYSQL_TYPE_STRING) ((char *)r_param->buffer)[copylen]= 0; } } *r_param->error= copylen > r_param->buffer_length; (*row)+= field_length; } /* }}} */ /* {{{ _mysqlnd_init_ps_subsystem */ void mysql_init_ps_subsystem(void) { memset(mysql_ps_fetch_functions, 0, sizeof(mysql_ps_fetch_functions)); mysql_ps_fetch_functions[MYSQL_TYPE_NULL].func= ps_fetch_null; mysql_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0; mysql_ps_fetch_functions[MYSQL_TYPE_NULL].max_len = 0; mysql_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8; mysql_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1; mysql_ps_fetch_functions[MYSQL_TYPE_TINY].max_len = 4; mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16; mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2; mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].max_len = 6; mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16; mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2; mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].max_len = 6; mysql_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32; mysql_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4; mysql_ps_fetch_functions[MYSQL_TYPE_INT24].max_len = 9; mysql_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32; mysql_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4; mysql_ps_fetch_functions[MYSQL_TYPE_LONG].max_len = 11; mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64; mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8; mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].max_len = 21; mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float; mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4; mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH; mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double; mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8; mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].max_len = MAX_DOUBLE_STRING_REP_LENGTH; mysql_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_datetime; mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_TIME].max_len = 15; mysql_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_datetime; mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_DATE].max_len = 10; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime; mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].max_len = 30; mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime; mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN; mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].max_len = 30; mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_bin; mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_bin; mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_bin; mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_bin; mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bin; mysql_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_BIT].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_STRING].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_SET].max_len = -1; mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string; mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQL_PS_SKIP_RESULT_STR; mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].max_len = -1; mysql_ps_subsystem_initialized= 1; } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */