1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: George Schlossnagle <george@omniti.com> |
16 : | Wez Furlong <wez@php.net> |
17 : | Johannes Schlueter <johannes@mysql.com> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : /* $Id: mysql_driver.c 288583 2009-09-22 15:31:35Z uw $ */
22 :
23 : #ifdef HAVE_CONFIG_H
24 : #include "config.h"
25 : #endif
26 :
27 : #include "php.h"
28 : #include "php_ini.h"
29 : #include "ext/standard/info.h"
30 : #include "pdo/php_pdo.h"
31 : #include "pdo/php_pdo_driver.h"
32 : #include "php_pdo_mysql.h"
33 : #include "php_pdo_mysql_int.h"
34 : #ifndef PDO_USE_MYSQLND
35 : #include <mysqld_error.h>
36 : #endif
37 : #include "zend_exceptions.h"
38 :
39 : #if PDO_USE_MYSQLND
40 : # define pdo_mysql_init(persistent) mysqlnd_init(persistent)
41 : #else
42 : # define pdo_mysql_init(persistent) mysql_init(NULL)
43 : #endif
44 :
45 : #if !HAVE_MYSQL_SQLSTATE && !PDO_USE_MYSQLND
46 : static const char *pdo_mysql_get_sqlstate(unsigned int my_errno) { /* {{{ */
47 : switch (my_errno) {
48 : /* import auto-generated case: code */
49 : #include "php_pdo_mysql_sqlstate.h"
50 : default: return "HY000";
51 : }
52 : }
53 : /* }}} */
54 : #endif
55 :
56 : /* {{{ _pdo_mysql_error */
57 : int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC) /* {{{ */
58 611 : {
59 611 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
60 : pdo_error_type *pdo_err;
61 : pdo_mysql_error_info *einfo;
62 611 : pdo_mysql_stmt *S = NULL;
63 :
64 611 : PDO_DBG_ENTER("_pdo_mysql_error");
65 611 : PDO_DBG_INF_FMT("file=%s line=%d", file, line);
66 611 : if (stmt) {
67 31 : S = (pdo_mysql_stmt*)stmt->driver_data;
68 31 : pdo_err = &stmt->error_code;
69 31 : einfo = &S->einfo;
70 : } else {
71 580 : pdo_err = &dbh->error_code;
72 580 : einfo = &H->einfo;
73 : }
74 :
75 : #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
76 614 : if (S && S->stmt) {
77 3 : einfo->errcode = mysql_stmt_errno(S->stmt);
78 : }
79 : else
80 : #endif
81 : {
82 608 : einfo->errcode = mysql_errno(H->server);
83 : }
84 :
85 611 : einfo->file = file;
86 611 : einfo->line = line;
87 :
88 611 : if (einfo->errmsg) {
89 355 : pefree(einfo->errmsg, dbh->is_persistent);
90 355 : einfo->errmsg = NULL;
91 : }
92 :
93 611 : if (einfo->errcode) {
94 601 : if (einfo->errcode == 2014) {
95 8 : einfo->errmsg = pestrdup(
96 : "Cannot execute queries while other unbuffered queries are active. "
97 : "Consider using PDOStatement::fetchAll(). Alternatively, if your code "
98 : "is only ever going to run against mysql, you may enable query "
99 : "buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.",
100 : dbh->is_persistent);
101 593 : } else if (einfo->errcode == 2057) {
102 0 : einfo->errmsg = pestrdup(
103 : "A stored procedure returning result sets of different size was called. "
104 : "This is not supported by libmysql",
105 : dbh->is_persistent);
106 :
107 : } else {
108 593 : einfo->errmsg = pestrdup(mysql_error(H->server), dbh->is_persistent);
109 : }
110 : } else { /* no error */
111 10 : strcpy(*pdo_err, PDO_ERR_NONE);
112 10 : PDO_DBG_RETURN(0);
113 : }
114 :
115 : #if HAVE_MYSQL_SQLSTATE || PDO_USE_MYSQLND
116 : # if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
117 628 : if (S && S->stmt) {
118 3 : strcpy(*pdo_err, mysql_stmt_sqlstate(S->stmt));
119 : } else
120 : # endif
121 : {
122 598 : strcpy(*pdo_err, mysql_sqlstate(H->server));
123 : }
124 : #else
125 : strcpy(*pdo_err, pdo_mysql_get_sqlstate(einfo->errcode));
126 : #endif
127 :
128 601 : if (!dbh->methods) {
129 10 : PDO_DBG_INF("Throwing exception");
130 10 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
131 : *pdo_err, einfo->errcode, einfo->errmsg);
132 : }
133 :
134 601 : PDO_DBG_RETURN(einfo->errcode);
135 : }
136 : /* }}} */
137 :
138 : /* {{{ pdo_mysql_fetch_error_func */
139 : static int pdo_mysql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
140 848 : {
141 848 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
142 848 : pdo_mysql_error_info *einfo = &H->einfo;
143 :
144 848 : PDO_DBG_ENTER("pdo_mysql_fetch_error_func");
145 848 : PDO_DBG_INF_FMT("dbh=%p stmt=%p", dbh, stmt);
146 848 : if (stmt) {
147 781 : pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
148 781 : einfo = &S->einfo;
149 : } else {
150 67 : einfo = &H->einfo;
151 : }
152 :
153 848 : if (einfo->errcode) {
154 81 : add_next_index_long(info, einfo->errcode);
155 81 : add_next_index_string(info, einfo->errmsg, 1);
156 : }
157 :
158 848 : PDO_DBG_RETURN(1);
159 : }
160 : /* }}} */
161 :
162 : /* {{{ mysql_handle_closer */
163 : static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
164 425 : {
165 425 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
166 :
167 425 : PDO_DBG_ENTER("mysql_handle_closer");
168 425 : PDO_DBG_INF_FMT("dbh=%p", dbh);
169 425 : if (H) {
170 425 : if (H->server) {
171 425 : mysql_close(H->server);
172 425 : H->server = NULL;
173 : }
174 425 : if (H->einfo.errmsg) {
175 221 : pefree(H->einfo.errmsg, dbh->is_persistent);
176 221 : H->einfo.errmsg = NULL;
177 : }
178 425 : pefree(H, dbh->is_persistent);
179 425 : dbh->driver_data = NULL;
180 : }
181 425 : PDO_DBG_RETURN(0);
182 : }
183 : /* }}} */
184 :
185 : /* {{{ mysql_handle_preparer */
186 : static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
187 1558 : {
188 1558 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
189 1558 : pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
190 : #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
191 1558 : char *nsql = NULL;
192 1558 : int nsql_len = 0;
193 : int ret;
194 : int server_version;
195 : #endif
196 :
197 1558 : PDO_DBG_ENTER("mysql_handle_preparer");
198 1558 : PDO_DBG_INF_FMT("dbh=%p", dbh);
199 1558 : PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
200 :
201 1558 : S->H = H;
202 1558 : stmt->driver_data = S;
203 1558 : stmt->methods = &mysql_stmt_methods;
204 :
205 1558 : if (H->emulate_prepare) {
206 769 : goto end;
207 : }
208 :
209 : #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
210 789 : server_version = mysql_get_server_version(H->server);
211 789 : if (server_version < 40100) {
212 0 : goto fallback;
213 : }
214 789 : stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
215 789 : ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
216 :
217 789 : if (ret == 1) {
218 : /* query was rewritten */
219 113 : sql = nsql;
220 113 : sql_len = nsql_len;
221 676 : } else if (ret == -1) {
222 : /* failed to parse */
223 1 : strcpy(dbh->error_code, stmt->error_code);
224 1 : PDO_DBG_RETURN(0);
225 : }
226 :
227 788 : if (!(S->stmt = mysql_stmt_init(H->server))) {
228 0 : pdo_mysql_error(dbh);
229 0 : if (nsql) {
230 0 : efree(nsql);
231 : }
232 0 : PDO_DBG_RETURN(0);
233 : }
234 :
235 788 : if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
236 : /* TODO: might need to pull statement specific info here? */
237 : /* if the query isn't supported by the protocol, fallback to emulation */
238 11 : if (mysql_errno(H->server) == 1295) {
239 1 : if (nsql) {
240 0 : efree(nsql);
241 : }
242 1 : goto fallback;
243 : }
244 10 : pdo_mysql_error(dbh);
245 10 : if (nsql) {
246 1 : efree(nsql);
247 : }
248 10 : PDO_DBG_RETURN(0);
249 : }
250 777 : if (nsql) {
251 112 : efree(nsql);
252 : }
253 :
254 777 : S->num_params = mysql_stmt_param_count(S->stmt);
255 :
256 777 : if (S->num_params) {
257 378 : S->params_given = 0;
258 : #if PDO_USE_MYSQLND
259 378 : S->params = NULL;
260 : #else
261 : S->params = ecalloc(S->num_params, sizeof(MYSQL_BIND));
262 : S->in_null = ecalloc(S->num_params, sizeof(my_bool));
263 : S->in_length = ecalloc(S->num_params, sizeof(unsigned long));
264 : #endif
265 : }
266 777 : dbh->alloc_own_columns = 1;
267 :
268 777 : S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
269 :
270 777 : PDO_DBG_RETURN(1);
271 :
272 770 : fallback:
273 : #endif
274 770 : end:
275 770 : stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
276 :
277 770 : PDO_DBG_RETURN(1);
278 : }
279 : /* }}} */
280 :
281 : /* {{{ mysql_handle_doer */
282 : static long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
283 1557 : {
284 1557 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
285 1557 : PDO_DBG_ENTER("mysql_handle_doer");
286 1557 : PDO_DBG_INF_FMT("dbh=%p", dbh);
287 1557 : PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
288 :
289 1557 : if (mysql_real_query(H->server, sql, sql_len)) {
290 557 : pdo_mysql_error(dbh);
291 557 : PDO_DBG_RETURN(-1);
292 : } else {
293 1000 : my_ulonglong c = mysql_affected_rows(H->server);
294 1000 : if (c == (my_ulonglong) -1) {
295 3 : pdo_mysql_error(dbh);
296 3 : PDO_DBG_RETURN(H->einfo.errcode ? -1 : 0);
297 : } else {
298 :
299 : #if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
300 : /* MULTI_QUERY support - eat up all unfetched result sets */
301 : MYSQL_RES* result;
302 1998 : while (mysql_more_results(H->server)) {
303 4 : if (mysql_next_result(H->server)) {
304 0 : PDO_DBG_RETURN(1);
305 : }
306 4 : result = mysql_store_result(H->server);
307 4 : if (result) {
308 0 : mysql_free_result(result);
309 : }
310 : }
311 : #endif
312 997 : PDO_DBG_RETURN((int)c);
313 : }
314 : }
315 : }
316 : /* }}} */
317 :
318 : /* {{{ pdo_mysql_last_insert_id */
319 : static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
320 12 : {
321 12 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
322 12 : char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
323 12 : PDO_DBG_ENTER("pdo_mysql_last_insert_id");
324 12 : *len = strlen(id);
325 12 : PDO_DBG_RETURN(id);
326 : }
327 :
328 : /* {{{ mysql_handle_quoter */
329 : static int mysql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
330 247 : {
331 247 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
332 247 : PDO_DBG_ENTER("mysql_handle_quoter");
333 247 : PDO_DBG_INF_FMT("dbh=%p", dbh);
334 247 : PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted);
335 247 : *quoted = safe_emalloc(2, unquotedlen, 3);
336 247 : *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
337 247 : (*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
338 247 : (*quoted)[++*quotedlen] = '\0';
339 247 : PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted);
340 247 : PDO_DBG_RETURN(1);
341 : }
342 : /* }}} */
343 :
344 : /* {{{ mysql_handle_begin */
345 : static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
346 21 : {
347 21 : PDO_DBG_ENTER("mysql_handle_quoter");
348 21 : PDO_DBG_INF_FMT("dbh=%p", dbh);
349 21 : PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC));
350 : }
351 : /* }}} */
352 :
353 : /* {{{ mysql_handle_commit */
354 : static int mysql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
355 10 : {
356 10 : PDO_DBG_ENTER("mysql_handle_commit");
357 10 : PDO_DBG_INF_FMT("dbh=%p", dbh);
358 : #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
359 10 : PDO_DBG_RETURN(0 <= mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server));
360 : #else
361 : PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC));
362 : #endif
363 : }
364 :
365 : /* {{{ mysql_handle_rollback */
366 : static int mysql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
367 11 : {
368 11 : PDO_DBG_ENTER("mysql_handle_rollback");
369 11 : PDO_DBG_INF_FMT("dbh=%p", dbh);
370 : #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
371 11 : PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server));
372 : #else
373 : PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC));
374 : #endif
375 : }
376 : /* }}} */
377 :
378 : /* {{{ mysql_handle_autocommit */
379 : static inline int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
380 7 : {
381 7 : PDO_DBG_ENTER("mysql_handle_autocommit");
382 7 : PDO_DBG_INF_FMT("dbh=%p", dbh);
383 7 : PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit);
384 : #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
385 7 : PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit));
386 : #else
387 : if (dbh->auto_commit) {
388 : PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC));
389 : } else {
390 : PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC));
391 : }
392 : #endif
393 : }
394 : /* }}} */
395 :
396 : /* {{{ pdo_mysql_set_attribute */
397 : static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
398 294 : {
399 294 : PDO_DBG_ENTER("pdo_mysql_set_attribute");
400 294 : PDO_DBG_INF_FMT("dbh=%p", dbh);
401 294 : PDO_DBG_INF_FMT("attr=%l", attr);
402 294 : switch (attr) {
403 : case PDO_ATTR_AUTOCOMMIT:
404 10 : convert_to_boolean(val);
405 :
406 : /* ignore if the new value equals the old one */
407 10 : if (dbh->auto_commit ^ Z_BVAL_P(val)) {
408 6 : dbh->auto_commit = Z_BVAL_P(val);
409 6 : mysql_handle_autocommit(dbh TSRMLS_CC);
410 : }
411 10 : PDO_DBG_RETURN(1);
412 :
413 : case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
414 32 : ((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
415 32 : PDO_DBG_RETURN(1);
416 : case PDO_MYSQL_ATTR_DIRECT_QUERY:
417 : case PDO_ATTR_EMULATE_PREPARES:
418 209 : ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
419 209 : PDO_DBG_RETURN(1);
420 : case PDO_ATTR_FETCH_TABLE_NAMES:
421 2 : ((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = Z_BVAL_P(val);
422 2 : PDO_DBG_RETURN(1);
423 : #ifndef PDO_USE_MYSQLND
424 : case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
425 : if (Z_LVAL_P(val) < 0) {
426 : /* TODO: Johannes, can we throw a warning here? */
427 : ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = 1024*1024;
428 : PDO_DBG_INF_FMT("Adjusting invalid buffer size to =%l", ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size);
429 : } else {
430 : ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = Z_LVAL_P(val);
431 : }
432 : PDO_DBG_RETURN(1);
433 : break;
434 : #endif
435 :
436 : default:
437 41 : PDO_DBG_RETURN(0);
438 : }
439 : }
440 : /* }}} */
441 :
442 : /* {{{ pdo_mysql_get_attribute */
443 : static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
444 88 : {
445 88 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
446 :
447 88 : PDO_DBG_ENTER("pdo_mysql_get_attribute");
448 88 : PDO_DBG_INF_FMT("dbh=%p", dbh);
449 88 : PDO_DBG_INF_FMT("attr=%l", attr);
450 88 : switch (attr) {
451 : case PDO_ATTR_CLIENT_VERSION:
452 3 : ZVAL_STRING(return_value, (char *)mysql_get_client_info(), 1);
453 3 : break;
454 :
455 : case PDO_ATTR_SERVER_VERSION:
456 3 : ZVAL_STRING(return_value, (char *)mysql_get_server_info(H->server), 1);
457 3 : break;
458 :
459 : case PDO_ATTR_CONNECTION_STATUS:
460 2 : ZVAL_STRING(return_value, (char *)mysql_get_host_info(H->server), 1);
461 2 : break;
462 : case PDO_ATTR_SERVER_INFO: {
463 : char *tmp;
464 : #if PDO_USE_MYSQLND
465 : int tmp_len;
466 :
467 2 : if (mysqlnd_stat(H->server, &tmp, &tmp_len) == PASS) {
468 2 : ZVAL_STRINGL(return_value, tmp, tmp_len, 0);
469 : #else
470 : if ((tmp = (char *)mysql_stat(H->server))) {
471 : ZVAL_STRING(return_value, tmp, 1);
472 : #endif
473 : } else {
474 0 : pdo_mysql_error(dbh);
475 0 : PDO_DBG_RETURN(-1);
476 : }
477 : }
478 2 : break;
479 : case PDO_ATTR_AUTOCOMMIT:
480 17 : ZVAL_LONG(return_value, dbh->auto_commit);
481 17 : break;
482 :
483 : case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
484 3 : ZVAL_LONG(return_value, H->buffered);
485 3 : break;
486 :
487 : case PDO_MYSQL_ATTR_DIRECT_QUERY:
488 43 : ZVAL_LONG(return_value, H->emulate_prepare);
489 43 : break;
490 :
491 : #ifndef PDO_USE_MYSQLND
492 : case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
493 : ZVAL_LONG(return_value, H->max_buffer_size);
494 : break;
495 : #endif
496 :
497 : default:
498 15 : PDO_DBG_RETURN(0);
499 : }
500 :
501 73 : PDO_DBG_RETURN(1);
502 : }
503 : /* }}} */
504 :
505 : /* {{{ pdo_mysql_check_liveness */
506 : static int pdo_mysql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
507 24 : {
508 24 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
509 : #if MYSQL_VERSION_ID <= 32230
510 : void (*handler) (int);
511 : unsigned int my_errno;
512 : #endif
513 :
514 24 : PDO_DBG_ENTER("pdo_mysql_check_liveness");
515 24 : PDO_DBG_INF_FMT("dbh=%p", dbh);
516 :
517 : #if MYSQL_VERSION_ID > 32230
518 24 : if (mysql_ping(H->server)) {
519 0 : PDO_DBG_RETURN(FAILURE);
520 : }
521 : #else /* no mysql_ping() */
522 : handler = signal(SIGPIPE, SIG_IGN);
523 : mysql_stat(H->server);
524 : switch (mysql_errno(H->server)) {
525 : case CR_SERVER_GONE_ERROR:
526 : case CR_SERVER_LOST:
527 : signal(SIGPIPE, handler);
528 : PDO_DBG_RETURN(FAILURE);
529 : default:
530 : break;
531 : }
532 : signal(SIGPIPE, handler);
533 : #endif /* end mysql_ping() */
534 24 : PDO_DBG_RETURN(SUCCESS);
535 : }
536 : /* }}} */
537 :
538 : /* {{{ mysql_methods */
539 : static struct pdo_dbh_methods mysql_methods = {
540 : mysql_handle_closer,
541 : mysql_handle_preparer,
542 : mysql_handle_doer,
543 : mysql_handle_quoter,
544 : mysql_handle_begin,
545 : mysql_handle_commit,
546 : mysql_handle_rollback,
547 : pdo_mysql_set_attribute,
548 : pdo_mysql_last_insert_id,
549 : pdo_mysql_fetch_error_func,
550 : pdo_mysql_get_attribute,
551 : pdo_mysql_check_liveness
552 : };
553 : /* }}} */
554 :
555 : #ifdef PDO_USE_MYSQLND
556 : # ifdef PHP_WIN32
557 : # define MYSQL_UNIX_ADDR "MySQL"
558 : # else
559 : # define MYSQL_UNIX_ADDR PDO_MYSQL_G(default_socket)
560 : # endif
561 : #endif
562 :
563 : /* {{{ pdo_mysql_handle_factory */
564 : static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
565 426 : {
566 : pdo_mysql_db_handle *H;
567 426 : int i, ret = 0;
568 426 : char *host = NULL, *unix_socket = NULL;
569 426 : unsigned int port = 3306;
570 : char *dbname;
571 : struct pdo_data_src_parser vars[] = {
572 : { "charset", NULL, 0 },
573 : { "dbname", "", 0 },
574 : { "host", "localhost", 0 },
575 : { "port", "3306", 0 },
576 : { "unix_socket", MYSQL_UNIX_ADDR, 0 },
577 426 : };
578 : int connect_opts = 0
579 : #ifdef CLIENT_MULTI_RESULTS
580 : |CLIENT_MULTI_RESULTS
581 : #endif
582 : #ifdef CLIENT_MULTI_STATEMENTS
583 : |CLIENT_MULTI_STATEMENTS
584 : #endif
585 426 : ;
586 :
587 : #if PDO_USE_MYSQLND
588 426 : int dbname_len = 0;
589 426 : int password_len = 0;
590 : #endif
591 426 : PDO_DBG_ENTER("pdo_mysql_handle_factory");
592 426 : PDO_DBG_INF_FMT("dbh=%p", dbh);
593 : #ifdef CLIENT_MULTI_RESULTS
594 426 : PDO_DBG_INF("multi results");
595 : #endif
596 :
597 426 : php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
598 :
599 426 : H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
600 :
601 426 : H->einfo.errcode = 0;
602 426 : H->einfo.errmsg = NULL;
603 :
604 : /* allocate an environment */
605 :
606 : /* handle for the server */
607 426 : if (!(H->server = pdo_mysql_init(dbh->is_persistent))) {
608 0 : pdo_mysql_error(dbh);
609 0 : goto cleanup;
610 : }
611 :
612 426 : dbh->driver_data = H;
613 :
614 : #ifndef PDO_USE_MYSQLND
615 : H->max_buffer_size = 1024*1024;
616 : #endif
617 :
618 426 : H->buffered = H->emulate_prepare = 1;
619 :
620 : /* handle MySQL options */
621 426 : if (driver_options) {
622 24 : long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
623 24 : long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
624 24 : char *init_cmd = NULL;
625 : #ifndef PDO_USE_MYSQLND
626 : char *default_file = NULL, *default_group = NULL;
627 : long compress = 0;
628 : #endif
629 24 : H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1 TSRMLS_CC);
630 :
631 24 : H->emulate_prepare = pdo_attr_lval(driver_options,
632 : PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
633 24 : H->emulate_prepare = pdo_attr_lval(driver_options,
634 : PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
635 :
636 : #ifndef PDO_USE_MYSQLND
637 : H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
638 : #endif
639 :
640 24 : if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_FOUND_ROWS, 0 TSRMLS_CC)) {
641 0 : connect_opts |= CLIENT_FOUND_ROWS;
642 : }
643 :
644 24 : if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_IGNORE_SPACE, 0 TSRMLS_CC)) {
645 0 : connect_opts |= CLIENT_IGNORE_SPACE;
646 : }
647 :
648 24 : if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
649 0 : pdo_mysql_error(dbh);
650 0 : goto cleanup;
651 : }
652 :
653 : #if PHP_MAJOR_VERSION < 6
654 : if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode))
655 : #else
656 24 : if (PG(open_basedir) && PG(open_basedir)[0] != '\0')
657 : #endif
658 : {
659 0 : local_infile = 0;
660 : }
661 : #ifdef MYSQL_OPT_LOCAL_INFILE
662 : if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
663 : pdo_mysql_error(dbh);
664 : goto cleanup;
665 : }
666 : #endif
667 : #ifdef MYSQL_OPT_RECONNECT
668 : /* since 5.0.3, the default for this option is 0 if not specified.
669 : * we want the old behaviour */
670 : {
671 : long reconnect = 1;
672 : mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
673 : }
674 : #endif
675 24 : init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
676 24 : if (init_cmd) {
677 4 : if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
678 0 : efree(init_cmd);
679 0 : pdo_mysql_error(dbh);
680 0 : goto cleanup;
681 : }
682 4 : efree(init_cmd);
683 : }
684 : #ifndef PDO_USE_MYSQLND
685 : default_file = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_FILE, NULL TSRMLS_CC);
686 : if (default_file) {
687 : if (mysql_options(H->server, MYSQL_READ_DEFAULT_FILE, (const char *)default_file)) {
688 : efree(default_file);
689 : pdo_mysql_error(dbh);
690 : goto cleanup;
691 : }
692 : efree(default_file);
693 : }
694 :
695 : default_group= pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP, NULL TSRMLS_CC);
696 : if (default_group) {
697 : if (mysql_options(H->server, MYSQL_READ_DEFAULT_GROUP, (const char *)default_group)) {
698 : efree(default_group);
699 : pdo_mysql_error(dbh);
700 : goto cleanup;
701 : }
702 : efree(default_group);
703 : }
704 :
705 : compress = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_COMPRESS, 0 TSRMLS_CC);
706 : if (compress) {
707 : if (mysql_options(H->server, MYSQL_OPT_COMPRESS, 0)) {
708 : pdo_mysql_error(dbh);
709 : goto cleanup;
710 : }
711 : }
712 : #endif
713 : }
714 :
715 426 : dbname = vars[1].optval;
716 426 : host = vars[2].optval;
717 426 : if(vars[3].optval) {
718 426 : port = atoi(vars[3].optval);
719 : }
720 426 : if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
721 422 : unix_socket = vars[4].optval;
722 : }
723 :
724 : /* TODO: - Check zval cache + ZTS */
725 : #ifdef PDO_USE_MYSQLND
726 426 : if (dbname) {
727 426 : dbname_len = strlen(dbname);
728 : }
729 :
730 426 : if (dbh->password) {
731 425 : password_len = strlen(dbh->password);
732 : }
733 :
734 426 : if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
735 : port, unix_socket, connect_opts, PDO_MYSQL_G(mysqlnd_thd_zval_cache) TSRMLS_CC) == NULL) {
736 : #else
737 : if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
738 : #endif
739 10 : pdo_mysql_error(dbh);
740 10 : goto cleanup;
741 : }
742 :
743 416 : if (!dbh->auto_commit) {
744 1 : mysql_handle_autocommit(dbh TSRMLS_CC);
745 : }
746 :
747 416 : H->attached = 1;
748 :
749 416 : dbh->alloc_own_columns = 1;
750 416 : dbh->max_escaped_char_length = 2;
751 416 : dbh->methods = &mysql_methods;
752 :
753 416 : ret = 1;
754 :
755 426 : cleanup:
756 2556 : for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
757 2130 : if (vars[i].freeme) {
758 842 : efree(vars[i].optval);
759 : }
760 : }
761 :
762 426 : dbh->methods = &mysql_methods;
763 :
764 426 : PDO_DBG_RETURN(ret);
765 : }
766 : /* }}} */
767 :
768 : pdo_driver_t pdo_mysql_driver = {
769 : PDO_DRIVER_HEADER(mysql),
770 : pdo_mysql_handle_factory
771 : };
772 :
773 : /*
774 : * Local variables:
775 : * tab-width: 4
776 : * c-basic-offset: 4
777 : * End:
778 : * vim600: noet sw=4 ts=4 fdm=marker
779 : * vim<600: noet sw=4 ts=4
780 : */
|