Return to mysqlnd.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / mysqlnd |
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.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 22: #include "php.h" ! 23: #include "mysqlnd.h" ! 24: #include "mysqlnd_wireprotocol.h" ! 25: #include "mysqlnd_priv.h" ! 26: #include "mysqlnd_result.h" ! 27: #include "mysqlnd_statistics.h" ! 28: #include "mysqlnd_charset.h" ! 29: #include "mysqlnd_debug.h" ! 30: /* for php_get_current_user() */ ! 31: #include "ext/standard/basic_functions.h" ! 32: ! 33: /* ! 34: TODO : ! 35: - Don't bind so tightly the metadata with the result set. This means ! 36: that the metadata reading should not expect a MYSQLND_RES pointer, it ! 37: does not need it, but return a pointer to the metadata (MYSQLND_FIELD *). ! 38: For normal statements we will then just assign it to a member of ! 39: MYSQLND_RES. For PS statements, it will stay as part of the statement ! 40: (MYSQLND_STMT) between prepare and execute. At execute the new metadata ! 41: will be sent by the server, so we will discard the old one and then ! 42: finally attach it to the result set. This will make the code more clean, ! 43: as a prepared statement won't have anymore stmt->result != NULL, as it ! 44: is now, just to have where to store the metadata. ! 45: ! 46: - Change mysqlnd_simple_command to accept a heap dynamic array of MYSQLND_STRING ! 47: terminated by a string with ptr being NULL. Thus, multi-part messages can be ! 48: sent to the network like writev() and this can save at least for ! 49: mysqlnd_stmt_send_long_data() new malloc. This change will probably make the ! 50: code in few other places cleaner. ! 51: */ ! 52: ! 53: extern MYSQLND_CHARSET *mysqlnd_charsets; ! 54: ! 55: ! 56: ! 57: PHPAPI const char * const mysqlnd_old_passwd = "mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. " ! 58: "Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will " ! 59: "store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords " ! 60: "flag from your my.cnf file"; ! 61: ! 62: PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away"; ! 63: PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now"; ! 64: PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory"; ! 65: ! 66: PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL; ! 67: static zend_bool mysqlnd_library_initted = FALSE; ! 68: ! 69: static struct st_mysqlnd_conn_methods *mysqlnd_conn_methods; ! 70: ! 71: /* {{{ mysqlnd_library_end */ ! 72: PHPAPI void mysqlnd_library_end(TSRMLS_D) ! 73: { ! 74: if (mysqlnd_library_initted == TRUE) { ! 75: mysqlnd_stats_end(mysqlnd_global_stats); ! 76: mysqlnd_global_stats = NULL; ! 77: mysqlnd_library_initted = FALSE; ! 78: } ! 79: } ! 80: /* }}} */ ! 81: ! 82: ! 83: /* {{{ mysqlnd_conn::free_options */ ! 84: static void ! 85: MYSQLND_METHOD(mysqlnd_conn, free_options)(MYSQLND * conn TSRMLS_DC) ! 86: { ! 87: zend_bool pers = conn->persistent; ! 88: ! 89: if (conn->options.charset_name) { ! 90: mnd_pefree(conn->options.charset_name, pers); ! 91: conn->options.charset_name = NULL; ! 92: } ! 93: if (conn->options.num_commands) { ! 94: unsigned int i; ! 95: for (i = 0; i < conn->options.num_commands; i++) { ! 96: /* allocated with pestrdup */ ! 97: mnd_pefree(conn->options.init_commands[i], pers); ! 98: } ! 99: mnd_pefree(conn->options.init_commands, pers); ! 100: conn->options.init_commands = NULL; ! 101: } ! 102: if (conn->options.cfg_file) { ! 103: mnd_pefree(conn->options.cfg_file, pers); ! 104: conn->options.cfg_file = NULL; ! 105: } ! 106: if (conn->options.cfg_section) { ! 107: mnd_pefree(conn->options.cfg_section, pers); ! 108: conn->options.cfg_section = NULL; ! 109: } ! 110: } ! 111: /* }}} */ ! 112: ! 113: ! 114: /* {{{ mysqlnd_conn::free_contents */ ! 115: static void ! 116: MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND * conn TSRMLS_DC) ! 117: { ! 118: zend_bool pers = conn->persistent; ! 119: ! 120: DBG_ENTER("mysqlnd_conn::free_contents"); ! 121: ! 122: mysqlnd_local_infile_default(conn); ! 123: if (conn->current_result) { ! 124: conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC); ! 125: conn->current_result = NULL; ! 126: } ! 127: ! 128: if (conn->net) { ! 129: conn->net->m.free_contents(conn->net TSRMLS_CC); ! 130: } ! 131: ! 132: DBG_INF("Freeing memory of members"); ! 133: ! 134: if (conn->host) { ! 135: DBG_INF("Freeing host"); ! 136: mnd_pefree(conn->host, pers); ! 137: conn->host = NULL; ! 138: } ! 139: if (conn->user) { ! 140: DBG_INF("Freeing user"); ! 141: mnd_pefree(conn->user, pers); ! 142: conn->user = NULL; ! 143: } ! 144: if (conn->passwd) { ! 145: DBG_INF("Freeing passwd"); ! 146: mnd_pefree(conn->passwd, pers); ! 147: conn->passwd = NULL; ! 148: } ! 149: if (conn->connect_or_select_db) { ! 150: DBG_INF("Freeing connect_or_select_db"); ! 151: mnd_pefree(conn->connect_or_select_db, pers); ! 152: conn->connect_or_select_db = NULL; ! 153: } ! 154: if (conn->unix_socket) { ! 155: DBG_INF("Freeing unix_socket"); ! 156: mnd_pefree(conn->unix_socket, pers); ! 157: conn->unix_socket = NULL; ! 158: } ! 159: DBG_INF_FMT("scheme=%s", conn->scheme); ! 160: if (conn->scheme) { ! 161: DBG_INF("Freeing scheme"); ! 162: mnd_pefree(conn->scheme, pers); ! 163: conn->scheme = NULL; ! 164: } ! 165: if (conn->server_version) { ! 166: DBG_INF("Freeing server_version"); ! 167: mnd_pefree(conn->server_version, pers); ! 168: conn->server_version = NULL; ! 169: } ! 170: if (conn->host_info) { ! 171: DBG_INF("Freeing host_info"); ! 172: mnd_pefree(conn->host_info, pers); ! 173: conn->host_info = NULL; ! 174: } ! 175: if (conn->scramble) { ! 176: DBG_INF("Freeing scramble"); ! 177: mnd_pefree(conn->scramble, pers); ! 178: conn->scramble = NULL; ! 179: } ! 180: if (conn->last_message) { ! 181: mnd_pefree(conn->last_message, pers); ! 182: conn->last_message = NULL; ! 183: } ! 184: conn->charset = NULL; ! 185: conn->greet_charset = NULL; ! 186: ! 187: DBG_VOID_RETURN; ! 188: } ! 189: /* }}} */ ! 190: ! 191: ! 192: /* {{{ mysqlnd_conn::dtor */ ! 193: static void ! 194: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND * conn TSRMLS_DC) ! 195: { ! 196: DBG_ENTER("mysqlnd_conn::dtor"); ! 197: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 198: ! 199: conn->m->free_contents(conn TSRMLS_CC); ! 200: conn->m->free_options(conn TSRMLS_CC); ! 201: ! 202: if (conn->net) { ! 203: DBG_INF("Freeing net"); ! 204: mysqlnd_net_free(conn->net TSRMLS_CC); ! 205: conn->net = NULL; ! 206: } ! 207: ! 208: if (conn->protocol) { ! 209: DBG_INF("Freeing protocol"); ! 210: mysqlnd_protocol_free(conn->protocol TSRMLS_CC); ! 211: conn->protocol = NULL; ! 212: } ! 213: ! 214: if (conn->stats) { ! 215: mysqlnd_stats_end(conn->stats); ! 216: } ! 217: ! 218: mnd_pefree(conn, conn->persistent); ! 219: ! 220: DBG_VOID_RETURN; ! 221: } ! 222: /* }}} */ ! 223: ! 224: ! 225: /* {{{ mysqlnd_conn::simple_command_handle_response */ ! 226: static enum_func_status ! 227: MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enum mysqlnd_packet_type ok_packet, ! 228: zend_bool silent, enum php_mysqlnd_server_command command, ! 229: zend_bool ignore_upsert_status TSRMLS_DC) ! 230: { ! 231: enum_func_status ret = FAIL; ! 232: ! 233: DBG_ENTER("mysqlnd_conn::simple_command_handle_response"); ! 234: DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]); ! 235: ! 236: switch (ok_packet) { ! 237: case PROT_OK_PACKET:{ ! 238: MYSQLND_PACKET_OK * ok_response = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); ! 239: if (!ok_response) { ! 240: SET_OOM_ERROR(conn->error_info); ! 241: break; ! 242: } ! 243: if (FAIL == (ret = PACKET_READ(ok_response, conn))) { ! 244: if (!silent) { ! 245: DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]); ! 246: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet. PID=%u", ! 247: mysqlnd_command_to_text[command], getpid()); ! 248: } ! 249: } else { ! 250: DBG_INF_FMT("OK from server"); ! 251: if (0xFF == ok_response->field_count) { ! 252: /* The server signalled error. Set the error */ ! 253: SET_CLIENT_ERROR(conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error); ! 254: ret = FAIL; ! 255: /* ! 256: Cover a protocol design error: error packet does not ! 257: contain the server status. Therefore, the client has no way ! 258: to find out whether there are more result sets of ! 259: a multiple-result-set statement pending. Luckily, in 5.0 an ! 260: error always aborts execution of a statement, wherever it is ! 261: a multi-statement or a stored procedure, so it should be ! 262: safe to unconditionally turn off the flag here. ! 263: */ ! 264: conn->upsert_status.server_status &= ~SERVER_MORE_RESULTS_EXISTS; ! 265: SET_ERROR_AFF_ROWS(conn); ! 266: } else { ! 267: SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, ! 268: ok_response->message, ok_response->message_len, ! 269: conn->persistent); ! 270: ! 271: if (!ignore_upsert_status) { ! 272: conn->upsert_status.warning_count = ok_response->warning_count; ! 273: conn->upsert_status.server_status = ok_response->server_status; ! 274: conn->upsert_status.affected_rows = ok_response->affected_rows; ! 275: conn->upsert_status.last_insert_id = ok_response->last_insert_id; ! 276: } ! 277: } ! 278: } ! 279: PACKET_FREE(ok_response); ! 280: break; ! 281: } ! 282: case PROT_EOF_PACKET:{ ! 283: MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC); ! 284: if (!ok_response) { ! 285: SET_OOM_ERROR(conn->error_info); ! 286: break; ! 287: } ! 288: if (FAIL == (ret = PACKET_READ(ok_response, conn))) { ! 289: SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, ! 290: "Malformed packet"); ! 291: if (!silent) { ! 292: DBG_ERR_FMT("Error while reading %s's EOF packet", mysqlnd_command_to_text[command]); ! 293: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet. PID=%d", ! 294: mysqlnd_command_to_text[command], getpid()); ! 295: } ! 296: } else if (0xFF == ok_response->field_count) { ! 297: /* The server signalled error. Set the error */ ! 298: SET_CLIENT_ERROR(conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error); ! 299: SET_ERROR_AFF_ROWS(conn); ! 300: } else if (0xFE != ok_response->field_count) { ! 301: SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet"); ! 302: if (!silent) { ! 303: DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", ok_response->field_count); ! 304: php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X", ! 305: ok_response->field_count); ! 306: } ! 307: } else { ! 308: DBG_INF_FMT("OK from server"); ! 309: } ! 310: PACKET_FREE(ok_response); ! 311: break; ! 312: } ! 313: default: ! 314: SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet"); ! 315: php_error_docref(NULL TSRMLS_CC, E_ERROR, "Wrong response packet %u passed to the function", ok_packet); ! 316: break; ! 317: } ! 318: DBG_INF(ret == PASS ? "PASS":"FAIL"); ! 319: DBG_RETURN(ret); ! 320: } ! 321: /* }}} */ ! 322: ! 323: ! 324: /* {{{ mysqlnd_conn::simple_command */ ! 325: static enum_func_status ! 326: MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND * conn, enum php_mysqlnd_server_command command, ! 327: const char * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent, ! 328: zend_bool ignore_upsert_status TSRMLS_DC) ! 329: { ! 330: enum_func_status ret = PASS; ! 331: MYSQLND_PACKET_COMMAND * cmd_packet; ! 332: ! 333: DBG_ENTER("mysqlnd_conn::simple_command"); ! 334: DBG_INF_FMT("command=%s ok_packet=%u silent=%u", mysqlnd_command_to_text[command], ok_packet, silent); ! 335: ! 336: switch (CONN_GET_STATE(conn)) { ! 337: case CONN_READY: ! 338: break; ! 339: case CONN_QUIT_SENT: ! 340: SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); ! 341: DBG_ERR("Server is gone"); ! 342: DBG_RETURN(FAIL); ! 343: default: ! 344: SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); ! 345: DBG_ERR_FMT("Command out of sync. State=%u", CONN_GET_STATE(conn)); ! 346: DBG_RETURN(FAIL); ! 347: } ! 348: ! 349: /* clean UPSERT info */ ! 350: if (!ignore_upsert_status) { ! 351: memset(&conn->upsert_status, 0, sizeof(conn->upsert_status)); ! 352: } ! 353: SET_ERROR_AFF_ROWS(conn); ! 354: SET_EMPTY_ERROR(conn->error_info); ! 355: ! 356: cmd_packet = conn->protocol->m.get_command_packet(conn->protocol, FALSE TSRMLS_CC); ! 357: if (!cmd_packet) { ! 358: SET_OOM_ERROR(conn->error_info); ! 359: DBG_RETURN(FAIL); ! 360: } ! 361: ! 362: cmd_packet->command = command; ! 363: if (arg && arg_len) { ! 364: cmd_packet->argument = arg; ! 365: cmd_packet->arg_len = arg_len; ! 366: } ! 367: ! 368: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ ); ! 369: ! 370: if (! PACKET_WRITE(cmd_packet, conn)) { ! 371: if (!silent) { ! 372: DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]); ! 373: php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid()); ! 374: } ! 375: DBG_ERR("Server is gone"); ! 376: ret = FAIL; ! 377: } else if (ok_packet != PROT_LAST) { ! 378: ret = conn->m->simple_command_handle_response(conn, ok_packet, silent, command, ignore_upsert_status TSRMLS_CC); ! 379: } ! 380: ! 381: PACKET_FREE(cmd_packet); ! 382: DBG_INF(ret == PASS ? "PASS":"FAIL"); ! 383: DBG_RETURN(ret); ! 384: } ! 385: /* }}} */ ! 386: ! 387: ! 388: /* {{{ mysqlnd_conn::set_server_option */ ! 389: static enum_func_status ! 390: MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC) ! 391: { ! 392: enum_func_status ret; ! 393: char buffer[2]; ! 394: DBG_ENTER("mysqlnd_conn::set_server_option"); ! 395: ! 396: int2store(buffer, (unsigned int) option); ! 397: ret = conn->m->simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer), PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC); ! 398: DBG_RETURN(ret); ! 399: } ! 400: /* }}} */ ! 401: ! 402: ! 403: /* {{{ mysqlnd_conn::restart_psession */ ! 404: static enum_func_status ! 405: MYSQLND_METHOD(mysqlnd_conn, restart_psession)(MYSQLND * conn TSRMLS_DC) ! 406: { ! 407: DBG_ENTER("mysqlnd_conn::restart_psession"); ! 408: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_REUSED); ! 409: /* Free here what should not be seen by the next script */ ! 410: if (conn->last_message) { ! 411: mnd_pefree(conn->last_message, conn->persistent); ! 412: conn->last_message = NULL; ! 413: } ! 414: DBG_RETURN(PASS); ! 415: } ! 416: /* }}} */ ! 417: ! 418: ! 419: /* {{{ mysqlnd_conn::end_psession */ ! 420: static enum_func_status ! 421: MYSQLND_METHOD(mysqlnd_conn, end_psession)(MYSQLND * conn TSRMLS_DC) ! 422: { ! 423: DBG_ENTER("mysqlnd_conn::end_psession"); ! 424: DBG_RETURN(PASS); ! 425: } ! 426: /* }}} */ ! 427: ! 428: ! 429: #define MYSQLND_ASSEBLED_PACKET_MAX_SIZE 3UL*1024UL*1024UL*1024UL ! 430: /* {{{ mysqlnd_connect_run_authentication */ ! 431: static enum_func_status ! 432: mysqlnd_connect_run_authentication( ! 433: MYSQLND * conn, ! 434: const char * const user, ! 435: const char * const passwd, ! 436: const char * const db, ! 437: size_t db_len, ! 438: const MYSQLND_PACKET_GREET * const greet_packet, ! 439: const MYSQLND_OPTIONS * const options, ! 440: unsigned long mysql_flags ! 441: TSRMLS_DC) ! 442: { ! 443: const MYSQLND_CHARSET * charset = NULL; ! 444: enum_func_status ret = FAIL; ! 445: MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC); ! 446: MYSQLND_PACKET_OK * ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); ! 447: ! 448: DBG_ENTER("mysqlnd_connect_run_authentication"); ! 449: ! 450: if (!auth_packet || !ok_packet) { ! 451: SET_OOM_ERROR(conn->error_info); ! 452: goto err; ! 453: } ! 454: ! 455: #ifdef MYSQLND_SSL_SUPPORTED ! 456: if ((greet_packet->server_capabilities & CLIENT_SSL) && (mysql_flags & CLIENT_SSL)) { ! 457: auth_packet->send_half_packet = TRUE; ! 458: } ! 459: #endif ! 460: auth_packet->user = user; ! 461: auth_packet->password = passwd; ! 462: ! 463: if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) { ! 464: auth_packet->charset_no = charset->nr; ! 465: } else { ! 466: #if MYSQLND_UNICODE ! 467: auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */ ! 468: #else ! 469: auth_packet->charset_no = greet_packet->charset_no; ! 470: #endif ! 471: } ! 472: auth_packet->db = db; ! 473: auth_packet->db_len = db_len; ! 474: auth_packet->max_packet_size= MYSQLND_ASSEBLED_PACKET_MAX_SIZE; ! 475: auth_packet->client_flags= mysql_flags; ! 476: ! 477: conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent); ! 478: if (!conn->scramble) { ! 479: SET_OOM_ERROR(conn->error_info); ! 480: goto err; ! 481: } ! 482: memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH); ! 483: ! 484: if (!PACKET_WRITE(auth_packet, conn)) { ! 485: CONN_SET_STATE(conn, CONN_QUIT_SENT); ! 486: SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); ! 487: goto err; ! 488: } ! 489: ! 490: #ifdef MYSQLND_SSL_SUPPORTED ! 491: if (auth_packet->send_half_packet) { ! 492: zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE; ! 493: DBG_INF("Switching to SSL"); ! 494: ! 495: conn->net->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC); ! 496: ! 497: if (FAIL == conn->net->m.enable_ssl(conn->net TSRMLS_CC)) { ! 498: goto err; ! 499: } ! 500: ! 501: auth_packet->send_half_packet = FALSE; ! 502: if (!PACKET_WRITE(auth_packet, conn)) { ! 503: CONN_SET_STATE(conn, CONN_QUIT_SENT); ! 504: SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); ! 505: goto err; ! 506: } ! 507: } ! 508: #endif ! 509: ! 510: ! 511: if (FAIL == PACKET_READ(ok_packet, conn) || ok_packet->field_count >= 0xFE) { ! 512: if (ok_packet->field_count == 0xFE) { ! 513: /* old authentication with new server !*/ ! 514: DBG_ERR(mysqlnd_old_passwd); ! 515: SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); ! 516: } else if (ok_packet->field_count == 0xFF) { ! 517: if (ok_packet->sqlstate[0]) { ! 518: strlcpy(conn->error_info.sqlstate, ok_packet->sqlstate, sizeof(conn->error_info.sqlstate)); ! 519: DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", ok_packet->error_no, ok_packet->sqlstate, ok_packet->error); ! 520: } ! 521: conn->error_info.error_no = ok_packet->error_no; ! 522: strlcpy(conn->error_info.error, ok_packet->error, sizeof(conn->error_info.error)); ! 523: } ! 524: goto err; ! 525: } ! 526: ! 527: SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, ! 528: ok_packet->message, ok_packet->message_len, ! 529: conn->persistent); ! 530: conn->charset = mysqlnd_find_charset_nr(auth_packet->charset_no); ! 531: ret = PASS; ! 532: err: ! 533: PACKET_FREE(auth_packet); ! 534: PACKET_FREE(ok_packet); ! 535: DBG_RETURN(ret); ! 536: } ! 537: /* }}} */ ! 538: ! 539: ! 540: #define MYSQLND_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | \ ! 541: CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | \ ! 542: CLIENT_MULTI_RESULTS) ! 543: ! 544: ! 545: ! 546: /* {{{ mysqlnd_conn::connect */ ! 547: static enum_func_status ! 548: MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, ! 549: const char *host, const char *user, ! 550: const char *passwd, unsigned int passwd_len, ! 551: const char *db, unsigned int db_len, ! 552: unsigned int port, ! 553: const char * socket_or_pipe, ! 554: unsigned int mysql_flags ! 555: TSRMLS_DC) ! 556: { ! 557: char *errstr = NULL; ! 558: int errcode = 0, host_len; ! 559: zend_bool unix_socket = FALSE; ! 560: zend_bool reconnect = FALSE; ! 561: zend_bool saved_compression = FALSE; ! 562: ! 563: MYSQLND_PACKET_GREET * greet_packet = NULL; ! 564: ! 565: DBG_ENTER("mysqlnd_conn::connect"); ! 566: ! 567: DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u", ! 568: host?host:"", user?user:"", db?db:"", port, mysql_flags, ! 569: conn? conn->persistent:0, conn? CONN_GET_STATE(conn):-1); ! 570: ! 571: if (conn && CONN_GET_STATE(conn) > CONN_ALLOCED && CONN_GET_STATE(conn) ) { ! 572: DBG_INF("Connecting on a connected handle."); ! 573: ! 574: if (CONN_GET_STATE(conn) < CONN_QUIT_SENT) { ! 575: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CLOSE_IMPLICIT); ! 576: reconnect = TRUE; ! 577: conn->m->send_close(conn TSRMLS_CC); ! 578: } ! 579: ! 580: conn->m->free_contents(conn TSRMLS_CC); ! 581: MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS); ! 582: if (conn->persistent) { ! 583: MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS); ! 584: } ! 585: /* Now reconnect using the same handle */ ! 586: if (conn->net->compressed) { ! 587: /* ! 588: we need to save the state. As we will re-connect, net->compressed should be off, or ! 589: we will look for a compression header as part of the greet message, but there will ! 590: be none. ! 591: */ ! 592: saved_compression = TRUE; ! 593: conn->net->compressed = FALSE; ! 594: } ! 595: } ! 596: ! 597: if (!host || !host[0]) { ! 598: host = "localhost"; ! 599: } ! 600: if (!user) { ! 601: DBG_INF_FMT("no user given, using empty string"); ! 602: user = ""; ! 603: } ! 604: if (!passwd) { ! 605: DBG_INF_FMT("no password given, using empty string"); ! 606: passwd = ""; ! 607: passwd_len = 0; ! 608: } ! 609: if (!db) { ! 610: DBG_INF_FMT("no db given, using empty string"); ! 611: db = ""; ! 612: db_len = 0; ! 613: } ! 614: ! 615: host_len = strlen(host); ! 616: { ! 617: char * transport = NULL; ! 618: int transport_len; ! 619: #ifndef PHP_WIN32 ! 620: if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) { ! 621: DBG_INF_FMT("socket=%s", socket_or_pipe? socket_or_pipe:"n/a"); ! 622: if (!socket_or_pipe) { ! 623: socket_or_pipe = "/tmp/mysql.sock"; ! 624: } ! 625: transport_len = spprintf(&transport, 0, "unix://%s", socket_or_pipe); ! 626: unix_socket = TRUE; ! 627: } else ! 628: #endif ! 629: { ! 630: if (!port) { ! 631: port = 3306; ! 632: } ! 633: transport_len = spprintf(&transport, 0, "tcp://%s:%u", host, port); ! 634: } ! 635: if (!transport) { ! 636: SET_OOM_ERROR(conn->error_info); ! 637: goto err; /* OOM */ ! 638: } ! 639: DBG_INF_FMT("transport=%s conn->scheme=%s", transport, conn->scheme); ! 640: conn->scheme = mnd_pestrndup(transport, transport_len, conn->persistent); ! 641: conn->scheme_len = transport_len; ! 642: efree(transport); /* allocated by spprintf */ ! 643: transport = NULL; ! 644: if (!conn->scheme) { ! 645: goto err; /* OOM */ ! 646: } ! 647: } ! 648: ! 649: greet_packet = conn->protocol->m.get_greet_packet(conn->protocol, FALSE TSRMLS_CC); ! 650: if (!greet_packet) { ! 651: SET_OOM_ERROR(conn->error_info); ! 652: goto err; /* OOM */ ! 653: } ! 654: ! 655: if (FAIL == conn->net->m.connect(conn->net, conn->scheme, conn->scheme_len, conn->persistent, &errstr, &errcode TSRMLS_CC)) { ! 656: goto err; ! 657: } ! 658: ! 659: DBG_INF_FMT("stream=%p", conn->net->stream); ! 660: ! 661: if (FAIL == PACKET_READ(greet_packet, conn)) { ! 662: DBG_ERR("Error while reading greeting packet"); ! 663: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet. PID=%d", getpid()); ! 664: goto err; ! 665: } else if (greet_packet->error_no) { ! 666: DBG_ERR_FMT("errorno=%u error=%s", greet_packet->error_no, greet_packet->error); ! 667: SET_CLIENT_ERROR(conn->error_info, greet_packet->error_no, greet_packet->sqlstate, greet_packet->error); ! 668: goto err; ! 669: } else if (greet_packet->pre41) { ! 670: DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s", greet_packet->server_version); ! 671: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 " ! 672: " is not supported. Server is %-.32s", greet_packet->server_version); ! 673: SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, ! 674: "Connecting to 3.22, 3.23 & 4.0 servers is not supported"); ! 675: goto err; ! 676: } ! 677: ! 678: conn->thread_id = greet_packet->thread_id; ! 679: conn->protocol_version = greet_packet->protocol_version; ! 680: conn->server_version = mnd_pestrdup(greet_packet->server_version, conn->persistent); ! 681: ! 682: conn->greet_charset = mysqlnd_find_charset_nr(greet_packet->charset_no); ! 683: /* we allow load data local infile by default */ ! 684: mysql_flags |= CLIENT_LOCAL_FILES | CLIENT_PS_MULTI_RESULTS; ! 685: mysql_flags |= MYSQLND_CAPABILITIES; ! 686: ! 687: if (db) { ! 688: mysql_flags |= CLIENT_CONNECT_WITH_DB; ! 689: } ! 690: ! 691: if (PG(open_basedir) && strlen(PG(open_basedir))) { ! 692: mysql_flags ^= CLIENT_LOCAL_FILES; ! 693: } ! 694: ! 695: #ifndef MYSQLND_COMPRESSION_ENABLED ! 696: if (mysql_flags & CLIENT_COMPRESS) { ! 697: mysql_flags &= ~CLIENT_COMPRESS; ! 698: } ! 699: #else ! 700: if (conn->net->options.flags & MYSQLND_NET_FLAG_USE_COMPRESSION) { ! 701: mysql_flags |= CLIENT_COMPRESS; ! 702: } ! 703: #endif ! 704: #ifndef MYSQLND_SSL_SUPPORTED ! 705: if (mysql_flags & CLIENT_SSL) { ! 706: mysql_flags &= ~CLIENT_SSL; ! 707: } ! 708: #else ! 709: if (conn->net->options.ssl_key || conn->net->options.ssl_cert || ! 710: conn->net->options.ssl_ca || conn->net->options.ssl_capath || conn->net->options.ssl_cipher) ! 711: { ! 712: mysql_flags |= CLIENT_SSL; ! 713: } ! 714: #endif ! 715: ! 716: if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, greet_packet, &conn->options, mysql_flags TSRMLS_CC)) { ! 717: goto err; ! 718: } ! 719: ! 720: { ! 721: CONN_SET_STATE(conn, CONN_READY); ! 722: ! 723: if (saved_compression) { ! 724: conn->net->compressed = TRUE; ! 725: } ! 726: /* ! 727: If a connect on a existing handle is performed and mysql_flags is ! 728: passed which doesn't CLIENT_COMPRESS, then we need to overwrite the value ! 729: which we set based on saved_compression. ! 730: */ ! 731: conn->net->compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE; ! 732: ! 733: conn->user = mnd_pestrdup(user, conn->persistent); ! 734: conn->user_len = strlen(conn->user); ! 735: conn->passwd = mnd_pestrndup(passwd, passwd_len, conn->persistent); ! 736: conn->passwd_len = passwd_len; ! 737: conn->port = port; ! 738: conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent); ! 739: conn->connect_or_select_db_len = db_len; ! 740: ! 741: if (!conn->user || !conn->passwd || !conn->connect_or_select_db) { ! 742: SET_OOM_ERROR(conn->error_info); ! 743: goto err; /* OOM */ ! 744: } ! 745: ! 746: if (!unix_socket) { ! 747: conn->host = mnd_pestrdup(host, conn->persistent); ! 748: if (!conn->host) { ! 749: SET_OOM_ERROR(conn->error_info); ! 750: goto err; /* OOM */ ! 751: } ! 752: conn->host_len = strlen(conn->host); ! 753: { ! 754: char *p; ! 755: spprintf(&p, 0, "%s via TCP/IP", conn->host); ! 756: if (!p) { ! 757: SET_OOM_ERROR(conn->error_info); ! 758: goto err; /* OOM */ ! 759: } ! 760: conn->host_info = mnd_pestrdup(p, conn->persistent); ! 761: efree(p); /* allocated by spprintf */ ! 762: if (!conn->host_info) { ! 763: SET_OOM_ERROR(conn->error_info); ! 764: goto err; /* OOM */ ! 765: } ! 766: } ! 767: } else { ! 768: conn->unix_socket = mnd_pestrdup(socket_or_pipe, conn->persistent); ! 769: conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); ! 770: if (!conn->unix_socket || !conn->host_info) { ! 771: SET_OOM_ERROR(conn->error_info); ! 772: goto err; /* OOM */ ! 773: } ! 774: conn->unix_socket_len = strlen(conn->unix_socket); ! 775: } ! 776: conn->client_flag = mysql_flags; ! 777: conn->max_packet_size = MYSQLND_ASSEBLED_PACKET_MAX_SIZE; ! 778: /* todo: check if charset is available */ ! 779: conn->server_capabilities = greet_packet->server_capabilities; ! 780: conn->upsert_status.warning_count = 0; ! 781: conn->upsert_status.server_status = greet_packet->server_status; ! 782: conn->upsert_status.affected_rows = 0; ! 783: ! 784: SET_EMPTY_ERROR(conn->error_info); ! 785: ! 786: mysqlnd_local_infile_default(conn); ! 787: ! 788: #if MYSQLND_UNICODE ! 789: { ! 790: unsigned int as_unicode = 1; ! 791: conn->m->set_client_option(conn, MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE, (char *)&as_unicode TSRMLS_CC); ! 792: DBG_INF("unicode set"); ! 793: } ! 794: #endif ! 795: if (conn->options.init_commands) { ! 796: unsigned int current_command = 0; ! 797: for (; current_command < conn->options.num_commands; ++current_command) { ! 798: const char * const command = conn->options.init_commands[current_command]; ! 799: if (command) { ! 800: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT); ! 801: if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) { ! 802: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT); ! 803: goto err; ! 804: } ! 805: if (conn->last_query_type == QUERY_SELECT) { ! 806: MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC); ! 807: if (result) { ! 808: result->m.free_result(result, TRUE TSRMLS_CC); ! 809: } ! 810: } ! 811: } ! 812: } ! 813: } ! 814: ! 815: ! 816: MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_CONNECT_SUCCESS, 1, STAT_OPENED_CONNECTIONS, 1); ! 817: if (reconnect) { ! 818: MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT); ! 819: } ! 820: if (conn->persistent) { ! 821: MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_PCONNECT_SUCCESS, 1, STAT_OPENED_PERSISTENT_CONNECTIONS, 1); ! 822: } ! 823: ! 824: DBG_INF_FMT("connection_id=%llu", conn->thread_id); ! 825: ! 826: PACKET_FREE(greet_packet); ! 827: ! 828: DBG_RETURN(PASS); ! 829: } ! 830: err: ! 831: PACKET_FREE(greet_packet); ! 832: ! 833: if (errstr) { ! 834: DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", errcode, errstr, conn->scheme); ! 835: SET_CLIENT_ERROR(conn->error_info, errcode? errcode:CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, errstr); ! 836: php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%u] %.128s (trying to connect via %s)", errcode, errstr, conn->scheme); ! 837: /* no mnd_ since we don't allocate it */ ! 838: efree(errstr); ! 839: } ! 840: conn->m->free_contents(conn TSRMLS_CC); ! 841: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE); ! 842: ! 843: DBG_RETURN(FAIL); ! 844: } ! 845: /* }}} */ ! 846: ! 847: ! 848: /* {{{ mysqlnd_connect */ ! 849: PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn, ! 850: const char *host, const char *user, ! 851: const char *passwd, unsigned int passwd_len, ! 852: const char *db, unsigned int db_len, ! 853: unsigned int port, ! 854: const char *socket_or_pipe, ! 855: unsigned int mysql_flags ! 856: TSRMLS_DC) ! 857: { ! 858: enum_func_status ret = FAIL; ! 859: zend_bool self_alloced = FALSE; ! 860: ! 861: DBG_ENTER("mysqlnd_connect"); ! 862: DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u", host?host:"", user?user:"", db?db:"", port, mysql_flags); ! 863: ! 864: if (!conn) { ! 865: self_alloced = TRUE; ! 866: if (!(conn = mysqlnd_init(FALSE))) { ! 867: /* OOM */ ! 868: DBG_RETURN(NULL); ! 869: } ! 870: } ! 871: ! 872: ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags TSRMLS_CC); ! 873: ! 874: if (ret == FAIL) { ! 875: if (self_alloced) { ! 876: /* ! 877: We have alloced, thus there are no references to this ! 878: object - we are free to kill it! ! 879: */ ! 880: conn->m->dtor(conn TSRMLS_CC); ! 881: } ! 882: DBG_RETURN(NULL); ! 883: } ! 884: DBG_RETURN(conn); ! 885: } ! 886: /* }}} */ ! 887: ! 888: ! 889: /* {{{ mysqlnd_conn::change_user */ ! 890: static enum_func_status ! 891: MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, ! 892: const char *user, ! 893: const char *passwd, ! 894: const char *db, ! 895: zend_bool silent TSRMLS_DC) ! 896: { ! 897: size_t user_len; ! 898: enum_func_status ret = FAIL; ! 899: MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp; ! 900: char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 2 /* charset*/ + 2]; ! 901: char *p = buffer; ! 902: const MYSQLND_CHARSET * old_cs = conn->charset; ! 903: ! 904: DBG_ENTER("mysqlnd_conn::change_user"); ! 905: DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u", ! 906: conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 ); ! 907: ! 908: SET_ERROR_AFF_ROWS(conn); ! 909: ! 910: if (!user) { ! 911: user = ""; ! 912: } ! 913: if (!passwd) { ! 914: passwd = ""; ! 915: } ! 916: if (!db) { ! 917: db = ""; ! 918: } ! 919: ! 920: /* 1. user ASCIIZ */ ! 921: user_len = MIN(strlen(user), MYSQLND_MAX_ALLOWED_USER_LEN); ! 922: memcpy(p, user, user_len); ! 923: p += user_len; ! 924: *p++ = '\0'; ! 925: ! 926: /* 2. password SCRAMBLE_LENGTH followed by the scramble or \0 */ ! 927: if (passwd[0]) { ! 928: *p++ = SCRAMBLE_LENGTH; ! 929: php_mysqlnd_scramble((unsigned char *)p, conn->scramble, (unsigned char *)passwd); ! 930: p += SCRAMBLE_LENGTH; ! 931: } else { ! 932: *p++ = '\0'; ! 933: } ! 934: ! 935: /* 3. db ASCIIZ */ ! 936: if (db[0]) { ! 937: size_t db_len = MIN(strlen(db), MYSQLND_MAX_ALLOWED_DB_LEN); ! 938: memcpy(p, db, db_len); ! 939: p += db_len; ! 940: } ! 941: *p++ = '\0'; ! 942: ! 943: /* ! 944: 4. request the current charset, or it will be reset to the system one. ! 945: 5.0 doesn't support it. Support added in 5.1.23 by fixing the following bug : ! 946: Bug #30472 libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call ! 947: */ ! 948: if (mysqlnd_get_server_version(conn) >= 50123) { ! 949: int2store(p, conn->charset->nr); ! 950: p+=2; ! 951: } ! 952: ! 953: if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer, p - buffer, ! 954: PROT_LAST /* we will handle the OK packet*/, ! 955: silent, TRUE TSRMLS_CC)) { ! 956: DBG_RETURN(FAIL); ! 957: } ! 958: ! 959: chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC); ! 960: if (!chg_user_resp) { ! 961: SET_OOM_ERROR(conn->error_info); ! 962: goto end; ! 963: } ! 964: ret = PACKET_READ(chg_user_resp, conn); ! 965: conn->error_info = chg_user_resp->error_info; ! 966: ! 967: if (conn->error_info.error_no) { ! 968: ret = FAIL; ! 969: /* ! 970: COM_CHANGE_USER is broken in 5.1. At least in 5.1.15 and 5.1.14, 5.1.11 is immune. ! 971: bug#25371 mysql_change_user() triggers "packets out of sync" ! 972: When it gets fixed, there should be one more check here ! 973: */ ! 974: if (mysqlnd_get_server_version(conn) > 50113L && mysqlnd_get_server_version(conn) < 50118L) { ! 975: MYSQLND_PACKET_OK * redundant_error_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); ! 976: if (redundant_error_packet) { ! 977: PACKET_READ(redundant_error_packet, conn); ! 978: PACKET_FREE(redundant_error_packet); ! 979: DBG_INF_FMT("Server is %u, buggy, sends two ERR messages", mysqlnd_get_server_version(conn)); ! 980: } else { ! 981: SET_OOM_ERROR(conn->error_info); ! 982: } ! 983: } ! 984: } ! 985: if (ret == PASS) { ! 986: char * tmp = NULL; ! 987: /* if we get conn->user as parameter and then we first free it, then estrndup it, we will crash */ ! 988: tmp = mnd_pestrndup(user, user_len, conn->persistent); ! 989: if (conn->user) { ! 990: mnd_pefree(conn->user, conn->persistent); ! 991: } ! 992: conn->user = tmp; ! 993: ! 994: tmp = mnd_pestrdup(passwd, conn->persistent); ! 995: if (conn->passwd) { ! 996: mnd_pefree(conn->passwd, conn->persistent); ! 997: } ! 998: conn->passwd = tmp; ! 999: ! 1000: if (conn->last_message) { ! 1001: mnd_pefree(conn->last_message, conn->persistent); ! 1002: conn->last_message = NULL; ! 1003: } ! 1004: memset(&conn->upsert_status, 0, sizeof(conn->upsert_status)); ! 1005: /* set charset for old servers */ ! 1006: if (mysqlnd_get_server_version(conn) < 50123) { ! 1007: ret = conn->m->set_charset(conn, old_cs->name TSRMLS_CC); ! 1008: } ! 1009: } else if (ret == FAIL && chg_user_resp->server_asked_323_auth == TRUE) { ! 1010: /* old authentication with new server !*/ ! 1011: DBG_ERR(mysqlnd_old_passwd); ! 1012: SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); ! 1013: } ! 1014: end: ! 1015: PACKET_FREE(chg_user_resp); ! 1016: ! 1017: /* ! 1018: Here we should close all statements. Unbuffered queries should not be a ! 1019: problem as we won't allow sending COM_CHANGE_USER. ! 1020: */ ! 1021: DBG_INF(ret == PASS? "PASS":"FAIL"); ! 1022: DBG_RETURN(ret); ! 1023: } ! 1024: /* }}} */ ! 1025: ! 1026: ! 1027: /* {{{ mysqlnd_conn::query */ ! 1028: /* ! 1029: If conn->error_info.error_no is not zero, then we had an error. ! 1030: Still the result from the query is PASS ! 1031: */ ! 1032: static enum_func_status ! 1033: MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND * conn, const char * query, unsigned int query_len TSRMLS_DC) ! 1034: { ! 1035: enum_func_status ret = FAIL; ! 1036: DBG_ENTER("mysqlnd_conn::query"); ! 1037: DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query); ! 1038: ! 1039: if (PASS == conn->m->send_query(conn, query, query_len TSRMLS_CC) && ! 1040: PASS == conn->m->reap_query(conn TSRMLS_CC)) ! 1041: { ! 1042: ret = PASS; ! 1043: if (conn->last_query_type == QUERY_UPSERT && conn->upsert_status.affected_rows) { ! 1044: MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status.affected_rows); ! 1045: } ! 1046: } ! 1047: DBG_RETURN(ret); ! 1048: } ! 1049: /* }}} */ ! 1050: ! 1051: ! 1052: /* {{{ mysqlnd_conn::send_query */ ! 1053: static enum_func_status ! 1054: MYSQLND_METHOD(mysqlnd_conn, send_query)(MYSQLND * conn, const char * query, unsigned int query_len TSRMLS_DC) ! 1055: { ! 1056: enum_func_status ret; ! 1057: DBG_ENTER("mysqlnd_conn::send_query"); ! 1058: DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query); ! 1059: ! 1060: ret = conn->m->simple_command(conn, COM_QUERY, query, query_len, ! 1061: PROT_LAST /* we will handle the OK packet*/, ! 1062: FALSE, FALSE TSRMLS_CC); ! 1063: if (PASS == ret) { ! 1064: CONN_SET_STATE(conn, CONN_QUERY_SENT); ! 1065: } ! 1066: DBG_RETURN(ret); ! 1067: } ! 1068: /* }}} */ ! 1069: ! 1070: ! 1071: /* {{{ mysqlnd_conn::reap_query */ ! 1072: static enum_func_status ! 1073: MYSQLND_METHOD(mysqlnd_conn, reap_query)(MYSQLND * conn TSRMLS_DC) ! 1074: { ! 1075: enum_mysqlnd_connection_state state = CONN_GET_STATE(conn); ! 1076: DBG_ENTER("mysqlnd_conn::reap_query"); ! 1077: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1078: ! 1079: if (state <= CONN_READY || state == CONN_QUIT_SENT) { ! 1080: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not opened, clear or has been closed"); ! 1081: DBG_ERR_FMT("Connection not opened, clear or has been closed. State=%u", state); ! 1082: DBG_RETURN(FAIL); ! 1083: } ! 1084: /* ! 1085: Here read the result set. We don't do it in simple_command because it need ! 1086: information from the ok packet. We will fetch it ourselves. ! 1087: */ ! 1088: DBG_RETURN(conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC)); ! 1089: } ! 1090: /* }}} */ ! 1091: ! 1092: ! 1093: #include "php_network.h" ! 1094: ! 1095: MYSQLND ** mysqlnd_stream_array_check_for_readiness(MYSQLND ** conn_array TSRMLS_DC) ! 1096: { ! 1097: int cnt = 0; ! 1098: MYSQLND **p = conn_array, **p_p; ! 1099: MYSQLND **ret = NULL; ! 1100: ! 1101: while (*p) { ! 1102: if (CONN_GET_STATE(*p) <= CONN_READY || CONN_GET_STATE(*p) == CONN_QUIT_SENT) { ! 1103: cnt++; ! 1104: } ! 1105: p++; ! 1106: } ! 1107: if (cnt) { ! 1108: MYSQLND **ret_p = ret = ecalloc(cnt + 1, sizeof(MYSQLND *)); ! 1109: p_p = p = conn_array; ! 1110: while (*p) { ! 1111: if (CONN_GET_STATE(*p) <= CONN_READY || CONN_GET_STATE(*p) == CONN_QUIT_SENT) { ! 1112: *ret_p = *p; ! 1113: *p = NULL; ! 1114: ret_p++; ! 1115: } else { ! 1116: *p_p = *p; ! 1117: p_p++; ! 1118: } ! 1119: p++; ! 1120: } ! 1121: *ret_p = NULL; ! 1122: } ! 1123: return ret; ! 1124: } ! 1125: ! 1126: ! 1127: /* {{{ stream_select mysqlnd_stream_array_to_fd_set functions */ ! 1128: static int mysqlnd_stream_array_to_fd_set(MYSQLND **conn_array, fd_set *fds, php_socket_t *max_fd TSRMLS_DC) ! 1129: { ! 1130: php_socket_t this_fd; ! 1131: int cnt = 0; ! 1132: MYSQLND **p = conn_array; ! 1133: ! 1134: while (*p) { ! 1135: /* get the fd. ! 1136: * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag ! 1137: * when casting. It is only used here so that the buffered data warning ! 1138: * is not displayed. ! 1139: * */ ! 1140: if (SUCCESS == php_stream_cast((*p)->net->stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, ! 1141: (void*)&this_fd, 1) && this_fd >= 0) { ! 1142: ! 1143: PHP_SAFE_FD_SET(this_fd, fds); ! 1144: ! 1145: if (this_fd > *max_fd) { ! 1146: *max_fd = this_fd; ! 1147: } ! 1148: cnt++; ! 1149: } ! 1150: p++; ! 1151: } ! 1152: return cnt ? 1 : 0; ! 1153: } ! 1154: ! 1155: static int mysqlnd_stream_array_from_fd_set(MYSQLND **conn_array, fd_set *fds TSRMLS_DC) ! 1156: { ! 1157: php_socket_t this_fd; ! 1158: int ret = 0; ! 1159: zend_bool disproportion = FALSE; ! 1160: ! 1161: ! 1162: MYSQLND **fwd = conn_array, **bckwd = conn_array; ! 1163: ! 1164: while (*fwd) { ! 1165: if (SUCCESS == php_stream_cast((*fwd)->net->stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, ! 1166: (void*)&this_fd, 1) && this_fd >= 0) { ! 1167: if (PHP_SAFE_FD_ISSET(this_fd, fds)) { ! 1168: if (disproportion) { ! 1169: *bckwd = *fwd; ! 1170: } ! 1171: bckwd++; ! 1172: fwd++; ! 1173: ret++; ! 1174: continue; ! 1175: } ! 1176: } ! 1177: disproportion = TRUE; ! 1178: fwd++; ! 1179: } ! 1180: *bckwd = NULL;/* NULL-terminate the list */ ! 1181: ! 1182: return ret; ! 1183: } ! 1184: /* }}} */ ! 1185: ! 1186: #ifndef PHP_WIN32 ! 1187: #define php_select(m, r, w, e, t) select(m, r, w, e, t) ! 1188: #else ! 1189: #include "win32/select.h" ! 1190: #endif ! 1191: ! 1192: /* {{{ _mysqlnd_poll */ ! 1193: PHPAPI enum_func_status ! 1194: _mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, uint * desc_num TSRMLS_DC) ! 1195: { ! 1196: ! 1197: struct timeval tv; ! 1198: struct timeval *tv_p = NULL; ! 1199: fd_set rfds, wfds, efds; ! 1200: php_socket_t max_fd = 0; ! 1201: int retval, sets = 0; ! 1202: int set_count, max_set_count = 0; ! 1203: DBG_ENTER("mysqlnd_poll"); ! 1204: ! 1205: if (sec < 0 || usec < 0) { ! 1206: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative values passed for sec and/or usec"); ! 1207: DBG_RETURN(FAIL); ! 1208: } ! 1209: ! 1210: *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array TSRMLS_CC); ! 1211: ! 1212: FD_ZERO(&rfds); ! 1213: FD_ZERO(&wfds); ! 1214: FD_ZERO(&efds); ! 1215: ! 1216: if (r_array != NULL) { ! 1217: set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC); ! 1218: if (set_count > max_set_count) { ! 1219: max_set_count = set_count; ! 1220: } ! 1221: sets += set_count; ! 1222: } ! 1223: ! 1224: if (e_array != NULL) { ! 1225: set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC); ! 1226: if (set_count > max_set_count) { ! 1227: max_set_count = set_count; ! 1228: } ! 1229: sets += set_count; ! 1230: } ! 1231: ! 1232: if (!sets) { ! 1233: php_error_docref(NULL TSRMLS_CC, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed"); ! 1234: DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed"); ! 1235: DBG_RETURN(FAIL); ! 1236: } ! 1237: ! 1238: PHP_SAFE_MAX_FD(max_fd, max_set_count); ! 1239: ! 1240: /* Solaris + BSD do not like microsecond values which are >= 1 sec */ ! 1241: if (usec > 999999) { ! 1242: tv.tv_sec = sec + (usec / 1000000); ! 1243: tv.tv_usec = usec % 1000000; ! 1244: } else { ! 1245: tv.tv_sec = sec; ! 1246: tv.tv_usec = usec; ! 1247: } ! 1248: ! 1249: tv_p = &tv; ! 1250: ! 1251: retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p); ! 1252: ! 1253: if (retval == -1) { ! 1254: php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)", ! 1255: errno, strerror(errno), max_fd); ! 1256: DBG_RETURN(FAIL); ! 1257: } ! 1258: ! 1259: if (r_array != NULL) { ! 1260: mysqlnd_stream_array_from_fd_set(r_array, &rfds TSRMLS_CC); ! 1261: } ! 1262: if (e_array != NULL) { ! 1263: mysqlnd_stream_array_from_fd_set(e_array, &efds TSRMLS_CC); ! 1264: } ! 1265: ! 1266: *desc_num = retval; ! 1267: ! 1268: DBG_RETURN(PASS); ! 1269: } ! 1270: /* }}} */ ! 1271: ! 1272: ! 1273: /* ! 1274: COM_FIELD_LIST is special, different from a SHOW FIELDS FROM : ! 1275: - There is no result set header - status from the command, which ! 1276: impacts us to allocate big chunk of memory for reading the metadata. ! 1277: - The EOF packet is consumed by the metadata packet reader. ! 1278: */ ! 1279: ! 1280: /* {{{ mysqlnd_conn::list_fields */ ! 1281: MYSQLND_RES * ! 1282: MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, const char *achtung_wild TSRMLS_DC) ! 1283: { ! 1284: /* db + \0 + wild + \0 (for wild) */ ! 1285: char buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p; ! 1286: size_t table_len, wild_len; ! 1287: MYSQLND_RES *result = NULL; ! 1288: DBG_ENTER("mysqlnd_conn::list_fields"); ! 1289: DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:""); ! 1290: ! 1291: p = buff; ! 1292: if (table && (table_len = strlen(table))) { ! 1293: size_t to_copy = MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN); ! 1294: memcpy(p, table, to_copy); ! 1295: p += to_copy; ! 1296: *p++ = '\0'; ! 1297: } ! 1298: ! 1299: if (achtung_wild && (wild_len = strlen(achtung_wild))) { ! 1300: size_t to_copy = MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN); ! 1301: memcpy(p, achtung_wild, to_copy); ! 1302: p += to_copy; ! 1303: *p++ = '\0'; ! 1304: } ! 1305: ! 1306: if (PASS != conn->m->simple_command(conn, COM_FIELD_LIST, buff, p - buff, ! 1307: PROT_LAST /* we will handle the OK packet*/, ! 1308: FALSE, TRUE TSRMLS_CC)) { ! 1309: DBG_RETURN(NULL); ! 1310: } ! 1311: ! 1312: /* ! 1313: Prepare for the worst case. ! 1314: MyISAM goes to 2500 BIT columns, double it for safety. ! 1315: */ ! 1316: result = conn->m->result_init(5000, conn->persistent TSRMLS_CC); ! 1317: if (!result) { ! 1318: DBG_RETURN(NULL); ! 1319: } ! 1320: ! 1321: if (FAIL == result->m.read_result_metadata(result, conn TSRMLS_CC)) { ! 1322: DBG_ERR("Error ocurred while reading metadata"); ! 1323: result->m.free_result(result, TRUE TSRMLS_CC); ! 1324: DBG_RETURN(NULL); ! 1325: } ! 1326: ! 1327: result->type = MYSQLND_RES_NORMAL; ! 1328: result->m.fetch_row = result->m.fetch_row_normal_unbuffered; ! 1329: result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED)); ! 1330: if (!result->unbuf) { ! 1331: /* OOM */ ! 1332: SET_OOM_ERROR(conn->error_info); ! 1333: result->m.free_result(result, TRUE TSRMLS_CC); ! 1334: DBG_RETURN(NULL); ! 1335: } ! 1336: result->unbuf->eof_reached = TRUE; ! 1337: ! 1338: DBG_RETURN(result); ! 1339: } ! 1340: /* }}} */ ! 1341: ! 1342: ! 1343: /* {{{ mysqlnd_conn::list_method */ ! 1344: MYSQLND_RES * ! 1345: MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND * conn, const char * query, const char *achtung_wild, char *par1 TSRMLS_DC) ! 1346: { ! 1347: char *show_query = NULL; ! 1348: size_t show_query_len; ! 1349: MYSQLND_RES *result = NULL; ! 1350: ! 1351: DBG_ENTER("mysqlnd_conn::list_method"); ! 1352: DBG_INF_FMT("conn=%llu query=%s wild=%u", conn->thread_id, query, achtung_wild); ! 1353: ! 1354: if (par1) { ! 1355: if (achtung_wild) { ! 1356: show_query_len = spprintf(&show_query, 0, query, par1, achtung_wild); ! 1357: } else { ! 1358: show_query_len = spprintf(&show_query, 0, query, par1); ! 1359: } ! 1360: } else { ! 1361: if (achtung_wild) { ! 1362: show_query_len = spprintf(&show_query, 0, query, achtung_wild); ! 1363: } else { ! 1364: show_query_len = strlen(show_query = (char *)query); ! 1365: } ! 1366: } ! 1367: ! 1368: if (PASS == conn->m->query(conn, show_query, show_query_len TSRMLS_CC)) { ! 1369: result = conn->m->store_result(conn TSRMLS_CC); ! 1370: } ! 1371: if (show_query != query) { ! 1372: efree(show_query); /* allocated by spprintf */ ! 1373: } ! 1374: DBG_RETURN(result); ! 1375: } ! 1376: /* }}} */ ! 1377: ! 1378: ! 1379: /* {{{ mysqlnd_conn::errno */ ! 1380: static unsigned int ! 1381: MYSQLND_METHOD(mysqlnd_conn, errno)(const MYSQLND * const conn TSRMLS_DC) ! 1382: { ! 1383: return conn->error_info.error_no; ! 1384: } ! 1385: /* }}} */ ! 1386: ! 1387: ! 1388: /* {{{ mysqlnd_conn::error */ ! 1389: static const char * ! 1390: MYSQLND_METHOD(mysqlnd_conn, error)(const MYSQLND * const conn TSRMLS_DC) ! 1391: { ! 1392: return conn->error_info.error; ! 1393: } ! 1394: /* }}} */ ! 1395: ! 1396: ! 1397: /* {{{ mysqlnd_conn::sqlstate */ ! 1398: static const char * ! 1399: MYSQLND_METHOD(mysqlnd_conn, sqlstate)(const MYSQLND * const conn TSRMLS_DC) ! 1400: { ! 1401: return conn->error_info.sqlstate[0] ? conn->error_info.sqlstate:MYSQLND_SQLSTATE_NULL; ! 1402: } ! 1403: /* }}} */ ! 1404: ! 1405: ! 1406: /* {{{ mysqlnd_old_escape_string */ ! 1407: PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC) ! 1408: { ! 1409: DBG_ENTER("mysqlnd_old_escape_string"); ! 1410: DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), newstr, escapestr, escapestr_len TSRMLS_CC)); ! 1411: } ! 1412: /* }}} */ ! 1413: ! 1414: /* {{{ mysqlnd_conn::ssl_set */ ! 1415: static enum_func_status ! 1416: MYSQLND_METHOD(mysqlnd_conn, ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC) ! 1417: { ! 1418: return (PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_KEY, key TSRMLS_CC) && ! 1419: PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CERT, cert TSRMLS_CC) && ! 1420: PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CA, ca TSRMLS_CC) && ! 1421: PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CAPATH, capath TSRMLS_CC) && ! 1422: PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CIPHER, cipher TSRMLS_CC)) ? PASS : FAIL; ! 1423: } ! 1424: /* }}} */ ! 1425: ! 1426: ! 1427: /* {{{ mysqlnd_conn::escape_string */ ! 1428: static ulong ! 1429: MYSQLND_METHOD(mysqlnd_conn, escape_string)(MYSQLND * const conn, char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC) ! 1430: { ! 1431: DBG_ENTER("mysqlnd_conn::escape_string"); ! 1432: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1433: if (conn->upsert_status.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) { ! 1434: DBG_RETURN(mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC)); ! 1435: } ! 1436: DBG_RETURN(mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC)); ! 1437: } ! 1438: /* }}} */ ! 1439: ! 1440: ! 1441: /* {{{ mysqlnd_conn::dump_debug_info */ ! 1442: static enum_func_status ! 1443: MYSQLND_METHOD(mysqlnd_conn, dump_debug_info)(MYSQLND * const conn TSRMLS_DC) ! 1444: { ! 1445: DBG_ENTER("mysqlnd_conn::dump_debug_info"); ! 1446: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1447: DBG_RETURN(conn->m->simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC)); ! 1448: } ! 1449: /* }}} */ ! 1450: ! 1451: ! 1452: /* {{{ mysqlnd_conn::select_db */ ! 1453: static enum_func_status ! 1454: MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn, const char * const db, unsigned int db_len TSRMLS_DC) ! 1455: { ! 1456: enum_func_status ret; ! 1457: ! 1458: DBG_ENTER("mysqlnd_conn::select_db"); ! 1459: DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db); ! 1460: ! 1461: ret = conn->m->simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC); ! 1462: /* ! 1463: The server sends 0 but libmysql doesn't read it and has established ! 1464: a protocol of giving back -1. Thus we have to follow it :( ! 1465: */ ! 1466: SET_ERROR_AFF_ROWS(conn); ! 1467: if (ret == PASS) { ! 1468: if (conn->connect_or_select_db) { ! 1469: mnd_pefree(conn->connect_or_select_db, conn->persistent); ! 1470: } ! 1471: conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent); ! 1472: conn->connect_or_select_db_len = db_len; ! 1473: if (!conn->connect_or_select_db) { ! 1474: /* OOM */ ! 1475: SET_OOM_ERROR(conn->error_info); ! 1476: ret = FAIL; ! 1477: } ! 1478: } ! 1479: DBG_RETURN(ret); ! 1480: } ! 1481: /* }}} */ ! 1482: ! 1483: ! 1484: /* {{{ mysqlnd_conn::ping */ ! 1485: static enum_func_status ! 1486: MYSQLND_METHOD(mysqlnd_conn, ping)(MYSQLND * const conn TSRMLS_DC) ! 1487: { ! 1488: enum_func_status ret; ! 1489: ! 1490: DBG_ENTER("mysqlnd_conn::ping"); ! 1491: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1492: ! 1493: ret = conn->m->simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE, TRUE TSRMLS_CC); ! 1494: /* ! 1495: The server sends 0 but libmysql doesn't read it and has established ! 1496: a protocol of giving back -1. Thus we have to follow it :( ! 1497: */ ! 1498: SET_ERROR_AFF_ROWS(conn); ! 1499: ! 1500: DBG_INF_FMT("ret=%u", ret); ! 1501: DBG_RETURN(ret); ! 1502: } ! 1503: /* }}} */ ! 1504: ! 1505: ! 1506: /* {{{ mysqlnd_conn::statistic */ ! 1507: static enum_func_status ! 1508: MYSQLND_METHOD(mysqlnd_conn, statistic)(MYSQLND * conn, char **message, unsigned int * message_len TSRMLS_DC) ! 1509: { ! 1510: enum_func_status ret; ! 1511: MYSQLND_PACKET_STATS * stats_header; ! 1512: ! 1513: DBG_ENTER("mysqlnd_conn::statistic"); ! 1514: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1515: ! 1516: ret = conn->m->simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE, TRUE TSRMLS_CC); ! 1517: if (FAIL == ret) { ! 1518: DBG_RETURN(FAIL); ! 1519: } ! 1520: stats_header = conn->protocol->m.get_stats_packet(conn->protocol, FALSE TSRMLS_CC); ! 1521: if (!stats_header) { ! 1522: SET_OOM_ERROR(conn->error_info); ! 1523: DBG_RETURN(FAIL); ! 1524: } ! 1525: ! 1526: if (FAIL == (ret = PACKET_READ(stats_header, conn))) { ! 1527: DBG_RETURN(FAIL); ! 1528: } ! 1529: /* will be freed by Zend, thus don't use the mnd_ allocator */ ! 1530: *message = estrndup(stats_header->message, stats_header->message_len); ! 1531: *message_len = stats_header->message_len; ! 1532: PACKET_FREE(stats_header); ! 1533: ! 1534: DBG_INF(*message); ! 1535: DBG_RETURN(PASS); ! 1536: } ! 1537: /* }}} */ ! 1538: ! 1539: ! 1540: /* {{{ mysqlnd_conn::kill */ ! 1541: static enum_func_status ! 1542: MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND * conn, unsigned int pid TSRMLS_DC) ! 1543: { ! 1544: enum_func_status ret; ! 1545: char buff[4]; ! 1546: ! 1547: DBG_ENTER("mysqlnd_conn::kill"); ! 1548: DBG_INF_FMT("conn=%llu pid=%u", conn->thread_id, pid); ! 1549: ! 1550: int4store(buff, pid); ! 1551: ! 1552: /* If we kill ourselves don't expect OK packet, PROT_LAST will skip it */ ! 1553: if (pid != conn->thread_id) { ! 1554: ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC); ! 1555: /* ! 1556: The server sends 0 but libmysql doesn't read it and has established ! 1557: a protocol of giving back -1. Thus we have to follow it :( ! 1558: */ ! 1559: SET_ERROR_AFF_ROWS(conn); ! 1560: } else if (PASS == (ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_LAST, FALSE, TRUE TSRMLS_CC))) { ! 1561: CONN_SET_STATE(conn, CONN_QUIT_SENT); ! 1562: } ! 1563: DBG_RETURN(ret); ! 1564: } ! 1565: /* }}} */ ! 1566: ! 1567: ! 1568: /* {{{ mysqlnd_conn::set_charset */ ! 1569: static enum_func_status ! 1570: MYSQLND_METHOD(mysqlnd_conn, set_charset)(MYSQLND * const conn, const char * const csname TSRMLS_DC) ! 1571: { ! 1572: enum_func_status ret = PASS; ! 1573: char * query; ! 1574: size_t query_len; ! 1575: const MYSQLND_CHARSET * const charset = mysqlnd_find_charset_name(csname); ! 1576: ! 1577: DBG_ENTER("mysqlnd_conn::set_charset"); ! 1578: DBG_INF_FMT("conn=%llu cs=%s", conn->thread_id, csname); ! 1579: ! 1580: if (!charset) { ! 1581: SET_CLIENT_ERROR(conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE, ! 1582: "Invalid characterset or character set not supported"); ! 1583: DBG_RETURN(FAIL); ! 1584: } ! 1585: ! 1586: query_len = spprintf(&query, 0, "SET NAMES %s", csname); ! 1587: ! 1588: if (FAIL == conn->m->query(conn, query, query_len TSRMLS_CC)) { ! 1589: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error executing query"); ! 1590: } else if (conn->error_info.error_no) { ! 1591: ret = FAIL; ! 1592: } else { ! 1593: conn->charset = charset; ! 1594: } ! 1595: efree(query); /* allocated by spprintf */ ! 1596: ! 1597: DBG_INF(ret == PASS? "PASS":"FAIL"); ! 1598: DBG_RETURN(ret); ! 1599: } ! 1600: /* }}} */ ! 1601: ! 1602: ! 1603: /* {{{ mysqlnd_conn::refresh */ ! 1604: static enum_func_status ! 1605: MYSQLND_METHOD(mysqlnd_conn, refresh)(MYSQLND * const conn, uint8_t options TSRMLS_DC) ! 1606: { ! 1607: zend_uchar bits[1]; ! 1608: DBG_ENTER("mysqlnd_conn::refresh"); ! 1609: DBG_INF_FMT("conn=%llu options=%lu", conn->thread_id, options); ! 1610: ! 1611: int1store(bits, options); ! 1612: ! 1613: DBG_RETURN(conn->m->simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC)); ! 1614: } ! 1615: /* }}} */ ! 1616: ! 1617: ! 1618: /* {{{ mysqlnd_conn::shutdown */ ! 1619: static enum_func_status ! 1620: MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, uint8_t level TSRMLS_DC) ! 1621: { ! 1622: zend_uchar bits[1]; ! 1623: DBG_ENTER("mysqlnd_conn::shutdown"); ! 1624: DBG_INF_FMT("conn=%llu level=%lu", conn->thread_id, level); ! 1625: ! 1626: int1store(bits, level); ! 1627: ! 1628: DBG_RETURN(conn->m->simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC)); ! 1629: } ! 1630: /* }}} */ ! 1631: ! 1632: ! 1633: /* {{{ mysqlnd_send_close */ ! 1634: static enum_func_status ! 1635: MYSQLND_METHOD(mysqlnd_conn, send_close)(MYSQLND * const conn TSRMLS_DC) ! 1636: { ! 1637: enum_func_status ret = PASS; ! 1638: ! 1639: DBG_ENTER("mysqlnd_send_close"); ! 1640: DBG_INF_FMT("conn=%llu conn->net->stream->abstract=%p", ! 1641: conn->thread_id, conn->net->stream? conn->net->stream->abstract:NULL); ! 1642: ! 1643: switch (CONN_GET_STATE(conn)) { ! 1644: case CONN_READY: ! 1645: DBG_INF("Connection clean, sending COM_QUIT"); ! 1646: if (conn->net->stream) { ! 1647: ret = conn->m->simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST, TRUE, TRUE TSRMLS_CC); ! 1648: } ! 1649: /* Do nothing */ ! 1650: break; ! 1651: case CONN_SENDING_LOAD_DATA: ! 1652: /* ! 1653: Don't send COM_QUIT if we are in a middle of a LOAD DATA or we ! 1654: will crash (assert) a debug server. ! 1655: */ ! 1656: case CONN_NEXT_RESULT_PENDING: ! 1657: case CONN_QUERY_SENT: ! 1658: case CONN_FETCHING_DATA: ! 1659: MYSQLND_INC_GLOBAL_STATISTIC(STAT_CLOSE_IN_MIDDLE); ! 1660: DBG_ERR_FMT("Brutally closing connection [%p][%s]", conn, conn->scheme); ! 1661: /* ! 1662: Do nothing, the connection will be brutally closed ! 1663: and the server will catch it and free close from its side. ! 1664: */ ! 1665: case CONN_ALLOCED: ! 1666: /* ! 1667: Allocated but not connected or there was failure when trying ! 1668: to connect with pre-allocated connect. ! 1669: ! 1670: Fall-through ! 1671: */ ! 1672: case CONN_QUIT_SENT: ! 1673: /* The user has killed its own connection */ ! 1674: break; ! 1675: } ! 1676: /* ! 1677: We hold one reference, and every other object which needs the ! 1678: connection does increase it by 1. ! 1679: */ ! 1680: CONN_SET_STATE(conn, CONN_QUIT_SENT); ! 1681: ! 1682: DBG_RETURN(ret); ! 1683: } ! 1684: /* }}} */ ! 1685: ! 1686: ! 1687: /* {{{ mysqlnd_conn::close */ ! 1688: static enum_func_status ! 1689: MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn, enum_connection_close_type close_type TSRMLS_DC) ! 1690: { ! 1691: enum_func_status ret = PASS; ! 1692: static enum_mysqlnd_collected_stats ! 1693: close_type_to_stat_map[MYSQLND_CLOSE_LAST] = { ! 1694: STAT_CLOSE_EXPLICIT, ! 1695: STAT_CLOSE_IMPLICIT, ! 1696: STAT_CLOSE_DISCONNECT ! 1697: }; ! 1698: enum_mysqlnd_collected_stats statistic = close_type_to_stat_map[close_type]; ! 1699: ! 1700: DBG_ENTER("mysqlnd_conn::close"); ! 1701: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1702: ! 1703: if (conn->state >= CONN_READY) { ! 1704: MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic); ! 1705: MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS); ! 1706: if (conn->persistent) { ! 1707: MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS); ! 1708: } ! 1709: } ! 1710: ! 1711: /* ! 1712: Close now, free_reference will try, ! 1713: if we are last, but that's not a problem. ! 1714: */ ! 1715: ret = conn->m->send_close(conn TSRMLS_CC); ! 1716: ! 1717: ret = conn->m->free_reference(conn TSRMLS_CC); ! 1718: ! 1719: DBG_RETURN(ret); ! 1720: } ! 1721: /* }}} */ ! 1722: ! 1723: ! 1724: /* {{{ mysqlnd_conn::get_reference */ ! 1725: static MYSQLND * ! 1726: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference)(MYSQLND * const conn TSRMLS_DC) ! 1727: { ! 1728: DBG_ENTER("mysqlnd_conn::get_reference"); ! 1729: ++conn->refcount; ! 1730: DBG_INF_FMT("conn=%llu new_refcount=%u", conn->thread_id, conn->refcount); ! 1731: DBG_RETURN(conn); ! 1732: } ! 1733: /* }}} */ ! 1734: ! 1735: ! 1736: /* {{{ mysqlnd_conn::free_reference */ ! 1737: static enum_func_status ! 1738: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference)(MYSQLND * const conn TSRMLS_DC) ! 1739: { ! 1740: enum_func_status ret = PASS; ! 1741: DBG_ENTER("mysqlnd_conn::free_reference"); ! 1742: DBG_INF_FMT("conn=%llu old_refcount=%u", conn->thread_id, conn->refcount); ! 1743: if (!(--conn->refcount)) { ! 1744: /* ! 1745: No multithreading issues as we don't share the connection :) ! 1746: This will free the object too, of course because references has ! 1747: reached zero. ! 1748: */ ! 1749: ret = conn->m->send_close(conn TSRMLS_CC); ! 1750: conn->m->dtor(conn TSRMLS_CC); ! 1751: } ! 1752: DBG_RETURN(ret); ! 1753: } ! 1754: /* }}} */ ! 1755: ! 1756: ! 1757: /* {{{ mysqlnd_conn::get_state */ ! 1758: static enum mysqlnd_connection_state ! 1759: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state)(MYSQLND * const conn TSRMLS_DC) ! 1760: { ! 1761: DBG_ENTER("mysqlnd_conn::get_state"); ! 1762: DBG_RETURN(conn->state); ! 1763: } ! 1764: /* }}} */ ! 1765: ! 1766: ! 1767: /* {{{ mysqlnd_conn::set_state */ ! 1768: static void ! 1769: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC) ! 1770: { ! 1771: DBG_ENTER("mysqlnd_conn::set_state"); ! 1772: DBG_INF_FMT("New state=%u", new_state); ! 1773: conn->state = new_state; ! 1774: DBG_VOID_RETURN; ! 1775: } ! 1776: /* }}} */ ! 1777: ! 1778: ! 1779: /* {{{ mysqlnd_conn::field_count */ ! 1780: static unsigned int ! 1781: MYSQLND_METHOD(mysqlnd_conn, field_count)(const MYSQLND * const conn TSRMLS_DC) ! 1782: { ! 1783: return conn->field_count; ! 1784: } ! 1785: /* }}} */ ! 1786: ! 1787: ! 1788: /* {{{ mysqlnd_conn::insert_id */ ! 1789: static uint64_t ! 1790: MYSQLND_METHOD(mysqlnd_conn, insert_id)(const MYSQLND * const conn TSRMLS_DC) ! 1791: { ! 1792: return conn->upsert_status.last_insert_id; ! 1793: } ! 1794: /* }}} */ ! 1795: ! 1796: ! 1797: /* {{{ mysqlnd_conn::affected_rows */ ! 1798: static uint64_t ! 1799: MYSQLND_METHOD(mysqlnd_conn, affected_rows)(const MYSQLND * const conn TSRMLS_DC) ! 1800: { ! 1801: return conn->upsert_status.affected_rows; ! 1802: } ! 1803: /* }}} */ ! 1804: ! 1805: ! 1806: /* {{{ mysqlnd_conn::warning_count */ ! 1807: static unsigned int ! 1808: MYSQLND_METHOD(mysqlnd_conn, warning_count)(const MYSQLND * const conn TSRMLS_DC) ! 1809: { ! 1810: return conn->upsert_status.warning_count; ! 1811: } ! 1812: /* }}} */ ! 1813: ! 1814: ! 1815: /* {{{ mysqlnd_conn::info */ ! 1816: static const char * ! 1817: MYSQLND_METHOD(mysqlnd_conn, info)(const MYSQLND * const conn TSRMLS_DC) ! 1818: { ! 1819: return conn->last_message; ! 1820: } ! 1821: /* }}} */ ! 1822: ! 1823: #if !defined(MYSQLND_USE_OPTIMISATIONS) || MYSQLND_USE_OPTIMISATIONS == 0 ! 1824: /* {{{ mysqlnd_get_client_info */ ! 1825: PHPAPI const char * mysqlnd_get_client_info() ! 1826: { ! 1827: return MYSQLND_VERSION; ! 1828: } ! 1829: /* }}} */ ! 1830: ! 1831: ! 1832: /* {{{ mysqlnd_get_client_version */ ! 1833: PHPAPI unsigned int mysqlnd_get_client_version() ! 1834: { ! 1835: return MYSQLND_VERSION_ID; ! 1836: } ! 1837: /* }}} */ ! 1838: #endif ! 1839: ! 1840: /* {{{ mysqlnd_conn::get_server_info */ ! 1841: static const char * ! 1842: MYSQLND_METHOD(mysqlnd_conn, get_server_info)(const MYSQLND * const conn TSRMLS_DC) ! 1843: { ! 1844: return conn->server_version; ! 1845: } ! 1846: /* }}} */ ! 1847: ! 1848: ! 1849: /* {{{ mysqlnd_conn::get_host_info */ ! 1850: static const char * ! 1851: MYSQLND_METHOD(mysqlnd_conn, get_host_info)(const MYSQLND * const conn TSRMLS_DC) ! 1852: { ! 1853: return conn->host_info; ! 1854: } ! 1855: /* }}} */ ! 1856: ! 1857: ! 1858: /* {{{ mysqlnd_conn::get_proto_info */ ! 1859: static unsigned int ! 1860: MYSQLND_METHOD(mysqlnd_conn, get_proto_info)(const MYSQLND *const conn TSRMLS_DC) ! 1861: { ! 1862: return conn->protocol_version; ! 1863: } ! 1864: /* }}} */ ! 1865: ! 1866: ! 1867: /* {{{ mysqlnd_conn::charset_name */ ! 1868: static const char * ! 1869: MYSQLND_METHOD(mysqlnd_conn, charset_name)(const MYSQLND * const conn TSRMLS_DC) ! 1870: { ! 1871: return conn->charset->name; ! 1872: } ! 1873: /* }}} */ ! 1874: ! 1875: ! 1876: /* {{{ mysqlnd_conn::thread_id */ ! 1877: static uint64_t ! 1878: MYSQLND_METHOD(mysqlnd_conn, thread_id)(const MYSQLND * const conn TSRMLS_DC) ! 1879: { ! 1880: return conn->thread_id; ! 1881: } ! 1882: /* }}} */ ! 1883: ! 1884: ! 1885: /* {{{ mysqlnd_conn::get_server_version */ ! 1886: static unsigned long ! 1887: MYSQLND_METHOD(mysqlnd_conn, get_server_version)(const MYSQLND * const conn TSRMLS_DC) ! 1888: { ! 1889: long major, minor, patch; ! 1890: char *p; ! 1891: ! 1892: if (!(p = conn->server_version)) { ! 1893: return 0; ! 1894: } ! 1895: ! 1896: major = strtol(p, &p, 10); ! 1897: p += 1; /* consume the dot */ ! 1898: minor = strtol(p, &p, 10); ! 1899: p += 1; /* consume the dot */ ! 1900: patch = strtol(p, &p, 10); ! 1901: ! 1902: return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch)); ! 1903: } ! 1904: /* }}} */ ! 1905: ! 1906: ! 1907: /* {{{ mysqlnd_conn::more_results */ ! 1908: static zend_bool ! 1909: MYSQLND_METHOD(mysqlnd_conn, more_results)(const MYSQLND * const conn TSRMLS_DC) ! 1910: { ! 1911: DBG_ENTER("mysqlnd_conn::more_results"); ! 1912: /* (conn->state == CONN_NEXT_RESULT_PENDING) too */ ! 1913: DBG_RETURN(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS? TRUE:FALSE); ! 1914: } ! 1915: /* }}} */ ! 1916: ! 1917: ! 1918: /* {{{ mysqlnd_conn::next_result */ ! 1919: static enum_func_status ! 1920: MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC) ! 1921: { ! 1922: enum_func_status ret; ! 1923: ! 1924: DBG_ENTER("mysqlnd_conn::next_result"); ! 1925: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 1926: ! 1927: if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING) { ! 1928: DBG_RETURN(FAIL); ! 1929: } ! 1930: ! 1931: SET_EMPTY_ERROR(conn->error_info); ! 1932: SET_ERROR_AFF_ROWS(conn); ! 1933: /* ! 1934: We are sure that there is a result set, since conn->state is set accordingly ! 1935: in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered() ! 1936: */ ! 1937: if (FAIL == (ret = conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC))) { ! 1938: /* ! 1939: There can be an error in the middle of a multi-statement, which will cancel the multi-statement. ! 1940: So there are no more results and we should just return FALSE, error_no has been set ! 1941: */ ! 1942: if (!conn->error_info.error_no) { ! 1943: DBG_ERR_FMT("Serious error. %s::%u", __FILE__, __LINE__); ! 1944: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. PID=%d", getpid()); ! 1945: CONN_SET_STATE(conn, CONN_QUIT_SENT); ! 1946: } else { ! 1947: DBG_INF_FMT("Error from the server : (%u) %s", conn->error_info.error_no, conn->error_info.error); ! 1948: } ! 1949: } ! 1950: if (ret == PASS && conn->last_query_type == QUERY_UPSERT && conn->upsert_status.affected_rows) { ! 1951: MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status.affected_rows); ! 1952: } ! 1953: ! 1954: DBG_RETURN(ret); ! 1955: } ! 1956: /* }}} */ ! 1957: ! 1958: ! 1959: /* {{{ mysqlnd_field_type_name */ ! 1960: PHPAPI const char *mysqlnd_field_type_name(enum mysqlnd_field_types field_type) ! 1961: { ! 1962: switch(field_type) { ! 1963: case FIELD_TYPE_STRING: ! 1964: case FIELD_TYPE_VAR_STRING: ! 1965: return "string"; ! 1966: case FIELD_TYPE_TINY: ! 1967: case FIELD_TYPE_SHORT: ! 1968: case FIELD_TYPE_LONG: ! 1969: case FIELD_TYPE_LONGLONG: ! 1970: case FIELD_TYPE_INT24: ! 1971: return "int"; ! 1972: case FIELD_TYPE_FLOAT: ! 1973: case FIELD_TYPE_DOUBLE: ! 1974: case FIELD_TYPE_DECIMAL: ! 1975: case FIELD_TYPE_NEWDECIMAL: ! 1976: return "real"; ! 1977: case FIELD_TYPE_TIMESTAMP: ! 1978: return "timestamp"; ! 1979: case FIELD_TYPE_YEAR: ! 1980: return "year"; ! 1981: case FIELD_TYPE_DATE: ! 1982: case FIELD_TYPE_NEWDATE: ! 1983: return "date"; ! 1984: case FIELD_TYPE_TIME: ! 1985: return "time"; ! 1986: case FIELD_TYPE_SET: ! 1987: return "set"; ! 1988: case FIELD_TYPE_ENUM: ! 1989: return "enum"; ! 1990: case FIELD_TYPE_GEOMETRY: ! 1991: return "geometry"; ! 1992: case FIELD_TYPE_DATETIME: ! 1993: return "datetime"; ! 1994: case FIELD_TYPE_TINY_BLOB: ! 1995: case FIELD_TYPE_MEDIUM_BLOB: ! 1996: case FIELD_TYPE_LONG_BLOB: ! 1997: case FIELD_TYPE_BLOB: ! 1998: return "blob"; ! 1999: case FIELD_TYPE_NULL: ! 2000: return "null"; ! 2001: case FIELD_TYPE_BIT: ! 2002: return "bit"; ! 2003: default: ! 2004: return "unknown"; ! 2005: } ! 2006: } ! 2007: /* }}} */ ! 2008: ! 2009: ! 2010: /* {{{ mysqlnd_conn::set_client_option */ ! 2011: static enum_func_status ! 2012: MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn, ! 2013: enum mysqlnd_option option, ! 2014: const char * const value ! 2015: TSRMLS_DC) ! 2016: { ! 2017: enum_func_status ret = PASS; ! 2018: DBG_ENTER("mysqlnd_conn::set_client_option"); ! 2019: DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option); ! 2020: switch (option) { ! 2021: case MYSQL_OPT_COMPRESS: ! 2022: #ifdef WHEN_SUPPORTED_BY_MYSQLI ! 2023: case MYSQL_OPT_READ_TIMEOUT: ! 2024: case MYSQL_OPT_WRITE_TIMEOUT: ! 2025: #endif ! 2026: case MYSQLND_OPT_SSL_KEY: ! 2027: case MYSQLND_OPT_SSL_CERT: ! 2028: case MYSQLND_OPT_SSL_CA: ! 2029: case MYSQLND_OPT_SSL_CAPATH: ! 2030: case MYSQLND_OPT_SSL_CIPHER: ! 2031: case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: ! 2032: case MYSQL_OPT_CONNECT_TIMEOUT: ! 2033: case MYSQLND_OPT_NET_CMD_BUFFER_SIZE: ! 2034: case MYSQLND_OPT_NET_READ_BUFFER_SIZE: ! 2035: ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC); ! 2036: break; ! 2037: #if MYSQLND_UNICODE ! 2038: case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE: ! 2039: conn->options.numeric_and_datetime_as_unicode = *(unsigned int*) value; ! 2040: break; ! 2041: #endif ! 2042: #ifdef MYSQLND_STRING_TO_INT_CONVERSION ! 2043: case MYSQLND_OPT_INT_AND_FLOAT_NATIVE: ! 2044: DBG_INF("MYSQLND_OPT_INT_AND_FLOAT_NATIVE"); ! 2045: conn->options.int_and_float_native = *(unsigned int*) value; ! 2046: break; ! 2047: #endif ! 2048: case MYSQL_OPT_LOCAL_INFILE: ! 2049: DBG_INF("MYSQL_OPT_LOCAL_INFILE"); ! 2050: if (!value || (*(unsigned int*) value) ? 1 : 0) { ! 2051: conn->options.flags |= CLIENT_LOCAL_FILES; ! 2052: } else { ! 2053: conn->options.flags &= ~CLIENT_LOCAL_FILES; ! 2054: } ! 2055: break; ! 2056: case MYSQL_INIT_COMMAND: ! 2057: { ! 2058: char ** new_init_commands; ! 2059: char * new_command; ! 2060: DBG_INF("MYSQL_INIT_COMMAND"); ! 2061: DBG_INF_FMT("command=%s", value); ! 2062: /* when num_commands is 0, then realloc will be effectively a malloc call, internally */ ! 2063: /* Don't assign to conn->options.init_commands because in case of OOM we will lose the pointer and leak */ ! 2064: new_init_commands = mnd_perealloc(conn->options.init_commands, sizeof(char *) * (conn->options.num_commands + 1), conn->persistent); ! 2065: if (!new_init_commands) { ! 2066: goto oom; ! 2067: } ! 2068: conn->options.init_commands = new_init_commands; ! 2069: new_command = mnd_pestrdup(value, conn->persistent); ! 2070: if (!new_command) { ! 2071: goto oom; ! 2072: } ! 2073: conn->options.init_commands[conn->options.num_commands] = new_command; ! 2074: ++conn->options.num_commands; ! 2075: break; ! 2076: } ! 2077: case MYSQL_READ_DEFAULT_FILE: ! 2078: case MYSQL_READ_DEFAULT_GROUP: ! 2079: #ifdef WHEN_SUPPORTED_BY_MYSQLI ! 2080: case MYSQL_SET_CLIENT_IP: ! 2081: case MYSQL_REPORT_DATA_TRUNCATION: ! 2082: #endif ! 2083: /* currently not supported. Todo!! */ ! 2084: break; ! 2085: case MYSQL_SET_CHARSET_NAME: ! 2086: { ! 2087: char * new_charset_name = mnd_pestrdup(value, conn->persistent); ! 2088: DBG_INF("MYSQL_SET_CHARSET_NAME"); ! 2089: if (!new_charset_name) { ! 2090: goto oom; ! 2091: } ! 2092: if (conn->options.charset_name) { ! 2093: mnd_pefree(conn->options.charset_name, conn->persistent); ! 2094: } ! 2095: conn->options.charset_name = new_charset_name; ! 2096: DBG_INF_FMT("charset=%s", conn->options.charset_name); ! 2097: break; ! 2098: } ! 2099: case MYSQL_OPT_NAMED_PIPE: ! 2100: conn->options.protocol = MYSQL_PROTOCOL_PIPE; ! 2101: break; ! 2102: case MYSQL_OPT_PROTOCOL: ! 2103: if (*(unsigned int*) value < MYSQL_PROTOCOL_LAST) { ! 2104: conn->options.protocol = *(unsigned int*) value; ! 2105: } ! 2106: break; ! 2107: #ifdef WHEN_SUPPORTED_BY_MYSQLI ! 2108: case MYSQL_SET_CHARSET_DIR: ! 2109: case MYSQL_OPT_RECONNECT: ! 2110: /* we don't need external character sets, all character sets are ! 2111: compiled in. For compatibility we just ignore this setting. ! 2112: Same for protocol, we don't support old protocol */ ! 2113: case MYSQL_OPT_USE_REMOTE_CONNECTION: ! 2114: case MYSQL_OPT_USE_EMBEDDED_CONNECTION: ! 2115: case MYSQL_OPT_GUESS_CONNECTION: ! 2116: /* todo: throw an error, we don't support embedded */ ! 2117: break; ! 2118: #endif ! 2119: ! 2120: #ifdef WHEN_SUPPORTED_BY_MYSQLI ! 2121: case MYSQL_SHARED_MEMORY_BASE_NAME: ! 2122: case MYSQL_OPT_USE_RESULT: ! 2123: case MYSQL_SECURE_AUTH: ! 2124: /* not sure, todo ? */ ! 2125: #endif ! 2126: default: ! 2127: ret = FAIL; ! 2128: } ! 2129: DBG_RETURN(ret); ! 2130: oom: ! 2131: SET_OOM_ERROR(conn->error_info); ! 2132: DBG_RETURN(FAIL); ! 2133: } ! 2134: /* }}} */ ! 2135: ! 2136: ! 2137: /* {{{ mysqlnd_conn::use_result */ ! 2138: static MYSQLND_RES * ! 2139: MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC) ! 2140: { ! 2141: MYSQLND_RES * result; ! 2142: ! 2143: DBG_ENTER("mysqlnd_conn::use_result"); ! 2144: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 2145: ! 2146: if (!conn->current_result) { ! 2147: DBG_RETURN(NULL); ! 2148: } ! 2149: ! 2150: /* Nothing to store for UPSERT/LOAD DATA */ ! 2151: if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) { ! 2152: SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, ! 2153: mysqlnd_out_of_sync); ! 2154: DBG_ERR("Command out of sync"); ! 2155: DBG_RETURN(NULL); ! 2156: } ! 2157: ! 2158: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_UNBUFFERED_SETS); ! 2159: ! 2160: conn->current_result->conn = conn->m->get_reference(conn TSRMLS_CC); ! 2161: result = conn->current_result->m.use_result(conn->current_result, FALSE TSRMLS_CC); ! 2162: ! 2163: if (!result) { ! 2164: conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC); ! 2165: } ! 2166: conn->current_result = NULL; ! 2167: ! 2168: DBG_RETURN(result); ! 2169: } ! 2170: /* }}} */ ! 2171: ! 2172: ! 2173: /* {{{ mysqlnd_conn::store_result */ ! 2174: static MYSQLND_RES * ! 2175: MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC) ! 2176: { ! 2177: MYSQLND_RES *result; ! 2178: ! 2179: DBG_ENTER("mysqlnd_conn::store_result"); ! 2180: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 2181: ! 2182: if (!conn->current_result) { ! 2183: DBG_RETURN(NULL); ! 2184: } ! 2185: ! 2186: /* Nothing to store for UPSERT/LOAD DATA*/ ! 2187: if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) { ! 2188: SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, ! 2189: mysqlnd_out_of_sync); ! 2190: DBG_ERR("Command out of sync"); ! 2191: DBG_RETURN(NULL); ! 2192: } ! 2193: ! 2194: MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS); ! 2195: ! 2196: result = conn->current_result->m.store_result(conn->current_result, conn, FALSE TSRMLS_CC); ! 2197: if (!result) { ! 2198: conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC); ! 2199: } ! 2200: conn->current_result = NULL; ! 2201: DBG_RETURN(result); ! 2202: } ! 2203: /* }}} */ ! 2204: ! 2205: ! 2206: /* {{{ mysqlnd_conn::get_connection_stats */ ! 2207: static void ! 2208: MYSQLND_METHOD(mysqlnd_conn, get_connection_stats)(const MYSQLND * const conn, ! 2209: zval *return_value ! 2210: TSRMLS_DC ZEND_FILE_LINE_DC) ! 2211: { ! 2212: DBG_ENTER("mysqlnd_conn::get_connection_stats"); ! 2213: DBG_INF_FMT("conn=%llu", conn->thread_id); ! 2214: mysqlnd_fill_stats_hash(conn->stats, mysqlnd_stats_values_names, return_value TSRMLS_CC ZEND_FILE_LINE_CC); ! 2215: DBG_VOID_RETURN; ! 2216: } ! 2217: /* }}} */ ! 2218: ! 2219: ! 2220: /* {{{ mysqlnd_conn::set_autocommit */ ! 2221: static enum_func_status ! 2222: MYSQLND_METHOD(mysqlnd_conn, set_autocommit)(MYSQLND * conn, unsigned int mode TSRMLS_DC) ! 2223: { ! 2224: enum_func_status ret; ! 2225: DBG_ENTER("mysqlnd_conn::set_autocommit"); ! 2226: ret = conn->m->query(conn, (mode) ? "SET AUTOCOMMIT=1":"SET AUTOCOMMIT=0", sizeof("SET AUTOCOMMIT=1") - 1 TSRMLS_CC); ! 2227: DBG_RETURN(ret); ! 2228: } ! 2229: /* }}} */ ! 2230: ! 2231: ! 2232: /* {{{ mysqlnd_conn::tx_commit */ ! 2233: static enum_func_status ! 2234: MYSQLND_METHOD(mysqlnd_conn, tx_commit)(MYSQLND * conn TSRMLS_DC) ! 2235: { ! 2236: enum_func_status ret; ! 2237: DBG_ENTER("mysqlnd_conn::tx_commit"); ! 2238: ret = conn->m->query(conn, "COMMIT", sizeof("COMMIT") - 1 TSRMLS_CC); ! 2239: DBG_RETURN(ret); ! 2240: } ! 2241: /* }}} */ ! 2242: ! 2243: ! 2244: /* {{{ mysqlnd_conn::tx_rollback */ ! 2245: static enum_func_status ! 2246: MYSQLND_METHOD(mysqlnd_conn, tx_rollback)(MYSQLND * conn TSRMLS_DC) ! 2247: { ! 2248: enum_func_status ret; ! 2249: DBG_ENTER("mysqlnd_conn::tx_rollback"); ! 2250: ret = conn->m->query(conn, "ROLLBACK", sizeof("ROLLBACK") - 1 TSRMLS_CC); ! 2251: DBG_RETURN(ret); ! 2252: } ! 2253: /* }}} */ ! 2254: ! 2255: ! 2256: ! 2257: MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC); ! 2258: static enum_func_status MYSQLND_METHOD(mysqlnd_conn, init)(MYSQLND * conn TSRMLS_DC); ! 2259: ! 2260: static ! 2261: MYSQLND_CLASS_METHODS_START(mysqlnd_conn) ! 2262: MYSQLND_METHOD(mysqlnd_conn, init), ! 2263: MYSQLND_METHOD(mysqlnd_conn, connect), ! 2264: ! 2265: MYSQLND_METHOD(mysqlnd_conn, escape_string), ! 2266: MYSQLND_METHOD(mysqlnd_conn, set_charset), ! 2267: MYSQLND_METHOD(mysqlnd_conn, query), ! 2268: MYSQLND_METHOD(mysqlnd_conn, send_query), ! 2269: MYSQLND_METHOD(mysqlnd_conn, reap_query), ! 2270: MYSQLND_METHOD(mysqlnd_conn, use_result), ! 2271: MYSQLND_METHOD(mysqlnd_conn, store_result), ! 2272: MYSQLND_METHOD(mysqlnd_conn, next_result), ! 2273: MYSQLND_METHOD(mysqlnd_conn, more_results), ! 2274: ! 2275: _mysqlnd_stmt_init, ! 2276: ! 2277: MYSQLND_METHOD(mysqlnd_conn, shutdown), ! 2278: MYSQLND_METHOD(mysqlnd_conn, refresh), ! 2279: ! 2280: MYSQLND_METHOD(mysqlnd_conn, ping), ! 2281: MYSQLND_METHOD(mysqlnd_conn, kill), ! 2282: MYSQLND_METHOD(mysqlnd_conn, select_db), ! 2283: MYSQLND_METHOD(mysqlnd_conn, dump_debug_info), ! 2284: MYSQLND_METHOD(mysqlnd_conn, change_user), ! 2285: ! 2286: MYSQLND_METHOD(mysqlnd_conn, errno), ! 2287: MYSQLND_METHOD(mysqlnd_conn, error), ! 2288: MYSQLND_METHOD(mysqlnd_conn, sqlstate), ! 2289: MYSQLND_METHOD(mysqlnd_conn, thread_id), ! 2290: ! 2291: MYSQLND_METHOD(mysqlnd_conn, get_connection_stats), ! 2292: ! 2293: MYSQLND_METHOD(mysqlnd_conn, get_server_version), ! 2294: MYSQLND_METHOD(mysqlnd_conn, get_server_info), ! 2295: MYSQLND_METHOD(mysqlnd_conn, statistic), ! 2296: MYSQLND_METHOD(mysqlnd_conn, get_host_info), ! 2297: MYSQLND_METHOD(mysqlnd_conn, get_proto_info), ! 2298: MYSQLND_METHOD(mysqlnd_conn, info), ! 2299: MYSQLND_METHOD(mysqlnd_conn, charset_name), ! 2300: MYSQLND_METHOD(mysqlnd_conn, list_fields), ! 2301: MYSQLND_METHOD(mysqlnd_conn, list_method), ! 2302: ! 2303: MYSQLND_METHOD(mysqlnd_conn, insert_id), ! 2304: MYSQLND_METHOD(mysqlnd_conn, affected_rows), ! 2305: MYSQLND_METHOD(mysqlnd_conn, warning_count), ! 2306: MYSQLND_METHOD(mysqlnd_conn, field_count), ! 2307: ! 2308: MYSQLND_METHOD(mysqlnd_conn, set_server_option), ! 2309: MYSQLND_METHOD(mysqlnd_conn, set_client_option), ! 2310: MYSQLND_METHOD(mysqlnd_conn, free_contents), ! 2311: MYSQLND_METHOD(mysqlnd_conn, free_options), ! 2312: MYSQLND_METHOD(mysqlnd_conn, close), ! 2313: ! 2314: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor), ! 2315: ! 2316: mysqlnd_query_read_result_set_header, ! 2317: ! 2318: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference), ! 2319: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference), ! 2320: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state), ! 2321: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, set_state), ! 2322: ! 2323: MYSQLND_METHOD(mysqlnd_conn, simple_command), ! 2324: MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response), ! 2325: MYSQLND_METHOD(mysqlnd_conn, restart_psession), ! 2326: MYSQLND_METHOD(mysqlnd_conn, end_psession), ! 2327: MYSQLND_METHOD(mysqlnd_conn, send_close), ! 2328: ! 2329: MYSQLND_METHOD(mysqlnd_conn, ssl_set), ! 2330: mysqlnd_result_init ! 2331: #ifdef AUTOCOMMIT_TX_COMMIT_ROLLBACK ! 2332: ,MYSQLND_METHOD(mysqlnd_conn, set_autocommit), ! 2333: MYSQLND_METHOD(mysqlnd_conn, tx_commit), ! 2334: MYSQLND_METHOD(mysqlnd_conn, tx_rollback) ! 2335: #endif ! 2336: MYSQLND_CLASS_METHODS_END; ! 2337: ! 2338: ! 2339: /* {{{ mysqlnd_conn::init */ ! 2340: static enum_func_status ! 2341: MYSQLND_METHOD(mysqlnd_conn, init)(MYSQLND * conn TSRMLS_DC) ! 2342: { ! 2343: DBG_ENTER("mysqlnd_conn::init"); ! 2344: mysqlnd_stats_init(&conn->stats, STAT_LAST); ! 2345: SET_ERROR_AFF_ROWS(conn); ! 2346: ! 2347: conn->net = mysqlnd_net_init(conn->persistent TSRMLS_CC); ! 2348: conn->protocol = mysqlnd_protocol_init(conn->persistent TSRMLS_CC); ! 2349: ! 2350: DBG_RETURN(conn->net && conn->protocol? PASS:FAIL); ! 2351: } ! 2352: /* }}} */ ! 2353: ! 2354: ! 2355: /* {{{ mysqlnd_init */ ! 2356: PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC) ! 2357: { ! 2358: size_t alloc_size = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *); ! 2359: MYSQLND *ret; ! 2360: ! 2361: DBG_ENTER("mysqlnd_init"); ! 2362: DBG_INF_FMT("persistent=%u", persistent); ! 2363: ret = mnd_pecalloc(1, alloc_size, persistent); ! 2364: if (!ret) { ! 2365: DBG_RETURN(NULL); ! 2366: } ! 2367: ! 2368: ret->persistent = persistent; ! 2369: ret->m = mysqlnd_conn_methods; ! 2370: CONN_SET_STATE(ret, CONN_ALLOCED); ! 2371: ret->m->get_reference(ret TSRMLS_CC); ! 2372: ! 2373: if (PASS != ret->m->init(ret TSRMLS_CC)) { ! 2374: ret->m->dtor(ret TSRMLS_CC); ! 2375: ret = NULL; ! 2376: } ! 2377: ! 2378: DBG_RETURN(ret); ! 2379: } ! 2380: /* }}} */ ! 2381: ! 2382: ! 2383: /* {{{ mysqlnd_library_init */ ! 2384: PHPAPI void mysqlnd_library_init(TSRMLS_D) ! 2385: { ! 2386: if (mysqlnd_library_initted == FALSE) { ! 2387: mysqlnd_library_initted = TRUE; ! 2388: mysqlnd_conn_methods = &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_conn); ! 2389: _mysqlnd_init_ps_subsystem(); ! 2390: /* Should be calloc, as mnd_calloc will reference LOCK_access*/ ! 2391: mysqlnd_stats_init(&mysqlnd_global_stats, STAT_LAST); ! 2392: } ! 2393: } ! 2394: /* }}} */ ! 2395: ! 2396: /* {{{ mysqlnd_conn_get_methods */ ! 2397: PHPAPI struct st_mysqlnd_conn_methods * mysqlnd_conn_get_methods() ! 2398: { ! 2399: return mysqlnd_conn_methods; ! 2400: } ! 2401: /* }}} */ ! 2402: ! 2403: /* {{{ mysqlnd_conn_set_methods */ ! 2404: PHPAPI void mysqlnd_conn_set_methods(struct st_mysqlnd_conn_methods *methods) ! 2405: { ! 2406: mysqlnd_conn_methods = methods; ! 2407: } ! 2408: /* }}} */ ! 2409: ! 2410: ! 2411: static unsigned int mysqlnd_plugins_counter = 0; ! 2412: ! 2413: /* {{{ mysqlnd_plugin_register */ ! 2414: PHPAPI unsigned int mysqlnd_plugin_register() ! 2415: { ! 2416: return mysqlnd_plugins_counter++; ! 2417: } ! 2418: /* }}} */ ! 2419: ! 2420: ! 2421: /* {{{ mysqlnd_plugin_count */ ! 2422: PHPAPI unsigned int mysqlnd_plugin_count() ! 2423: { ! 2424: return mysqlnd_plugins_counter; ! 2425: } ! 2426: /* }}} */ ! 2427: ! 2428: ! 2429: /* {{{ _mysqlnd_plugin_get_plugin_connection_data */ ! 2430: PHPAPI void ** _mysqlnd_plugin_get_plugin_connection_data(const MYSQLND * conn, unsigned int plugin_id TSRMLS_DC) ! 2431: { ! 2432: DBG_ENTER("_mysqlnd_plugin_get_plugin_connection_data"); ! 2433: DBG_INF_FMT("plugin_id=%u", plugin_id); ! 2434: if (!conn || plugin_id >= mysqlnd_plugin_count()) { ! 2435: return NULL; ! 2436: } ! 2437: DBG_RETURN((void *)((char *)conn + sizeof(MYSQLND) + plugin_id * sizeof(void *))); ! 2438: } ! 2439: /* }}} */ ! 2440: ! 2441: /* ! 2442: * Local variables: ! 2443: * tab-width: 4 ! 2444: * c-basic-offset: 4 ! 2445: * End: ! 2446: * vim600: noet sw=4 ts=4 fdm=marker ! 2447: * vim<600: noet sw=4 ts=4 ! 2448: */