PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/system/database/drivers/pdo/pdo_driver.php

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