You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

666 lines
14 KiB

7 years ago
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * Database Result Class
  41. *
  42. * This is the platform-independent result class.
  43. * This class will not be called directly. Rather, the adapter
  44. * class for the specific database will extend and instantiate it.
  45. *
  46. * @category Database
  47. * @author EllisLab Dev Team
  48. * @link https://codeigniter.com/user_guide/database/
  49. */
  50. class CI_DB_result {
  51. /**
  52. * Connection ID
  53. *
  54. * @var resource|object
  55. */
  56. public $conn_id;
  57. /**
  58. * Result ID
  59. *
  60. * @var resource|object
  61. */
  62. public $result_id;
  63. /**
  64. * Result Array
  65. *
  66. * @var array[]
  67. */
  68. public $result_array = array();
  69. /**
  70. * Result Object
  71. *
  72. * @var object[]
  73. */
  74. public $result_object = array();
  75. /**
  76. * Custom Result Object
  77. *
  78. * @var object[]
  79. */
  80. public $custom_result_object = array();
  81. /**
  82. * Current Row index
  83. *
  84. * @var int
  85. */
  86. public $current_row = 0;
  87. /**
  88. * Number of rows
  89. *
  90. * @var int
  91. */
  92. public $num_rows;
  93. /**
  94. * Row data
  95. *
  96. * @var array
  97. */
  98. public $row_data;
  99. // --------------------------------------------------------------------
  100. /**
  101. * Constructor
  102. *
  103. * @param object $driver_object
  104. * @return void
  105. */
  106. public function __construct(&$driver_object)
  107. {
  108. $this->conn_id = $driver_object->conn_id;
  109. $this->result_id = $driver_object->result_id;
  110. }
  111. // --------------------------------------------------------------------
  112. /**
  113. * Number of rows in the result set
  114. *
  115. * @return int
  116. */
  117. public function num_rows()
  118. {
  119. if (is_int($this->num_rows))
  120. {
  121. return $this->num_rows;
  122. }
  123. elseif (count($this->result_array) > 0)
  124. {
  125. return $this->num_rows = count($this->result_array);
  126. }
  127. elseif (count($this->result_object) > 0)
  128. {
  129. return $this->num_rows = count($this->result_object);
  130. }
  131. return $this->num_rows = count($this->result_array());
  132. }
  133. // --------------------------------------------------------------------
  134. /**
  135. * Query result. Acts as a wrapper function for the following functions.
  136. *
  137. * @param string $type 'object', 'array' or a custom class name
  138. * @return array
  139. */
  140. public function result($type = 'object')
  141. {
  142. if ($type === 'array')
  143. {
  144. return $this->result_array();
  145. }
  146. elseif ($type === 'object')
  147. {
  148. return $this->result_object();
  149. }
  150. else
  151. {
  152. return $this->custom_result_object($type);
  153. }
  154. }
  155. // --------------------------------------------------------------------
  156. /**
  157. * Custom query result.
  158. *
  159. * @param string $class_name
  160. * @return array
  161. */
  162. public function custom_result_object($class_name)
  163. {
  164. if (isset($this->custom_result_object[$class_name]))
  165. {
  166. return $this->custom_result_object[$class_name];
  167. }
  168. elseif ( ! $this->result_id OR $this->num_rows === 0)
  169. {
  170. return array();
  171. }
  172. // Don't fetch the result set again if we already have it
  173. $_data = NULL;
  174. if (($c = count($this->result_array)) > 0)
  175. {
  176. $_data = 'result_array';
  177. }
  178. elseif (($c = count($this->result_object)) > 0)
  179. {
  180. $_data = 'result_object';
  181. }
  182. if ($_data !== NULL)
  183. {
  184. for ($i = 0; $i < $c; $i++)
  185. {
  186. $this->custom_result_object[$class_name][$i] = new $class_name();
  187. foreach ($this->{$_data}[$i] as $key => $value)
  188. {
  189. $this->custom_result_object[$class_name][$i]->$key = $value;
  190. }
  191. }
  192. return $this->custom_result_object[$class_name];
  193. }
  194. is_null($this->row_data) OR $this->data_seek(0);
  195. $this->custom_result_object[$class_name] = array();
  196. while ($row = $this->_fetch_object($class_name))
  197. {
  198. $this->custom_result_object[$class_name][] = $row;
  199. }
  200. return $this->custom_result_object[$class_name];
  201. }
  202. // --------------------------------------------------------------------
  203. /**
  204. * Query result. "object" version.
  205. *
  206. * @return array
  207. */
  208. public function result_object()
  209. {
  210. if (count($this->result_object) > 0)
  211. {
  212. return $this->result_object;
  213. }
  214. // In the event that query caching is on, the result_id variable
  215. // will not be a valid resource so we'll simply return an empty
  216. // array.
  217. if ( ! $this->result_id OR $this->num_rows === 0)
  218. {
  219. return array();
  220. }
  221. if (($c = count($this->result_array)) > 0)
  222. {
  223. for ($i = 0; $i < $c; $i++)
  224. {
  225. $this->result_object[$i] = (object) $this->result_array[$i];
  226. }
  227. return $this->result_object;
  228. }
  229. is_null($this->row_data) OR $this->data_seek(0);
  230. while ($row = $this->_fetch_object())
  231. {
  232. $this->result_object[] = $row;
  233. }
  234. return $this->result_object;
  235. }
  236. // --------------------------------------------------------------------
  237. /**
  238. * Query result. "array" version.
  239. *
  240. * @return array
  241. */
  242. public function result_array()
  243. {
  244. if (count($this->result_array) > 0)
  245. {
  246. return $this->result_array;
  247. }
  248. // In the event that query caching is on, the result_id variable
  249. // will not be a valid resource so we'll simply return an empty
  250. // array.
  251. if ( ! $this->result_id OR $this->num_rows === 0)
  252. {
  253. return array();
  254. }
  255. if (($c = count($this->result_object)) > 0)
  256. {
  257. for ($i = 0; $i < $c; $i++)
  258. {
  259. $this->result_array[$i] = (array) $this->result_object[$i];
  260. }
  261. return $this->result_array;
  262. }
  263. is_null($this->row_data) OR $this->data_seek(0);
  264. while ($row = $this->_fetch_assoc())
  265. {
  266. $this->result_array[] = $row;
  267. }
  268. return $this->result_array;
  269. }
  270. // --------------------------------------------------------------------
  271. /**
  272. * Row
  273. *
  274. * A wrapper method.
  275. *
  276. * @param mixed $n
  277. * @param string $type 'object' or 'array'
  278. * @return mixed
  279. */
  280. public function row($n = 0, $type = 'object')
  281. {
  282. if ( ! is_numeric($n))
  283. {
  284. // We cache the row data for subsequent uses
  285. is_array($this->row_data) OR $this->row_data = $this->row_array(0);
  286. // array_key_exists() instead of isset() to allow for NULL values
  287. if (empty($this->row_data) OR ! array_key_exists($n, $this->row_data))
  288. {
  289. return NULL;
  290. }
  291. return $this->row_data[$n];
  292. }
  293. if ($type === 'object') return $this->row_object($n);
  294. elseif ($type === 'array') return $this->row_array($n);
  295. else return $this->custom_row_object($n, $type);
  296. }
  297. // --------------------------------------------------------------------
  298. /**
  299. * Assigns an item into a particular column slot
  300. *
  301. * @param mixed $key
  302. * @param mixed $value
  303. * @return void
  304. */
  305. public function set_row($key, $value = NULL)
  306. {
  307. // We cache the row data for subsequent uses
  308. if ( ! is_array($this->row_data))
  309. {
  310. $this->row_data = $this->row_array(0);
  311. }
  312. if (is_array($key))
  313. {
  314. foreach ($key as $k => $v)
  315. {
  316. $this->row_data[$k] = $v;
  317. }
  318. return;
  319. }
  320. if ($key !== '' && $value !== NULL)
  321. {
  322. $this->row_data[$key] = $value;
  323. }
  324. }
  325. // --------------------------------------------------------------------
  326. /**
  327. * Returns a single result row - custom object version
  328. *
  329. * @param int $n
  330. * @param string $type
  331. * @return object
  332. */
  333. public function custom_row_object($n, $type)
  334. {
  335. isset($this->custom_result_object[$type]) OR $this->custom_result_object($type);
  336. if (count($this->custom_result_object[$type]) === 0)
  337. {
  338. return NULL;
  339. }
  340. if ($n !== $this->current_row && isset($this->custom_result_object[$type][$n]))
  341. {
  342. $this->current_row = $n;
  343. }
  344. return $this->custom_result_object[$type][$this->current_row];
  345. }
  346. // --------------------------------------------------------------------
  347. /**
  348. * Returns a single result row - object version
  349. *
  350. * @param int $n
  351. * @return object
  352. */
  353. public function row_object($n = 0)
  354. {
  355. $result = $this->result_object();
  356. if (count($result) === 0)
  357. {
  358. return NULL;
  359. }
  360. if ($n !== $this->current_row && isset($result[$n]))
  361. {
  362. $this->current_row = $n;
  363. }
  364. return $result[$this->current_row];
  365. }
  366. // --------------------------------------------------------------------
  367. /**
  368. * Returns a single result row - array version
  369. *
  370. * @param int $n
  371. * @return array
  372. */
  373. public function row_array($n = 0)
  374. {
  375. $result = $this->result_array();
  376. if (count($result) === 0)
  377. {
  378. return NULL;
  379. }
  380. if ($n !== $this->current_row && isset($result[$n]))
  381. {
  382. $this->current_row = $n;
  383. }
  384. return $result[$this->current_row];
  385. }
  386. // --------------------------------------------------------------------
  387. /**
  388. * Returns the "first" row
  389. *
  390. * @param string $type
  391. * @return mixed
  392. */
  393. public function first_row($type = 'object')
  394. {
  395. $result = $this->result($type);
  396. return (count($result) === 0) ? NULL : $result[0];
  397. }
  398. // --------------------------------------------------------------------
  399. /**
  400. * Returns the "last" row
  401. *
  402. * @param string $type
  403. * @return mixed
  404. */
  405. public function last_row($type = 'object')
  406. {
  407. $result = $this->result($type);
  408. return (count($result) === 0) ? NULL : $result[count($result) - 1];
  409. }
  410. // --------------------------------------------------------------------
  411. /**
  412. * Returns the "next" row
  413. *
  414. * @param string $type
  415. * @return mixed
  416. */
  417. public function next_row($type = 'object')
  418. {
  419. $result = $this->result($type);
  420. if (count($result) === 0)
  421. {
  422. return NULL;
  423. }
  424. return isset($result[$this->current_row + 1])
  425. ? $result[++$this->current_row]
  426. : NULL;
  427. }
  428. // --------------------------------------------------------------------
  429. /**
  430. * Returns the "previous" row
  431. *
  432. * @param string $type
  433. * @return mixed
  434. */
  435. public function previous_row($type = 'object')
  436. {
  437. $result = $this->result($type);
  438. if (count($result) === 0)
  439. {
  440. return NULL;
  441. }
  442. if (isset($result[$this->current_row - 1]))
  443. {
  444. --$this->current_row;
  445. }
  446. return $result[$this->current_row];
  447. }
  448. // --------------------------------------------------------------------
  449. /**
  450. * Returns an unbuffered row and move pointer to next row
  451. *
  452. * @param string $type 'array', 'object' or a custom class name
  453. * @return mixed
  454. */
  455. public function unbuffered_row($type = 'object')
  456. {
  457. if ($type === 'array')
  458. {
  459. return $this->_fetch_assoc();
  460. }
  461. elseif ($type === 'object')
  462. {
  463. return $this->_fetch_object();
  464. }
  465. return $this->_fetch_object($type);
  466. }
  467. // --------------------------------------------------------------------
  468. /**
  469. * The following methods are normally overloaded by the identically named
  470. * methods in the platform-specific driver -- except when query caching
  471. * is used. When caching is enabled we do not load the other driver.
  472. * These functions are primarily here to prevent undefined function errors
  473. * when a cached result object is in use. They are not otherwise fully
  474. * operational due to the unavailability of the database resource IDs with
  475. * cached results.
  476. */
  477. // --------------------------------------------------------------------
  478. /**
  479. * Number of fields in the result set
  480. *
  481. * Overridden by driver result classes.
  482. *
  483. * @return int
  484. */
  485. public function num_fields()
  486. {
  487. return 0;
  488. }
  489. // --------------------------------------------------------------------
  490. /**
  491. * Fetch Field Names
  492. *
  493. * Generates an array of column names.
  494. *
  495. * Overridden by driver result classes.
  496. *
  497. * @return array
  498. */
  499. public function list_fields()
  500. {
  501. return array();
  502. }
  503. // --------------------------------------------------------------------
  504. /**
  505. * Field data
  506. *
  507. * Generates an array of objects containing field meta-data.
  508. *
  509. * Overridden by driver result classes.
  510. *
  511. * @return array
  512. */
  513. public function field_data()
  514. {
  515. return array();
  516. }
  517. // --------------------------------------------------------------------
  518. /**
  519. * Free the result
  520. *
  521. * Overridden by driver result classes.
  522. *
  523. * @return void
  524. */
  525. public function free_result()
  526. {
  527. $this->result_id = FALSE;
  528. }
  529. // --------------------------------------------------------------------
  530. /**
  531. * Data Seek
  532. *
  533. * Moves the internal pointer to the desired offset. We call
  534. * this internally before fetching results to make sure the
  535. * result set starts at zero.
  536. *
  537. * Overridden by driver result classes.
  538. *
  539. * @param int $n
  540. * @return bool
  541. */
  542. public function data_seek($n = 0)
  543. {
  544. return FALSE;
  545. }
  546. // --------------------------------------------------------------------
  547. /**
  548. * Result - associative array
  549. *
  550. * Returns the result set as an array.
  551. *
  552. * Overridden by driver result classes.
  553. *
  554. * @return array
  555. */
  556. protected function _fetch_assoc()
  557. {
  558. return array();
  559. }
  560. // --------------------------------------------------------------------
  561. /**
  562. * Result - object
  563. *
  564. * Returns the result set as an object.
  565. *
  566. * Overridden by driver result classes.
  567. *
  568. * @param string $class_name
  569. * @return object
  570. */
  571. protected function _fetch_object($class_name = 'stdClass')
  572. {
  573. return new $class_name();
  574. }
  575. }