summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_ps_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mysqlnd/mysqlnd_ps_codec.c')
-rw-r--r--ext/mysqlnd/mysqlnd_ps_codec.c854
1 files changed, 854 insertions, 0 deletions
diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c
new file mode 100644
index 0000000000..ea04cfb5fa
--- /dev/null
+++ b/ext/mysqlnd/mysqlnd_ps_codec.c
@@ -0,0 +1,854 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 6 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 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 <georg@mysql.com> |
+ | Andrey Hristov <andrey@mysql.com> |
+ | Ulf Wendel <uwendel@mysql.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+#include "php.h"
+#include "mysqlnd.h"
+#include "mysqlnd_wireprotocol.h"
+#include "mysqlnd_priv.h"
+#include "mysqlnd_debug.h"
+
+#define MYSQLND_SILENT
+
+
+
+typedef int8 my_int8;
+typedef uint8 my_uint8;
+
+typedef int16 my_int16;
+typedef uint16 my_uint16;
+
+typedef int32 my_int32;
+typedef uint32 my_uint32;
+
+
+enum mysqlnd_timestamp_type
+{
+ MYSQLND_TIMESTAMP_NONE= -2,
+ MYSQLND_TIMESTAMP_ERROR= -1,
+ MYSQLND_TIMESTAMP_DATE= 0,
+ MYSQLND_TIMESTAMP_DATETIME= 1,
+ MYSQLND_TIMESTAMP_TIME= 2
+};
+
+
+struct st_mysqlnd_time
+{
+ unsigned int year, month, day, hour, minute, second;
+ unsigned long second_part;
+ zend_bool neg;
+ enum mysqlnd_timestamp_type time_type;
+};
+
+
+
+struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
+
+#define MYSQLND_PS_SKIP_RESULT_W_LEN -1
+#define MYSQLND_PS_SKIP_RESULT_STR -2
+
+/* {{{ ps_fetch_from_1_to_8_bytes */
+void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row, zend_bool as_unicode,
+ unsigned int byte_count TSRMLS_DC)
+{
+ char tmp[22];
+ size_t tmp_len = 0;
+ zend_bool is_bit = field->type == MYSQL_TYPE_BIT;
+ if (field->flags & UNSIGNED_FLAG) {
+ my_uint64 uval = 0;
+
+ switch (byte_count) {
+ case 8:uval = is_bit? (my_uint64) bit_uint8korr(*row):(my_uint64) uint8korr(*row);break;
+ case 7:uval = bit_uint7korr(*row);break;
+ case 6:uval = bit_uint6korr(*row);break;
+ case 5:uval = bit_uint5korr(*row);break;
+ case 4:uval = is_bit? (my_uint64) bit_uint4korr(*row):(my_uint64) uint4korr(*row);break;
+ case 3:uval = is_bit? (my_uint64) bit_uint3korr(*row):(my_uint64) uint3korr(*row);break;
+ case 2:uval = is_bit? (my_uint64) bit_uint2korr(*row):(my_uint64) uint2korr(*row);break;
+ case 1:uval = (my_uint64) uint1korr(*row);break;
+ }
+
+#if SIZEOF_LONG==4
+ if (uval > INT_MAX) {
+ tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
+ } else
+#endif /* #if SIZEOF_LONG==4 */
+ {
+ if (byte_count < 8 || uval <= L64(9223372036854775807)) {
+ ZVAL_LONG(zv, uval);
+ } else {
+ tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
+ }
+ }
+ } else {
+ /* SIGNED */
+ my_int64 lval = 0;
+ switch (byte_count) {
+ case 8:lval = (my_int64) sint8korr(*row);break;
+ /*
+ 7, 6 and 5 are not possible.
+ BIT is only unsigned, thus only uint5|6|7 macroses exist
+ */
+ case 4:lval = (my_int64) sint4korr(*row);break;
+ case 3:lval = (my_int64) sint3korr(*row);break;
+ case 2:lval = (my_int64) sint2korr(*row);break;
+ case 1:lval = (my_int64) *(my_int8*)*row;break;
+ }
+
+#if SIZEOF_LONG==4
+ if ((L64(2147483647) < (my_int64) lval) || (L64(-2147483648) > (my_int64) lval)) {
+ tmp_len = sprintf((char *)&tmp, MYSQLND_LL_SPEC, lval);
+ } else
+#endif /* SIZEOF */
+ {
+ ZVAL_LONG(zv, lval);
+ }
+ }
+
+ if (tmp_len) {
+#if PHP_MAJOR_VERSION >= 6
+ if (as_unicode) {
+ ZVAL_UTF8_STRINGL(zv, tmp, tmp_len, ZSTR_DUPLICATE);
+ } else
+#endif
+ {
+ ZVAL_STRINGL(zv, tmp, tmp_len, 1);
+ }
+ }
+ (*row)+= byte_count;
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_null */
+static
+void ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ ZVAL_NULL(zv);
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_int8 */
+static
+void ps_fetch_int8(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 1 TSRMLS_CC);
+#if 0
+ if (field->flags & UNSIGNED_FLAG) {
+ ZVAL_LONG(zv, *(my_uint8*)*row);
+ } else {
+ ZVAL_LONG(zv, *(my_int8*)*row);
+ }
+ (*row)++;
+#endif
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_int16 */
+static
+void ps_fetch_int16(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 2 TSRMLS_CC);
+#if 0
+ if (field->flags & UNSIGNED_FLAG) {
+ ZVAL_LONG(zv, (my_uint16) sint2korr(*row));
+ } else {
+ ZVAL_LONG(zv, (my_int16) sint2korr(*row));
+ }
+ (*row)+= 2;
+#endif
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_int32 */
+static
+void ps_fetch_int32(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 4 TSRMLS_CC);
+#if 0
+
+ if (field->flags & UNSIGNED_FLAG) {
+ my_uint32 uval;
+
+ /* unsigned int (11) */
+ uval= (my_uint32) sint4korr(*row);
+#if SIZEOF_LONG==4
+ if (uval > INT_MAX) {
+ char *tmp, *p;
+ int j=10;
+ tmp= mnd_emalloc(11);
+ p= &tmp[9];
+ do {
+ *p-- = (uval % 10) + 48;
+ uval = uval / 10;
+ } while (--j > 0);
+ tmp[10]= '\0';
+ /* unsigned int > INT_MAX is 10 digits - ALWAYS */
+#if PHP_MAJOR_VERSION >= 6
+ if (!as_unicode) {
+#endif
+ ZVAL_STRING(zv, tmp, 0);
+#if PHP_MAJOR_VERSION >= 6
+ } else {
+ ZVAL_UTF8_STRINGL(zv, tmp, 10, ZSTR_AUTOFREE);
+ }
+#endif /* PHP_MAJOR_VERSION >= 6 */
+ } else
+#endif /* #if SIZEOF_LONG==4 */
+ {
+ ZVAL_LONG(zv, uval);
+ }
+ } else {
+ ZVAL_LONG(zv, (my_int32) sint4korr(*row));
+ }
+ (*row)+= 4;
+#endif /* 0 */
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_int64 */
+static
+void ps_fetch_int64(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 8 TSRMLS_CC);
+#if 0
+
+ my_uint64 llval = (my_uint64) sint8korr(*row);
+ zend_bool uns = field->flags & UNSIGNED_FLAG? TRUE:FALSE;
+
+#if SIZEOF_LONG==8
+ if (uns == TRUE && llval > 9223372036854775807L) {
+#elif SIZEOF_LONG==4
+ if ((uns == TRUE && llval > L64(2147483647)) ||
+ (uns == FALSE && ((L64( 2147483647) < (my_int64) llval) ||
+ (L64(-2147483648) > (my_int64) llval))))
+ {
+#endif
+ char tmp[22];
+ /* even though lval is declared as unsigned, the value
+ * may be negative. Therefor we cannot use MYSQLND_LLU_SPEC and must
+ * use MYSQLND_LL_SPEC.
+ */
+ sprintf((char *)&tmp, uns == TRUE? MYSQLND_LLU_SPEC : MYSQLND_LL_SPEC, llval);
+#if PHP_MAJOR_VERSION >= 6
+ if (!as_unicode) {
+#endif
+ ZVAL_STRING(zv, tmp, 1);
+#if PHP_MAJOR_VERSION >= 6
+ } else {
+ ZVAL_UTF8_STRING(zv, tmp, ZSTR_DUPLICATE);
+ }
+#endif
+ } else {
+ /* This cast is safe, as we have checked the values above */
+ ZVAL_LONG(zv, (long) llval);
+ }
+ (*row)+= 8;
+#endif /* 0 */
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_float */
+static
+void ps_fetch_float(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ float value;
+ float4get(value, *row);
+ ZVAL_DOUBLE(zv, value);
+ (*row)+= 4;
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_double */
+static
+void ps_fetch_double(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ double value;
+ float8get(value, *row);
+ ZVAL_DOUBLE(zv, value);
+ (*row)+= 8;
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_time */
+static
+void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ struct st_mysqlnd_time t;
+ unsigned int length; /* First byte encodes the length*/
+ char *to;
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
+ zend_uchar *to= *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_TIME;
+ t.neg = (zend_bool) to[0];
+
+ t.day = (unsigned long) sint4korr(to+1);
+ t.hour = (unsigned int) to[5];
+ t.minute = (unsigned int) to[6];
+ t.second = (unsigned int) to[7];
+ t.second_part = (length > 8) ? (unsigned long) sint4korr(to+8) : 0;
+ t.year = t.month= 0;
+ if (t.day) {
+ /* Convert days to hours at once */
+ t.hour += t.day*24;
+ t.day = 0;
+ }
+
+ (*row) += length;
+ } else {
+ memset(&t, 0, sizeof(t));
+ t.time_type = MYSQLND_TIMESTAMP_TIME;
+ }
+
+ /*
+ QQ : How to make this unicode without copying two times the buffer -
+ Unicode equivalent of spprintf?
+ */
+ length = spprintf(&to, 0, "%s%02u:%02u:%02u",
+ (t.neg ? "-" : ""), t.hour, t.minute, t.second);
+
+#if PHP_MAJOR_VERSION >= 6
+ if (!as_unicode) {
+#endif
+ ZVAL_STRINGL(zv, to, length, 1);
+ mnd_efree(to);
+#if PHP_MAJOR_VERSION >= 6
+ } else {
+ ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
+ }
+#endif
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_date */
+static
+void ps_fetch_date(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ struct st_mysqlnd_time t = {0};
+ unsigned int length; /* First byte encodes the length*/
+ char *to;
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
+ zend_uchar *to= *row;
+
+ t.time_type= MYSQLND_TIMESTAMP_DATE;
+ t.neg= 0;
+
+ t.second_part = t.hour = t.minute = t.second = 0;
+
+ t.year = (unsigned int) sint2korr(to);
+ t.month = (unsigned int) to[2];
+ t.day = (unsigned int) to[3];
+
+ (*row)+= length;
+ } else {
+ memset(&t, 0, sizeof(t));
+ t.time_type = MYSQLND_TIMESTAMP_DATE;
+ }
+
+ /*
+ QQ : How to make this unicode without copying two times the buffer -
+ Unicode equivalent of spprintf?
+ */
+ length = spprintf(&to, 0, "%04u-%02u-%02u", t.year, t.month, t.day);
+
+#if PHP_MAJOR_VERSION >= 6
+ if (!as_unicode) {
+#endif
+ ZVAL_STRINGL(zv, to, length, 1);
+ mnd_efree(to);
+#if PHP_MAJOR_VERSION >= 6
+ } else {
+ ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
+ }
+#endif
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_datetime */
+static
+void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ struct st_mysqlnd_time t;
+ unsigned int length; /* First byte encodes the length*/
+ char *to;
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
+ zend_uchar *to= *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_DATETIME;
+ t.neg = 0;
+
+ t.year = (unsigned int) sint2korr(to);
+ t.month = (unsigned int) to[2];
+ t.day = (unsigned int) to[3];
+
+ if (length > 4) {
+ t.hour = (unsigned int) to[4];
+ t.minute = (unsigned int) to[5];
+ t.second = (unsigned int) to[6];
+ } else {
+ t.hour = t.minute = t.second= 0;
+ }
+ t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0;
+
+ (*row)+= length;
+ } else {
+ memset(&t, 0, sizeof(t));
+ t.time_type = MYSQLND_TIMESTAMP_DATETIME;
+ }
+
+ /*
+ QQ : How to make this unicode without copying two times the buffer -
+ Unicode equivalent of spprintf?
+ */
+ length = spprintf(&to, 0, "%04u-%02u-%02u %02u:%02u:%02u",
+ t.year, t.month, t.day, t.hour, t.minute, t.second);
+
+#if PHP_MAJOR_VERSION >= 6
+ if (!as_unicode) {
+#endif
+ ZVAL_STRINGL(zv, to, length, 1);
+ mnd_efree(to);
+#if PHP_MAJOR_VERSION >= 6
+ } else {
+ ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
+ }
+#endif
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_string */
+static
+void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ /*
+ For now just copy, before we make it possible
+ to write \0 to the row buffer
+ */
+ unsigned long length= php_mysqlnd_net_field_length(row);
+
+#if PHP_MAJOR_VERSION < 6
+ ZVAL_STRINGL(zv, (char *)*row, length, 1);
+#else
+ if (field->charsetnr == MYSQLND_BINARY_CHARSET_NR) {
+ ZVAL_STRINGL(zv, (char *)*row, length, 1);
+ } else {
+ ZVAL_UTF8_STRINGL(zv, (char*)*row, length, ZSTR_DUPLICATE);
+ }
+#endif
+
+ (*row) += length;
+}
+/* }}} */
+
+
+/* {{{ ps_fetch_bit */
+static
+void ps_fetch_bit(zval *zv, const MYSQLND_FIELD * const field,
+ uint pack_len, zend_uchar **row,
+ zend_bool as_unicode TSRMLS_DC)
+{
+ unsigned long length= php_mysqlnd_net_field_length(row);
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, length TSRMLS_CC);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_init_ps_subsystem */
+void _mysqlnd_init_ps_subsystem()
+{
+ memset(mysqlnd_ps_fetch_functions, 0, sizeof(mysqlnd_ps_fetch_functions));
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func = ps_fetch_null;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].php_type = IS_NULL;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].php_type = IS_DOUBLE;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].php_type = IS_DOUBLE;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_time;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_date;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_date;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].php_type= IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].php_type= IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].is_possibly_blob = TRUE;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].is_possibly_blob = TRUE;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].php_type= IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].is_possibly_blob = TRUE;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].is_possibly_blob = TRUE;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bit;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = 8;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].php_type = IS_LONG;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].is_possibly_blob = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].is_possibly_blob = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].is_possibly_blob = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].php_type = IS_STRING;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].can_ret_as_str_in_uni = TRUE;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].php_type = IS_STRING;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].php_type = IS_STRING;
+
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
+ mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].php_type= IS_STRING;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt_execute_store_params */
+void
+mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uchar **p,
+ size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC)
+{
+ unsigned int i = 0;
+ unsigned left = (*buf_len - (*p - *buf));
+ unsigned int data_size = 0;
+
+/* 1. Store type information */
+ if (stmt->send_types_to_server) {
+
+ /* 2 bytes per type, and leave 20 bytes for future use */
+ if (left < ((stmt->param_count * 2) + 20)) {
+ unsigned int offset = *p - *buf;
+ zend_uchar *tmp_buf;
+ *buf_len = offset + stmt->param_count * 2 + 20;
+ tmp_buf = mnd_emalloc(*buf_len);
+ memcpy(tmp_buf, *buf, offset);
+ *buf = tmp_buf;
+
+ /* Update our pos pointer */
+ *p = *buf + offset;
+ }
+ for (i = 0; i < stmt->param_count; i++) {
+ /* our types are not unsigned */
+#if SIZEOF_LONG==8
+ if (stmt->param_bind[i].type == MYSQL_TYPE_LONG) {
+ stmt->param_bind[i].type = MYSQL_TYPE_LONGLONG;
+ }
+#endif
+ int2store(*p, stmt->param_bind[i].type);
+ *p+= 2;
+ }
+ }
+
+/* 2. Store data */
+ /* 2.1 Calculate how much space we need */
+ for (i = 0; i < stmt->param_count; i++) {
+ if (stmt->param_bind[i].zv &&
+ Z_TYPE_P(stmt->param_bind[i].zv) == IS_NULL) {
+ continue;
+ }
+
+ switch (stmt->param_bind[i].type) {
+ case MYSQL_TYPE_DOUBLE:
+ data_size += 8;
+ break;
+#if SIZEOF_LONG==8
+ case MYSQL_TYPE_LONGLONG:
+ data_size += 8;
+ break;
+#elif SIZEOF_LONG==4
+ case MYSQL_TYPE_LONG:
+ data_size += 4;
+ break;
+#else
+#error "Should not happen"
+#endif
+ case MYSQL_TYPE_LONG_BLOB:
+ if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
+ /*
+ User hasn't sent anything, we will send empty string.
+ Empty string has length of 0, encoded in 1 byte. No real
+ data will follow after it.
+ */
+ data_size++;
+ }
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ data_size += 8; /* max 8 bytes for size */
+ convert_to_string_ex(&stmt->param_bind[i].zv);
+ data_size += Z_STRLEN_P(stmt->param_bind[i].zv);
+ break;
+ }
+
+ }
+
+ /* 2.2 Enlarge the buffer, if needed */
+ left = (*buf_len - (*p - *buf));
+ if (left < data_size) {
+ unsigned int offset = *p - *buf;
+ zend_uchar *tmp_buf;
+ *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
+ tmp_buf = mnd_emalloc(*buf_len);
+ memcpy(tmp_buf, *buf, offset);
+ *buf = tmp_buf;
+ /* Update our pos pointer */
+ *p = *buf + offset;
+ }
+
+ /* 2.3 Store the actual data */
+ for (i = 0; i < stmt->param_count; i++) {
+ zval *data = stmt->param_bind[i].zv;
+ /* Handle long data */
+ if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) {
+ (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
+ } else {
+ switch (stmt->param_bind[i].type) {
+ case MYSQL_TYPE_DOUBLE:
+ convert_to_double_ex(&data);
+ float8store(*p, Z_DVAL_P(data));
+ (*p) += 8;
+ break;
+#if SIZEOF_LONG==8
+ case MYSQL_TYPE_LONGLONG:
+ convert_to_long_ex(&data);
+ int8store(*p, Z_LVAL_P(data));
+ (*p) += 8;
+ break;
+#elif SIZEOF_LONG==4
+ case MYSQL_TYPE_LONG:
+ convert_to_long_ex(&data);
+ int4store(*p, Z_LVAL_P(data));
+ (*p) += 4;
+ break;
+#else
+#error "Should not happen"
+#endif
+ case MYSQL_TYPE_LONG_BLOB:
+ if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
+ stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
+ } else {
+ /* send_long_data() not called, send empty string */
+ *p = php_mysqlnd_net_store_length(*p, 0);
+ }
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ /*
+ If the user uses refs, it could be that the type has
+ has changed and we need to convert, again. Which is noop,
+ if the type hasn't changed.
+ */
+ convert_to_string_ex(&stmt->param_bind[i].zv);
+ {
+ unsigned int len = Z_STRLEN_P(data);
+ /* to is after p. The latter hasn't been moved */
+ *p = php_mysqlnd_net_store_length(*p, len);
+ memcpy(*p, Z_STRVAL_P(data), len);
+ (*p) += len;
+ }
+
+ break;
+ default:
+ /* Won't happen, but set to NULL */
+ (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
+ break;
+ }
+ }
+ }
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt_execute_generate_request */
+zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
+ zend_bool *free_buffer TSRMLS_DC)
+{
+ zend_uchar *p = stmt->cmd_buffer.buffer,
+ *cmd_buffer = stmt->cmd_buffer.buffer;
+ size_t cmd_buffer_length = stmt->cmd_buffer.length;
+ unsigned int null_byte_offset,
+ null_count= (stmt->param_count + 7) / 8;
+
+ int4store(p, stmt->stmt_id);
+ p += 4;
+
+ /* flags is 4 bytes, we store just 1 */
+ int1store(p, (zend_uchar) stmt->flags);
+ p++;
+
+ /* Make it all zero */
+ int4store(p, 0);
+
+ int1store(p, 1); /* and send 1 for iteration count */
+ p+= 4;
+
+
+ null_byte_offset = p - cmd_buffer;
+ memset(p, 0, null_count);
+ p += null_count;
+
+
+ int1store(p, stmt->send_types_to_server);
+ p++;
+
+ mysqlnd_stmt_execute_store_params(stmt, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC);
+
+ *free_buffer = (cmd_buffer != stmt->cmd_buffer.buffer);
+ *request_len = (p - cmd_buffer);
+ return cmd_buffer;
+}
+/* }}} */
+
+/*
+ * 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
+ */