root/ext/pdo_mysql/mysql_driver.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _pdo_mysql_error
  2. pdo_mysql_fetch_error_func
  3. mysql_handle_closer
  4. mysql_handle_preparer
  5. mysql_handle_doer
  6. pdo_mysql_last_insert_id
  7. mysql_handle_quoter
  8. mysql_handle_begin
  9. mysql_handle_commit
  10. mysql_handle_rollback
  11. mysql_handle_autocommit
  12. pdo_mysql_set_attribute
  13. pdo_mysql_get_attribute
  14. pdo_mysql_check_liveness
  15. pdo_mysql_handle_factory

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

/* [<][>][^][v][top][bottom][index][help] */