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