mysqli_driver.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc.
  10. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  11. * @license http://codeigniter.com/user_guide/license.html
  12. * @link http://codeigniter.com
  13. * @since Version 1.0
  14. * @filesource
  15. */
  16. // ------------------------------------------------------------------------
  17. /**
  18. * MySQLi Database Adapter Class - MySQLi only works with PHP 5
  19. *
  20. * Note: _DB is an extender class that the app controller
  21. * creates dynamically based on whether the active record
  22. * class is being used or not.
  23. *
  24. * @package CodeIgniter
  25. * @subpackage Drivers
  26. * @category Database
  27. * @author EllisLab Dev Team
  28. * @link http://codeigniter.com/user_guide/database/
  29. */
  30. class CI_DB_mysqli_driver extends CI_DB {
  31. var $dbdriver = 'mysqli';
  32. // The character used for escaping
  33. var $_escape_char = '`';
  34. // clause and character used for LIKE escape sequences - not used in MySQL
  35. var $_like_escape_str = '';
  36. var $_like_escape_chr = '';
  37. /**
  38. * The syntax to count rows is slightly different across different
  39. * database engines, so this string appears in each driver and is
  40. * used for the count_all() and count_all_results() functions.
  41. */
  42. var $_count_string = "SELECT COUNT(*) AS ";
  43. var $_random_keyword = ' RAND()'; // database specific random keyword
  44. /**
  45. * Whether to use the MySQL "delete hack" which allows the number
  46. * of affected rows to be shown. Uses a preg_replace when enabled,
  47. * adding a bit more processing to all queries.
  48. */
  49. var $delete_hack = TRUE;
  50. // whether SET NAMES must be used to set the character set
  51. var $use_set_names;
  52. // --------------------------------------------------------------------
  53. /**
  54. * Non-persistent database connection
  55. *
  56. * @access private called by the base class
  57. * @return resource
  58. */
  59. function db_connect()
  60. {
  61. if ($this->port != '')
  62. {
  63. return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port);
  64. }
  65. else
  66. {
  67. return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
  68. }
  69. }
  70. // --------------------------------------------------------------------
  71. /**
  72. * Persistent database connection
  73. *
  74. * @access private called by the base class
  75. * @return resource
  76. */
  77. function db_pconnect()
  78. {
  79. return $this->db_connect();
  80. }
  81. // --------------------------------------------------------------------
  82. /**
  83. * Reconnect
  84. *
  85. * Keep / reestablish the db connection if no queries have been
  86. * sent for a length of time exceeding the server's idle timeout
  87. *
  88. * @access public
  89. * @return void
  90. */
  91. function reconnect()
  92. {
  93. if (mysqli_ping($this->conn_id) === FALSE)
  94. {
  95. $this->conn_id = FALSE;
  96. }
  97. }
  98. // --------------------------------------------------------------------
  99. /**
  100. * Select the database
  101. *
  102. * @access private called by the base class
  103. * @return resource
  104. */
  105. function db_select()
  106. {
  107. return @mysqli_select_db($this->conn_id, $this->database);
  108. }
  109. // --------------------------------------------------------------------
  110. /**
  111. * Set client character set
  112. *
  113. * @access private
  114. * @param string
  115. * @param string
  116. * @return resource
  117. */
  118. function _db_set_charset($charset, $collation)
  119. {
  120. if ( ! isset($this->use_set_names))
  121. {
  122. // mysqli_set_charset() requires MySQL >= 5.0.7, use SET NAMES as fallback
  123. $this->use_set_names = (version_compare(mysqli_get_server_info($this->conn_id), '5.0.7', '>=')) ? FALSE : TRUE;
  124. }
  125. if ($this->use_set_names === TRUE)
  126. {
  127. return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
  128. }
  129. else
  130. {
  131. return @mysqli_set_charset($this->conn_id, $charset);
  132. }
  133. }
  134. // --------------------------------------------------------------------
  135. /**
  136. * Version number query string
  137. *
  138. * @access public
  139. * @return string
  140. */
  141. function _version()
  142. {
  143. return "SELECT version() AS ver";
  144. }
  145. // --------------------------------------------------------------------
  146. /**
  147. * Execute the query
  148. *
  149. * @access private called by the base class
  150. * @param string an SQL query
  151. * @return resource
  152. */
  153. function _execute($sql)
  154. {
  155. $sql = $this->_prep_query($sql);
  156. $result = @mysqli_query($this->conn_id, $sql);
  157. return $result;
  158. }
  159. // --------------------------------------------------------------------
  160. /**
  161. * Prep the query
  162. *
  163. * If needed, each database adapter can prep the query string
  164. *
  165. * @access private called by execute()
  166. * @param string an SQL query
  167. * @return string
  168. */
  169. function _prep_query($sql)
  170. {
  171. // "DELETE FROM TABLE" returns 0 affected rows This hack modifies
  172. // the query so that it returns the number of affected rows
  173. if ($this->delete_hack === TRUE)
  174. {
  175. if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
  176. {
  177. $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql);
  178. }
  179. }
  180. return $sql;
  181. }
  182. // --------------------------------------------------------------------
  183. /**
  184. * Begin Transaction
  185. *
  186. * @access public
  187. * @return bool
  188. */
  189. function trans_begin($test_mode = FALSE)
  190. {
  191. if ( ! $this->trans_enabled)
  192. {
  193. return TRUE;
  194. }
  195. // When transactions are nested we only begin/commit/rollback the outermost ones
  196. if ($this->_trans_depth > 0)
  197. {
  198. return TRUE;
  199. }
  200. // Reset the transaction failure flag.
  201. // If the $test_mode flag is set to TRUE transactions will be rolled back
  202. // even if the queries produce a successful result.
  203. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
  204. $this->simple_query('SET AUTOCOMMIT=0');
  205. $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
  206. return TRUE;
  207. }
  208. // --------------------------------------------------------------------
  209. /**
  210. * Commit Transaction
  211. *
  212. * @access public
  213. * @return bool
  214. */
  215. function trans_commit()
  216. {
  217. if ( ! $this->trans_enabled)
  218. {
  219. return TRUE;
  220. }
  221. // When transactions are nested we only begin/commit/rollback the outermost ones
  222. if ($this->_trans_depth > 0)
  223. {
  224. return TRUE;
  225. }
  226. $this->simple_query('COMMIT');
  227. $this->simple_query('SET AUTOCOMMIT=1');
  228. return TRUE;
  229. }
  230. // --------------------------------------------------------------------
  231. /**
  232. * Rollback Transaction
  233. *
  234. * @access public
  235. * @return bool
  236. */
  237. function trans_rollback()
  238. {
  239. if ( ! $this->trans_enabled)
  240. {
  241. return TRUE;
  242. }
  243. // When transactions are nested we only begin/commit/rollback the outermost ones
  244. if ($this->_trans_depth > 0)
  245. {
  246. return TRUE;
  247. }
  248. $this->simple_query('ROLLBACK');
  249. $this->simple_query('SET AUTOCOMMIT=1');
  250. return TRUE;
  251. }
  252. // --------------------------------------------------------------------
  253. /**
  254. * Escape String
  255. *
  256. * @access public
  257. * @param string
  258. * @param bool whether or not the string will be used in a LIKE condition
  259. * @return string
  260. */
  261. function escape_str($str, $like = FALSE)
  262. {
  263. if (is_array($str))
  264. {
  265. foreach ($str as $key => $val)
  266. {
  267. $str[$key] = $this->escape_str($val, $like);
  268. }
  269. return $str;
  270. }
  271. $str = mysqli_real_escape_string($this->conn_id, $str);
  272. // escape LIKE condition wildcards
  273. if ($like === TRUE)
  274. {
  275. $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str);
  276. }
  277. return $str;
  278. }
  279. // --------------------------------------------------------------------
  280. /**
  281. * Affected Rows
  282. *
  283. * @access public
  284. * @return integer
  285. */
  286. function affected_rows()
  287. {
  288. return @mysqli_affected_rows($this->conn_id);
  289. }
  290. // --------------------------------------------------------------------
  291. /**
  292. * Insert ID
  293. *
  294. * @access public
  295. * @return integer
  296. */
  297. function insert_id()
  298. {
  299. return @mysqli_insert_id($this->conn_id);
  300. }
  301. // --------------------------------------------------------------------
  302. /**
  303. * "Count All" query
  304. *
  305. * Generates a platform-specific query string that counts all records in
  306. * the specified database
  307. *
  308. * @access public
  309. * @param string
  310. * @return string
  311. */
  312. function count_all($table = '')
  313. {
  314. if ($table == '')
  315. {
  316. return 0;
  317. }
  318. $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
  319. if ($query->num_rows() == 0)
  320. {
  321. return 0;
  322. }
  323. $row = $query->row();
  324. $this->_reset_select();
  325. return (int) $row->numrows;
  326. }
  327. // --------------------------------------------------------------------
  328. /**
  329. * List table query
  330. *
  331. * Generates a platform-specific query string so that the table names can be fetched
  332. *
  333. * @access private
  334. * @param boolean
  335. * @return string
  336. */
  337. function _list_tables($prefix_limit = FALSE)
  338. {
  339. $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char;
  340. if ($prefix_limit !== FALSE AND $this->dbprefix != '')
  341. {
  342. $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'";
  343. }
  344. return $sql;
  345. }
  346. // --------------------------------------------------------------------
  347. /**
  348. * Show column query
  349. *
  350. * Generates a platform-specific query string so that the column names can be fetched
  351. *
  352. * @access public
  353. * @param string the table name
  354. * @return string
  355. */
  356. function _list_columns($table = '')
  357. {
  358. return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE);
  359. }
  360. // --------------------------------------------------------------------
  361. /**
  362. * Field data query
  363. *
  364. * Generates a platform-specific query so that the column data can be retrieved
  365. *
  366. * @access public
  367. * @param string the table name
  368. * @return object
  369. */
  370. function _field_data($table)
  371. {
  372. return "DESCRIBE ".$table;
  373. }
  374. // --------------------------------------------------------------------
  375. /**
  376. * The error message string
  377. *
  378. * @access private
  379. * @return string
  380. */
  381. function _error_message()
  382. {
  383. return mysqli_error($this->conn_id);
  384. }
  385. // --------------------------------------------------------------------
  386. /**
  387. * The error message number
  388. *
  389. * @access private
  390. * @return integer
  391. */
  392. function _error_number()
  393. {
  394. return mysqli_errno($this->conn_id);
  395. }
  396. // --------------------------------------------------------------------
  397. /**
  398. * Escape the SQL Identifiers
  399. *
  400. * This function escapes column and table names
  401. *
  402. * @access private
  403. * @param string
  404. * @return string
  405. */
  406. function _escape_identifiers($item)
  407. {
  408. if ($this->_escape_char == '')
  409. {
  410. return $item;
  411. }
  412. foreach ($this->_reserved_identifiers as $id)
  413. {
  414. if (strpos($item, '.'.$id) !== FALSE)
  415. {
  416. $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
  417. // remove duplicates if the user already included the escape
  418. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  419. }
  420. }
  421. if (strpos($item, '.') !== FALSE)
  422. {
  423. $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
  424. }
  425. else
  426. {
  427. $str = $this->_escape_char.$item.$this->_escape_char;
  428. }
  429. // remove duplicates if the user already included the escape
  430. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  431. }
  432. // --------------------------------------------------------------------
  433. /**
  434. * From Tables
  435. *
  436. * This function implicitly groups FROM tables so there is no confusion
  437. * about operator precedence in harmony with SQL standards
  438. *
  439. * @access public
  440. * @param type
  441. * @return type
  442. */
  443. function _from_tables($tables)
  444. {
  445. if ( ! is_array($tables))
  446. {
  447. $tables = array($tables);
  448. }
  449. return '('.implode(', ', $tables).')';
  450. }
  451. // --------------------------------------------------------------------
  452. /**
  453. * Insert statement
  454. *
  455. * Generates a platform-specific insert string from the supplied data
  456. *
  457. * @access public
  458. * @param string the table name
  459. * @param array the insert keys
  460. * @param array the insert values
  461. * @return string
  462. */
  463. function _insert($table, $keys, $values)
  464. {
  465. return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
  466. }
  467. // --------------------------------------------------------------------
  468. /**
  469. * Insert_batch statement
  470. *
  471. * Generates a platform-specific insert string from the supplied data
  472. *
  473. * @access public
  474. * @param string the table name
  475. * @param array the insert keys
  476. * @param array the insert values
  477. * @return string
  478. */
  479. function _insert_batch($table, $keys, $values)
  480. {
  481. return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values);
  482. }
  483. // --------------------------------------------------------------------
  484. /**
  485. * Replace statement
  486. *
  487. * Generates a platform-specific replace string from the supplied data
  488. *
  489. * @access public
  490. * @param string the table name
  491. * @param array the insert keys
  492. * @param array the insert values
  493. * @return string
  494. */
  495. function _replace($table, $keys, $values)
  496. {
  497. return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
  498. }
  499. // --------------------------------------------------------------------
  500. /**
  501. * Update statement
  502. *
  503. * Generates a platform-specific update string from the supplied data
  504. *
  505. * @access public
  506. * @param string the table name
  507. * @param array the update data
  508. * @param array the where clause
  509. * @param array the orderby clause
  510. * @param array the limit clause
  511. * @return string
  512. */
  513. function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
  514. {
  515. foreach ($values as $key => $val)
  516. {
  517. $valstr[] = $key." = ".$val;
  518. }
  519. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  520. $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
  521. $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
  522. $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
  523. $sql .= $orderby.$limit;
  524. return $sql;
  525. }
  526. // --------------------------------------------------------------------
  527. /**
  528. * Update_Batch statement
  529. *
  530. * Generates a platform-specific batch update string from the supplied data
  531. *
  532. * @access public
  533. * @param string the table name
  534. * @param array the update data
  535. * @param array the where clause
  536. * @return string
  537. */
  538. function _update_batch($table, $values, $index, $where = NULL)
  539. {
  540. $ids = array();
  541. $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : '';
  542. foreach ($values as $key => $val)
  543. {
  544. $ids[] = $val[$index];
  545. foreach (array_keys($val) as $field)
  546. {
  547. if ($field != $index)
  548. {
  549. $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
  550. }
  551. }
  552. }
  553. $sql = "UPDATE ".$table." SET ";
  554. $cases = '';
  555. foreach ($final as $k => $v)
  556. {
  557. $cases .= $k.' = CASE '."\n";
  558. foreach ($v as $row)
  559. {
  560. $cases .= $row."\n";
  561. }
  562. $cases .= 'ELSE '.$k.' END, ';
  563. }
  564. $sql .= substr($cases, 0, -2);
  565. $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')';
  566. return $sql;
  567. }
  568. // --------------------------------------------------------------------
  569. /**
  570. * Truncate statement
  571. *
  572. * Generates a platform-specific truncate string from the supplied data
  573. * If the database does not support the truncate() command
  574. * This function maps to "DELETE FROM table"
  575. *
  576. * @access public
  577. * @param string the table name
  578. * @return string
  579. */
  580. function _truncate($table)
  581. {
  582. return "TRUNCATE ".$table;
  583. }
  584. // --------------------------------------------------------------------
  585. /**
  586. * Delete statement
  587. *
  588. * Generates a platform-specific delete string from the supplied data
  589. *
  590. * @access public
  591. * @param string the table name
  592. * @param array the where clause
  593. * @param string the limit clause
  594. * @return string
  595. */
  596. function _delete($table, $where = array(), $like = array(), $limit = FALSE)
  597. {
  598. $conditions = '';
  599. if (count($where) > 0 OR count($like) > 0)
  600. {
  601. $conditions = "\nWHERE ";
  602. $conditions .= implode("\n", $this->ar_where);
  603. if (count($where) > 0 && count($like) > 0)
  604. {
  605. $conditions .= " AND ";
  606. }
  607. $conditions .= implode("\n", $like);
  608. }
  609. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  610. return "DELETE FROM ".$table.$conditions.$limit;
  611. }
  612. // --------------------------------------------------------------------
  613. /**
  614. * Limit string
  615. *
  616. * Generates a platform-specific LIMIT clause
  617. *
  618. * @access public
  619. * @param string the sql query string
  620. * @param integer the number of rows to limit the query to
  621. * @param integer the offset value
  622. * @return string
  623. */
  624. function _limit($sql, $limit, $offset)
  625. {
  626. $sql .= "LIMIT ".$limit;
  627. if ($offset > 0)
  628. {
  629. $sql .= " OFFSET ".$offset;
  630. }
  631. return $sql;
  632. }
  633. // --------------------------------------------------------------------
  634. /**
  635. * Close DB Connection
  636. *
  637. * @access public
  638. * @param resource
  639. * @return void
  640. */
  641. function _close($conn_id)
  642. {
  643. @mysqli_close($conn_id);
  644. }
  645. }
  646. /* End of file mysqli_driver.php */
  647. /* Location: ./system/database/drivers/mysqli/mysqli_driver.php */