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_METHOD
  3. MYSQLND_METHOD
  4. MYSQLND_METHOD
  5. MYSQLND_METHOD
  6. MYSQLND_CLASS_METHODS_START
  7. mysqlnd_result_metadata_get_methods
  8. _mysqlnd_plugin_get_plugin_result_metadata_data

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   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)
  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                 if (meta->sname) {
  45                         zend_string_release(meta->sname);
  46                 }
  47         }
  48 }
  49 /* }}} */
  50 
  51 /* {{{ mysqlnd_res_meta::read_metadata */
  52 static enum_func_status
  53 MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND_CONN_DATA * conn)
  54 {
  55         unsigned int i = 0;
  56         MYSQLND_PACKET_RES_FIELD * field_packet;
  57 
  58         DBG_ENTER("mysqlnd_res_meta::read_metadata");
  59 
  60         field_packet = conn->protocol->m.get_result_field_packet(conn->protocol, FALSE);
  61         if (!field_packet) {
  62                 SET_OOM_ERROR(*conn->error_info);
  63                 DBG_RETURN(FAIL);
  64         }
  65         field_packet->persistent_alloc = meta->persistent;
  66         for (;i < meta->field_count; i++) {
  67                 zend_ulong idx;
  68 
  69                 if (meta->fields[i].root) {
  70                         /* We re-read metadata for PS */
  71                         mnd_pefree(meta->fields[i].root, meta->persistent);
  72                         meta->fields[i].root = NULL;
  73                 }
  74 
  75                 field_packet->metadata = &(meta->fields[i]);
  76                 if (FAIL == PACKET_READ(field_packet, conn)) {
  77                         PACKET_FREE(field_packet);
  78                         DBG_RETURN(FAIL);
  79                 }
  80                 if (field_packet->error_info.error_no) {
  81                         COPY_CLIENT_ERROR(*conn->error_info, field_packet->error_info);
  82                         /* Return back from CONN_QUERY_SENT */
  83                         PACKET_FREE(field_packet);
  84                         DBG_RETURN(FAIL);
  85                 }
  86 
  87                 if (field_packet->stupid_list_fields_eof == TRUE) {
  88                         meta->field_count = i;
  89                         break;
  90                 }
  91 
  92                 if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) {
  93                         DBG_ERR_FMT("Unknown type %u sent by the server.  Please send a report to the developers",
  94                                                 meta->fields[i].type);
  95                         php_error_docref(NULL, E_WARNING,
  96                                                          "Unknown type %u sent by the server. "
  97                                                          "Please send a report to the developers",
  98                                                          meta->fields[i].type);
  99                         PACKET_FREE(field_packet);
 100                         DBG_RETURN(FAIL);
 101                 }
 102                 if (meta->fields[i].type == MYSQL_TYPE_BIT) {
 103                         size_t field_len;
 104                         DBG_INF("BIT");
 105                         ++meta->bit_fields_count;
 106                         /* .length is in bits */
 107                         field_len = meta->fields[i].length / 8;
 108                         /*
 109                           If there is rest, add one byte :
 110                           8 bits = 1 byte but 9 bits = 2 bytes
 111                         */
 112                         if (meta->fields[i].length % 8) {
 113                                 ++field_len;
 114                         }
 115                         switch (field_len) {
 116                                 case 8:
 117                                 case 7:
 118                                 case 6:
 119                                 case 5:
 120                                         meta->bit_fields_total_len += 20;/* 21 digis, no sign*/
 121                                         break;
 122                                 case 4:
 123                                         meta->bit_fields_total_len += 10;/* 2 000 000 000*/
 124                                         break;
 125                                 case 3:
 126                                         meta->bit_fields_total_len += 8;/*  12 000 000*/
 127                                         break;
 128                                 case 2:
 129                                         meta->bit_fields_total_len += 5;/* 32 500 */
 130                                         break;
 131                                 case 1:
 132                                         meta->bit_fields_total_len += 3;/* 120 */
 133                                         break;
 134                         }
 135                 }
 136 
 137                 /* For BC we have to check whether the key is numeric and use it like this */
 138                 if ((meta->zend_hash_keys[i].is_numeric = ZEND_HANDLE_NUMERIC(field_packet->metadata->sname, idx))) {
 139                         meta->zend_hash_keys[i].key = idx;
 140                 }
 141         }
 142         PACKET_FREE(field_packet);
 143 
 144         DBG_RETURN(PASS);
 145 }
 146 /* }}} */
 147 
 148 
 149 /* {{{ mysqlnd_res_meta::free */
 150 static void
 151 MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA * meta)
 152 {
 153         int i;
 154         MYSQLND_FIELD *fields;
 155         DBG_ENTER("mysqlnd_res_meta::free");
 156         DBG_INF_FMT("persistent=%u", meta->persistent);
 157 
 158         if ((fields = meta->fields)) {
 159                 DBG_INF("Freeing fields metadata");
 160                 i = meta->field_count;
 161                 while (i--) {
 162                         php_mysqlnd_free_field_metadata(fields++, meta->persistent);
 163                 }
 164                 mnd_pefree(meta->fields, meta->persistent);
 165                 meta->fields = NULL;
 166         }
 167 
 168         if (meta->zend_hash_keys) {
 169                 DBG_INF("Freeing zend_hash_keys");
 170                 mnd_pefree(meta->zend_hash_keys, meta->persistent);
 171                 meta->zend_hash_keys = NULL;
 172         }
 173         DBG_INF("Freeing metadata structure");
 174         mnd_pefree(meta, meta->persistent);
 175 
 176         DBG_VOID_RETURN;
 177 }
 178 /* }}} */
 179 
 180 
 181 /* {{{ mysqlnd_res::clone_metadata */
 182 static MYSQLND_RES_METADATA *
 183 MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent)
 184 {
 185         unsigned int i;
 186         /* +1 is to have empty marker at the end */
 187         MYSQLND_RES_METADATA * new_meta = NULL;
 188         MYSQLND_FIELD * new_fields;
 189         MYSQLND_FIELD * orig_fields = meta->fields;
 190         size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);
 191 
 192         DBG_ENTER("mysqlnd_res_meta::clone_metadata");
 193         DBG_INF_FMT("persistent=%u", persistent);
 194 
 195         new_meta = mnd_pecalloc(1, sizeof(MYSQLND_RES_METADATA), persistent);
 196         if (!new_meta) {
 197                 goto oom;
 198         }
 199         new_meta->persistent = persistent;
 200         new_meta->m = meta->m;
 201 
 202         new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
 203         if (!new_fields) {
 204                 goto oom;
 205         }
 206 
 207         new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
 208         if (!new_meta->zend_hash_keys) {
 209                 goto oom;
 210         }
 211         memcpy(new_meta->zend_hash_keys, meta->zend_hash_keys, len);
 212 
 213         /*
 214           This will copy also the strings and the root, which we will have
 215           to adjust in the loop
 216         */
 217         memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
 218         for (i = 0; i < meta->field_count; i++) {
 219                 /* First copy the root, then field by field adjust the pointers */
 220                 new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);
 221 
 222                 if (!new_fields[i].root) {
 223                         goto oom;
 224                 }
 225 
 226                 memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);
 227 
 228                 if (orig_fields[i].sname) {
 229                         new_fields[i].sname = zend_string_copy(orig_fields[i].sname);
 230                         new_fields[i].name = ZSTR_VAL(new_fields[i].sname);
 231                         new_fields[i].name_length = ZSTR_LEN(new_fields[i].sname);
 232                 }
 233 
 234                 if (orig_fields[i].org_name && orig_fields[i].org_name != mysqlnd_empty_string) {
 235                         new_fields[i].org_name = new_fields[i].root +
 236                                 (orig_fields[i].org_name - orig_fields[i].root);
 237                 }
 238                 if (orig_fields[i].table && orig_fields[i].table != mysqlnd_empty_string) {
 239                         new_fields[i].table     = new_fields[i].root +
 240                                 (orig_fields[i].table - orig_fields[i].root);
 241                 }
 242                 if (orig_fields[i].org_table && orig_fields[i].org_table != mysqlnd_empty_string) {
 243                         new_fields[i].org_table = new_fields[i].root +
 244                                 (orig_fields[i].org_table - orig_fields[i].root);
 245                 }
 246                 if (orig_fields[i].db && orig_fields[i].db != mysqlnd_empty_string) {
 247                         new_fields[i].db = new_fields[i].root + (orig_fields[i].db - orig_fields[i].root);
 248                 }
 249                 if (orig_fields[i].catalog && orig_fields[i].catalog != mysqlnd_empty_string) {
 250                         new_fields[i].catalog = new_fields[i].root + (orig_fields[i].catalog - orig_fields[i].root);
 251                 }
 252                 /* def is not on the root, if allocated at all */
 253                 if (orig_fields[i].def) {
 254                         new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
 255                         if (!new_fields[i].def) {
 256                                 goto oom;
 257                         }
 258                         /* copy the trailing \0 too */
 259                         memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
 260                 }
 261         }
 262         new_meta->current_field = 0;
 263         new_meta->field_count = meta->field_count;
 264 
 265         new_meta->fields = new_fields;
 266 
 267         DBG_RETURN(new_meta);
 268 oom:
 269         if (new_meta) {
 270                 new_meta->m->free_metadata(new_meta);
 271                 new_meta = NULL;
 272         }
 273         DBG_RETURN(NULL);
 274 }
 275 /* }}} */
 276 
 277 
 278 /* {{{ mysqlnd_res_meta::fetch_field */
 279 static const MYSQLND_FIELD *
 280 MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta)
 281 {
 282         DBG_ENTER("mysqlnd_res_meta::fetch_field");
 283         if (meta->current_field >= meta->field_count) {
 284                 DBG_INF("no more fields");
 285                 DBG_RETURN(NULL);
 286         }
 287         DBG_INF_FMT("name=%s max_length=%u",
 288                 meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
 289                 meta->fields[meta->current_field].max_length);
 290         DBG_RETURN(&meta->fields[meta->current_field++]);
 291 }
 292 /* }}} */
 293 
 294 
 295 /* {{{ mysqlnd_res_meta::fetch_field_direct */
 296 static const MYSQLND_FIELD *
 297 MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, const MYSQLND_FIELD_OFFSET fieldnr)
 298 {
 299         DBG_ENTER("mysqlnd_res_meta::fetch_field_direct");
 300         DBG_INF_FMT("fieldnr=%u", fieldnr);
 301         DBG_INF_FMT("name=%s max_length=%u",
 302                 meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
 303                 meta->fields[meta->current_field].max_length);
 304         DBG_RETURN(&meta->fields[fieldnr]);
 305 }
 306 /* }}} */
 307 
 308 
 309 /* {{{ mysqlnd_res_meta::fetch_fields */
 310 static const MYSQLND_FIELD *
 311 MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields)(MYSQLND_RES_METADATA * const meta)
 312 {
 313         DBG_ENTER("mysqlnd_res_meta::fetch_fields");
 314         DBG_RETURN(meta->fields);
 315 }
 316 /* }}} */
 317 
 318 
 319 /* {{{ mysqlnd_res_meta::field_tell */
 320 static MYSQLND_FIELD_OFFSET
 321 MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const meta)
 322 {
 323         return meta->current_field;
 324 }
 325 /* }}} */
 326 
 327 
 328 /* {{{ mysqlnd_res_meta::field_seek */
 329 static MYSQLND_FIELD_OFFSET
 330 MYSQLND_METHOD(mysqlnd_res_meta, field_seek)(MYSQLND_RES_METADATA * const meta, const MYSQLND_FIELD_OFFSET field_offset)
 331 {
 332         MYSQLND_FIELD_OFFSET return_value = 0;
 333         DBG_ENTER("mysqlnd_res_meta::fetch_fields");
 334         return_value = meta->current_field;
 335         meta->current_field = field_offset;
 336         DBG_RETURN(return_value);
 337 }
 338 /* }}} */
 339 
 340 static
 341 MYSQLND_CLASS_METHODS_START(mysqlnd_res_meta)
 342         MYSQLND_METHOD(mysqlnd_res_meta, fetch_field),
 343         MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct),
 344         MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields),
 345         MYSQLND_METHOD(mysqlnd_res_meta, field_tell),
 346         MYSQLND_METHOD(mysqlnd_res_meta, field_seek),
 347         MYSQLND_METHOD(mysqlnd_res_meta, read_metadata),
 348         MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata),
 349         MYSQLND_METHOD(mysqlnd_res_meta, free),
 350 MYSQLND_CLASS_METHODS_END;
 351 
 352 
 353 /* {{{ mysqlnd_result_meta_init */
 354 PHPAPI MYSQLND_RES_METADATA *
 355 mysqlnd_result_meta_init(unsigned int field_count, zend_bool persistent)
 356 {
 357         size_t alloc_size = sizeof(MYSQLND_RES_METADATA) + mysqlnd_plugin_count() * sizeof(void *);
 358         MYSQLND_RES_METADATA *ret = mnd_pecalloc(1, alloc_size, persistent);
 359         DBG_ENTER("mysqlnd_result_meta_init");
 360         DBG_INF_FMT("persistent=%u", persistent);
 361 
 362         do {
 363                 if (!ret) {
 364                         break;
 365                 }
 366                 ret->m = & mysqlnd_mysqlnd_res_meta_methods;
 367 
 368                 ret->persistent = persistent;
 369                 ret->field_count = field_count;
 370                 /* +1 is to have empty marker at the end */
 371                 ret->fields = mnd_pecalloc(field_count + 1, sizeof(MYSQLND_FIELD), ret->persistent);
 372                 ret->zend_hash_keys = mnd_pecalloc(field_count, sizeof(struct mysqlnd_field_hash_key), ret->persistent);
 373                 if (!ret->fields || !ret->zend_hash_keys) {
 374                         break;
 375                 }
 376                 DBG_INF_FMT("meta=%p", ret);
 377                 DBG_RETURN(ret);
 378         } while (0);
 379         if (ret) {
 380                 ret->m->free_metadata(ret);
 381         }
 382         DBG_RETURN(NULL);
 383 }
 384 /* }}} */
 385 
 386 
 387 /* {{{ mysqlnd_res_meta_get_methods */
 388 PHPAPI struct st_mysqlnd_res_meta_methods *
 389 mysqlnd_result_metadata_get_methods()
 390 {
 391         return &mysqlnd_mysqlnd_res_meta_methods;
 392 }
 393 /* }}} */
 394 
 395 
 396 /* {{{ _mysqlnd_plugin_get_plugin_result_metadata_data */
 397 PHPAPI void **
 398 _mysqlnd_plugin_get_plugin_result_metadata_data(const MYSQLND_RES_METADATA * meta, unsigned int plugin_id)
 399 {
 400         DBG_ENTER("_mysqlnd_plugin_get_plugin_result_metadata_data");
 401         DBG_INF_FMT("plugin_id=%u", plugin_id);
 402         if (!meta || plugin_id >= mysqlnd_plugin_count()) {
 403                 return NULL;
 404         }
 405         DBG_RETURN((void *)((char *)meta + sizeof(MYSQLND_RES_METADATA) + plugin_id * sizeof(void *)));
 406 }
 407 /* }}} */
 408 
 409 /*
 410  * Local variables:
 411  * tab-width: 4
 412  * c-basic-offset: 4
 413  * End:
 414  * vim600: noet sw=4 ts=4 fdm=marker
 415  * vim<600: noet sw=4 ts=4
 416  */

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