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