mysqli_driver.php 17 KB

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