root/ext/mysqlnd/mysqlnd_result_meta.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_mysqlnd_free_field_metadata
  2. mysqlnd_is_key_numeric
  3. MYSQLND_METHOD
  4. MYSQLND_METHOD
  5. MYSQLND_METHOD
  6. MYSQLND_METHOD
  7. MYSQLND_CLASS_METHODS_START
  8. mysqlnd_result_metadata_get_methods
  9. _mysqlnd_plugin_get_plugin_result_metadata_data

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 5                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 2006-2016 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 php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent TSRMLS_DC)
  34 {
  35         if (meta) {
  36                 if (meta->root) {
  37                         mnd_pefree(meta->root, persistent);
  38                         meta->root = NULL;
  39                 }
  40                 if (meta->def) {
  41                         mnd_pefree(meta->def, persistent);
  42                         meta->def = NULL;
  43                 }
  44         }
  45 }
  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 mysqlnd_is_key_numeric(const char * key, size_t length, long *idx)
  56 {
  57         register const char * tmp = key;
  58 
  59         if (*tmp=='-') {
  60                 tmp++;
  61         }
  62         if ((*tmp>='0' && *tmp<='9')) {
  63                 do { /* possibly a numeric index */
  64                         const char *end=key+length-1;
  65 
  66                         if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */
  67                                 break;
  68                         }
  69                         while (tmp<end) {
  70                                 if (!(*tmp>='0' && *tmp<='9')) {
  71                                         break;
  72                                 }
  73                                 tmp++;
  74                         }
  75                         if (tmp==end && *tmp=='\0') { /* a numeric index */
  76                                 if (*key=='-') {
  77                                         *idx = strtol(key, NULL, 10);
  78                                         if (*idx!=LONG_MIN) {
  79                                                 return TRUE;
  80                                         }
  81                                 } else {
  82                                         *idx = strtol(key, NULL, 10);
  83                                         if (*idx!=LONG_MAX) {
  84                                                 return TRUE;
  85                                         }
  86                                 }
  87                         }
  88                 } while (0);
  89         }
  90         return FALSE;
  91 }
  92 /* }}} */
  93 
  94 
  95 /* {{{ mysqlnd_res_meta::read_metadata */
  96 static enum_func_status
  97 MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND_CONN_DATA * conn TSRMLS_DC)
  98 {
  99         unsigned int i = 0;
 100         MYSQLND_PACKET_RES_FIELD * field_packet;
 101 
 102         DBG_ENTER("mysqlnd_res_meta::read_metadata");
 103 
 104         field_packet = conn->protocol->m.get_result_field_packet(conn->protocol, FALSE TSRMLS_CC);
 105         if (!field_packet) {
 106                 SET_OOM_ERROR(*conn->error_info);
 107                 DBG_RETURN(FAIL);
 108         }
 109         field_packet->persistent_alloc = meta->persistent;
 110         for (;i < meta->field_count; i++) {
 111                 long idx;
 112 
 113                 if (meta->fields[i].root) {
 114                         /* We re-read metadata for PS */
 115                         mnd_pefree(meta->fields[i].root, meta->persistent);
 116                         meta->fields[i].root = NULL;
 117                 }
 118 
 119                 field_packet->metadata = &(meta->fields[i]);
 120                 if (FAIL == PACKET_READ(field_packet, conn)) {
 121                         PACKET_FREE(field_packet);
 122                         DBG_RETURN(FAIL);
 123                 }
 124                 if (field_packet->error_info.error_no) {
 125                         COPY_CLIENT_ERROR(*conn->error_info, field_packet->error_info);
 126                         /* Return back from CONN_QUERY_SENT */
 127                         PACKET_FREE(field_packet);
 128                         DBG_RETURN(FAIL);
 129                 }
 130 
 131                 if (field_packet->stupid_list_fields_eof == TRUE) {
 132                         meta->field_count = i;
 133                         break;
 134                 }
 135 
 136                 if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) {
 137                         DBG_ERR_FMT("Unknown type %u sent by the server.  Please send a report to the developers",
 138                                                 meta->fields[i].type);
 139                         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                                                          meta->fields[i].type);
 143                         PACKET_FREE(field_packet);
 144                         DBG_RETURN(FAIL);
 145                 }
 146                 if (meta->fields[i].type == MYSQL_TYPE_BIT) {
 147                         size_t field_len;
 148                         DBG_INF("BIT");
 149                         ++meta->bit_fields_count;
 150                         /* .length is in bits */
 151                         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                         if (meta->fields[i].length % 8) {
 157                                 ++field_len;
 158                         }
 159                         switch (field_len) {
 160                                 case 8:
 161                                 case 7:
 162                                 case 6:
 163                                 case 5:
 164                                         meta->bit_fields_total_len += 20;/* 21 digis, no sign*/
 165                                         break;
 166                                 case 4:
 167                                         meta->bit_fields_total_len += 10;/* 2 000 000 000*/
 168                                         break;
 169                                 case 3:
 170                                         meta->bit_fields_total_len += 8;/*  12 000 000*/
 171                                         break;
 172                                 case 2:
 173                                         meta->bit_fields_total_len += 5;/* 32 500 */
 174                                         break;
 175                                 case 1:
 176                                         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                 if ((meta->zend_hash_keys[i].is_numeric =
 183                                         mysqlnd_is_key_numeric(field_packet->metadata->name,
 184                                                                                    field_packet->metadata->name_length + 1,
 185                                                                                    &idx)))
 186                 {
 187                         meta->zend_hash_keys[i].key = idx;
 188                 } else {
 189                         meta->zend_hash_keys[i].key =
 190                                         zend_get_hash_value(field_packet->metadata->name,
 191                                                                                 field_packet->metadata->name_length + 1);
 192                 }
 193         }
 194         PACKET_FREE(field_packet);
 195 
 196         DBG_RETURN(PASS);
 197 }
 198 /* }}} */
 199 
 200 
 201 /* {{{ mysqlnd_res_meta::free */
 202 static void
 203 MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA * meta TSRMLS_DC)
 204 {
 205         int i;
 206         MYSQLND_FIELD *fields;
 207         DBG_ENTER("mysqlnd_res_meta::free");
 208         DBG_INF_FMT("persistent=%u", meta->persistent);
 209 
 210         if ((fields = meta->fields)) {
 211                 DBG_INF("Freeing fields metadata");
 212                 i = meta->field_count;
 213                 while (i--) {
 214                         php_mysqlnd_free_field_metadata(fields++, meta->persistent TSRMLS_CC);
 215                 }
 216                 mnd_pefree(meta->fields, meta->persistent);
 217                 meta->fields = NULL;
 218         }
 219 
 220         if (meta->zend_hash_keys) {
 221                 DBG_INF("Freeing zend_hash_keys");
 222                 mnd_pefree(meta->zend_hash_keys, meta->persistent);
 223                 meta->zend_hash_keys = NULL;
 224         }
 225         DBG_INF("Freeing metadata structure");
 226         mnd_pefree(meta, meta->persistent);
 227 
 228         DBG_VOID_RETURN;
 229 }
 230 /* }}} */
 231 
 232 
 233 /* {{{ mysqlnd_res::clone_metadata */
 234 static MYSQLND_RES_METADATA *
 235 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         MYSQLND_RES_METADATA * new_meta = NULL;
 240         MYSQLND_FIELD * new_fields;
 241         MYSQLND_FIELD * orig_fields = meta->fields;
 242         size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);
 243 
 244         DBG_ENTER("mysqlnd_res_meta::clone_metadata");
 245         DBG_INF_FMT("persistent=%u", persistent);
 246 
 247         new_meta = mnd_pecalloc(1, sizeof(MYSQLND_RES_METADATA), persistent);
 248         if (!new_meta) {
 249                 goto oom;
 250         }
 251         new_meta->persistent = persistent;
 252         new_meta->m = meta->m;
 253 
 254         new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
 255         if (!new_fields) {
 256                 goto oom;
 257         }
 258 
 259         new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
 260         if (!new_meta->zend_hash_keys) {
 261                 goto oom;
 262         }
 263         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         memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
 270         for (i = 0; i < meta->field_count; i++) {
 271                 /* First copy the root, then field by field adjust the pointers */
 272                 new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);
 273                 if (!new_fields[i].root) {
 274                         goto oom;
 275                 }
 276                 memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);
 277 
 278                 if (orig_fields[i].name && orig_fields[i].name != mysqlnd_empty_string) {
 279                         new_fields[i].name = new_fields[i].root +
 280                                                                  (orig_fields[i].name - orig_fields[i].root);
 281                 }
 282                 if (orig_fields[i].org_name && orig_fields[i].org_name != mysqlnd_empty_string) {
 283                         new_fields[i].org_name = new_fields[i].root +
 284                                                                          (orig_fields[i].org_name - orig_fields[i].root);
 285                 }
 286                 if (orig_fields[i].table && orig_fields[i].table != mysqlnd_empty_string) {
 287                         new_fields[i].table     = new_fields[i].root +
 288                                                                   (orig_fields[i].table - orig_fields[i].root);
 289                 }
 290                 if (orig_fields[i].org_table && orig_fields[i].org_table != mysqlnd_empty_string) {
 291                         new_fields[i].org_table = new_fields[i].root +
 292                                                                           (orig_fields[i].org_table - orig_fields[i].root);
 293                 }
 294                 if (orig_fields[i].db && orig_fields[i].db != mysqlnd_empty_string) {
 295                         new_fields[i].db = new_fields[i].root + (orig_fields[i].db - orig_fields[i].root);
 296                 }
 297                 if (orig_fields[i].catalog && orig_fields[i].catalog != mysqlnd_empty_string) {
 298                         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                 if (orig_fields[i].def) {
 302                         new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
 303                         if (!new_fields[i].def) {
 304                                 goto oom;
 305                         }
 306                         /* copy the trailing \0 too */
 307                         memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
 308                 }
 309         }
 310         new_meta->current_field = 0;
 311         new_meta->field_count = meta->field_count;
 312 
 313         new_meta->fields = new_fields;
 314 
 315         DBG_RETURN(new_meta);
 316 oom:
 317         if (new_meta) {
 318                 new_meta->m->free_metadata(new_meta TSRMLS_CC);
 319                 new_meta = NULL;
 320         }
 321         DBG_RETURN(NULL);
 322 }
 323 /* }}} */
 324 
 325 /* {{{ mysqlnd_res_meta::fetch_field */
 326 static const MYSQLND_FIELD *
 327 MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
 328 {
 329         DBG_ENTER("mysqlnd_res_meta::fetch_field");
 330         if (meta->current_field >= meta->field_count) {
 331                 DBG_INF("no more fields");
 332                 DBG_RETURN(NULL);
 333         }
 334         DBG_INF_FMT("name=%s max_length=%u",
 335                 meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
 336                 meta->fields[meta->current_field].max_length);
 337         DBG_RETURN(&meta->fields[meta->current_field++]);
 338 }
 339 /* }}} */
 340 
 341 
 342 /* {{{ mysqlnd_res_meta::fetch_field_direct */
 343 static const MYSQLND_FIELD *
 344 MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, const MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
 345 {
 346         DBG_ENTER("mysqlnd_res_meta::fetch_field_direct");
 347         DBG_INF_FMT("fieldnr=%u", fieldnr);
 348         DBG_INF_FMT("name=%s max_length=%u",
 349                 meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
 350                 meta->fields[meta->current_field].max_length);
 351         DBG_RETURN(&meta->fields[fieldnr]);
 352 }
 353 /* }}} */
 354 
 355 
 356 /* {{{ mysqlnd_res_meta::fetch_fields */
 357 static const MYSQLND_FIELD *
 358 MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
 359 {
 360         DBG_ENTER("mysqlnd_res_meta::fetch_fields");
 361         DBG_RETURN(meta->fields);
 362 }
 363 /* }}} */
 364 
 365 
 366 /* {{{ mysqlnd_res_meta::field_tell */
 367 static MYSQLND_FIELD_OFFSET
 368 MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const meta TSRMLS_DC)
 369 {
 370         return meta->current_field;
 371 }
 372 /* }}} */
 373 
 374 /* {{{ mysqlnd_res_meta::field_seek */
 375 static MYSQLND_FIELD_OFFSET
 376 MYSQLND_METHOD(mysqlnd_res_meta, field_seek)(MYSQLND_RES_METADATA * const meta, const MYSQLND_FIELD_OFFSET field_offset TSRMLS_DC)
 377 {
 378         MYSQLND_FIELD_OFFSET return_value = 0;
 379         DBG_ENTER("mysqlnd_res_meta::fetch_fields");
 380         return_value = meta->current_field;
 381         meta->current_field = field_offset;
 382         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 mysqlnd_result_meta_init(unsigned int field_count, zend_bool persistent TSRMLS_DC)
 402 {
 403         size_t alloc_size = sizeof(MYSQLND_RES_METADATA) + mysqlnd_plugin_count() * sizeof(void *);
 404         MYSQLND_RES_METADATA *ret = mnd_pecalloc(1, alloc_size, persistent);
 405         DBG_ENTER("mysqlnd_result_meta_init");
 406         DBG_INF_FMT("persistent=%u", persistent);
 407 
 408         do {
 409                 if (!ret) {
 410                         break;
 411                 }
 412                 ret->m = & mysqlnd_mysqlnd_res_meta_methods;
 413 
 414                 ret->persistent = persistent;
 415                 ret->field_count = field_count;
 416                 /* +1 is to have empty marker at the end */
 417                 ret->fields = mnd_pecalloc(field_count + 1, sizeof(MYSQLND_FIELD), ret->persistent);
 418                 ret->zend_hash_keys = mnd_pecalloc(field_count, sizeof(struct mysqlnd_field_hash_key), ret->persistent);
 419                 if (!ret->fields || !ret->zend_hash_keys) {
 420                         break;
 421                 }
 422                 DBG_INF_FMT("meta=%p", ret);
 423                 DBG_RETURN(ret);
 424         } while (0);
 425         if (ret) {
 426                 ret->m->free_metadata(ret TSRMLS_CC);
 427         }
 428         DBG_RETURN(NULL);
 429 }
 430 /* }}} */
 431 
 432 
 433 /* {{{ mysqlnd_res_meta_get_methods */
 434 PHPAPI struct st_mysqlnd_res_meta_methods *
 435 mysqlnd_result_metadata_get_methods()
 436 {
 437         return &mysqlnd_mysqlnd_res_meta_methods;
 438 }
 439 /* }}} */
 440 
 441 
 442 /* {{{ _mysqlnd_plugin_get_plugin_result_metadata_data */
 443 PHPAPI void **
 444 _mysqlnd_plugin_get_plugin_result_metadata_data(const MYSQLND_RES_METADATA * meta, unsigned int plugin_id TSRMLS_DC)
 445 {
 446         DBG_ENTER("_mysqlnd_plugin_get_plugin_result_metadata_data");
 447         DBG_INF_FMT("plugin_id=%u", plugin_id);
 448         if (!meta || plugin_id >= mysqlnd_plugin_count()) {
 449                 return NULL;
 450         }
 451         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  */

/* [<][>][^][v][top][bottom][index][help] */