File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / pdo_mysql / mysql_driver.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 08:02:28 2013 UTC (10 years, 9 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_20p0, v5_4_20, HEAD
v 5.4.20

    1: /*
    2:   +----------------------------------------------------------------------+
    3:   | PHP Version 5                                                        |
    4:   +----------------------------------------------------------------------+
    5:   | Copyright (c) 1997-2013 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,v 1.1.1.4 2013/10/14 08:02:28 misho Exp $ */
   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(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 TSRMLS_DC)
   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 TSRMLS_CC, "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 TSRMLS_DC)
  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, 1);
  134: 	}
  135: 
  136: 	PDO_DBG_RETURN(1);
  137: }
  138: /* }}} */
  139: 
  140: /* {{{ mysql_handle_closer */
  141: static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
  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: 			H->server = NULL;
  151: 		}
  152: 		if (H->einfo.errmsg) {
  153: 			pefree(H->einfo.errmsg, dbh->is_persistent);
  154: 			H->einfo.errmsg = NULL;
  155: 		}
  156: 		pefree(H, dbh->is_persistent);
  157: 		dbh->driver_data = NULL;
  158: 	}
  159: 	PDO_DBG_RETURN(0);
  160: }
  161: /* }}} */
  162: 
  163: /* {{{ mysql_handle_preparer */
  164: static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
  165: {
  166: 	pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
  167: 	pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
  168: 	char *nsql = NULL;
  169: 	int nsql_len = 0;
  170: 	int ret;
  171: 	int server_version;
  172: 	
  173: 	PDO_DBG_ENTER("mysql_handle_preparer");
  174: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  175: 	PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
  176: 
  177: 	S->H = H;
  178: 	stmt->driver_data = S;
  179: 	stmt->methods = &mysql_stmt_methods;
  180: 
  181: 	if (H->emulate_prepare) {
  182: 		goto end;
  183: 	}
  184: 
  185: 	server_version = mysql_get_server_version(H->server);
  186: 	if (server_version < 40100) {
  187: 		goto fallback;
  188: 	}
  189: 	stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
  190: 	ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
  191: 
  192: 	if (ret == 1) {
  193: 		/* query was rewritten */
  194: 		sql = nsql;
  195: 		sql_len = nsql_len;
  196: 	} else if (ret == -1) {
  197: 		/* failed to parse */
  198: 		strcpy(dbh->error_code, stmt->error_code);
  199: 		PDO_DBG_RETURN(0);
  200: 	}
  201: 
  202: 	if (!(S->stmt = mysql_stmt_init(H->server))) {
  203: 		pdo_mysql_error(dbh);
  204: 		if (nsql) {
  205: 			efree(nsql);
  206: 		}
  207: 		PDO_DBG_RETURN(0);
  208: 	}
  209: 	
  210: 	if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
  211: 		/* TODO: might need to pull statement specific info here? */
  212: 		/* if the query isn't supported by the protocol, fallback to emulation */
  213: 		if (mysql_errno(H->server) == 1295) {
  214: 			if (nsql) {
  215: 				efree(nsql);
  216: 			}
  217: 			goto fallback;
  218: 		}
  219: 		pdo_mysql_error(dbh);
  220: 		if (nsql) {
  221: 			efree(nsql);
  222: 		}
  223: 		PDO_DBG_RETURN(0);
  224: 	}
  225: 	if (nsql) {
  226: 		efree(nsql);
  227: 	}
  228: 
  229: 	S->num_params = mysql_stmt_param_count(S->stmt);
  230: 
  231: 	if (S->num_params) {
  232: 		S->params_given = 0;
  233: #if defined(PDO_USE_MYSQLND)
  234: 		S->params = NULL;
  235: #else
  236: 		S->params = ecalloc(S->num_params, sizeof(MYSQL_BIND));
  237: 		S->in_null = ecalloc(S->num_params, sizeof(my_bool));
  238: 		S->in_length = ecalloc(S->num_params, sizeof(unsigned long));
  239: #endif
  240: 	}
  241: 	dbh->alloc_own_columns = 1;
  242: 
  243: 	S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
  244: 
  245: 	PDO_DBG_RETURN(1);
  246: 
  247: fallback:
  248: end:
  249: 	stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
  250: 	
  251: 	PDO_DBG_RETURN(1);
  252: }
  253: /* }}} */
  254: 
  255: /* {{{ mysql_handle_doer */
  256: static long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
  257: {
  258: 	pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
  259: 	PDO_DBG_ENTER("mysql_handle_doer");
  260: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  261: 	PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
  262: 
  263: 	if (mysql_real_query(H->server, sql, sql_len)) {
  264: 		pdo_mysql_error(dbh);
  265: 		PDO_DBG_RETURN(-1);
  266: 	} else {
  267: 		my_ulonglong c = mysql_affected_rows(H->server);
  268: 		if (c == (my_ulonglong) -1) {
  269: 			pdo_mysql_error(dbh);
  270: 			PDO_DBG_RETURN(H->einfo.errcode ? -1 : 0);
  271: 		} else {
  272: 
  273: 			/* MULTI_QUERY support - eat up all unfetched result sets */
  274: 			MYSQL_RES* result;
  275: 			while (mysql_more_results(H->server)) {
  276: 				if (mysql_next_result(H->server)) {
  277: 					PDO_DBG_RETURN(1);
  278: 				}
  279: 				result = mysql_store_result(H->server);
  280: 				if (result) {
  281: 					mysql_free_result(result);
  282: 				}
  283: 			}
  284: 			PDO_DBG_RETURN((int)c);
  285: 		}
  286: 	}
  287: }
  288: /* }}} */
  289: 
  290: /* {{{ pdo_mysql_last_insert_id */
  291: static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
  292: {
  293: 	pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
  294: 	char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
  295: 	PDO_DBG_ENTER("pdo_mysql_last_insert_id");
  296: 	*len = strlen(id);
  297: 	PDO_DBG_RETURN(id);
  298: }
  299: /* }}} */
  300: 
  301: /* {{{ mysql_handle_quoter */
  302: 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)
  303: {
  304: 	pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
  305: 	PDO_DBG_ENTER("mysql_handle_quoter");
  306: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  307: 	PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted);
  308: 	*quoted = safe_emalloc(2, unquotedlen, 3);
  309: 	*quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
  310: 	(*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
  311: 	(*quoted)[++*quotedlen] = '\0';
  312: 	PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted);
  313: 	PDO_DBG_RETURN(1);
  314: }
  315: /* }}} */
  316: 
  317: /* {{{ mysql_handle_begin */
  318: static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
  319: {
  320: 	PDO_DBG_ENTER("mysql_handle_quoter");
  321: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  322: 	PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC));
  323: }
  324: /* }}} */
  325: 
  326: /* {{{ mysql_handle_commit */
  327: static int mysql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
  328: {
  329: 	PDO_DBG_ENTER("mysql_handle_commit");
  330: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  331: #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
  332: 	PDO_DBG_RETURN(0 <= mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server));
  333: #else
  334: 	PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC));
  335: #endif
  336: }
  337: /* }}} */
  338: 
  339: /* {{{ mysql_handle_rollback */
  340: static int mysql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
  341: {
  342: 	PDO_DBG_ENTER("mysql_handle_rollback");
  343: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  344: #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
  345: 	PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server));
  346: #else
  347: 	PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC));
  348: #endif
  349: }
  350: /* }}} */
  351: 
  352: /* {{{ mysql_handle_autocommit */
  353: static inline int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
  354: {
  355: 	PDO_DBG_ENTER("mysql_handle_autocommit");
  356: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  357: 	PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit);
  358: #if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
  359: 	PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit));
  360: #else
  361: 	if (dbh->auto_commit) {
  362: 		PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC));
  363: 	} else {
  364: 		PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC));
  365: 	}
  366: #endif
  367: }
  368: /* }}} */
  369: 
  370: /* {{{ pdo_mysql_set_attribute */
  371: static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
  372: {
  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: 			convert_to_boolean(val);
  379: 	
  380: 			/* ignore if the new value equals the old one */			
  381: 			if (dbh->auto_commit ^ Z_BVAL_P(val)) {
  382: 				dbh->auto_commit = Z_BVAL_P(val);
  383: 				mysql_handle_autocommit(dbh TSRMLS_CC);
  384: 			}
  385: 			PDO_DBG_RETURN(1);
  386: 
  387: 		case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
  388: 			((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
  389: 			PDO_DBG_RETURN(1);
  390: 		case PDO_MYSQL_ATTR_DIRECT_QUERY:
  391: 		case PDO_ATTR_EMULATE_PREPARES:
  392: 			((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
  393: 			PDO_DBG_RETURN(1);
  394: 		case PDO_ATTR_FETCH_TABLE_NAMES:
  395: 			((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = Z_BVAL_P(val);
  396: 			PDO_DBG_RETURN(1);
  397: #ifndef PDO_USE_MYSQLND
  398: 		case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
  399: 			if (Z_LVAL_P(val) < 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 = Z_LVAL_P(val);
  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, long attr, zval *return_value TSRMLS_DC)
  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(), 1);
  427: 			break;
  428: 
  429: 		case PDO_ATTR_SERVER_VERSION:
  430: 			ZVAL_STRING(return_value, (char *)mysql_get_server_info(H->server), 1);
  431: 			break;
  432: 
  433: 		case PDO_ATTR_CONNECTION_STATUS:
  434: 			ZVAL_STRING(return_value, (char *)mysql_get_host_info(H->server), 1);
  435: 			break;
  436: 		case PDO_ATTR_SERVER_INFO: {
  437: 			char *tmp;
  438: #if defined(PDO_USE_MYSQLND)
  439: 			unsigned int tmp_len;
  440: 
  441: 			if (mysqlnd_stat(H->server, &tmp, &tmp_len) == PASS) {
  442: 				ZVAL_STRINGL(return_value, tmp, tmp_len, 0);
  443: #else
  444: 			if ((tmp = (char *)mysql_stat(H->server))) {
  445: 				ZVAL_STRING(return_value, tmp, 1);
  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_MYSQL_ATTR_DIRECT_QUERY:
  462: 			ZVAL_LONG(return_value, H->emulate_prepare);
  463: 			break;
  464: 
  465: #ifndef PDO_USE_MYSQLND
  466: 		case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
  467: 			ZVAL_LONG(return_value, H->max_buffer_size);
  468: 			break;
  469: #endif
  470: 
  471: 		default:
  472: 			PDO_DBG_RETURN(0);	
  473: 	}
  474: 
  475: 	PDO_DBG_RETURN(1);
  476: }
  477: /* }}} */
  478: 
  479: /* {{{ pdo_mysql_check_liveness */
  480: static int pdo_mysql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC)
  481: {
  482: 	pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
  483: #if MYSQL_VERSION_ID <= 32230
  484: 	void (*handler) (int);
  485: 	unsigned int my_errno;
  486: #endif
  487: 
  488: 	PDO_DBG_ENTER("pdo_mysql_check_liveness");
  489: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  490: 
  491: #if MYSQL_VERSION_ID > 32230
  492: 	if (mysql_ping(H->server)) {
  493: 		PDO_DBG_RETURN(FAILURE);
  494: 	}
  495: #else /* no mysql_ping() */
  496: 	handler = signal(SIGPIPE, SIG_IGN);
  497: 	mysql_stat(H->server);
  498: 	switch (mysql_errno(H->server)) {
  499: 		case CR_SERVER_GONE_ERROR:
  500: 		case CR_SERVER_LOST:
  501: 			signal(SIGPIPE, handler);
  502: 			PDO_DBG_RETURN(FAILURE);
  503: 		default:
  504: 			break;
  505: 	}
  506: 	signal(SIGPIPE, handler);
  507: #endif /* end mysql_ping() */
  508: 	PDO_DBG_RETURN(SUCCESS);
  509: } 
  510: /* }}} */
  511: 
  512: /* {{{ mysql_methods */
  513: static struct pdo_dbh_methods mysql_methods = {
  514: 	mysql_handle_closer,
  515: 	mysql_handle_preparer,
  516: 	mysql_handle_doer,
  517: 	mysql_handle_quoter,
  518: 	mysql_handle_begin,
  519: 	mysql_handle_commit,
  520: 	mysql_handle_rollback,
  521: 	pdo_mysql_set_attribute,
  522: 	pdo_mysql_last_insert_id,
  523: 	pdo_mysql_fetch_error_func,
  524: 	pdo_mysql_get_attribute,
  525: 	pdo_mysql_check_liveness
  526: };
  527: /* }}} */
  528: 
  529: #ifdef PHP_WIN32
  530: # define PDO_DEFAULT_MYSQL_UNIX_ADDR	NULL
  531: #else
  532: # define PDO_DEFAULT_MYSQL_UNIX_ADDR	PDO_MYSQL_G(default_socket)
  533: #endif
  534: 
  535: /* {{{ pdo_mysql_handle_factory */
  536: static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
  537: {
  538: 	pdo_mysql_db_handle *H;
  539: 	int i, ret = 0;
  540: 	char *host = NULL, *unix_socket = NULL;
  541: 	unsigned int port = 3306;
  542: 	char *dbname;
  543: 	struct pdo_data_src_parser vars[] = {
  544: 		{ "charset",  NULL,	0 },
  545: 		{ "dbname",   "",	0 },
  546: 		{ "host",   "localhost",	0 },
  547: 		{ "port",   "3306",	0 },
  548: 		{ "unix_socket",  PDO_DEFAULT_MYSQL_UNIX_ADDR,	0 },
  549: 	};
  550: 	int connect_opts = 0
  551: #ifdef CLIENT_MULTI_RESULTS
  552: 		|CLIENT_MULTI_RESULTS
  553: #endif
  554: #ifdef CLIENT_MULTI_STATEMENTS
  555: 		|CLIENT_MULTI_STATEMENTS
  556: #endif
  557: 		;
  558: 
  559: #if defined(PDO_USE_MYSQLND)
  560: 	int dbname_len = 0;
  561: 	int password_len = 0;
  562: #endif
  563: 	PDO_DBG_ENTER("pdo_mysql_handle_factory");
  564: 	PDO_DBG_INF_FMT("dbh=%p", dbh);
  565: #ifdef CLIENT_MULTI_RESULTS
  566: 	PDO_DBG_INF("multi results");
  567: #endif
  568: 
  569: 	php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
  570: 
  571: 	H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
  572: 
  573: 	H->einfo.errcode = 0;
  574: 	H->einfo.errmsg = NULL;
  575: 
  576: 	/* allocate an environment */
  577: 
  578: 	/* handle for the server */
  579: 	if (!(H->server = pdo_mysql_init(dbh->is_persistent))) {
  580: 		pdo_mysql_error(dbh);
  581: 		goto cleanup;
  582: 	}
  583: 	
  584: 	dbh->driver_data = H;
  585: 
  586: #ifndef PDO_USE_MYSQLND
  587: 	H->max_buffer_size = 1024*1024;
  588: #endif
  589: 
  590: 	H->buffered = H->emulate_prepare = 1;
  591: 
  592: 	/* handle MySQL options */
  593: 	if (driver_options) {
  594: 		long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
  595: 		long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
  596: 		char *init_cmd = NULL;
  597: #ifndef PDO_USE_MYSQLND
  598: 		char *default_file = NULL, *default_group = NULL;
  599: #endif
  600: 		long compress = 0;
  601: 		char *ssl_key = NULL, *ssl_cert = NULL, *ssl_ca = NULL, *ssl_capath = NULL, *ssl_cipher = NULL;
  602: 		H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1 TSRMLS_CC);
  603: 
  604: 		H->emulate_prepare = pdo_attr_lval(driver_options,
  605: 			PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
  606: 		H->emulate_prepare = pdo_attr_lval(driver_options, 
  607: 			PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
  608: 
  609: #ifndef PDO_USE_MYSQLND
  610: 		H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
  611: #endif
  612: 
  613: 		if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_FOUND_ROWS, 0 TSRMLS_CC)) {
  614: 			connect_opts |= CLIENT_FOUND_ROWS;
  615: 		}
  616: 
  617: 		if (pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_IGNORE_SPACE, 0 TSRMLS_CC)) {
  618: 			connect_opts |= CLIENT_IGNORE_SPACE;
  619: 		}
  620: 
  621: 		if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
  622: 			pdo_mysql_error(dbh);
  623: 			goto cleanup;
  624: 		}
  625: 
  626: #if PHP_API_VERSION < 20100412
  627: 		if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode))
  628: #else
  629: 		if (PG(open_basedir) && PG(open_basedir)[0] != '\0') 
  630: #endif
  631: 		{
  632: 			local_infile = 0;
  633: 		}
  634: #if defined(MYSQL_OPT_LOCAL_INFILE) || defined(PDO_USE_MYSQLND)
  635: 		if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
  636: 			pdo_mysql_error(dbh);
  637: 			goto cleanup;
  638: 		}
  639: #endif
  640: #ifdef MYSQL_OPT_RECONNECT
  641: 		/* since 5.0.3, the default for this option is 0 if not specified.
  642: 		 * we want the old behaviour
  643: 		 * mysqlnd doesn't support reconnect, thus we don't have "|| defined(PDO_USE_MYSQLND)"
  644: 		*/
  645: 		{
  646: 			long reconnect = 1;
  647: 			mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
  648: 		}
  649: #endif
  650: 		init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
  651: 		if (init_cmd) {
  652: 			if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
  653: 				efree(init_cmd);
  654: 				pdo_mysql_error(dbh);
  655: 				goto cleanup;
  656: 			}
  657: 			efree(init_cmd);
  658: 		}
  659: #ifndef PDO_USE_MYSQLND		
  660: 		default_file = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_FILE, NULL TSRMLS_CC);
  661: 		if (default_file) {
  662: 			if (mysql_options(H->server, MYSQL_READ_DEFAULT_FILE, (const char *)default_file)) {
  663: 				efree(default_file);
  664: 				pdo_mysql_error(dbh);
  665: 				goto cleanup;
  666: 			}
  667: 			efree(default_file);
  668: 		}
  669: 		
  670: 		default_group= pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP, NULL TSRMLS_CC);
  671: 		if (default_group) {
  672: 			if (mysql_options(H->server, MYSQL_READ_DEFAULT_GROUP, (const char *)default_group)) {
  673: 				efree(default_group);
  674: 				pdo_mysql_error(dbh);
  675: 				goto cleanup;
  676: 			}
  677: 			efree(default_group);
  678: 		}
  679: #endif
  680: 		compress = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_COMPRESS, 0 TSRMLS_CC);
  681: 		if (compress) {
  682: 			if (mysql_options(H->server, MYSQL_OPT_COMPRESS, 0)) {
  683: 				pdo_mysql_error(dbh);
  684: 				goto cleanup;
  685: 			}
  686: 		}
  687: 
  688: 		ssl_key = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_KEY, NULL TSRMLS_CC);
  689: 		ssl_cert = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CERT, NULL TSRMLS_CC);
  690: 		ssl_ca = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CA, NULL TSRMLS_CC);
  691: 		ssl_capath = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CAPATH, NULL TSRMLS_CC);
  692: 		ssl_cipher = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SSL_CIPHER, NULL TSRMLS_CC);
  693: 		
  694: 		if (ssl_key || ssl_cert || ssl_ca || ssl_capath || ssl_cipher) {
  695: 			mysql_ssl_set(H->server, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher);
  696: 			if (ssl_key) {
  697: 				efree(ssl_key);
  698: 			}
  699: 			if (ssl_cert) {
  700: 				efree(ssl_cert);
  701: 			}
  702: 			if (ssl_ca) {
  703: 				efree(ssl_ca);
  704: 			}
  705: 			if (ssl_capath) {
  706: 				efree(ssl_capath);
  707: 			}
  708: 			if (ssl_cipher) {
  709: 				efree(ssl_cipher);
  710: 			}
  711: 		}
  712: 	}
  713: 
  714: #ifdef PDO_MYSQL_HAS_CHARSET
  715: 	if (vars[0].optval && mysql_options(H->server, MYSQL_SET_CHARSET_NAME, vars[0].optval)) {
  716: 		pdo_mysql_error(dbh);
  717: 		goto cleanup;
  718: 	}
  719: #endif
  720: 
  721: 	dbname = vars[1].optval;
  722: 	host = vars[2].optval;	
  723: 	if(vars[3].optval) {
  724: 		port = atoi(vars[3].optval);
  725: 	}
  726: 	if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
  727: 		unix_socket = vars[4].optval;  
  728: 	}
  729: 
  730: 	/* TODO: - Check zval cache + ZTS */
  731: #ifdef PDO_USE_MYSQLND
  732: 	if (dbname) {
  733: 		dbname_len = strlen(dbname);
  734: 	}
  735: 
  736: 	if (dbh->password) {
  737: 		password_len = strlen(dbh->password);
  738: 	}
  739: 
  740: 	if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
  741: 						port, unix_socket, connect_opts TSRMLS_CC) == NULL) {
  742: #else
  743: 	if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
  744: #endif
  745: 		pdo_mysql_error(dbh);
  746: 		goto cleanup;
  747: 	}
  748: 
  749: 	if (!dbh->auto_commit) {
  750: 		mysql_handle_autocommit(dbh TSRMLS_CC);
  751: 	}
  752: 
  753: 	H->attached = 1;
  754: 
  755: 	dbh->alloc_own_columns = 1;
  756: 	dbh->max_escaped_char_length = 2;
  757: 	dbh->methods = &mysql_methods;
  758: 
  759: 	ret = 1;
  760: 	
  761: cleanup:
  762: 	for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
  763: 		if (vars[i].freeme) {
  764: 			efree(vars[i].optval);
  765: 		}
  766: 	}
  767: 	
  768: 	dbh->methods = &mysql_methods;
  769: 
  770: 	PDO_DBG_RETURN(ret);
  771: }
  772: /* }}} */
  773: 
  774: pdo_driver_t pdo_mysql_driver = {
  775: 	PDO_DRIVER_HEADER(mysql),
  776: 	pdo_mysql_handle_factory
  777: };
  778: 
  779: /*
  780:  * Local variables:
  781:  * tab-width: 4
  782:  * c-basic-offset: 4
  783:  * End:
  784:  * vim600: noet sw=4 ts=4 fdm=marker
  785:  * vim<600: noet sw=4 ts=4
  786:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>