Merge "Handle missing namespace prefix in XML dumps more gracefully"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / resultwrapper / ResultWrapper.php
1 <?php
2
3 namespace Wikimedia\Rdbms;
4
5 use IDatabase;
6 use stdClass;
7 use RuntimeException;
8
9 /**
10 * Result wrapper for grabbing data queried from an IDatabase object
11 *
12 * Note that using the Iterator methods in combination with the non-Iterator
13 * DB result iteration functions may cause rows to be skipped or repeated.
14 *
15 * By default, this will use the iteration methods of the IDatabase handle if provided.
16 * Subclasses can override methods to make it solely work on the result resource instead.
17 * If no database is provided, and the subclass does not override the DB iteration methods,
18 * then a RuntimeException will be thrown when iteration is attempted.
19 *
20 * The result resource field should not be accessed from non-Database related classes.
21 * It is database class specific and is stored here to associate iterators with queries.
22 *
23 * @ingroup Database
24 */
25 class ResultWrapper implements IResultWrapper {
26 /** @var resource|array|null Optional underlying result handle for subclass usage */
27 public $result;
28
29 /** @var IDatabase|null */
30 protected $db;
31
32 /** @var int */
33 protected $pos = 0;
34 /** @var stdClass|null */
35 protected $currentRow = null;
36
37 /**
38 * Create a row iterator from a result resource and an optional Database object
39 *
40 * Only Database-related classes should construct ResultWrapper. Other code may
41 * use the FakeResultWrapper subclass for convenience or compatibility shims, however.
42 *
43 * @param IDatabase|null $db Optional database handle
44 * @param ResultWrapper|array|resource $result Optional underlying result handle
45 */
46 public function __construct( IDatabase $db = null, $result ) {
47 $this->db = $db;
48 if ( $result instanceof ResultWrapper ) {
49 $this->result = $result->result;
50 } else {
51 $this->result = $result;
52 }
53 }
54
55 public function numRows() {
56 return $this->getDB()->numRows( $this );
57 }
58
59 public function fetchObject() {
60 return $this->getDB()->fetchObject( $this );
61 }
62
63 public function fetchRow() {
64 return $this->getDB()->fetchRow( $this );
65 }
66
67 public function seek( $row ) {
68 $this->getDB()->dataSeek( $this, $row );
69 }
70
71 public function free() {
72 if ( $this->db ) {
73 $this->db->freeResult( $this );
74 $this->db = null;
75 }
76 $this->result = null;
77 }
78
79 /**
80 * @return IDatabase
81 * @throws RuntimeException
82 */
83 private function getDB() {
84 if ( !$this->db ) {
85 throw new RuntimeException( static::class . ' needs a DB handle for iteration.' );
86 }
87
88 return $this->db;
89 }
90
91 function rewind() {
92 if ( $this->numRows() ) {
93 $this->getDB()->dataSeek( $this, 0 );
94 }
95 $this->pos = 0;
96 $this->currentRow = null;
97 }
98
99 function current() {
100 if ( is_null( $this->currentRow ) ) {
101 $this->next();
102 }
103
104 return $this->currentRow;
105 }
106
107 function key() {
108 return $this->pos;
109 }
110
111 function next() {
112 $this->pos++;
113 $this->currentRow = $this->fetchObject();
114
115 return $this->currentRow;
116 }
117
118 function valid() {
119 return $this->current() !== false;
120 }
121 }
122
123 class_alias( ResultWrapper::class, 'ResultWrapper' );