ResultWrapper.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. namespace Wikimedia\Rdbms;
  3. use stdClass;
  4. use RuntimeException;
  5. use InvalidArgumentException;
  6. /**
  7. * Result wrapper for grabbing data queried from an IDatabase object
  8. *
  9. * Only IDatabase-related classes should construct these. Other code may
  10. * use the FakeResultWrapper class for convenience or compatibility shims.
  11. *
  12. * Note that using the Iterator methods in combination with the non-Iterator
  13. * IDatabase 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. *
  18. * @ingroup Database
  19. */
  20. class ResultWrapper implements IResultWrapper {
  21. /** @var IDatabase */
  22. protected $db;
  23. /** @var mixed|null RDBMS driver-specific result resource */
  24. protected $result;
  25. /** @var int */
  26. protected $pos = 0;
  27. /** @var stdClass|bool|null */
  28. protected $currentRow;
  29. /**
  30. * @param IDatabase $db Database handle that the result comes from
  31. * @param self|mixed $result RDBMS driver-specific result resource
  32. */
  33. public function __construct( IDatabase $db, $result ) {
  34. $this->db = $db;
  35. if ( $result instanceof self ) {
  36. $this->result = $result->result;
  37. } elseif ( $result !== null ) {
  38. $this->result = $result;
  39. } else {
  40. throw new InvalidArgumentException( "Null result resource provided" );
  41. }
  42. }
  43. /**
  44. * Get the underlying RDBMS driver-specific result resource
  45. *
  46. * The result resource field should not be accessed from non-Database related classes.
  47. * It is database class specific and is stored here to associate iterators with queries.
  48. *
  49. * @param self|mixed &$res
  50. * @return mixed
  51. * @since 1.34
  52. */
  53. public static function &unwrap( &$res ) {
  54. if ( $res instanceof self ) {
  55. if ( $res->result === null ) {
  56. throw new RuntimeException( "The result resource was already freed" );
  57. }
  58. return $res->result;
  59. } else {
  60. return $res;
  61. }
  62. }
  63. public function numRows() {
  64. return $this->getDB()->numRows( $this );
  65. }
  66. public function fetchObject() {
  67. return $this->getDB()->fetchObject( $this );
  68. }
  69. public function fetchRow() {
  70. return $this->getDB()->fetchRow( $this );
  71. }
  72. public function seek( $pos ) {
  73. $this->getDB()->dataSeek( $this, $pos );
  74. $this->pos = $pos;
  75. }
  76. public function free() {
  77. $this->db = null;
  78. $this->result = null;
  79. }
  80. function rewind() {
  81. if ( $this->numRows() ) {
  82. $this->getDB()->dataSeek( $this, 0 );
  83. }
  84. $this->pos = 0;
  85. $this->currentRow = null;
  86. }
  87. function current() {
  88. if ( $this->currentRow === null ) {
  89. $this->currentRow = $this->fetchObject();
  90. }
  91. return $this->currentRow;
  92. }
  93. function key() {
  94. return $this->pos;
  95. }
  96. function next() {
  97. $this->pos++;
  98. $this->currentRow = $this->fetchObject();
  99. return $this->currentRow;
  100. }
  101. function valid() {
  102. return $this->current() !== false;
  103. }
  104. /**
  105. * @return IDatabase
  106. * @throws RuntimeException
  107. */
  108. private function getDB() {
  109. if ( !$this->db ) {
  110. throw new RuntimeException( "Database handle was already freed" );
  111. }
  112. return $this->db;
  113. }
  114. }
  115. /**
  116. * @deprecated since 1.29
  117. */
  118. class_alias( ResultWrapper::class, 'ResultWrapper' );