PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/system/database/drivers/mysqli/mysqli_driver.php

https://bitbucket.org/code_noodle/scratchpad
PHP | 510 lines | 220 code | 78 blank | 212 comment | 25 complexity | 7d76e959925faaf4618a304c3871a659 MD5 | raw file
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.2.4 or newer
  6. *
  7. * NOTICE OF LICENSE
  8. *
  9. * Licensed under the Open Software License version 3.0
  10. *
  11. * This source file is subject to the Open Software License (OSL 3.0) that is
  12. * bundled with this package in the files license.txt / license.rst. It is
  13. * also available through the world wide web at this URL:
  14. * http://opensource.org/licenses/OSL-3.0
  15. * If you did not receive a copy of the license and are unable to obtain it
  16. * through the world wide web, please send an email to
  17. * licensing@ellislab.com so we can send you a copy immediately.
  18. *
  19. * @package CodeIgniter
  20. * @author EllisLab Dev Team
  21. * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  22. * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  23. * @link http://codeigniter.com
  24. * @since Version 1.0
  25. * @filesource
  26. */
  27. /**
  28. * MySQLi Database Adapter Class
  29. *
  30. * Note: _DB is an extender class that the app controller
  31. * creates dynamically based on whether the query builder
  32. * class is being used or not.
  33. *
  34. * @package CodeIgniter
  35. * @subpackage Drivers
  36. * @category Database
  37. * @author EllisLab Dev Team
  38. * @link http://codeigniter.com/user_guide/database/
  39. */
  40. class CI_DB_mysqli_driver extends CI_DB {
  41. public $dbdriver = 'mysqli';
  42. // The character used for escaping
  43. protected $_escape_char = '`';
  44. protected $_random_keyword = ' RAND()'; // database specific random keyword
  45. /**
  46. * Whether to use the MySQL "delete hack" which allows the number
  47. * of affected rows to be shown. Uses a preg_replace when enabled,
  48. * adding a bit more processing to all queries.
  49. */
  50. public $delete_hack = TRUE;
  51. /**
  52. * Non-persistent database connection
  53. *
  54. * @return object
  55. */
  56. public function db_connect()
  57. {
  58. // Use MySQL client compression?
  59. if ($this->compress === TRUE)
  60. {
  61. $port = empty($this->port) ? NULL : $this->port;
  62. $mysqli = new mysqli();
  63. @$mysqli->real_connect($this->hostname, $this->username, $this->password, $this->database, $port, NULL, MYSQLI_CLIENT_COMPRESS);
  64. return $mysqli;
  65. }
  66. return empty($this->port)
  67. ? @new mysqli($this->hostname, $this->username, $this->password, $this->database)
  68. : @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port);
  69. }
  70. // --------------------------------------------------------------------
  71. /**
  72. * Persistent database connection
  73. *
  74. * @return object
  75. */
  76. public function db_pconnect()
  77. {
  78. // Persistent connection support was added in PHP 5.3.0
  79. if ( ! is_php('5.3'))
  80. {
  81. return $this->db_connect();
  82. }
  83. // Use MySQL client compression?
  84. if ($this->compress === TRUE)
  85. {
  86. $port = empty($this->port) ? NULL : $this->port;
  87. $mysqli = mysqli_init();
  88. $mysqli->real_connect('p:'.$this->hostname, $this->username, $this->password, $this->database, $port, NULL, MYSQLI_CLIENT_COMPRESS);
  89. return $mysqli;
  90. }
  91. return empty($this->port)
  92. ? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database)
  93. : @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port);
  94. }
  95. // --------------------------------------------------------------------
  96. /**
  97. * Reconnect
  98. *
  99. * Keep / reestablish the db connection if no queries have been
  100. * sent for a length of time exceeding the server's idle timeout
  101. *
  102. * @return void
  103. */
  104. public function reconnect()
  105. {
  106. if ($this->conn_id !== FALSE && $this->conn_id->ping() === FALSE)
  107. {
  108. $this->conn_id = FALSE;
  109. }
  110. }
  111. // --------------------------------------------------------------------
  112. /**
  113. * Select the database
  114. *
  115. * @param string database name
  116. * @return bool
  117. */
  118. public function db_select($database = '')
  119. {
  120. if ($database === '')
  121. {
  122. $database = $this->database;
  123. }
  124. if (@$this->conn_id->select_db($database))
  125. {
  126. $this->database = $database;
  127. return TRUE;
  128. }
  129. return FALSE;
  130. }
  131. // --------------------------------------------------------------------
  132. /**
  133. * Set client character set
  134. *
  135. * @param string
  136. * @return bool
  137. */
  138. protected function _db_set_charset($charset)
  139. {
  140. return @$this->conn_id->set_charset($charset);
  141. }
  142. // --------------------------------------------------------------------
  143. /**
  144. * Database version number
  145. *
  146. * @return string
  147. */
  148. public function version()
  149. {
  150. return isset($this->data_cache['version'])
  151. ? $this->data_cache['version']
  152. : $this->data_cache['version'] = $this->conn_id->server_info;
  153. }
  154. // --------------------------------------------------------------------
  155. /**
  156. * Execute the query
  157. *
  158. * @param string an SQL query
  159. * @return mixed
  160. */
  161. protected function _execute($sql)
  162. {
  163. return @$this->conn_id->query($this->_prep_query($sql));
  164. }
  165. // --------------------------------------------------------------------
  166. /**
  167. * Prep the query
  168. *
  169. * If needed, each database adapter can prep the query string
  170. *
  171. * @param string an SQL query
  172. * @return string
  173. */
  174. protected function _prep_query($sql)
  175. {
  176. // mysqli_affected_rows() returns 0 for "DELETE FROM TABLE" queries. This hack
  177. // modifies the query so that it a proper number of affected rows is returned.
  178. if ($this->delete_hack === TRUE && preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
  179. {
  180. return preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', 'DELETE FROM \\1 WHERE 1=1', $sql);
  181. }
  182. return $sql;
  183. }
  184. // --------------------------------------------------------------------
  185. /**
  186. * Begin Transaction
  187. *
  188. * @return bool
  189. */
  190. public function trans_begin($test_mode = FALSE)
  191. {
  192. // When transactions are nested we only begin/commit/rollback the outermost ones
  193. if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
  194. {
  195. return TRUE;
  196. }
  197. // Reset the transaction failure flag.
  198. // If the $test_mode flag is set to TRUE transactions will be rolled back
  199. // even if the queries produce a successful result.
  200. $this->_trans_failure = ($test_mode === TRUE);
  201. $this->simple_query('SET AUTOCOMMIT=0');
  202. $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
  203. return TRUE;
  204. }
  205. // --------------------------------------------------------------------
  206. /**
  207. * Commit Transaction
  208. *
  209. * @return bool
  210. */
  211. public function trans_commit()
  212. {
  213. // When transactions are nested we only begin/commit/rollback the outermost ones
  214. if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
  215. {
  216. return TRUE;
  217. }
  218. $this->simple_query('COMMIT');
  219. $this->simple_query('SET AUTOCOMMIT=1');
  220. return TRUE;
  221. }
  222. // --------------------------------------------------------------------
  223. /**
  224. * Rollback Transaction
  225. *
  226. * @return bool
  227. */
  228. public function trans_rollback()
  229. {
  230. // When transactions are nested we only begin/commit/rollback the outermost ones
  231. if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
  232. {
  233. return TRUE;
  234. }
  235. $this->simple_query('ROLLBACK');
  236. $this->simple_query('SET AUTOCOMMIT=1');
  237. return TRUE;
  238. }
  239. // --------------------------------------------------------------------
  240. /**
  241. * Escape String
  242. *
  243. * @param string
  244. * @param bool whether or not the string will be used in a LIKE condition
  245. * @return string
  246. */
  247. public function escape_str($str, $like = FALSE)
  248. {
  249. if (is_array($str))
  250. {
  251. foreach ($str as $key => $val)
  252. {
  253. $str[$key] = $this->escape_str($val, $like);
  254. }
  255. return $str;
  256. }
  257. $str = is_object($this->conn_id) ? $this->conn_id->real_escape_string($str) : addslashes($str);
  258. // escape LIKE condition wildcards
  259. if ($like === TRUE)
  260. {
  261. return str_replace(array($this->_like_escape_chr, '%', '_'),
  262. array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
  263. $str);
  264. }
  265. return $str;
  266. }
  267. // --------------------------------------------------------------------
  268. /**
  269. * Affected Rows
  270. *
  271. * @return int
  272. */
  273. public function affected_rows()
  274. {
  275. return $this->conn_id->affected_rows;
  276. }
  277. // --------------------------------------------------------------------
  278. /**
  279. * Insert ID
  280. *
  281. * @return int
  282. */
  283. public function insert_id()
  284. {
  285. return $this->conn_id->insert_id;
  286. }
  287. // --------------------------------------------------------------------
  288. /**
  289. * List table query
  290. *
  291. * Generates a platform-specific query string so that the table names can be fetched
  292. *
  293. * @param bool
  294. * @return string
  295. */
  296. protected function _list_tables($prefix_limit = FALSE)
  297. {
  298. $sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database);
  299. if ($prefix_limit !== FALSE && $this->dbprefix !== '')
  300. {
  301. return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'";
  302. }
  303. return $sql;
  304. }
  305. // --------------------------------------------------------------------
  306. /**
  307. * Show column query
  308. *
  309. * Generates a platform-specific query string so that the column names can be fetched
  310. *
  311. * @param string the table name
  312. * @return string
  313. */
  314. protected function _list_columns($table = '')
  315. {
  316. return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE);
  317. }
  318. // --------------------------------------------------------------------
  319. /**
  320. * Returns an object with field data
  321. *
  322. * @param string the table name
  323. * @return object
  324. */
  325. public function field_data($table = '')
  326. {
  327. if ($table === '')
  328. {
  329. return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
  330. }
  331. $query = $this->query('DESCRIBE '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
  332. $query = $query->result_object();
  333. $retval = array();
  334. for ($i = 0, $c = count($query); $i < $c; $i++)
  335. {
  336. preg_match('/([a-z]+)(\(\d+\))?/', $query[$i]->Type, $matches);
  337. $retval[$i] = new stdClass();
  338. $retval[$i]->name = $query[$i]->Field;
  339. $retval[$i]->type = empty($matches[1]) ? NULL : $matches[1];
  340. $retval[$i]->default = $query[$i]->Default;
  341. $retval[$i]->max_length = empty($matches[2]) ? NULL : preg_replace('/[^\d]/', '', $matches[2]);
  342. $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI');
  343. }
  344. return $retval;
  345. }
  346. // --------------------------------------------------------------------
  347. /**
  348. * Error
  349. *
  350. * Returns an array containing code and message of the last
  351. * database error that has occured.
  352. *
  353. * @return array
  354. */
  355. public function error()
  356. {
  357. if ( ! empty($this->conn_id->connect_errno))
  358. {
  359. return array(
  360. 'code' => $this->conn_id->connect_errno,
  361. 'message' => is_php('5.2.9') ? $this->conn_id->connect_error : mysqli_connect_error()
  362. );
  363. }
  364. return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error);
  365. }
  366. // --------------------------------------------------------------------
  367. /**
  368. * Update_Batch statement
  369. *
  370. * Generates a platform-specific batch update string from the supplied data
  371. *
  372. * @param string the table name
  373. * @param array the update data
  374. * @param array the where clause
  375. * @return string
  376. */
  377. protected function _update_batch($table, $values, $index, $where = NULL)
  378. {
  379. $ids = array();
  380. foreach ($values as $key => $val)
  381. {
  382. $ids[] = $val[$index];
  383. foreach (array_keys($val) as $field)
  384. {
  385. if ($field !== $index)
  386. {
  387. $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
  388. }
  389. }
  390. }
  391. $cases = '';
  392. foreach ($final as $k => $v)
  393. {
  394. $cases .= $k.' = CASE '."\n"
  395. .implode("\n", $v)."\n"
  396. .'ELSE '.$k.' END, ';
  397. }
  398. $where = ($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '';
  399. return 'UPDATE '.$table.' SET '.substr($cases, 0, -2)
  400. .' WHERE '.(($where !== '' && count($where) > 0) ? implode(' ', $where).' AND ' : '')
  401. .$index.' IN('.implode(',', $ids).')';
  402. }
  403. // --------------------------------------------------------------------
  404. /**
  405. * FROM tables
  406. *
  407. * Groups tables in FROM clauses if needed, so there is no confusion
  408. * about operator precedence.
  409. *
  410. * @return string
  411. */
  412. protected function _from_tables()
  413. {
  414. if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
  415. {
  416. return '('.implode(', ', $this->qb_from).')';
  417. }
  418. return implode(', ', $this->qb_from);
  419. }
  420. // --------------------------------------------------------------------
  421. /**
  422. * Close DB Connection
  423. *
  424. * @return void
  425. */
  426. protected function _close()
  427. {
  428. $this->conn_id->close();
  429. }
  430. }
  431. /* End of file mysqli_driver.php */
  432. /* Location: ./system/database/drivers/mysqli/mysqli_driver.php */