Back to index

php5  5.3.10
mysql_driver.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: George Schlossnagle <george@omniti.com>                      |
00016   |         Wez Furlong <wez@php.net>                                    |
00017   |         Johannes Schlueter <johannes@mysql.com>                      |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: mysql_driver.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include "php.h"
00028 #include "php_ini.h"
00029 #include "ext/standard/info.h"
00030 #include "pdo/php_pdo.h"
00031 #include "pdo/php_pdo_driver.h"
00032 #include "php_pdo_mysql.h"
00033 #include "php_pdo_mysql_int.h"
00034 #ifndef PDO_USE_MYSQLND
00035 #include <mysqld_error.h>
00036 #endif
00037 #include "zend_exceptions.h"
00038 
00039 #if PDO_USE_MYSQLND
00040 #      define pdo_mysql_init(persistent) mysqlnd_init(persistent)
00041 #else
00042 #      define pdo_mysql_init(persistent) mysql_init(NULL)
00043 #endif
00044 
00045 #if !defined(HAVE_MYSQL_SQLSTATE) && !defined(PDO_USE_MYSQLND)
00046 static const char *pdo_mysql_get_sqlstate(unsigned int my_errno) { /* {{{ */
00047        switch (my_errno) {
00048               /* import auto-generated case: code */
00049 #include "php_pdo_mysql_sqlstate.h"
00050        default: return "HY000";
00051        }
00052 }
00053 /* }}} */
00054 #endif
00055 
00056 /* {{{ _pdo_mysql_error */
00057 int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC)
00058 {
00059        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00060        pdo_error_type *pdo_err; 
00061        pdo_mysql_error_info *einfo;
00062        pdo_mysql_stmt *S = NULL;
00063 
00064        PDO_DBG_ENTER("_pdo_mysql_error");
00065        PDO_DBG_INF_FMT("file=%s line=%d", file, line);
00066        if (stmt) {
00067               S = (pdo_mysql_stmt*)stmt->driver_data;
00068               pdo_err = &stmt->error_code;
00069               einfo   = &S->einfo;
00070        } else {
00071               pdo_err = &dbh->error_code;
00072               einfo   = &H->einfo;
00073        }
00074 
00075 #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
00076        if (S && S->stmt) {
00077               einfo->errcode = mysql_stmt_errno(S->stmt);
00078        }
00079        else
00080 #endif
00081        {
00082               einfo->errcode = mysql_errno(H->server);
00083        }
00084 
00085        einfo->file = file;
00086        einfo->line = line;
00087 
00088        if (einfo->errmsg) {
00089               pefree(einfo->errmsg, dbh->is_persistent);
00090               einfo->errmsg = NULL;
00091        }
00092 
00093        if (einfo->errcode) {
00094               if (einfo->errcode == 2014) {
00095                      einfo->errmsg = pestrdup(
00096                             "Cannot execute queries while other unbuffered queries are active.  "
00097                             "Consider using PDOStatement::fetchAll().  Alternatively, if your code "
00098                             "is only ever going to run against mysql, you may enable query "
00099                             "buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.",
00100                             dbh->is_persistent);
00101               } else if (einfo->errcode == 2057) {
00102                      einfo->errmsg = pestrdup(
00103                             "A stored procedure returning result sets of different size was called. "
00104                             "This is not supported by libmysql",
00105                             dbh->is_persistent);
00106 
00107               } else {
00108                      einfo->errmsg = pestrdup(mysql_error(H->server), dbh->is_persistent);
00109               }
00110        } else { /* no error */
00111               strcpy(*pdo_err, PDO_ERR_NONE);
00112               PDO_DBG_RETURN(0);
00113        }
00114 
00115 #if defined(HAVE_MYSQL_SQLSTATE) || defined(PDO_USE_MYSQLND)
00116 # if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
00117        if (S && S->stmt) {
00118               strcpy(*pdo_err, mysql_stmt_sqlstate(S->stmt));
00119        } else
00120 # endif
00121        {
00122               strcpy(*pdo_err, mysql_sqlstate(H->server));
00123        }
00124 #else
00125        strcpy(*pdo_err, pdo_mysql_get_sqlstate(einfo->errcode));
00126 #endif
00127 
00128        if (!dbh->methods) {
00129               PDO_DBG_INF("Throwing exception");
00130               zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
00131                             *pdo_err, einfo->errcode, einfo->errmsg);
00132        }
00133 
00134        PDO_DBG_RETURN(einfo->errcode);
00135 }
00136 /* }}} */
00137 
00138 /* {{{ pdo_mysql_fetch_error_func */
00139 static int pdo_mysql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
00140 {
00141        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00142        pdo_mysql_error_info *einfo = &H->einfo;
00143 
00144        PDO_DBG_ENTER("pdo_mysql_fetch_error_func");
00145        PDO_DBG_INF_FMT("dbh=%p stmt=%p", dbh, stmt);
00146        if (stmt) {
00147               pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
00148               einfo = &S->einfo;
00149        } else {
00150               einfo = &H->einfo;
00151        }
00152 
00153        if (einfo->errcode) {
00154               add_next_index_long(info, einfo->errcode);
00155               add_next_index_string(info, einfo->errmsg, 1);
00156        }
00157 
00158        PDO_DBG_RETURN(1);
00159 }
00160 /* }}} */
00161 
00162 /* {{{ mysql_handle_closer */
00163 static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
00164 {
00165        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00166        
00167        PDO_DBG_ENTER("mysql_handle_closer");
00168        PDO_DBG_INF_FMT("dbh=%p", dbh);
00169        if (H) {
00170               if (H->server) {
00171                      mysql_close(H->server);
00172                      H->server = NULL;
00173               }
00174               if (H->einfo.errmsg) {
00175                      pefree(H->einfo.errmsg, dbh->is_persistent);
00176                      H->einfo.errmsg = NULL;
00177               }
00178               pefree(H, dbh->is_persistent);
00179               dbh->driver_data = NULL;
00180        }
00181        PDO_DBG_RETURN(0);
00182 }
00183 /* }}} */
00184 
00185 /* {{{ mysql_handle_preparer */
00186 static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
00187 {
00188        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00189        pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
00190 #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
00191        char *nsql = NULL;
00192        int nsql_len = 0;
00193        int ret;
00194        int server_version;
00195 #endif
00196        
00197        PDO_DBG_ENTER("mysql_handle_preparer");
00198        PDO_DBG_INF_FMT("dbh=%p", dbh);
00199        PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
00200 
00201        S->H = H;
00202        stmt->driver_data = S;
00203        stmt->methods = &mysql_stmt_methods;
00204 
00205        if (H->emulate_prepare) {
00206               goto end;
00207        }
00208 
00209 #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
00210        server_version = mysql_get_server_version(H->server);
00211        if (server_version < 40100) {
00212               goto fallback;
00213        }
00214        stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
00215        ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
00216 
00217        if (ret == 1) {
00218               /* query was rewritten */
00219               sql = nsql;
00220               sql_len = nsql_len;
00221        } else if (ret == -1) {
00222               /* failed to parse */
00223               strcpy(dbh->error_code, stmt->error_code);
00224               PDO_DBG_RETURN(0);
00225        }
00226 
00227        if (!(S->stmt = mysql_stmt_init(H->server))) {
00228               pdo_mysql_error(dbh);
00229               if (nsql) {
00230                      efree(nsql);
00231               }
00232               PDO_DBG_RETURN(0);
00233        }
00234        
00235        if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
00236               /* TODO: might need to pull statement specific info here? */
00237               /* if the query isn't supported by the protocol, fallback to emulation */
00238               if (mysql_errno(H->server) == 1295) {
00239                      if (nsql) {
00240                             efree(nsql);
00241                      }
00242                      goto fallback;
00243               }
00244               pdo_mysql_error(dbh);
00245               if (nsql) {
00246                      efree(nsql);
00247               }
00248               PDO_DBG_RETURN(0);
00249        }
00250        if (nsql) {
00251               efree(nsql);
00252        }
00253 
00254        S->num_params = mysql_stmt_param_count(S->stmt);
00255 
00256        if (S->num_params) {
00257               S->params_given = 0;
00258 #ifdef PDO_USE_MYSQLND
00259               S->params = NULL;
00260 #else
00261               S->params = ecalloc(S->num_params, sizeof(MYSQL_BIND));
00262               S->in_null = ecalloc(S->num_params, sizeof(my_bool));
00263               S->in_length = ecalloc(S->num_params, sizeof(unsigned long));
00264 #endif
00265        }
00266        dbh->alloc_own_columns = 1;
00267 
00268        S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
00269 
00270        PDO_DBG_RETURN(1);
00271 
00272 fallback:
00273 #endif
00274 end:
00275        stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
00276        
00277        PDO_DBG_RETURN(1);
00278 }
00279 /* }}} */
00280 
00281 /* {{{ mysql_handle_doer */
00282 static long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
00283 {
00284        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00285        PDO_DBG_ENTER("mysql_handle_doer");
00286        PDO_DBG_INF_FMT("dbh=%p", dbh);
00287        PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
00288 
00289        if (mysql_real_query(H->server, sql, sql_len)) {
00290               pdo_mysql_error(dbh);
00291               PDO_DBG_RETURN(-1);
00292        } else {
00293               my_ulonglong c = mysql_affected_rows(H->server);
00294               if (c == (my_ulonglong) -1) {
00295                      pdo_mysql_error(dbh);
00296                      PDO_DBG_RETURN(H->einfo.errcode ? -1 : 0);
00297               } else {
00298 
00299 #if defined(HAVE_MYSQL_NEXT_RESULT) || defined(PDO_USE_MYSQLND)
00300                      /* MULTI_QUERY support - eat up all unfetched result sets */
00301                      MYSQL_RES* result;
00302                      while (mysql_more_results(H->server)) {
00303                             if (mysql_next_result(H->server)) {
00304                                    PDO_DBG_RETURN(1);
00305                             }
00306                             result = mysql_store_result(H->server);
00307                             if (result) {
00308                                    mysql_free_result(result);
00309                             }
00310                      }
00311 #endif
00312                      PDO_DBG_RETURN((int)c);
00313               }
00314        }
00315 }
00316 /* }}} */
00317 
00318 /* {{{ pdo_mysql_last_insert_id */
00319 static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
00320 {
00321        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00322        char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
00323        PDO_DBG_ENTER("pdo_mysql_last_insert_id");
00324        *len = strlen(id);
00325        PDO_DBG_RETURN(id);
00326 }
00327 /* }}} */ 
00328 
00329 /* {{{ mysql_handle_quoter */
00330 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)
00331 {
00332        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00333        PDO_DBG_ENTER("mysql_handle_quoter");
00334        PDO_DBG_INF_FMT("dbh=%p", dbh);
00335        PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted);
00336        *quoted = safe_emalloc(2, unquotedlen, 3);
00337        *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
00338        (*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
00339        (*quoted)[++*quotedlen] = '\0';
00340        PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted);
00341        PDO_DBG_RETURN(1);
00342 }
00343 /* }}} */
00344 
00345 /* {{{ mysql_handle_begin */
00346 static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
00347 {
00348        PDO_DBG_ENTER("mysql_handle_quoter");
00349        PDO_DBG_INF_FMT("dbh=%p", dbh);
00350        PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC));
00351 }
00352 /* }}} */
00353 
00354 /* {{{ mysql_handle_commit */
00355 static int mysql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
00356 {
00357        PDO_DBG_ENTER("mysql_handle_commit");
00358        PDO_DBG_INF_FMT("dbh=%p", dbh);
00359 #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
00360        PDO_DBG_RETURN(0 <= mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server));
00361 #else
00362        PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC));
00363 #endif
00364 }
00365 /* }}} */
00366 
00367 /* {{{ mysql_handle_rollback */
00368 static int mysql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
00369 {
00370        PDO_DBG_ENTER("mysql_handle_rollback");
00371        PDO_DBG_INF_FMT("dbh=%p", dbh);
00372 #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
00373        PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server));
00374 #else
00375        PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC));
00376 #endif
00377 }
00378 /* }}} */
00379 
00380 /* {{{ mysql_handle_autocommit */
00381 static inline int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
00382 {
00383        PDO_DBG_ENTER("mysql_handle_autocommit");
00384        PDO_DBG_INF_FMT("dbh=%p", dbh);
00385        PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit);
00386 #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
00387        PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit));
00388 #else
00389        if (dbh->auto_commit) {
00390               PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC));
00391        } else {
00392               PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC));
00393        }
00394 #endif
00395 }
00396 /* }}} */
00397 
00398 /* {{{ pdo_mysql_set_attribute */
00399 static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
00400 {
00401        PDO_DBG_ENTER("pdo_mysql_set_attribute");
00402        PDO_DBG_INF_FMT("dbh=%p", dbh);
00403        PDO_DBG_INF_FMT("attr=%l", attr);
00404        switch (attr) {
00405               case PDO_ATTR_AUTOCOMMIT:          
00406                      convert_to_boolean(val);
00407        
00408                      /* ignore if the new value equals the old one */               
00409                      if (dbh->auto_commit ^ Z_BVAL_P(val)) {
00410                             dbh->auto_commit = Z_BVAL_P(val);
00411                             mysql_handle_autocommit(dbh TSRMLS_CC);
00412                      }
00413                      PDO_DBG_RETURN(1);
00414 
00415               case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
00416                      ((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
00417                      PDO_DBG_RETURN(1);
00418               case PDO_MYSQL_ATTR_DIRECT_QUERY:
00419               case PDO_ATTR_EMULATE_PREPARES:
00420                      ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
00421                      PDO_DBG_RETURN(1);
00422               case PDO_ATTR_FETCH_TABLE_NAMES:
00423                      ((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = Z_BVAL_P(val);
00424                      PDO_DBG_RETURN(1);
00425 #ifndef PDO_USE_MYSQLND
00426               case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
00427                      if (Z_LVAL_P(val) < 0) {
00428                             /* TODO: Johannes, can we throw a warning here? */
00429                             ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = 1024*1024;
00430                             PDO_DBG_INF_FMT("Adjusting invalid buffer size to =%l", ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size);
00431                      } else {
00432                             ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = Z_LVAL_P(val);
00433                      }
00434                      PDO_DBG_RETURN(1);
00435                      break;
00436 #endif
00437 
00438               default:
00439                      PDO_DBG_RETURN(0);
00440        }
00441 }
00442 /* }}} */
00443 
00444 /* {{{ pdo_mysql_get_attribute */
00445 static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
00446 {
00447        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00448 
00449        PDO_DBG_ENTER("pdo_mysql_get_attribute");
00450        PDO_DBG_INF_FMT("dbh=%p", dbh);
00451        PDO_DBG_INF_FMT("attr=%l", attr);
00452        switch (attr) {
00453               case PDO_ATTR_CLIENT_VERSION:
00454                      ZVAL_STRING(return_value, (char *)mysql_get_client_info(), 1);
00455                      break;
00456 
00457               case PDO_ATTR_SERVER_VERSION:
00458                      ZVAL_STRING(return_value, (char *)mysql_get_server_info(H->server), 1);
00459                      break;
00460 
00461               case PDO_ATTR_CONNECTION_STATUS:
00462                      ZVAL_STRING(return_value, (char *)mysql_get_host_info(H->server), 1);
00463                      break;
00464               case PDO_ATTR_SERVER_INFO: {
00465                      char *tmp;
00466 #ifdef PDO_USE_MYSQLND
00467                      unsigned int tmp_len;
00468 
00469                      if (mysqlnd_stat(H->server, &tmp, &tmp_len) == PASS) {
00470                             ZVAL_STRINGL(return_value, tmp, tmp_len, 0);
00471 #else
00472                      if ((tmp = (char *)mysql_stat(H->server))) {
00473                             ZVAL_STRING(return_value, tmp, 1);
00474 #endif
00475                      } else {
00476                             pdo_mysql_error(dbh);
00477                             PDO_DBG_RETURN(-1);
00478                      }
00479               }
00480                      break;
00481               case PDO_ATTR_AUTOCOMMIT:
00482                      ZVAL_LONG(return_value, dbh->auto_commit);
00483                      break;
00484                      
00485               case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
00486                      ZVAL_LONG(return_value, H->buffered);
00487                      break;
00488 
00489               case PDO_MYSQL_ATTR_DIRECT_QUERY:
00490                      ZVAL_LONG(return_value, H->emulate_prepare);
00491                      break;
00492 
00493 #ifndef PDO_USE_MYSQLND
00494               case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
00495                      ZVAL_LONG(return_value, H->max_buffer_size);
00496                      break;
00497 #endif
00498 
00499               default:
00500                      PDO_DBG_RETURN(0);   
00501        }
00502 
00503        PDO_DBG_RETURN(1);
00504 }
00505 /* }}} */
00506 
00507 /* {{{ pdo_mysql_check_liveness */
00508 static int pdo_mysql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC)
00509 {
00510        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
00511 #if MYSQL_VERSION_ID <= 32230
00512        void (*handler) (int);
00513        unsigned int my_errno;
00514 #endif
00515 
00516        PDO_DBG_ENTER("pdo_mysql_check_liveness");
00517        PDO_DBG_INF_FMT("dbh=%p", dbh);
00518 
00519 #if MYSQL_VERSION_ID > 32230
00520        if (mysql_ping(H->server)) {
00521               PDO_DBG_RETURN(FAILURE);
00522        }
00523 #else /* no mysql_ping() */
00524        handler = signal(SIGPIPE, SIG_IGN);
00525        mysql_stat(H->server);
00526        switch (mysql_errno(H->server)) {
00527               case CR_SERVER_GONE_ERROR:
00528               case CR_SERVER_LOST:
00529                      signal(SIGPIPE, handler);
00530                      PDO_DBG_RETURN(FAILURE);
00531               default:
00532                      break;
00533        }
00534        signal(SIGPIPE, handler);
00535 #endif /* end mysql_ping() */
00536        PDO_DBG_RETURN(SUCCESS);
00537 } 
00538 /* }}} */
00539 
00540 /* {{{ mysql_methods */
00541 static struct pdo_dbh_methods mysql_methods = {
00542        mysql_handle_closer,
00543        mysql_handle_preparer,
00544        mysql_handle_doer,
00545        mysql_handle_quoter,
00546        mysql_handle_begin,
00547        mysql_handle_commit,
00548        mysql_handle_rollback,
00549        pdo_mysql_set_attribute,
00550        pdo_mysql_last_insert_id,
00551        pdo_mysql_fetch_error_func,
00552        pdo_mysql_get_attribute,
00553        pdo_mysql_check_liveness
00554 };
00555 /* }}} */
00556 
00557 #ifdef PHP_WIN32
00558 # define MYSQL_UNIX_ADDR    NULL
00559 #else
00560 # define MYSQL_UNIX_ADDR    PDO_MYSQL_G(default_socket)
00561 #endif
00562 
00563 /* {{{ pdo_mysql_handle_factory */
00564 static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
00565 {
00566        pdo_mysql_db_handle *H;
00567        int i, ret = 0;
00568        char *host = NULL, *unix_socket = NULL;
00569        unsigned int port = 3306;
00570        char *dbname;
00571        struct pdo_data_src_parser vars[] = {
00572               { "charset",  NULL,  0 },
00573               { "dbname",   "",    0 },
00574               { "host",   "localhost",    0 },
00575               { "port",   "3306",  0 },
00576               { "unix_socket",  MYSQL_UNIX_ADDR, 0 },
00577        };
00578        int connect_opts = 0
00579 #ifdef CLIENT_MULTI_RESULTS
00580               |CLIENT_MULTI_RESULTS
00581 #endif
00582 #ifdef CLIENT_MULTI_STATEMENTS
00583               |CLIENT_MULTI_STATEMENTS
00584 #endif
00585               ;
00586 
00587 #ifdef PDO_USE_MYSQLND
00588        int dbname_len = 0;
00589        int password_len = 0;
00590 #endif
00591        PDO_DBG_ENTER("pdo_mysql_handle_factory");
00592        PDO_DBG_INF_FMT("dbh=%p", dbh);
00593 #ifdef CLIENT_MULTI_RESULTS
00594        PDO_DBG_INF("multi results");
00595 #endif
00596 
00597        php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
00598 
00599        H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
00600 
00601        H->einfo.errcode = 0;
00602        H->einfo.errmsg = NULL;
00603 
00604        /* allocate an environment */
00605 
00606        /* handle for the server */
00607        if (!(H->server = pdo_mysql_init(dbh->is_persistent))) {
00608               pdo_mysql_error(dbh);
00609               goto cleanup;
00610        }
00611        
00612        dbh->driver_data = H;
00613 
00614 #ifndef PDO_USE_MYSQLND
00615        H->max_buffer_size = 1024*1024;
00616 #endif
00617 
00618        H->buffered = H->emulate_prepare = 1;
00619 
00620        /* handle MySQL options */
00621        if (driver_options) {
00622               long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
00623               long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
00624               char *init_cmd = NULL;
00625 #ifndef PDO_USE_MYSQLND
00626               char *default_file = NULL, *default_group = NULL;
00627               long compress = 0;
00628 #endif
00629 #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
00630               char *ssl_key = NULL, *ssl_cert = NULL, *ssl_ca = NULL, *ssl_capath = NULL, *ssl_cipher = NULL;
00631 #endif
00632               H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1 TSRMLS_CC);
00633 
00634               H->emulate_prepare = pdo_attr_lval(driver_options,
00635                      PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
00636               H->emulate_prepare = pdo_attr_lval(driver_options, 
00637                      PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
00638 
00639 #ifndef PDO_USE_MYSQLND
00640               H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
00641 #endif
00642 
00643               if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_FOUND_ROWS, 0 TSRMLS_CC)) {
00644                      connect_opts |= CLIENT_FOUND_ROWS;
00645               }
00646 
00647               if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_IGNORE_SPACE, 0 TSRMLS_CC)) {
00648                      connect_opts |= CLIENT_IGNORE_SPACE;
00649               }
00650 
00651               if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
00652                      pdo_mysql_error(dbh);
00653                      goto cleanup;
00654               }
00655 
00656 #if PHP_API_VERSION < 20100412
00657               if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode))
00658 #else
00659               if (PG(open_basedir) && PG(open_basedir)[0] != '\0') 
00660 #endif
00661               {
00662                      local_infile = 0;
00663               }
00664 #if defined(MYSQL_OPT_LOCAL_INFILE) || defined(PDO_USE_MYSQLND)
00665               if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
00666                      pdo_mysql_error(dbh);
00667                      goto cleanup;
00668               }
00669 #endif
00670 #ifdef MYSQL_OPT_RECONNECT
00671               /* since 5.0.3, the default for this option is 0 if not specified.
00672                * we want the old behaviour
00673                * mysqlnd doesn't support reconnect, thus we don't have "|| defined(PDO_USE_MYSQLND)"
00674               */
00675               {
00676                      long reconnect = 1;
00677                      mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
00678               }
00679 #endif
00680               init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
00681               if (init_cmd) {
00682                      if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
00683                             efree(init_cmd);
00684                             pdo_mysql_error(dbh);
00685                             goto cleanup;
00686                      }
00687                      efree(init_cmd);
00688               }
00689 #ifndef PDO_USE_MYSQLND            
00690               default_file = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_FILE, NULL TSRMLS_CC);
00691               if (default_file) {
00692                      if (mysql_options(H->server, MYSQL_READ_DEFAULT_FILE, (const char *)default_file)) {
00693                             efree(default_file);
00694                             pdo_mysql_error(dbh);
00695                             goto cleanup;
00696                      }
00697                      efree(default_file);
00698               }
00699               
00700               default_group= pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP, NULL TSRMLS_CC);
00701               if (default_group) {
00702                      if (mysql_options(H->server, MYSQL_READ_DEFAULT_GROUP, (const char *)default_group)) {
00703                             efree(default_group);
00704                             pdo_mysql_error(dbh);
00705                             goto cleanup;
00706                      }
00707                      efree(default_group);
00708               }
00709 
00710               compress = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_COMPRESS, 0 TSRMLS_CC);
00711               if (compress) {
00712                      if (mysql_options(H->server, MYSQL_OPT_COMPRESS, 0)) {
00713                             pdo_mysql_error(dbh);
00714                             goto cleanup;
00715                      }
00716               }
00717 #endif
00718 #if defined(HAVE_MYSQL_STMT_PREPARE) || defined(PDO_USE_MYSQLND)
00719               ssl_key = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_KEY, NULL TSRMLS_CC);
00720               ssl_cert = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CERT, NULL TSRMLS_CC);
00721               ssl_ca = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CA, NULL TSRMLS_CC);
00722               ssl_capath = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CAPATH, NULL TSRMLS_CC);
00723               ssl_cipher = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CIPHER, NULL TSRMLS_CC);
00724               
00725               if (ssl_key || ssl_cert || ssl_ca || ssl_capath || ssl_cipher) {
00726                      mysql_ssl_set(H->server, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher);
00727                      if (ssl_key) {
00728                             efree(ssl_key);
00729                      }
00730                      if (ssl_cert) {
00731                             efree(ssl_cert);
00732                      }
00733                      if (ssl_ca) {
00734                             efree(ssl_ca);
00735                      }
00736                      if (ssl_capath) {
00737                             efree(ssl_capath);
00738                      }
00739                      if (ssl_cipher) {
00740                             efree(ssl_cipher);
00741                      }
00742               }
00743 #endif
00744        }
00745 
00746 #ifdef PDO_MYSQL_HAS_CHARSET
00747        if (vars[0].optval && mysql_options(H->server, MYSQL_SET_CHARSET_NAME, vars[0].optval)) {
00748               pdo_mysql_error(dbh);
00749               goto cleanup;
00750        }
00751 #endif
00752 
00753        dbname = vars[1].optval;
00754        host = vars[2].optval;      
00755        if(vars[3].optval) {
00756               port = atoi(vars[3].optval);
00757        }
00758        if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
00759               unix_socket = vars[4].optval;  
00760        }
00761 
00762        /* TODO: - Check zval cache + ZTS */
00763 #ifdef PDO_USE_MYSQLND
00764        if (dbname) {
00765               dbname_len = strlen(dbname);
00766        }
00767 
00768        if (dbh->password) {
00769               password_len = strlen(dbh->password);
00770        }
00771 
00772        if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
00773                                           port, unix_socket, connect_opts TSRMLS_CC) == NULL) {
00774 #else
00775        if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
00776 #endif
00777               pdo_mysql_error(dbh);
00778               goto cleanup;
00779        }
00780 
00781        if (!dbh->auto_commit) {
00782               mysql_handle_autocommit(dbh TSRMLS_CC);
00783        }
00784 
00785        H->attached = 1;
00786 
00787        dbh->alloc_own_columns = 1;
00788        dbh->max_escaped_char_length = 2;
00789        dbh->methods = &mysql_methods;
00790 
00791        ret = 1;
00792        
00793 cleanup:
00794        for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
00795               if (vars[i].freeme) {
00796                      efree(vars[i].optval);
00797               }
00798        }
00799        
00800        dbh->methods = &mysql_methods;
00801 
00802        PDO_DBG_RETURN(ret);
00803 }
00804 /* }}} */
00805 
00806 pdo_driver_t pdo_mysql_driver = {
00807        PDO_DRIVER_HEADER(mysql),
00808        pdo_mysql_handle_factory
00809 };
00810 
00811 /*
00812  * Local variables:
00813  * tab-width: 4
00814  * c-basic-offset: 4
00815  * End:
00816  * vim600: noet sw=4 ts=4 fdm=marker
00817  * vim<600: noet sw=4 ts=4
00818  */