3 namespace Wikimedia\Rdbms
;
5 use OutOfBoundsException
;
9 * Result wrapper for grabbing data queried from an IDatabase object
11 * Only IDatabase-related classes should construct these. Other code may
12 * use the FakeResultWrapper class for convenience or compatibility shims.
14 * Note that using the Iterator methods in combination with the non-Iterator
15 * IDatabase result iteration functions may cause rows to be skipped or repeated.
17 * By default, this will use the iteration methods of the IDatabase handle if provided.
18 * Subclasses can override methods to make it solely work on the result resource instead.
22 abstract class ResultWrapper
implements IResultWrapper
{
24 * @var int The offset of the row that would be returned by the next call
27 protected $nextPos = 0;
30 * @var int The offset of the current row that would be returned by current()
31 * and may have been previously returned by fetchObject().
33 protected $currentPos = 0;
36 * @var stdClass|array|bool|null The row at $this->currentPos, or null if it has
37 * not yet been retrieved, or false if the current row was past the end.
39 protected $currentRow;
42 * @var string[]|null Cache of field names
47 * Get the number of rows in the result set
52 abstract protected function doNumRows();
55 * Get the next row as a stdClass object, or false if iteration has
56 * proceeded past the end. The offset within the result set is in
60 * @return stdClass|bool
62 abstract protected function doFetchObject();
65 * Get the next row as an array containing the data duplicated, once with
66 * string keys and once with numeric keys, per the PDO::FETCH_BOTH
67 * convention. Or false if iteration has proceeded past the end.
71 abstract protected function doFetchRow();
74 * Modify the current cursor position to the row with the specified offset.
75 * If $pos is out of bounds, the behaviour is undefined.
79 abstract protected function doSeek( $pos );
82 * Free underlying data. It is not necessary to do anything.
84 abstract protected function doFree();
87 * Get the field names in the result set.
91 abstract protected function doGetFieldNames();
93 public function numRows() {
94 return $this->doNumRows();
97 public function count(): int {
98 return $this->doNumRows();
101 public function fetchObject() {
102 $this->currentPos
= $this->nextPos++
;
103 $this->currentRow
= $this->doFetchObject();
104 return $this->currentRow
;
107 public function fetchRow() {
108 $this->currentPos
= $this->nextPos++
;
109 $this->currentRow
= $this->doFetchRow();
110 return $this->currentRow
;
113 public function seek( $pos ): void
{
114 $numRows = $this->numRows();
115 // Allow seeking to zero if there are no results
116 $max = $numRows ?
$numRows - 1 : 0;
117 if ( $pos < 0 ||
$pos > $max ) {
118 throw new OutOfBoundsException( __METHOD__
. ': invalid position' );
121 $this->doSeek( $pos );
123 $this->nextPos
= $pos;
124 $this->currentPos
= $pos;
125 $this->currentRow
= null;
128 public function free() {
130 $this->currentRow
= false;
133 public function rewind(): void
{
137 #[\ReturnTypeWillChange]
138 public function current() {
139 $this->currentRow ??
= $this->fetchObject();
141 return $this->currentRow
;
144 public function key(): int {
145 return $this->currentPos
;
148 public function next(): void
{
149 $this->fetchObject();
152 public function valid(): bool {
153 return $this->currentPos
>= 0
154 && $this->currentPos
< $this->numRows();
157 public function getFieldNames() {
158 $this->fieldNames ??
= $this->doGetFieldNames();
159 return $this->fieldNames
;