/* {{{ ps_fetch_time */ static void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field, unsigned int 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; DBG_ENTER("ps_fetch_time"); 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); DBG_INF_FMT("%s", to); #if PHP_MAJOR_VERSION >= 6 if (!as_unicode) { #endif ZVAL_STRINGL(zv, to, length, 1); efree(to); /* allocated by spprintf */ #if PHP_MAJOR_VERSION >= 6 } else { ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE); } #endif DBG_VOID_RETURN; }
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]; if (type == MYSQL_TYPE_TIME) t->hour+= t->day * 24; 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_time */ static void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field, unsigned int 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 * value; DBG_ENTER("ps_fetch_time"); 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; } length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second); DBG_INF_FMT("%s", value); #if MYSQLND_UNICODE if (!as_unicode) { #endif ZVAL_STRINGL(zv, value, length, 1); mnd_sprintf_free(value); #if MYSQLND_UNICODE } else { ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE); } #endif DBG_VOID_RETURN; }
/* {{{ 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; }
/* {{{ 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_datetime */ static void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field, unsigned int 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 * value; DBG_ENTER("ps_fetch_datetime"); 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(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second); DBG_INF_FMT("%s", value); #if MYSQLND_UNICODE if (!as_unicode) { #endif ZVAL_STRINGL(zv, value, length, 1); efree(value); /* allocated by spprintf */ #if MYSQLND_UNICODE } else { ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE); } #endif DBG_VOID_RETURN; }
/* {{{ ps_fetch_datetime */ static void ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row) { struct st_mysqlnd_time t; zend_ulong length; /* First byte encodes the length*/ char * value; DBG_ENTER("ps_fetch_datetime"); 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) ? (zend_ulong) sint4korr(to+7) : 0; (*row)+= length; } else { memset(&t, 0, sizeof(t)); t.time_type = MYSQLND_TIMESTAMP_DATETIME; } length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second); DBG_INF_FMT("%s", value); ZVAL_STRINGL(zv, value, length); mnd_sprintf_free(value); DBG_VOID_RETURN; }
/* {{{ ps_fetch_from_1_to_8_bytes */ void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field, unsigned int 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; DBG_ENTER("ps_fetch_from_1_to_8_bytes"); DBG_INF_FMT("zv=%p byte_count=%d", zv, byte_count); if (field->flags & UNSIGNED_FLAG) { uint64_t uval = 0; switch (byte_count) { case 8:uval = is_bit? (uint64_t) bit_uint8korr(*row):(uint64_t) 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? (uint64_t) bit_uint4korr(*row):(uint64_t) uint4korr(*row);break; case 3:uval = is_bit? (uint64_t) bit_uint3korr(*row):(uint64_t) uint3korr(*row);break; case 2:uval = is_bit? (uint64_t) bit_uint2korr(*row):(uint64_t) uint2korr(*row);break; case 1:uval = (uint64_t) uint1korr(*row);break; } #if SIZEOF_LONG==4 if (uval > INT_MAX) { DBG_INF("stringify"); 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 { DBG_INF("stringify"); tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval); } } } else { /* SIGNED */ int64_t lval = 0; switch (byte_count) { case 8:lval = (int64_t) sint8korr(*row);break; /* 7, 6 and 5 are not possible. BIT is only unsigned, thus only uint5|6|7 macroses exist */ case 4:lval = (int64_t) sint4korr(*row);break; case 3:lval = (int64_t) sint3korr(*row);break; case 2:lval = (int64_t) sint2korr(*row);break; case 1:lval = (int64_t) *(int8_t*)*row;break; } #if SIZEOF_LONG==4 if ((L64(2147483647) < (int64_t) lval) || (L64(-2147483648) > (int64_t) lval)) { DBG_INF("stringify"); 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) { DBG_INF("stringify"); ZVAL_UTF8_STRINGL(zv, tmp, tmp_len, ZSTR_DUPLICATE); } else #endif { DBG_INF("stringify"); ZVAL_STRINGL(zv, tmp, tmp_len, 1); } } (*row)+= byte_count; DBG_VOID_RETURN; }
/************************************************** read data in binary type **************************************************/ int mysac_decode_binary_row(char *buf, int packet_len, MYSAC_RES *res, MYSAC_ROWS *row) { int j; int i; char nul; unsigned long len; int tmp_len; char *wh; char _null_ptr[16]; char *null_ptr; unsigned char bit; wh = buf; null_ptr = _null_ptr; bit = 4; /* first 2 bits are reserved */ /* first bit is unused */ i = 1; /* skip null bits */ tmp_len = ( (res->nb_cols + 9) / 8 ); if (i + tmp_len > packet_len) return -1; memcpy(_null_ptr, &buf[i], tmp_len); i += tmp_len; for (j = 0; j < res->nb_cols; j++) { /* We should set both row_ptr and is_null to be able to see nulls in mysql_stmt_fetch_column. This is because is_null may point to user data which can be overwritten between mysql_stmt_fetch and mysql_stmt_fetch_column, and in this case nullness of column will be lost. See mysql_stmt_fetch_column for details. */ if ( (*null_ptr & bit) != 0 ) { /* do nothing */ } else { switch (res->cols[j].type) { /* read null */ case MYSQL_TYPE_NULL: row->data[j].blob = NULL; /* read blob */ case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: /* decimal ? maybe for very big num ... crypto key ? */ case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: /* .... */ case MYSQL_TYPE_BIT: /* read text */ case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: /* read date */ case MYSQL_TYPE_NEWDATE: tmp_len = my_lcb(&buf[i], &len, &nul, packet_len-i); if (tmp_len == -1) return -1; i += tmp_len; if (i + len > (unsigned int)packet_len) return -1; if (nul == 1) row->data[j].blob = NULL; else { memmove(wh, &buf[i], len); row->data[j].blob = wh; row->data[j].blob[len] = '\0'; i += len; wh += len + 1; } row->lengths[j] = len; break; case MYSQL_TYPE_TINY: if (i > packet_len - 1) return -1; row->data[j].stiny = buf[i]; i++; break; case MYSQL_TYPE_SHORT: if (i > packet_len - 2) return -1; row->data[j].ssmall = sint2korr(&buf[i]); i += 2; break; case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONG: if (i > packet_len - 4) return -1; row->data[j].sint = sint4korr(&buf[i]); i += 4; break; case MYSQL_TYPE_LONGLONG: if (i > packet_len - 8) return -1; row->data[j].sbigint = sint8korr(&buf[i]); i += 8; break; case MYSQL_TYPE_FLOAT: if (i > packet_len - 4) return -1; float4get(row->data[j].mfloat, &buf[i]); i += 4; break; case MYSQL_TYPE_DOUBLE: if (i > packet_len - 8) return -1; float8get(row->data[j].mdouble, &buf[i]); i += 8; break; /* libmysql/libmysql.c:3370 * static void read_binary_time(MYSQL_TIME *tm, uchar **pos) */ case MYSQL_TYPE_TIME: tmp_len = my_lcb(&buf[i], &len, &nul, packet_len-i); if (tmp_len == -1) return -1; i += tmp_len; if (i + len > (unsigned int)packet_len) return -1; if (nul == 1) row->data[j].blob = NULL; if (len > 0) { row->data[j].tv.tv_sec = ( uint4korr(&buf[i+1]) * 86400 ) + ( buf[i+5] * 3600 ) + ( buf[i+6] * 60 ) + buf[i+7]; if (buf[i] != 0) row->data[j].tv.tv_sec = - row->data[j].tv.tv_sec; if (len > 8) row->data[j].tv.tv_usec = uint4korr(&buf[i+8]); else row->data[j].tv.tv_usec = 0; } i += len; break; case MYSQL_TYPE_YEAR: row->data[j].tm->tm_year = uint2korr(&buf[i]) - 1900; row->data[j].tm->tm_mday = 1; i += 2; break; /* libmysql/libmysql.c:3400 * static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) */ case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME: tmp_len = my_lcb(&buf[i], &len, &nul, packet_len-i); if (tmp_len == -1) return -1; i += tmp_len; if (i + len > (unsigned int)packet_len) return -1; if (nul == 1) row->data[j].blob = NULL; row->data[j].tm->tm_year = uint2korr(&buf[i+0]) - 1900; row->data[j].tm->tm_mon = buf[i+2] - 1; row->data[j].tm->tm_mday = buf[i+3]; if (len > 4) { row->data[j].tm->tm_hour = buf[i+4]; row->data[j].tm->tm_min = buf[i+5]; row->data[j].tm->tm_sec = buf[i+6]; } if (len > 7) { /* les microsecondes ... */ } i += len; break; /* libmysql/libmysql.c:3430 * static void read_binary_date(MYSQL_TIME *tm, uchar **pos) */ case MYSQL_TYPE_DATE: tmp_len = my_lcb(&buf[i], &len, &nul, packet_len-i); if (tmp_len == -1) return -1; i += tmp_len; if (i + len > (unsigned int)packet_len) return -1; if (nul == 1) row->data[j].blob = NULL; row->data[j].tm->tm_year = uint2korr(&buf[i+0]) - 1900; row->data[j].tm->tm_mon = buf[i+2] - 1; row->data[j].tm->tm_mday = buf[i+3]; i += len; break; case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: case MYSQL_TYPE_GEOMETRY: break; } } /* To next bit */ bit <<= 1; /* To next byte */ if ( (bit & 255) == 0 ) { bit = 1; null_ptr++; } } return wh - buf; }