mysql_driver.php 17 KB

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