Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_result_meta.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 2006-2012 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: Georg Richter <georg@mysql.com> |
! 16: | Andrey Hristov <andrey@mysql.com> |
! 17: | Ulf Wendel <uwendel@mysql.com> |
! 18: +----------------------------------------------------------------------+
! 19: */
! 20:
! 21: /* $Id: mysqlnd_result_meta.c 321634 2012-01-01 13:15:04Z felipe $ */
! 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: #if MYSQLND_UNICODE
! 96: /* {{{ mysqlnd_unicode_is_key_numeric */
! 97: static zend_bool
! 98: mysqlnd_unicode_is_key_numeric(UChar *key, size_t length, long *idx)
! 99: {
! 100: register UChar * tmp=key;
! 101:
! 102: if (*tmp==0x2D /*'-'*/) {
! 103: tmp++;
! 104: }
! 105: if ((*tmp>=0x30 /*'0'*/ && *tmp<=0x39 /*'9'*/)) { /* possibly a numeric index */
! 106: do {
! 107: UChar *end=key+length-1;
! 108:
! 109: if (*tmp++==0x30 && length>2) { /* don't accept numbers with leading zeros */
! 110: break;
! 111: }
! 112: while (tmp<end) {
! 113: if (!(*tmp>=0x30 /*'0'*/ && *tmp<=0x39 /*'9'*/)) {
! 114: break;
! 115: }
! 116: tmp++;
! 117: }
! 118: if (tmp==end && *tmp==0) { /* a numeric index */
! 119: if (*key==0x2D /*'-'*/) {
! 120: *idx = zend_u_strtol(key, NULL, 10);
! 121: if (*idx!=LONG_MIN) {
! 122: return TRUE;
! 123: }
! 124: } else {
! 125: *idx = zend_u_strtol(key, NULL, 10);
! 126: if (*idx!=LONG_MAX) {
! 127: return TRUE;
! 128: }
! 129: }
! 130: }
! 131: } while (0);
! 132: }
! 133: return FALSE;
! 134: }
! 135: /* }}} */
! 136: #endif
! 137:
! 138:
! 139: /* {{{ mysqlnd_res_meta::read_metadata */
! 140: static enum_func_status
! 141: MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND *conn TSRMLS_DC)
! 142: {
! 143: unsigned int i = 0;
! 144: MYSQLND_PACKET_RES_FIELD * field_packet;
! 145: #if MYSQLND_UNICODE
! 146: UChar *ustr;
! 147: int ulen;
! 148: #endif
! 149:
! 150: DBG_ENTER("mysqlnd_res_meta::read_metadata");
! 151:
! 152: field_packet = conn->protocol->m.get_result_field_packet(conn->protocol, FALSE TSRMLS_CC);
! 153: if (!field_packet) {
! 154: SET_OOM_ERROR(conn->error_info);
! 155: DBG_RETURN(FAIL);
! 156: }
! 157: field_packet->persistent_alloc = meta->persistent;
! 158: for (;i < meta->field_count; i++) {
! 159: long idx;
! 160:
! 161: if (meta->fields[i].root) {
! 162: /* We re-read metadata for PS */
! 163: mnd_pefree(meta->fields[i].root, meta->persistent);
! 164: meta->fields[i].root = NULL;
! 165: }
! 166:
! 167: field_packet->metadata = &(meta->fields[i]);
! 168: if (FAIL == PACKET_READ(field_packet, conn)) {
! 169: PACKET_FREE(field_packet);
! 170: DBG_RETURN(FAIL);
! 171: }
! 172: if (field_packet->error_info.error_no) {
! 173: conn->error_info = field_packet->error_info;
! 174: /* Return back from CONN_QUERY_SENT */
! 175: PACKET_FREE(field_packet);
! 176: DBG_RETURN(FAIL);
! 177: }
! 178:
! 179: if (field_packet->stupid_list_fields_eof == TRUE) {
! 180: meta->field_count = i;
! 181: break;
! 182: }
! 183:
! 184: if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) {
! 185: DBG_ERR_FMT("Unknown type %u sent by the server. Please send a report to the developers",
! 186: meta->fields[i].type);
! 187: php_error_docref(NULL TSRMLS_CC, E_WARNING,
! 188: "Unknown type %u sent by the server. "
! 189: "Please send a report to the developers",
! 190: meta->fields[i].type);
! 191: PACKET_FREE(field_packet);
! 192: DBG_RETURN(FAIL);
! 193: }
! 194: if (meta->fields[i].type == MYSQL_TYPE_BIT) {
! 195: size_t field_len;
! 196: DBG_INF("BIT");
! 197: ++meta->bit_fields_count;
! 198: /* .length is in bits */
! 199: field_len = meta->fields[i].length / 8;
! 200: /*
! 201: If there is rest, add one byte :
! 202: 8 bits = 1 byte but 9 bits = 2 bytes
! 203: */
! 204: if (meta->fields[i].length % 8) {
! 205: ++field_len;
! 206: }
! 207: switch (field_len) {
! 208: case 8:
! 209: case 7:
! 210: case 6:
! 211: case 5:
! 212: meta->bit_fields_total_len += 20;/* 21 digis, no sign*/
! 213: break;
! 214: case 4:
! 215: meta->bit_fields_total_len += 10;/* 2 000 000 000*/
! 216: break;
! 217: case 3:
! 218: meta->bit_fields_total_len += 8;/* 12 000 000*/
! 219: break;
! 220: case 2:
! 221: meta->bit_fields_total_len += 5;/* 32 500 */
! 222: break;
! 223: case 1:
! 224: meta->bit_fields_total_len += 3;/* 120 */
! 225: break;
! 226: }
! 227: }
! 228:
! 229: #if MYSQLND_UNICODE
! 230: zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen,
! 231: meta->fields[i].name,
! 232: meta->fields[i].name_length TSRMLS_CC);
! 233: if ((meta->zend_hash_keys[i].is_numeric =
! 234: mysqlnd_unicode_is_key_numeric(ustr, ulen + 1, &idx)))
! 235: {
! 236: meta->zend_hash_keys[i].key = idx;
! 237: mnd_efree(ustr);
! 238: } else {
! 239: meta->zend_hash_keys[i].ustr.u = ustr;
! 240: meta->zend_hash_keys[i].ulen = ulen;
! 241: meta->zend_hash_keys[i].key = zend_u_get_hash_value(IS_UNICODE, ZSTR(ustr), ulen + 1);
! 242: }
! 243: #else
! 244: /* For BC we have to check whether the key is numeric and use it like this */
! 245: if ((meta->zend_hash_keys[i].is_numeric =
! 246: mysqlnd_is_key_numeric(field_packet->metadata->name,
! 247: field_packet->metadata->name_length + 1,
! 248: &idx)))
! 249: {
! 250: meta->zend_hash_keys[i].key = idx;
! 251: } else {
! 252: meta->zend_hash_keys[i].key =
! 253: zend_get_hash_value(field_packet->metadata->name,
! 254: field_packet->metadata->name_length + 1);
! 255: }
! 256: #endif
! 257: }
! 258: PACKET_FREE(field_packet);
! 259:
! 260: DBG_RETURN(PASS);
! 261: }
! 262: /* }}} */
! 263:
! 264:
! 265: /* {{{ mysqlnd_res_meta::free */
! 266: static void
! 267: MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA * meta TSRMLS_DC)
! 268: {
! 269: int i;
! 270: MYSQLND_FIELD *fields;
! 271: DBG_ENTER("mysqlnd_res_meta::free");
! 272: DBG_INF_FMT("persistent=%u", meta->persistent);
! 273:
! 274: if ((fields = meta->fields)) {
! 275: DBG_INF("Freeing fields metadata");
! 276: i = meta->field_count;
! 277: while (i--) {
! 278: php_mysqlnd_free_field_metadata(fields++, meta->persistent TSRMLS_CC);
! 279: }
! 280: mnd_pefree(meta->fields, meta->persistent);
! 281: meta->fields = NULL;
! 282: }
! 283:
! 284: if (meta->zend_hash_keys) {
! 285: DBG_INF("Freeing zend_hash_keys");
! 286: #if MYSQLND_UNICODE
! 287: if (UG(unicode)) {
! 288: for (i = 0; i < meta->field_count; i++) {
! 289: if (meta->zend_hash_keys[i].ustr.v) {
! 290: mnd_pefree(meta->zend_hash_keys[i].ustr.v, meta->persistent);
! 291: }
! 292: }
! 293: }
! 294: #endif
! 295: mnd_pefree(meta->zend_hash_keys, meta->persistent);
! 296: meta->zend_hash_keys = NULL;
! 297: }
! 298: DBG_INF("Freeing metadata structure");
! 299: mnd_pefree(meta, meta->persistent);
! 300:
! 301: DBG_VOID_RETURN;
! 302: }
! 303: /* }}} */
! 304:
! 305:
! 306: /* {{{ mysqlnd_res::clone_metadata */
! 307: static MYSQLND_RES_METADATA *
! 308: MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent TSRMLS_DC)
! 309: {
! 310: unsigned int i;
! 311: /* +1 is to have empty marker at the end */
! 312: MYSQLND_RES_METADATA * new_meta = NULL;
! 313: MYSQLND_FIELD * new_fields;
! 314: MYSQLND_FIELD * orig_fields = meta->fields;
! 315: size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);
! 316:
! 317: DBG_ENTER("mysqlnd_res_meta::clone_metadata");
! 318: DBG_INF_FMT("persistent=%u", persistent);
! 319:
! 320: new_meta = mnd_pecalloc(1, sizeof(MYSQLND_RES_METADATA), persistent);
! 321: if (!new_meta) {
! 322: goto oom;
! 323: }
! 324: new_meta->persistent = persistent;
! 325: new_meta->m = meta->m;
! 326:
! 327: new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
! 328: if (!new_fields) {
! 329: goto oom;
! 330: }
! 331:
! 332: new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
! 333: if (!new_meta->zend_hash_keys) {
! 334: goto oom;
! 335: }
! 336: memcpy(new_meta->zend_hash_keys, meta->zend_hash_keys, len);
! 337:
! 338: /*
! 339: This will copy also the strings and the root, which we will have
! 340: to adjust in the loop
! 341: */
! 342: memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
! 343: for (i = 0; i < meta->field_count; i++) {
! 344: /* First copy the root, then field by field adjust the pointers */
! 345: new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);
! 346: if (!new_fields[i].root) {
! 347: goto oom;
! 348: }
! 349: memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);
! 350:
! 351: if (orig_fields[i].name && orig_fields[i].name != mysqlnd_empty_string) {
! 352: new_fields[i].name = new_fields[i].root +
! 353: (orig_fields[i].name - orig_fields[i].root);
! 354: }
! 355: if (orig_fields[i].org_name && orig_fields[i].org_name != mysqlnd_empty_string) {
! 356: new_fields[i].org_name = new_fields[i].root +
! 357: (orig_fields[i].org_name - orig_fields[i].root);
! 358: }
! 359: if (orig_fields[i].table && orig_fields[i].table != mysqlnd_empty_string) {
! 360: new_fields[i].table = new_fields[i].root +
! 361: (orig_fields[i].table - orig_fields[i].root);
! 362: }
! 363: if (orig_fields[i].org_table && orig_fields[i].org_table != mysqlnd_empty_string) {
! 364: new_fields[i].org_table = new_fields[i].root +
! 365: (orig_fields[i].org_table - orig_fields[i].root);
! 366: }
! 367: if (orig_fields[i].db && orig_fields[i].db != mysqlnd_empty_string) {
! 368: new_fields[i].db = new_fields[i].root + (orig_fields[i].db - orig_fields[i].root);
! 369: }
! 370: if (orig_fields[i].catalog && orig_fields[i].catalog != mysqlnd_empty_string) {
! 371: new_fields[i].catalog = new_fields[i].root + (orig_fields[i].catalog - orig_fields[i].root);
! 372: }
! 373: /* def is not on the root, if allocated at all */
! 374: if (orig_fields[i].def) {
! 375: new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
! 376: if (!new_fields[i].def) {
! 377: goto oom;
! 378: }
! 379: /* copy the trailing \0 too */
! 380: memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
! 381: }
! 382: #if MYSQLND_UNICODE
! 383: if (new_meta->zend_hash_keys[i].ustr.u) {
! 384: new_meta->zend_hash_keys[i].ustr.u =
! 385: eustrndup(new_meta->zend_hash_keys[i].ustr.u, new_meta->zend_hash_keys[i].ulen);
! 386: if (!new_meta->zend_hash_keys[i].ustr.u) {
! 387: goto oom;
! 388: }
! 389: }
! 390: #endif
! 391: }
! 392: new_meta->current_field = 0;
! 393: new_meta->field_count = meta->field_count;
! 394:
! 395: new_meta->fields = new_fields;
! 396:
! 397: DBG_RETURN(new_meta);
! 398: oom:
! 399: if (new_meta) {
! 400: new_meta->m->free_metadata(new_meta TSRMLS_CC);
! 401: new_meta = NULL;
! 402: }
! 403: DBG_RETURN(NULL);
! 404: }
! 405: /* }}} */
! 406:
! 407: /* {{{ mysqlnd_res_meta::fetch_field */
! 408: static const MYSQLND_FIELD *
! 409: MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
! 410: {
! 411: DBG_ENTER("mysqlnd_res_meta::fetch_field");
! 412: if (meta->current_field >= meta->field_count) {
! 413: DBG_INF("no more fields");
! 414: DBG_RETURN(NULL);
! 415: }
! 416: DBG_INF_FMT("name=%s max_length=%u",
! 417: meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
! 418: meta->fields[meta->current_field].max_length);
! 419: DBG_RETURN(&meta->fields[meta->current_field++]);
! 420: }
! 421: /* }}} */
! 422:
! 423:
! 424: /* {{{ mysqlnd_res_meta::fetch_field_direct */
! 425: static const MYSQLND_FIELD *
! 426: MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
! 427: {
! 428: DBG_ENTER("mysqlnd_res_meta::fetch_field_direct");
! 429: DBG_INF_FMT("fieldnr=%u", fieldnr);
! 430: DBG_INF_FMT("name=%s max_length=%u",
! 431: meta->fields[meta->current_field].name? meta->fields[meta->current_field].name:"",
! 432: meta->fields[meta->current_field].max_length);
! 433: DBG_RETURN(&meta->fields[fieldnr]);
! 434: }
! 435: /* }}} */
! 436:
! 437:
! 438: /* {{{ mysqlnd_res_meta::fetch_fields */
! 439: static const MYSQLND_FIELD *
! 440: MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
! 441: {
! 442: DBG_ENTER("mysqlnd_res_meta::fetch_fields");
! 443: DBG_RETURN(meta->fields);
! 444: }
! 445: /* }}} */
! 446:
! 447:
! 448: /* {{{ mysqlnd_res_meta::field_tell */
! 449: static MYSQLND_FIELD_OFFSET
! 450: MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const meta TSRMLS_DC)
! 451: {
! 452: return meta->current_field;
! 453: }
! 454: /* }}} */
! 455:
! 456:
! 457: static
! 458: MYSQLND_CLASS_METHODS_START(mysqlnd_res_meta)
! 459: MYSQLND_METHOD(mysqlnd_res_meta, fetch_field),
! 460: MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct),
! 461: MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields),
! 462: MYSQLND_METHOD(mysqlnd_res_meta, field_tell),
! 463: MYSQLND_METHOD(mysqlnd_res_meta, read_metadata),
! 464: MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata),
! 465: MYSQLND_METHOD(mysqlnd_res_meta, free),
! 466: MYSQLND_CLASS_METHODS_END;
! 467:
! 468:
! 469: /* {{{ mysqlnd_result_meta_init */
! 470: PHPAPI MYSQLND_RES_METADATA *
! 471: mysqlnd_result_meta_init(unsigned int field_count, zend_bool persistent TSRMLS_DC)
! 472: {
! 473: size_t alloc_size = sizeof(MYSQLND_RES_METADATA) + mysqlnd_plugin_count() * sizeof(void *);
! 474: MYSQLND_RES_METADATA *ret = mnd_pecalloc(1, alloc_size, persistent);
! 475: DBG_ENTER("mysqlnd_result_meta_init");
! 476: DBG_INF_FMT("persistent=%u", persistent);
! 477:
! 478: do {
! 479: if (!ret) {
! 480: break;
! 481: }
! 482: ret->m = & mysqlnd_mysqlnd_res_meta_methods;
! 483:
! 484: ret->persistent = persistent;
! 485: ret->field_count = field_count;
! 486: /* +1 is to have empty marker at the end */
! 487: ret->fields = mnd_pecalloc(field_count + 1, sizeof(MYSQLND_FIELD), ret->persistent);
! 488: ret->zend_hash_keys = mnd_pecalloc(field_count, sizeof(struct mysqlnd_field_hash_key), ret->persistent);
! 489: if (!ret->fields || !ret->zend_hash_keys) {
! 490: break;
! 491: }
! 492: DBG_INF_FMT("meta=%p", ret);
! 493: DBG_RETURN(ret);
! 494: } while (0);
! 495: if (ret) {
! 496: ret->m->free_metadata(ret TSRMLS_CC);
! 497: }
! 498: DBG_RETURN(NULL);
! 499: }
! 500: /* }}} */
! 501:
! 502:
! 503: /* {{{ mysqlnd_res_meta_get_methods */
! 504: PHPAPI struct st_mysqlnd_res_meta_methods *
! 505: mysqlnd_result_metadata_get_methods()
! 506: {
! 507: return &mysqlnd_mysqlnd_res_meta_methods;
! 508: }
! 509: /* }}} */
! 510:
! 511:
! 512: /* {{{ _mysqlnd_plugin_get_plugin_result_metadata_data */
! 513: PHPAPI void **
! 514: _mysqlnd_plugin_get_plugin_result_metadata_data(const MYSQLND_RES_METADATA * meta, unsigned int plugin_id TSRMLS_DC)
! 515: {
! 516: DBG_ENTER("_mysqlnd_plugin_get_plugin_result_metadata_data");
! 517: DBG_INF_FMT("plugin_id=%u", plugin_id);
! 518: if (!meta || plugin_id >= mysqlnd_plugin_count()) {
! 519: return NULL;
! 520: }
! 521: DBG_RETURN((void *)((char *)meta + sizeof(MYSQLND_RES_METADATA) + plugin_id * sizeof(void *)));
! 522: }
! 523: /* }}} */
! 524:
! 525: /*
! 526: * Local variables:
! 527: * tab-width: 4
! 528: * c-basic-offset: 4
! 529: * End:
! 530: * vim600: noet sw=4 ts=4 fdm=marker
! 531: * vim<600: noet sw=4 ts=4
! 532: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>