2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
18 * Native postgresql recordset.
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');
30 * pgsql specific moodle recordset class
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
{
39 /** @var current row as array.*/
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 */
49 /** @var bool True if there are no more rows to fetch from the cursor */
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;
67 $this->cursorname
= $cursorname;
69 // When there is a cursor, do the initial fetch.
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 = $this->db
->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();
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() {
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
);
97 throw new coding_exception('Unexpected failure when fetching from cursor');
101 public function __destruct() {
105 private function fetch_next() {
106 if (!$this->result
) {
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;
128 foreach ($this->blobs
as $blob) {
129 $row[$blob] = $row[$blob] !== null ?
pg_unescape_bytea($row[$blob]) : null;
136 public function current() {
137 return (object)$this->current
;
140 public function key() {
141 // return first column value as key
142 if (!$this->current
) {
145 $key = reset($this->current
);
149 public function next() {
150 $this->current
= $this->fetch_next();
153 public function valid() {
154 return !empty($this->current
);
157 public function close() {
159 pg_free_result($this->result
);
160 $this->result
= null;
162 $this->current
= null;
165 // If using cursors, close the cursor.
166 if ($this->cursorname
) {
167 $this->db
->close_cursor($this->cursorname
);
168 $this->cursorname
= null;