Merge "maintenance: Script to rename titles for Unicode uppercasing changes"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / resultwrapper / ResultWrapper.php
1 <?php
2
3 namespace Wikimedia\Rdbms;
4
5 use stdClass;
6 use RuntimeException;
7 use InvalidArgumentException;
8
9 /**
10 * Result wrapper for grabbing data queried from an IDatabase object
11 *
12 * Only IDatabase-related classes should construct these. Other code may
13 * use the FakeResultWrapper class for convenience or compatibility shims.
14 *
15 * Note that using the Iterator methods in combination with the non-Iterator
16 * IDatabase result iteration functions may cause rows to be skipped or repeated.
17 *
18 * By default, this will use the iteration methods of the IDatabase handle if provided.
19 * Subclasses can override methods to make it solely work on the result resource instead.
20 *
21 * @ingroup Database
22 */
23 class ResultWrapper implements IResultWrapper {
24 /** @var IDatabase */
25 protected $db;
26 /** @var mixed|null RDBMS driver-specific result resource */
27 protected $result;
28
29 /** @var int */
30 protected $pos = 0;
31 /** @var stdClass|bool|null */
32 protected $currentRow;
33
34 /**
35 * @param IDatabase $db Database handle that the result comes from
36 * @param self|mixed $result RDBMS driver-specific result resource
37 */
38 public function __construct( IDatabase $db, $result ) {
39 $this->db = $db;
40 if ( $result instanceof self ) {
41 $this->result = $result->result;
42 } elseif ( $result !== null ) {
43 $this->result = $result;
44 } else {
45 throw new InvalidArgumentException( "Null result resource provided" );
46 }
47 }
48
49 /**
50 * Get the underlying RDBMS driver-specific result resource
51 *
52 * The result resource field should not be accessed from non-Database related classes.
53 * It is database class specific and is stored here to associate iterators with queries.
54 *
55 * @param self|mixed &$res
56 * @return mixed
57 * @since 1.34
58 */
59 public static function &unwrap( &$res ) {
60 if ( $res instanceof self ) {
61 if ( $res->result === null ) {
62 throw new RuntimeException( "The result resource was already freed" );
63 }
64
65 return $res->result;
66 } else {
67 return $res;
68 }
69 }
70
71 public function numRows() {
72 return $this->getDB()->numRows( $this );
73 }
74
75 public function fetchObject() {
76 return $this->getDB()->fetchObject( $this );
77 }
78
79 public function fetchRow() {
80 return $this->getDB()->fetchRow( $this );
81 }
82
83 public function seek( $pos ) {
84 $this->getDB()->dataSeek( $this, $pos );
85 $this->pos = $pos;
86 }
87
88 public function free() {
89 $this->db = null;
90 $this->result = null;
91 }
92
93 function rewind() {
94 if ( $this->numRows() ) {
95 $this->getDB()->dataSeek( $this, 0 );
96 }
97 $this->pos = 0;
98 $this->currentRow = null;
99 }
100
101 function current() {
102 if ( $this->currentRow === null ) {
103 $this->currentRow = $this->fetchObject();
104 }
105
106 return $this->currentRow;
107 }
108
109 function key() {
110 return $this->pos;
111 }
112
113 function next() {
114 $this->pos++;
115 $this->currentRow = $this->fetchObject();
116
117 return $this->currentRow;
118 }
119
120 function valid() {
121 return $this->current() !== false;
122 }
123
124 /**
125 * @return IDatabase
126 * @throws RuntimeException
127 */
128 private function getDB() {
129 if ( !$this->db ) {
130 throw new RuntimeException( "Database handle was already freed" );
131 }
132
133 return $this->db;
134 }
135 }
136
137 /**
138 * @deprecated since 1.29
139 */
140 class_alias( ResultWrapper::class, 'ResultWrapper' );