PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd_result_meta.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 171 207 82.6 %
Date: 2014-08-04 Functions: 11 13 84.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 5                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2014 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Andrey Hristov <andrey@mysql.com>                           |
      16             :   |          Ulf Wendel <uwendel@mysql.com>                              |
      17             :   |          Georg Richter <georg@mysql.com>                             |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : #include "php.h"
      23             : #include "mysqlnd.h"
      24             : #include "mysqlnd_priv.h"
      25             : #include "mysqlnd_result.h"
      26             : #include "mysqlnd_wireprotocol.h"
      27             : #include "mysqlnd_debug.h"
      28             : #include "ext/standard/basic_functions.h"
      29             : 
      30             : 
      31             : /* {{{ php_mysqlnd_free_field_metadata */
      32             : static void
      33       32141 : php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent TSRMLS_DC)
      34             : {
      35       32141 :         if (meta) {
      36       32141 :                 if (meta->root) {
      37       27141 :                         mnd_pefree(meta->root, persistent);
      38       27141 :                         meta->root = NULL;
      39             :                 }
      40       32141 :                 if (meta->def) {
      41           3 :                         mnd_pefree(meta->def, persistent);
      42           3 :                         meta->def = NULL;
      43             :                 }
      44             :         }
      45       32141 : }
      46             : /* }}} */
      47             : 
      48             : 
      49             : /* {{{ mysqlnd_handle_numeric */
      50             : /*
      51             :   The following code is stolen from ZE - HANDLE_NUMERIC() macro from zend_hash.c
      52             :   and modified for the needs of mysqlnd.
      53             : */
      54             : static zend_bool
      55       23706 : mysqlnd_is_key_numeric(const char * key, size_t length, long *idx)
      56             : {
      57       23706 :         register const char * tmp = key;
      58             : 
      59       23706 :         if (*tmp=='-') {
      60           5 :                 tmp++;
      61             :         }
      62       23706 :         if ((*tmp>='0' && *tmp<='9')) {
      63             :                 do { /* possibly a numeric index */
      64          76 :                         const char *end=key+length-1;
      65             : 
      66          76 :                         if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */
      67           2 :                                 break;
      68             :                         }
      69         174 :                         while (tmp<end) {
      70          30 :                                 if (!(*tmp>='0' && *tmp<='9')) {
      71             :                                         break;
      72             :                                 }
      73          26 :                                 tmp++;
      74             :                         }
      75          74 :                         if (tmp==end && *tmp=='\0') { /* a numeric index */
      76          70 :                                 if (*key=='-') {
      77           4 :                                         *idx = strtol(key, NULL, 10);
      78           4 :                                         if (*idx!=LONG_MIN) {
      79           4 :                                                 return TRUE;
      80             :                                         }
      81             :                                 } else {
      82          66 :                                         *idx = strtol(key, NULL, 10);
      83          66 :                                         if (*idx!=LONG_MAX) {
      84          66 :                                                 return TRUE;
      85             :                                         }
      86             :                                 }
      87             :                         }
      88             :                 } while (0);
      89             :         }
      90       23636 :         return FALSE;
      91             : }
      92             : /* }}} */
      93             : 
      94             : 
      95             : /* {{{ mysqlnd_res_meta::read_metadata */
      96             : static enum_func_status
      97        7061 : MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND_CONN_DATA * conn TSRMLS_DC)
      98             : {
      99        7061 :         unsigned int i = 0;
     100             :         MYSQLND_PACKET_RES_FIELD * field_packet;
     101             : 
     102        7061 :         DBG_ENTER("mysqlnd_res_meta::read_metadata");
     103             : 
     104        7061 :         field_packet = conn->protocol->m.get_result_field_packet(conn->protocol, FALSE TSRMLS_CC);
     105        7061 :         if (!field_packet) {
     106           0 :                 SET_OOM_ERROR(*conn->error_info);
     107           0 :                 DBG_RETURN(FAIL);
     108             :         }
     109        7061 :         field_packet->persistent_alloc = meta->persistent;
     110       30767 :         for (;i < meta->field_count; i++) {
     111             :                 long idx;
     112             : 
     113       23710 :                 if (meta->fields[i].root) {
     114             :                         /* We re-read metadata for PS */
     115           0 :                         mnd_pefree(meta->fields[i].root, meta->persistent);
     116           0 :                         meta->fields[i].root = NULL;
     117             :                 }
     118             : 
     119       23710 :                 field_packet->metadata = &(meta->fields[i]);
     120       23710 :                 if (FAIL == PACKET_READ(field_packet, conn)) {
     121           0 :                         PACKET_FREE(field_packet);
     122           0 :                         DBG_RETURN(FAIL);
     123             :                 }
     124       23710 :                 if (field_packet->error_info.error_no) {
     125           1 :                         COPY_CLIENT_ERROR(*conn->error_info, field_packet->error_info);
     126             :                         /* Return back from CONN_QUERY_SENT */
     127           1 :                         PACKET_FREE(field_packet);
     128           1 :                         DBG_RETURN(FAIL);
     129             :                 }
     130             : 
     131       23709 :                 if (field_packet->stupid_list_fields_eof == TRUE) {
     132           3 :                         meta->field_count = i;
     133           3 :                         break;
     134             :                 }
     135             : 
     136       23706 :                 if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) {
     137           0 :                         DBG_ERR_FMT("Unknown type %u sent by the server.  Please send a report to the developers",
     138           0 :                                                 meta->fields[i].type);
     139           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
     140             :                                                          "Unknown type %u sent by the server. "
     141             :                                                          "Please send a report to the developers",
     142           0 :                                                          meta->fields[i].type);
     143           0 :                         PACKET_FREE(field_packet);
     144           0 :                         DBG_RETURN(FAIL);
     145             :                 }
     146       23706 :                 if (meta->fields[i].type == MYSQL_TYPE_BIT) {
     147             :                         size_t field_len;
     148        5739 :                         DBG_INF("BIT");
     149        5739 :                         ++meta->bit_fields_count;
     150             :                         /* .length is in bits */
     151        5739 :                         field_len = meta->fields[i].length / 8;
     152             :                         /*
     153             :                           If there is rest, add one byte :
     154             :                           8 bits = 1 byte but 9 bits = 2 bytes
     155             :                         */
     156        5739 :                         if (meta->fields[i].length % 8) {
     157        5115 :                                 ++field_len;
     158             :                         }
     159        5739 :                         switch (field_len) {
     160             :                                 case 8:
     161             :                                 case 7:
     162             :                                 case 6:
     163             :                                 case 5:
     164        1400 :                                         meta->bit_fields_total_len += 20;/* 21 digis, no sign*/
     165        1400 :                                         break;
     166             :                                 case 4:
     167        1080 :                                         meta->bit_fields_total_len += 10;/* 2 000 000 000*/
     168        1080 :                                         break;
     169             :                                 case 3:
     170        1120 :                                         meta->bit_fields_total_len += 8;/*  12 000 000*/
     171        1120 :                                         break;
     172             :                                 case 2:
     173        1120 :                                         meta->bit_fields_total_len += 5;/* 32 500 */
     174        1120 :                                         break;
     175             :                                 case 1:
     176        1019 :                                         meta->bit_fields_total_len += 3;/* 120 */
     177             :                                         break;
     178             :                         }
     179             :                 }
     180             : 
     181             :                 /* For BC we have to check whether the key is numeric and use it like this */
     182       47412 :                 if ((meta->zend_hash_keys[i].is_numeric =
     183       23706 :                                         mysqlnd_is_key_numeric(field_packet->metadata->name,
     184       23706 :                                                                                    field_packet->metadata->name_length + 1,
     185             :                                                                                    &idx)))
     186             :                 {
     187          70 :                         meta->zend_hash_keys[i].key = idx;
     188             :                 } else {
     189       47272 :                         meta->zend_hash_keys[i].key =
     190       23636 :                                         zend_get_hash_value(field_packet->metadata->name,
     191       23636 :                                                                                 field_packet->metadata->name_length + 1);
     192             :                 }
     193             :         }
     194        7060 :         PACKET_FREE(field_packet);
     195             : 
     196        7060 :         DBG_RETURN(PASS);
     197             : }
     198             : /* }}} */
     199             : 
     200             : 
     201             : /* {{{ mysqlnd_res_meta::free */
     202             : static void
     203        8293 : MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA * meta TSRMLS_DC)
     204             : {
     205             :         int i;
     206             :         MYSQLND_FIELD *fields;
     207        8293 :         DBG_ENTER("mysqlnd_res_meta::free");
     208        8293 :         DBG_INF_FMT("persistent=%u", meta->persistent);
     209             : 
     210        8293 :         if ((fields = meta->fields)) {
     211        8293 :                 DBG_INF("Freeing fields metadata");
     212        8293 :                 i = meta->field_count;
     213       48727 :                 while (i--) {
     214       32141 :                         php_mysqlnd_free_field_metadata(fields++, meta->persistent TSRMLS_CC);
     215             :                 }
     216        8293 :                 mnd_pefree(meta->fields, meta->persistent);
     217        8293 :                 meta->fields = NULL;
     218             :         }
     219             : 
     220        8293 :         if (meta->zend_hash_keys) {
     221        8293 :                 DBG_INF("Freeing zend_hash_keys");
     222        8293 :                 mnd_pefree(meta->zend_hash_keys, meta->persistent);
     223        8293 :                 meta->zend_hash_keys = NULL;
     224             :         }
     225        8293 :         DBG_INF("Freeing metadata structure");
     226        8293 :         mnd_pefree(meta, meta->persistent);
     227             : 
     228        8293 :         DBG_VOID_RETURN;
     229             : }
     230             : /* }}} */
     231             : 
     232             : 
     233             : /* {{{ mysqlnd_res::clone_metadata */
     234             : static MYSQLND_RES_METADATA *
     235        1231 : MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent TSRMLS_DC)
     236             : {
     237             :         unsigned int i;
     238             :         /* +1 is to have empty marker at the end */
     239        1231 :         MYSQLND_RES_METADATA * new_meta = NULL;
     240             :         MYSQLND_FIELD * new_fields;
     241        1231 :         MYSQLND_FIELD * orig_fields = meta->fields;
     242        1231 :         size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);
     243             : 
     244        1231 :         DBG_ENTER("mysqlnd_res_meta::clone_metadata");
     245        1231 :         DBG_INF_FMT("persistent=%u", persistent);
     246             : 
     247        1231 :         new_meta = mnd_pecalloc(1, sizeof(MYSQLND_RES_METADATA), persistent);
     248        1231 :         if (!new_meta) {
     249           0 :                 goto oom;
     250             :         }
     251        1231 :         new_meta->persistent = persistent;
     252        1231 :         new_meta->m = meta->m;
     253             : 
     254        1231 :         new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
     255        1231 :         if (!new_fields) {
     256           0 :                 goto oom;
     257             :         }
     258             : 
     259        1231 :         new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
     260        1231 :         if (!new_meta->zend_hash_keys) {
     261           0 :                 goto oom;
     262             :         }
     263        1231 :         memcpy(new_meta->zend_hash_keys, meta->zend_hash_keys, len);
     264             : 
     265             :         /*
     266             :           This will copy also the strings and the root, which we will have
     267             :           to adjust in the loop
     268             :         */
     269        1231 :         memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
     270        4666 :         for (i = 0; i < meta->field_count; i++) {
     271             :                 /* First copy the root, then field by field adjust the pointers */
     272        3435 :                 new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);
     273        3435 :                 if (!new_fields[i].root) {
     274           0 :                         goto oom;
     275             :                 }
     276        3435 :                 memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);
     277             : 
     278        3435 :                 if (orig_fields[i].name && orig_fields[i].name != mysqlnd_empty_string) {
     279        6870 :                         new_fields[i].name = new_fields[i].root +
     280        3435 :                                                                  (orig_fields[i].name - orig_fields[i].root);
     281             :                 }
     282        3435 :                 if (orig_fields[i].org_name && orig_fields[i].org_name != mysqlnd_empty_string) {
     283        5708 :                         new_fields[i].org_name = new_fields[i].root +
     284        2854 :                                                                          (orig_fields[i].org_name - orig_fields[i].root);
     285             :                 }
     286        3435 :                 if (orig_fields[i].table && orig_fields[i].table != mysqlnd_empty_string) {
     287        5692 :                         new_fields[i].table     = new_fields[i].root +
     288        2846 :                                                                   (orig_fields[i].table - orig_fields[i].root);
     289             :                 }
     290        3435 :                 if (orig_fields[i].org_table && orig_fields[i].org_table != mysqlnd_empty_string) {
     291        5636 :                         new_fields[i].org_table = new_fields[i].root +
     292        2818 :                                                                           (orig_fields[i].org_table - orig_fields[i].root);
     293             :                 }
     294        3435 :                 if (orig_fields[i].db && orig_fields[i].db != mysqlnd_empty_string) {
     295        2818 :                         new_fields[i].db = new_fields[i].root + (orig_fields[i].db - orig_fields[i].root);
     296             :                 }
     297        3435 :                 if (orig_fields[i].catalog && orig_fields[i].catalog != mysqlnd_empty_string) {
     298        3435 :                         new_fields[i].catalog = new_fields[i].root + (orig_fields[i].catalog - orig_fields[i].root);
     299             :                 }
     300             :                 /* def is not on the root, if allocated at all */
     301        3435 :                 if (orig_fields[i].def) {
     302           0 :                         new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
     303           0 :                         if (!new_fields[i].def) {
     304           0 :                                 goto oom;
     305             :                         }
     306             :                         /* copy the trailing \0 too */
     307           0 :                         memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
     308             :                 }
     309             :         }
     310        1231 :         new_meta->current_field = 0;
     311        1231 :         new_meta->field_count = meta->field_count;
     312             : 
     313        1231 :         new_meta->fields = new_fields;
     314             : 
     315        1231 :         DBG_RETURN(new_meta);
     316             : oom:
     317           0 :         if (new_meta) {
     318           0 :                 new_meta->m->free_metadata(new_meta TSRMLS_CC);
     319           0 :                 new_meta = NULL;
     320             :         }
     321           0 :         DBG_RETURN(NULL);
     322             : }
     323             : /* }}} */
     324             : 
     325             : /* {{{ mysqlnd_res_meta::fetch_field */
     326             : static const MYSQLND_FIELD *
     327         314 : MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
     328             : {
     329         314 :         DBG_ENTER("mysqlnd_res_meta::fetch_field");
     330         314 :         if (meta->current_field >= meta->field_count) {
     331          18 :                 DBG_INF("no more fields");
     332          18 :                 DBG_RETURN(NULL);
     333             :         }
     334         888 :         DBG_INF_FMT("name=%s max_length=%u",
     335         592 :                 meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
     336         296 :                 meta->fields[meta->current_field].max_length);
     337         296 :         DBG_RETURN(&meta->fields[meta->current_field++]);
     338             : }
     339             : /* }}} */
     340             : 
     341             : 
     342             : /* {{{ mysqlnd_res_meta::fetch_field_direct */
     343             : static const MYSQLND_FIELD *
     344        1080 : MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, const MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
     345             : {
     346        1080 :         DBG_ENTER("mysqlnd_res_meta::fetch_field_direct");
     347        1080 :         DBG_INF_FMT("fieldnr=%u", fieldnr);
     348        3228 :         DBG_INF_FMT("name=%s max_length=%u",
     349        2148 :                 meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
     350        1080 :                 meta->fields[meta->current_field].max_length);
     351        1080 :         DBG_RETURN(&meta->fields[fieldnr]);
     352             : }
     353             : /* }}} */
     354             : 
     355             : 
     356             : /* {{{ mysqlnd_res_meta::fetch_fields */
     357             : static const MYSQLND_FIELD *
     358         952 : MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
     359             : {
     360         952 :         DBG_ENTER("mysqlnd_res_meta::fetch_fields");
     361         952 :         DBG_RETURN(meta->fields);
     362             : }
     363             : /* }}} */
     364             : 
     365             : 
     366             : /* {{{ mysqlnd_res_meta::field_tell */
     367             : static MYSQLND_FIELD_OFFSET
     368         155 : MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const meta TSRMLS_DC)
     369             : {
     370         155 :         return meta->current_field;
     371             : }
     372             : /* }}} */
     373             : 
     374             : /* {{{ mysqlnd_res_meta::field_seek */
     375             : static MYSQLND_FIELD_OFFSET
     376         213 : MYSQLND_METHOD(mysqlnd_res_meta, field_seek)(MYSQLND_RES_METADATA * const meta, const MYSQLND_FIELD_OFFSET field_offset TSRMLS_DC)
     377             : {
     378         213 :         MYSQLND_FIELD_OFFSET return_value = 0;
     379         213 :         DBG_ENTER("mysqlnd_res_meta::fetch_fields");
     380         213 :         return_value = meta->current_field;
     381         213 :         meta->current_field = field_offset;
     382         213 :         DBG_RETURN(return_value);
     383             : }
     384             : /* }}} */
     385             : 
     386             : static
     387             : MYSQLND_CLASS_METHODS_START(mysqlnd_res_meta)
     388             :         MYSQLND_METHOD(mysqlnd_res_meta, fetch_field),
     389             :         MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct),
     390             :         MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields),
     391             :         MYSQLND_METHOD(mysqlnd_res_meta, field_tell),
     392             :         MYSQLND_METHOD(mysqlnd_res_meta, field_seek),
     393             :         MYSQLND_METHOD(mysqlnd_res_meta, read_metadata),
     394             :         MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata),
     395             :         MYSQLND_METHOD(mysqlnd_res_meta, free),
     396             : MYSQLND_CLASS_METHODS_END;
     397             : 
     398             : 
     399             : /* {{{ mysqlnd_result_meta_init */
     400             : PHPAPI MYSQLND_RES_METADATA *
     401        7061 : mysqlnd_result_meta_init(unsigned int field_count, zend_bool persistent TSRMLS_DC)
     402             : {
     403        7061 :         size_t alloc_size = sizeof(MYSQLND_RES_METADATA) + mysqlnd_plugin_count() * sizeof(void *);
     404        7061 :         MYSQLND_RES_METADATA *ret = mnd_pecalloc(1, alloc_size, persistent);
     405        7061 :         DBG_ENTER("mysqlnd_result_meta_init");
     406        7061 :         DBG_INF_FMT("persistent=%u", persistent);
     407             : 
     408             :         do {
     409        7061 :                 if (!ret) {
     410           0 :                         break;
     411             :                 }
     412        7061 :                 ret->m = & mysqlnd_mysqlnd_res_meta_methods;
     413             : 
     414        7061 :                 ret->persistent = persistent;
     415        7061 :                 ret->field_count = field_count;
     416             :                 /* +1 is to have empty marker at the end */
     417        7061 :                 ret->fields = mnd_pecalloc(field_count + 1, sizeof(MYSQLND_FIELD), ret->persistent);
     418        7061 :                 ret->zend_hash_keys = mnd_pecalloc(field_count, sizeof(struct mysqlnd_field_hash_key), ret->persistent);
     419        7061 :                 if (!ret->fields || !ret->zend_hash_keys) {
     420             :                         break;
     421             :                 }
     422        7061 :                 DBG_INF_FMT("meta=%p", ret);
     423        7061 :                 DBG_RETURN(ret);
     424             :         } while (0);
     425           0 :         if (ret) {
     426           0 :                 ret->m->free_metadata(ret TSRMLS_CC);
     427             :         }
     428           0 :         DBG_RETURN(NULL);
     429             : }
     430             : /* }}} */
     431             : 
     432             : 
     433             : /* {{{ mysqlnd_res_meta_get_methods */
     434             : PHPAPI struct st_mysqlnd_res_meta_methods *
     435           0 : mysqlnd_result_metadata_get_methods()
     436             : {
     437           0 :         return &mysqlnd_mysqlnd_res_meta_methods;
     438             : }
     439             : /* }}} */
     440             : 
     441             : 
     442             : /* {{{ _mysqlnd_plugin_get_plugin_result_metadata_data */
     443             : PHPAPI void **
     444           0 : _mysqlnd_plugin_get_plugin_result_metadata_data(const MYSQLND_RES_METADATA * meta, unsigned int plugin_id TSRMLS_DC)
     445             : {
     446           0 :         DBG_ENTER("_mysqlnd_plugin_get_plugin_result_metadata_data");
     447           0 :         DBG_INF_FMT("plugin_id=%u", plugin_id);
     448           0 :         if (!meta || plugin_id >= mysqlnd_plugin_count()) {
     449           0 :                 return NULL;
     450             :         }
     451           0 :         DBG_RETURN((void *)((char *)meta + sizeof(MYSQLND_RES_METADATA) + plugin_id * sizeof(void *)));
     452             : }
     453             : /* }}} */
     454             : 
     455             : /*
     456             :  * Local variables:
     457             :  * tab-width: 4
     458             :  * c-basic-offset: 4
     459             :  * End:
     460             :  * vim600: noet sw=4 ts=4 fdm=marker
     461             :  * vim<600: noet sw=4 ts=4
     462             :  */

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:07 +0000 (29 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.