1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
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 650 : {
59 650 : 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 650 : pdo_mysql_stmt *S = NULL;
63 :
64 650 : PDO_DBG_ENTER("_pdo_mysql_error");
65 650 : PDO_DBG_INF_FMT("file=%s line=%d", file, line);
66 650 : if (stmt) {
67 33 : S = (pdo_mysql_stmt*)stmt->driver_data;
68 33 : pdo_err = &stmt->error_code;
69 33 : einfo = &S->einfo;
70 : } else {
71 617 : pdo_err = &dbh->error_code;
72 617 : einfo = &H->einfo;
73 : }
74 :
75 : #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
76 653 : if (S && S->stmt) {
77 3 : einfo->errcode = mysql_stmt_errno(S->stmt);
78 : }
79 : else
80 : #endif
81 : {
82 647 : einfo->errcode = mysql_errno(H->server);
83 : }
84 :
85 650 : einfo->file = file;
86 650 : einfo->line = line;
87 :
88 650 : if (einfo->errmsg) {
89 377 : pefree(einfo->errmsg, dbh->is_persistent);
90 377 : einfo->errmsg = NULL;
91 : }
92 :
93 650 : if (einfo->errcode) {
94 640 : 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 632 : } 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 632 : 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 669 : if (S && S->stmt) {
118 3 : strcpy(*pdo_err, mysql_stmt_sqlstate(S->stmt));
119 : } else
120 : # endif
121 : {
122 637 : strcpy(*pdo_err, mysql_sqlstate(H->server));
123 : }
124 : #else
125 : strcpy(*pdo_err, pdo_mysql_get_sqlstate(einfo->errcode));
126 : #endif
127 :
128 640 : 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 640 : 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 800 : {
141 800 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
142 800 : pdo_mysql_error_info *einfo = &H->einfo;
143 :
144 800 : PDO_DBG_ENTER("pdo_mysql_fetch_error_func");
145 800 : PDO_DBG_INF_FMT("dbh=%p stmt=%p", dbh, stmt);
146 800 : if (stmt) {
147 740 : pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
148 740 : einfo = &S->einfo;
149 : } else {
150 60 : einfo = &H->einfo;
151 : }
152 :
153 800 : if (einfo->errcode) {
154 82 : add_next_index_long(info, einfo->errcode);
155 82 : add_next_index_string(info, einfo->errmsg, 1);
156 : }
157 :
158 800 : PDO_DBG_RETURN(1);
159 : }
160 : /* }}} */
161 :
162 : /* {{{ mysql_handle_closer */
163 : static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
164 441 : {
165 441 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
166 :
167 441 : PDO_DBG_ENTER("mysql_handle_closer");
168 441 : PDO_DBG_INF_FMT("dbh=%p", dbh);
169 441 : if (H) {
170 441 : if (H->server) {
171 441 : mysql_close(H->server);
172 441 : H->server = NULL;
173 : }
174 441 : if (H->einfo.errmsg) {
175 236 : pefree(H->einfo.errmsg, dbh->is_persistent);
176 236 : H->einfo.errmsg = NULL;
177 : }
178 441 : pefree(H, dbh->is_persistent);
179 441 : dbh->driver_data = NULL;
180 : }
181 441 : 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 1535 : {
188 1535 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
189 1535 : pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
190 : #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
191 1535 : char *nsql = NULL;
192 1535 : int nsql_len = 0;
193 : int ret;
194 : int server_version;
195 : #endif
196 :
197 1535 : PDO_DBG_ENTER("mysql_handle_preparer");
198 1535 : PDO_DBG_INF_FMT("dbh=%p", dbh);
199 1535 : PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
200 :
201 1535 : S->H = H;
202 1535 : stmt->driver_data = S;
203 1535 : stmt->methods = &mysql_stmt_methods;
204 :
205 1535 : if (H->emulate_prepare) {
206 802 : goto end;
207 : }
208 :
209 : #if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
210 733 : server_version = mysql_get_server_version(H->server);
211 733 : if (server_version < 40100) {
212 0 : goto fallback;
213 : }
214 733 : stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
215 733 : ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
216 :
217 733 : if (ret == 1) {
218 : /* query was rewritten */
219 113 : sql = nsql;
220 113 : sql_len = nsql_len;
221 620 : } 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 732 : 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 732 : 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 721 : if (nsql) {
251 112 : efree(nsql);
252 : }
253 :
254 721 : S->num_params = mysql_stmt_param_count(S->stmt);
255 :
256 721 : if (S->num_params) {
257 379 : S->params_given = 0;
258 : #if PDO_USE_MYSQLND
259 379 : 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 721 : dbh->alloc_own_columns = 1;
267 :
268 721 : S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
269 :
270 721 : PDO_DBG_RETURN(1);
271 :
272 803 : fallback:
273 : #endif
274 803 : end:
275 803 : stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
276 :
277 803 : 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 1608 : {
284 1608 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
285 1608 : PDO_DBG_ENTER("mysql_handle_doer");
286 1608 : PDO_DBG_INF_FMT("dbh=%p", dbh);
287 1608 : PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
288 :
289 1608 : if (mysql_real_query(H->server, sql, sql_len)) {
290 594 : pdo_mysql_error(dbh);
291 594 : PDO_DBG_RETURN(-1);
292 : } else {
293 1014 : my_ulonglong c = mysql_affected_rows(H->server);
294 1014 : 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 2026 : 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 1011 : 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 320 : {
331 320 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
332 320 : PDO_DBG_ENTER("mysql_handle_quoter");
333 320 : PDO_DBG_INF_FMT("dbh=%p", dbh);
334 320 : PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted);
335 320 : *quoted = safe_emalloc(2, unquotedlen, 3);
336 320 : *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
337 320 : (*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
338 320 : (*quoted)[++*quotedlen] = '\0';
339 320 : PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted);
340 320 : 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 87 : {
445 87 : pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
446 :
447 87 : PDO_DBG_ENTER("pdo_mysql_get_attribute");
448 87 : PDO_DBG_INF_FMT("dbh=%p", dbh);
449 87 : PDO_DBG_INF_FMT("attr=%l", attr);
450 87 : 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 42 : ZVAL_LONG(return_value, H->emulate_prepare);
489 42 : 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 72 : 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 1 : 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 23 : 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 : #ifdef PDO_USE_MYSQLND
555 : # ifdef PHP_WIN32
556 : # define MYSQL_UNIX_ADDR "MySQL"
557 : # else
558 : # define MYSQL_UNIX_ADDR PDO_MYSQL_G(default_socket)
559 : # endif
560 : #endif
561 :
562 : /* {{{ pdo_mysql_handle_factory */
563 : static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
564 442 : {
565 : pdo_mysql_db_handle *H;
566 442 : int i, ret = 0;
567 442 : char *host = NULL, *unix_socket = NULL;
568 442 : unsigned int port = 3306;
569 : char *dbname;
570 : struct pdo_data_src_parser vars[] = {
571 : { "charset", NULL, 0 },
572 : { "dbname", "", 0 },
573 : { "host", "localhost", 0 },
574 : { "port", "3306", 0 },
575 : { "unix_socket", MYSQL_UNIX_ADDR, 0 },
576 442 : };
577 : int connect_opts = 0
578 : #ifdef CLIENT_MULTI_RESULTS
579 : |CLIENT_MULTI_RESULTS
580 : #endif
581 : #ifdef CLIENT_MULTI_STATEMENTS
582 : |CLIENT_MULTI_STATEMENTS
583 : #endif
584 442 : ;
585 :
586 : #if PDO_USE_MYSQLND
587 442 : int dbname_len = 0;
588 442 : int password_len = 0;
589 : #endif
590 442 : PDO_DBG_ENTER("pdo_mysql_handle_factory");
591 442 : PDO_DBG_INF_FMT("dbh=%p", dbh);
592 : #ifdef CLIENT_MULTI_RESULTS
593 442 : PDO_DBG_INF("multi results");
594 : #endif
595 :
596 442 : php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
597 :
598 442 : H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
599 :
600 442 : H->einfo.errcode = 0;
601 442 : H->einfo.errmsg = NULL;
602 :
603 : /* allocate an environment */
604 :
605 : /* handle for the server */
606 442 : if (!(H->server = pdo_mysql_init(dbh->is_persistent))) {
607 0 : pdo_mysql_error(dbh);
608 0 : goto cleanup;
609 : }
610 :
611 442 : dbh->driver_data = H;
612 :
613 : #ifndef PDO_USE_MYSQLND
614 : H->max_buffer_size = 1024*1024;
615 : #endif
616 :
617 442 : H->buffered = H->emulate_prepare = 1;
618 :
619 : /* handle MySQL options */
620 442 : if (driver_options) {
621 25 : long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
622 25 : long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
623 25 : char *init_cmd = NULL;
624 : #ifndef PDO_USE_MYSQLND
625 : char *default_file = NULL, *default_group = NULL;
626 : long compress = 0;
627 : #endif
628 25 : H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1 TSRMLS_CC);
629 :
630 25 : H->emulate_prepare = pdo_attr_lval(driver_options,
631 : PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
632 25 : H->emulate_prepare = pdo_attr_lval(driver_options,
633 : PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
634 :
635 : #ifndef PDO_USE_MYSQLND
636 : H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
637 : #endif
638 :
639 25 : if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_FOUND_ROWS, 0 TSRMLS_CC)) {
640 0 : connect_opts |= CLIENT_FOUND_ROWS;
641 : }
642 :
643 25 : if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_IGNORE_SPACE, 0 TSRMLS_CC)) {
644 0 : connect_opts |= CLIENT_IGNORE_SPACE;
645 : }
646 :
647 25 : if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
648 0 : pdo_mysql_error(dbh);
649 0 : goto cleanup;
650 : }
651 :
652 : #if PHP_MAJOR_VERSION < 6
653 25 : if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode))
654 : #else
655 : if (PG(open_basedir) && PG(open_basedir)[0] != '\0')
656 : #endif
657 : {
658 0 : local_infile = 0;
659 : }
660 : #ifdef MYSQL_OPT_LOCAL_INFILE
661 : if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
662 : pdo_mysql_error(dbh);
663 : goto cleanup;
664 : }
665 : #endif
666 : #ifdef MYSQL_OPT_RECONNECT
667 : /* since 5.0.3, the default for this option is 0 if not specified.
668 : * we want the old behaviour */
669 : {
670 : long reconnect = 1;
671 : mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
672 : }
673 : #endif
674 25 : init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
675 25 : if (init_cmd) {
676 4 : if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
677 0 : efree(init_cmd);
678 0 : pdo_mysql_error(dbh);
679 0 : goto cleanup;
680 : }
681 4 : efree(init_cmd);
682 : }
683 : #ifndef PDO_USE_MYSQLND
684 : default_file = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_FILE, NULL TSRMLS_CC);
685 : if (default_file) {
686 : if (mysql_options(H->server, MYSQL_READ_DEFAULT_FILE, (const char *)default_file)) {
687 : efree(default_file);
688 : pdo_mysql_error(dbh);
689 : goto cleanup;
690 : }
691 : efree(default_file);
692 : }
693 :
694 : default_group= pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP, NULL TSRMLS_CC);
695 : if (default_group) {
696 : if (mysql_options(H->server, MYSQL_READ_DEFAULT_GROUP, (const char *)default_group)) {
697 : efree(default_group);
698 : pdo_mysql_error(dbh);
699 : goto cleanup;
700 : }
701 : efree(default_group);
702 : }
703 :
704 : compress = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_COMPRESS, 0 TSRMLS_CC);
705 : if (compress) {
706 : if (mysql_options(H->server, MYSQL_OPT_COMPRESS, 0)) {
707 : pdo_mysql_error(dbh);
708 : goto cleanup;
709 : }
710 : }
711 : #endif
712 : }
713 :
714 442 : dbname = vars[1].optval;
715 442 : host = vars[2].optval;
716 442 : if(vars[3].optval) {
717 442 : port = atoi(vars[3].optval);
718 : }
719 442 : if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
720 438 : unix_socket = vars[4].optval;
721 : }
722 :
723 : /* TODO: - Check zval cache + ZTS */
724 : #ifdef PDO_USE_MYSQLND
725 442 : if (dbname) {
726 442 : dbname_len = strlen(dbname);
727 : }
728 :
729 442 : if (dbh->password) {
730 441 : password_len = strlen(dbh->password);
731 : }
732 :
733 442 : if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
734 : port, unix_socket, connect_opts, PDO_MYSQL_G(mysqlnd_thd_zval_cache) TSRMLS_CC) == NULL) {
735 : #else
736 : if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
737 : #endif
738 10 : pdo_mysql_error(dbh);
739 10 : goto cleanup;
740 : }
741 :
742 432 : if (!dbh->auto_commit) {
743 1 : mysql_handle_autocommit(dbh TSRMLS_CC);
744 : }
745 :
746 432 : H->attached = 1;
747 :
748 432 : dbh->alloc_own_columns = 1;
749 432 : dbh->max_escaped_char_length = 2;
750 432 : dbh->methods = &mysql_methods;
751 :
752 432 : ret = 1;
753 :
754 442 : cleanup:
755 2652 : for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
756 2210 : if (vars[i].freeme) {
757 876 : efree(vars[i].optval);
758 : }
759 : }
760 :
761 442 : dbh->methods = &mysql_methods;
762 :
763 442 : PDO_DBG_RETURN(ret);
764 : }
765 : /* }}} */
766 :
767 : pdo_driver_t pdo_mysql_driver = {
768 : PDO_DRIVER_HEADER(mysql),
769 : pdo_mysql_handle_factory
770 : };
771 :
772 : /*
773 : * Local variables:
774 : * tab-width: 4
775 : * c-basic-offset: 4
776 : * End:
777 : * vim600: noet sw=4 ts=4 fdm=marker
778 : * vim<600: noet sw=4 ts=4
779 : */
|