Merge branch 'MDL-64012' of https://github.com/timhunt/moodle
[moodle.git] / lib / dml / pgsql_native_moodle_recordset.php
bloba6eed21d0304828f13cdb5b5b48fb728f11feb99
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Native postgresql recordset.
20 * @package core_dml
21 * @copyright 2008 Petr Skoda (http://skodak.org)
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 require_once(__DIR__.'/moodle_recordset.php');
29 /**
30 * pgsql specific moodle recordset class
32 * @package core_dml
33 * @copyright 2008 Petr Skoda (http://skodak.org)
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class pgsql_native_moodle_recordset extends moodle_recordset {
38 protected $result;
39 /** @var current row as array.*/
40 protected $current;
41 protected $blobs = array();
43 /** @var string Name of cursor or '' if none */
44 protected $cursorname;
46 /** @var pgsql_native_moodle_database Postgres database resource */
47 protected $db;
49 /** @var bool True if there are no more rows to fetch from the cursor */
50 protected $lastbatch;
52 /**
53 * Build a new recordset to iterate over.
55 * When using cursors, $result will be null initially.
57 * @param resource|null $result A pg_query() result object to create a recordset from.
58 * @param pgsql_native_moodle_database $db Database object (only required when using cursors)
59 * @param string $cursorname Name of cursor or '' if none
61 public function __construct($result, pgsql_native_moodle_database $db = null, $cursorname = '') {
62 if ($cursorname && !$db) {
63 throw new coding_exception('When specifying a cursor, $db is required');
65 $this->result = $result;
66 $this->db = $db;
67 $this->cursorname = $cursorname;
69 // When there is a cursor, do the initial fetch.
70 if ($cursorname) {
71 $this->fetch_cursor_block();
74 // Find out if there are any blobs.
75 $numfields = pg_num_fields($this->result);
76 for ($i = 0; $i < $numfields; $i++) {
77 $type = pg_field_type($this->result, $i);
78 if ($type == 'bytea') {
79 $this->blobs[] = pg_field_name($this->result, $i);
83 $this->current = $this->fetch_next();
86 /**
87 * Fetches the next block of data when using cursors.
89 * @throws coding_exception If you call this when the fetch buffer wasn't freed yet
91 protected function fetch_cursor_block() {
92 if ($this->result) {
93 throw new coding_exception('Unexpected non-empty result when fetching from cursor');
95 list($this->result, $this->lastbatch) = $this->db->fetch_from_cursor($this->cursorname);
96 if (!$this->result) {
97 throw new coding_exception('Unexpected failure when fetching from cursor');
101 public function __destruct() {
102 $this->close();
105 private function fetch_next() {
106 if (!$this->result) {
107 return false;
109 if (!$row = pg_fetch_assoc($this->result)) {
110 // There are no more rows in this result.
111 pg_free_result($this->result);
112 $this->result = null;
114 // If using a cursor, can we fetch the next block?
115 if ($this->cursorname && !$this->lastbatch) {
116 $this->fetch_cursor_block();
117 if (!$row = pg_fetch_assoc($this->result)) {
118 pg_free_result($this->result);
119 $this->result = null;
120 return false;
122 } else {
123 return false;
127 if ($this->blobs) {
128 foreach ($this->blobs as $blob) {
129 $row[$blob] = $row[$blob] !== null ? pg_unescape_bytea($row[$blob]) : null;
133 return $row;
136 public function current() {
137 return (object)$this->current;
140 public function key() {
141 // return first column value as key
142 if (!$this->current) {
143 return false;
145 $key = reset($this->current);
146 return $key;
149 public function next() {
150 $this->current = $this->fetch_next();
153 public function valid() {
154 return !empty($this->current);
157 public function close() {
158 if ($this->result) {
159 pg_free_result($this->result);
160 $this->result = null;
162 $this->current = null;
163 $this->blobs = null;
165 // If using cursors, close the cursor.
166 if ($this->cursorname) {
167 $this->db->close_cursor($this->cursorname);
168 $this->cursorname = null;