Annotation of embedaddon/php/ext/mysqlnd/mysqlnd.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.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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>