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