mysql_driver.c 22 KB

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