xref: /plugin/sqlite/helper.php (revision 44685fc6dc9a7b8566e729094d211d9075143f43)
1a1e6784eSAndreas Gohr<?php
2a1e6784eSAndreas Gohr/**
3a1e6784eSAndreas Gohr * DokuWiki Plugin sqlite (Helper Component)
4a1e6784eSAndreas Gohr *
5a1e6784eSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6a1e6784eSAndreas Gohr * @author  Andreas Gohr <gohr@cosmocode.de>
7a1e6784eSAndreas Gohr */
8a1e6784eSAndreas Gohr
9a1e6784eSAndreas Gohr// must be run within Dokuwiki
10a1e6784eSAndreas Gohrif(!defined('DOKU_INC')) die();
11a1e6784eSAndreas Gohr
12a1e6784eSAndreas Gohrif(!defined('DOKU_LF')) define('DOKU_LF', "\n");
13a1e6784eSAndreas Gohrif(!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
14a1e6784eSAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
15a1e6784eSAndreas Gohr
1687fa2c18Sstretchyboyif(!defined('DOKU_EXT_SQLITE')) define('DOKU_EXT_SQLITE', 'sqlite');
1787fa2c18Sstretchyboyif(!defined('DOKU_EXT_PDO')) define('DOKU_EXT_PDO', 'pdo');
1887fa2c18Sstretchyboy
19aa81d781SKlap-inrequire_once(DOKU_PLUGIN.'sqlite/classes/adapter.php');
2087fa2c18Sstretchyboy
21a1e6784eSAndreas Gohrclass helper_plugin_sqlite extends DokuWiki_Plugin {
22aa81d781SKlap-in    var $adapter = null;
23aa81d781SKlap-in
24aa81d781SKlap-in    public function getInfo() {
25a1e6784eSAndreas Gohr        return confToHash(dirname(__FILE__).'plugin.info.txt');
26a1e6784eSAndreas Gohr    }
27a1e6784eSAndreas Gohr
28ca2f2adaSKlap-in    public function getAdapter() {
29ca2f2adaSKlap-in        return $this->adapter;
30ca2f2adaSKlap-in    }
31ca2f2adaSKlap-in
32a1e6784eSAndreas Gohr    /**
33aa81d781SKlap-in     * Keep separate instances for every call to keep database connections
34aa81d781SKlap-in     */
35aa81d781SKlap-in    public function isSingleton() {
36aa81d781SKlap-in        return false;
37aa81d781SKlap-in    }
38aa81d781SKlap-in
39aa81d781SKlap-in    /**
40a1e6784eSAndreas Gohr     * constructor
41a1e6784eSAndreas Gohr     */
42aa81d781SKlap-in    public function helper_plugin_sqlite() {
4387fa2c18Sstretchyboy
4413896259SKlap-in        if(!$this->adapter) {
45aa81d781SKlap-in            if($this->existsPDOSqlite()) {
46aa81d781SKlap-in                require_once(DOKU_PLUGIN.'sqlite/classes/adapter_pdosqlite.php');
47aa81d781SKlap-in                $this->adapter = new helper_plugin_sqlite_adapter_pdosqlite();
48aa81d781SKlap-in            }
49aa81d781SKlap-in        }
50aa81d781SKlap-in
5113896259SKlap-in        if(!$this->adapter) {
52aa81d781SKlap-in            if($this->existsSqlite2()) {
53aa81d781SKlap-in                require_once(DOKU_PLUGIN.'sqlite/classes/adapter_sqlite2.php');
54aa81d781SKlap-in                $this->adapter = new helper_plugin_sqlite_adapter_sqlite2();
55aa81d781SKlap-in            }
56aa81d781SKlap-in        }
57aa81d781SKlap-in
5813896259SKlap-in        if(!$this->adapter) {
59aa81d781SKlap-in            msg('SQLite & PDO SQLite support missing in this PHP install - plugin will not work', -1);
60aa81d781SKlap-in        }
61aa81d781SKlap-in    }
62aa81d781SKlap-in
63aa81d781SKlap-in    /**
64aa81d781SKlap-in     * check availabilty of PHPs sqlite extension (for sqlite2 support)
65aa81d781SKlap-in     */
66aa81d781SKlap-in    public function existsSqlite2() {
67aa81d781SKlap-in        if(!extension_loaded('sqlite')) {
68aa81d781SKlap-in            $prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : '';
69aa81d781SKlap-in            if(function_exists('dl')) @dl($prefix.'sqlite.'.PHP_SHLIB_SUFFIX);
70aa81d781SKlap-in        }
71aa81d781SKlap-in
72aa81d781SKlap-in        return function_exists('sqlite_open');
73aa81d781SKlap-in    }
74aa81d781SKlap-in
75aa81d781SKlap-in    /**
76aa81d781SKlap-in     * check availabilty of PHP PDO sqlite3
77aa81d781SKlap-in     */
78aa81d781SKlap-in    public function existsPDOSqlite() {
7987fa2c18Sstretchyboy        if(!extension_loaded('pdo_sqlite')) {
8087fa2c18Sstretchyboy            $prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : '';
8187fa2c18Sstretchyboy            if(function_exists('dl')) @dl($prefix.'pdo_sqlite.'.PHP_SHLIB_SUFFIX);
8287fa2c18Sstretchyboy        }
8387fa2c18Sstretchyboy
8487fa2c18Sstretchyboy        if(class_exists('pdo')) {
85aa81d781SKlap-in            foreach(PDO::getAvailableDrivers() as $driver) {
86aa81d781SKlap-in                if($driver == 'sqlite') {
87aa81d781SKlap-in                    return true;
8887fa2c18Sstretchyboy                }
8987fa2c18Sstretchyboy            }
907ed6069fSAdrian Lang        }
91aa81d781SKlap-in        return false;
92a1e6784eSAndreas Gohr    }
93a1e6784eSAndreas Gohr
94a1e6784eSAndreas Gohr    /**
95a1e6784eSAndreas Gohr     * Initializes and opens the database
96a1e6784eSAndreas Gohr     *
97a1e6784eSAndreas Gohr     * Needs to be called right after loading this helper plugin
98aa81d781SKlap-in     *
99aa81d781SKlap-in     * @param string $dbname
100aa81d781SKlap-in     * @param string $updatedir - Database update infos
101aa81d781SKlap-in     * @return bool
102a1e6784eSAndreas Gohr     */
103aa81d781SKlap-in    public function init($dbname, $updatedir) {
104a1e6784eSAndreas Gohr
105aa81d781SKlap-in        $init = null; // set by initdb()
106c5e5294cSKlap-in        if(!$this->adapter OR !$this->adapter->initdb($dbname, $init)) return false;
107a1e6784eSAndreas Gohr
108aa81d781SKlap-in        return $this->_updatedb($init, $updatedir);
109a1e6784eSAndreas Gohr    }
110a1e6784eSAndreas Gohr
111a1e6784eSAndreas Gohr    /**
112a1e6784eSAndreas Gohr     * Return the current Database Version
113a1e6784eSAndreas Gohr     */
114aa81d781SKlap-in    private function _currentDBversion() {
115a1e6784eSAndreas Gohr        $sql = "SELECT val FROM opts WHERE opt = 'dbversion';";
116a1e6784eSAndreas Gohr        $res = $this->query($sql);
117a1e6784eSAndreas Gohr        if(!$res) return false;
118a1e6784eSAndreas Gohr        $row = $this->res2row($res, 0);
119a1e6784eSAndreas Gohr        return (int) $row['val'];
120a1e6784eSAndreas Gohr    }
121aa81d781SKlap-in
122a1e6784eSAndreas Gohr    /**
123a1e6784eSAndreas Gohr     * Update the database if needed
124a1e6784eSAndreas Gohr     *
125a1e6784eSAndreas Gohr     * @param bool   $init      - true if this is a new database to initialize
126a1e6784eSAndreas Gohr     * @param string $updatedir - Database update infos
127aa81d781SKlap-in     * @return bool
128a1e6784eSAndreas Gohr     */
12913896259SKlap-in    private function _updatedb($init, $updatedir) {
130a1e6784eSAndreas Gohr        if($init) {
1314d9093b4Sstretchyboy
132a1e6784eSAndreas Gohr            $current = 0;
133a1e6784eSAndreas Gohr        } else {
134a1e6784eSAndreas Gohr            $current = $this->_currentDBversion();
135a1e6784eSAndreas Gohr            if(!$current) {
136aa81d781SKlap-in                msg("SQLite: no DB version found. '".$this->adapter->getDbname()."' DB probably broken.", -1);
137a1e6784eSAndreas Gohr                return false;
138a1e6784eSAndreas Gohr            }
139a1e6784eSAndreas Gohr        }
140a1e6784eSAndreas Gohr
141a1e6784eSAndreas Gohr        // in case of init, add versioning table
142a1e6784eSAndreas Gohr        if($init) {
143a1e6784eSAndreas Gohr            if(!$this->_runupdatefile(dirname(__FILE__).'/db.sql', 0)) {
144aa81d781SKlap-in                msg("SQLite: '".$this->adapter->getDbname()."' database upgrade failed for version ", -1);
145a1e6784eSAndreas Gohr                return false;
146a1e6784eSAndreas Gohr            }
147a1e6784eSAndreas Gohr        }
148a1e6784eSAndreas Gohr
149a1e6784eSAndreas Gohr        $latest = (int) trim(io_readFile($updatedir.'/latest.version'));
150a1e6784eSAndreas Gohr
151a1e6784eSAndreas Gohr        // all up to date?
152a1e6784eSAndreas Gohr        if($current >= $latest) return true;
153a1e6784eSAndreas Gohr        for($i = $current + 1; $i <= $latest; $i++) {
154a1e6784eSAndreas Gohr            $file = sprintf($updatedir.'/update%04d.sql', $i);
155a1e6784eSAndreas Gohr            if(file_exists($file)) {
156a1e6784eSAndreas Gohr                if(!$this->_runupdatefile($file, $i)) {
157aa81d781SKlap-in                    msg("SQLite: '".$this->adapter->getDbname()."' database upgrade failed for version ".$i, -1);
158a1e6784eSAndreas Gohr                    return false;
159a1e6784eSAndreas Gohr                }
160a1e6784eSAndreas Gohr            }
161a1e6784eSAndreas Gohr        }
162a1e6784eSAndreas Gohr        return true;
163a1e6784eSAndreas Gohr    }
164a1e6784eSAndreas Gohr
165a1e6784eSAndreas Gohr    /**
166a1e6784eSAndreas Gohr     * Updates the database structure using the given file to
167a1e6784eSAndreas Gohr     * the given version.
168a1e6784eSAndreas Gohr     */
169aa81d781SKlap-in    private function _runupdatefile($file, $version) {
170a1e6784eSAndreas Gohr        $sql = io_readFile($file, false);
171a1e6784eSAndreas Gohr
172f10ea6c1SKlap-in        $sql = $this->SQLstring2array($sql);
173a1e6784eSAndreas Gohr        array_unshift($sql, 'BEGIN TRANSACTION');
174a1e6784eSAndreas Gohr        array_push($sql, "INSERT OR REPLACE INTO opts (val,opt) VALUES ($version,'dbversion')");
175a1e6784eSAndreas Gohr        array_push($sql, "COMMIT TRANSACTION");
176a1e6784eSAndreas Gohr
177f10ea6c1SKlap-in        if(!$this->doTransaction($sql)) {
178f10ea6c1SKlap-in            return false;
179f10ea6c1SKlap-in        }
180f10ea6c1SKlap-in        return ($version == $this->_currentDBversion());
181f10ea6c1SKlap-in    }
182f10ea6c1SKlap-in
183f10ea6c1SKlap-in    /**
184f10ea6c1SKlap-in     * Split sql queries on semicolons, unless when semicolons are quoted
185f10ea6c1SKlap-in     *
186f10ea6c1SKlap-in     * @param string $sql
187f10ea6c1SKlap-in     * @return array sql queries
188f10ea6c1SKlap-in     */
189f10ea6c1SKlap-in    public function SQLstring2array($sql) {
190f10ea6c1SKlap-in        return preg_split("/;(?=([^']*'[^']*')*[^']*$)/", $sql);
191f10ea6c1SKlap-in    }
192f10ea6c1SKlap-in
193f10ea6c1SKlap-in    /**
194f10ea6c1SKlap-in     * @param array $sql queries without terminating semicolon
195f10ea6c1SKlap-in     * @param bool  $sqlpreparing
196f10ea6c1SKlap-in     * @return bool
197f10ea6c1SKlap-in     */
198f10ea6c1SKlap-in    public function doTransaction($sql, $sqlpreparing = true) {
199a1e6784eSAndreas Gohr        foreach($sql as $s) {
200a1e6784eSAndreas Gohr            $s = preg_replace('!^\s*--.*$!m', '', $s);
201a1e6784eSAndreas Gohr            $s = trim($s);
202a1e6784eSAndreas Gohr            if(!$s) continue;
203fd69a32cSAndreas Gohr
204f10ea6c1SKlap-in            if($sqlpreparing) {
205a1e6784eSAndreas Gohr                $res = $this->query("$s;");
206f10ea6c1SKlap-in            } else {
207f10ea6c1SKlap-in                $res = $this->adapter->executeQuery("$s;");
208f10ea6c1SKlap-in            }
209a1e6784eSAndreas Gohr            if($res === false) {
210f10ea6c1SKlap-in                //TODO check rollback for sqlite PDO
21113896259SKlap-in                if($this->adapter->getName() == DOKU_EXT_SQLITE) {
2121dc19626SKlap-in                    $this->query('ROLLBACK TRANSACTION');
213a1e6784eSAndreas Gohr                }
21405f176edSstretchyboy                return false;
21505f176edSstretchyboy            }
216a1e6784eSAndreas Gohr        }
217f10ea6c1SKlap-in        return true;
218a1e6784eSAndreas Gohr    }
219a1e6784eSAndreas Gohr
220a34ef333SKlap-in    /**
221a34ef333SKlap-in     * Dump db into a file in meta directory
222a34ef333SKlap-in     *
223a34ef333SKlap-in     */
224a34ef333SKlap-in    public function dumpDatabase($dbname, $from = DOKU_EXT_SQLITE) {
225a34ef333SKlap-in        global $conf;
226a34ef333SKlap-in        $adapterDumpDb = null;
227a34ef333SKlap-in        //connect to desired database
228a34ef333SKlap-in        if($this->adapter->getName() == $from) {
229a34ef333SKlap-in            $adapterDumpDb =& $this->adapter;
230a34ef333SKlap-in        } else {
231a34ef333SKlap-in            if($from == DOKU_EXT_SQLITE) {
232a34ef333SKlap-in                //TODO test connecting to sqlite2 database
233a34ef333SKlap-in                if($this->existsSqlite2()) {
234a34ef333SKlap-in                    require_once(DOKU_PLUGIN.'sqlite/classes/adapter_sqlite2.php');
235a34ef333SKlap-in                    $adapterDumpDb = new helper_plugin_sqlite_adapter_sqlite2();
236a34ef333SKlap-in                } else {
237a34ef333SKlap-in                    msg('PHP Sqlite Extension(needed for sqlite2) not available, database "'.hsc($dbname).'" is not dumped to file.');
238a34ef333SKlap-in                    return false;
239a34ef333SKlap-in                }
240a34ef333SKlap-in            }
241a34ef333SKlap-in        }
242a34ef333SKlap-in        if($adapterDumpDb === null) {
243a34ef333SKlap-in            msg('No adapter loaded');
244a34ef333SKlap-in            return false;
245a34ef333SKlap-in        }
246a34ef333SKlap-in        $init = false;
247a34ef333SKlap-in        if(!$adapterDumpDb->initdb($dbname, $init)) {
248a34ef333SKlap-in            msg('Opening database fails.', -1);
249a34ef333SKlap-in            return false;
250a34ef333SKlap-in        }
251f10ea6c1SKlap-in
252a34ef333SKlap-in        $res    = $adapterDumpDb->query(array("SELECT name,sql FROM sqlite_master WHERE type='table'"));
253a34ef333SKlap-in        $tables = $adapterDumpDb->res2arr($res);
254a34ef333SKlap-in
255a34ef333SKlap-in        $filename = $conf['metadir'].'/dumpfile_'.$dbname.'.sql';
256a34ef333SKlap-in        if($fp = fopen($filename, 'w')) {
257a34ef333SKlap-in
258a34ef333SKlap-in            fwrite($fp, 'BEGIN TRANSACTION;'."\n");
259a34ef333SKlap-in
260a34ef333SKlap-in            foreach($tables as $table) {
261a34ef333SKlap-in
262a34ef333SKlap-in                fwrite($fp, $table['sql'].";\n");
263a34ef333SKlap-in
264a34ef333SKlap-in                $sql = "SELECT * FROM ".$table['name'];
265a34ef333SKlap-in                $res = $adapterDumpDb->query(array($sql));
266a34ef333SKlap-in
267a34ef333SKlap-in                while($row = $adapterDumpDb->res_fetch_array($res)) {
268a34ef333SKlap-in
269a34ef333SKlap-in                    $line = 'INSERT INTO '.$table['name'].' VALUES(';
270a34ef333SKlap-in                    foreach($row as $no_entry => $entry) {
271a34ef333SKlap-in                        if($no_entry !== 0) {
272a34ef333SKlap-in                            $line .= ',';
273a34ef333SKlap-in                        }
274a34ef333SKlap-in
275a34ef333SKlap-in                        if(is_null($entry)) {
276a34ef333SKlap-in                            $line .= 'NULL';
277a34ef333SKlap-in                        } elseif(!is_numeric($entry)) {
278a34ef333SKlap-in                            $line .= $adapterDumpDb->quote_string($entry);
279a34ef333SKlap-in                        } else {
280a34ef333SKlap-in                            //TODO depending on locale extra leading zeros are truncated e.g 1.300 (thousand three hunderd)-> 1.3
281a34ef333SKlap-in                            $line .= $entry;
282a34ef333SKlap-in                        }
283a34ef333SKlap-in                    }
284a34ef333SKlap-in                    $line .= ');'."\n";
285a34ef333SKlap-in
286a34ef333SKlap-in                    fwrite($fp, $line);
287a34ef333SKlap-in                }
288a34ef333SKlap-in            }
289a34ef333SKlap-in
290a34ef333SKlap-in            $res     = $adapterDumpDb->query(array("SELECT name,sql FROM sqlite_master WHERE type='index'"));
291a34ef333SKlap-in            $indexes = $adapterDumpDb->res2arr($res);
292a34ef333SKlap-in            foreach($indexes as $index) {
293a34ef333SKlap-in                fwrite($fp, $index['sql'].";\n");
294a34ef333SKlap-in            }
295a34ef333SKlap-in
296a34ef333SKlap-in            fwrite($fp, 'COMMIT;'."\n");
297a34ef333SKlap-in
298a34ef333SKlap-in            fclose($fp);
299a34ef333SKlap-in            return $filename;
300a34ef333SKlap-in        } else {
301a34ef333SKlap-in            msg('Dumping "'.hsc($dbname).'" has failed. Could not open '.$filename);
302a34ef333SKlap-in            return false;
303a34ef333SKlap-in        }
304a34ef333SKlap-in    }
305a34ef333SKlap-in
306a34ef333SKlap-in    /**
307a34ef333SKlap-in     * Read $dumpfile and try to add it to database.
308a34ef333SKlap-in     * A existing database is backuped first as e.g. dbname.copy2.sqlite3
309a34ef333SKlap-in     *
310a34ef333SKlap-in     * @param string $dbname
311a34ef333SKlap-in     * @param string $dumpfile
312a34ef333SKlap-in     * @return bool true on succes
313a34ef333SKlap-in     */
314a34ef333SKlap-in    public function fillDatabaseFromDump($dbname, $dumpfile) {
315a34ef333SKlap-in        global $conf;
316a34ef333SKlap-in        //backup existing stuff
317a34ef333SKlap-in        $dbf    = $conf['metadir'].'/'.$dbname;
318a34ef333SKlap-in        $dbext  = $this->adapter->getFileextension();
319a34ef333SKlap-in        $dbfile = $dbf.$dbext;
320a34ef333SKlap-in        if(@file_exists($dbfile)) {
321a34ef333SKlap-in
322a34ef333SKlap-in            $i            = 0;
323a34ef333SKlap-in            $backupdbfile = $dbfile;
324a34ef333SKlap-in            do {
325a34ef333SKlap-in                $i++;
326a34ef333SKlap-in                $backupdbfile = $dbf.".copy$i".$dbext;
327a34ef333SKlap-in            } while(@file_exists($backupdbfile));
328a34ef333SKlap-in
329a34ef333SKlap-in            io_rename($dbfile, $backupdbfile);
330a34ef333SKlap-in        }
331a34ef333SKlap-in
332a34ef333SKlap-in        $init = false;
333a34ef333SKlap-in        if(!$this->adapter->initdb($dbname, $init, $sqliteupgrade = true)) {
334a34ef333SKlap-in            msg('Initialize db fails');
335a34ef333SKlap-in            return false;
336a34ef333SKlap-in        }
337a34ef333SKlap-in
338a34ef333SKlap-in        $sql = io_readFile($dumpfile, false);
339a34ef333SKlap-in        $sql = $this->SQLstring2array($sql);
340a34ef333SKlap-in
341a34ef333SKlap-in        //skip preparing, because it interprets question marks as placeholders.
342a34ef333SKlap-in        return $this->doTransaction($sql, $sqlpreparing = false);
343a34ef333SKlap-in    }
344f10ea6c1SKlap-in
345a1e6784eSAndreas Gohr    /**
3463ae3f79eSKlap-in     * Registers a User Defined Function for use in SQL statements
3473ae3f79eSKlap-in     */
348aa81d781SKlap-in    public function create_function($function_name, $callback, $num_args) {
349aa81d781SKlap-in        $this->adapter->create_function($function_name, $callback, $num_args);
3503ae3f79eSKlap-in    }
3513ae3f79eSKlap-in
3523ae3f79eSKlap-in    /**
353a1e6784eSAndreas Gohr     * Execute a query with the given parameters.
354a1e6784eSAndreas Gohr     *
355a1e6784eSAndreas Gohr     * Takes care of escaping
356a1e6784eSAndreas Gohr     *
357aa81d781SKlap-in     * @internal param string $sql - the statement
358aa81d781SKlap-in     * @internal param $arguments ...
359aa81d781SKlap-in     * @return bool|\SQLiteResult
360a1e6784eSAndreas Gohr     */
361aa81d781SKlap-in    public function query() {
362a1e6784eSAndreas Gohr        // get function arguments
363a1e6784eSAndreas Gohr        $args = func_get_args();
364a1e6784eSAndreas Gohr
365aa81d781SKlap-in        return $this->adapter->query($args);
36687fa2c18Sstretchyboy    }
367a1e6784eSAndreas Gohr
368a1e6784eSAndreas Gohr    /**
369a1e6784eSAndreas Gohr     * Join the given values and quote them for SQL insertion
370a1e6784eSAndreas Gohr     */
371aa81d781SKlap-in    public function quote_and_join($vals, $sep = ',') {
372aa81d781SKlap-in        return $this->adapter->quote_and_join($vals, $sep);
373a1e6784eSAndreas Gohr    }
374a1e6784eSAndreas Gohr
375a1e6784eSAndreas Gohr    /**
376a1e6784eSAndreas Gohr     * Run sqlite_escape_string() on the given string and surround it
377a1e6784eSAndreas Gohr     * with quotes
378a1e6784eSAndreas Gohr     */
379aa81d781SKlap-in    public function quote_string($string) {
380aa81d781SKlap-in        return $this->adapter->quote_string($string);
381a1e6784eSAndreas Gohr    }
382a1e6784eSAndreas Gohr
383b5b947d7SAndreas Gohr    /**
384fee3b689Sstretchyboy     * Escape string for sql
385fee3b689Sstretchyboy     */
386aa81d781SKlap-in    public function escape_string($str) {
387aa81d781SKlap-in        return $this->adapter->escape_string($str);
388ff97cc8fSstretchyboy    }
389ff97cc8fSstretchyboy
390ff97cc8fSstretchyboy    /**
391aa81d781SKlap-in     * Returns a complete result set as array
392ff97cc8fSstretchyboy     */
393ef383ac5SKlap-in    public function res2arr($res, $assoc = true) {
394ef383ac5SKlap-in        return $this->adapter->res2arr($res, $assoc);
395b5b947d7SAndreas Gohr    }
396b5b947d7SAndreas Gohr
397b5b947d7SAndreas Gohr    /**
398aa81d781SKlap-in     * Return the wanted row from a given result set as
399aa81d781SKlap-in     * associative array
400b5b947d7SAndreas Gohr     */
401aa81d781SKlap-in    public function res2row($res, $rownum = 0) {
402aa81d781SKlap-in        return $this->adapter->res2row($res, $rownum);
403b5b947d7SAndreas Gohr    }
404b5b947d7SAndreas Gohr
405e7112ccbSAdrian Lang    /**
406*44685fc6SKlap-in     * Return the first value from the next row.
407e7112ccbSAdrian Lang     */
408aa81d781SKlap-in    public function res2single($res) {
409aa81d781SKlap-in        return $this->adapter->res2single($res);
410e7112ccbSAdrian Lang    }
411fee3b689Sstretchyboy
412fee3b689Sstretchyboy    /**
413fee3b689Sstretchyboy     * fetch the next row as zero indexed array
414fee3b689Sstretchyboy     */
415aa81d781SKlap-in    public function res_fetch_array($res) {
416aa81d781SKlap-in        return $this->adapter->res_fetch_array($res);
41787fa2c18Sstretchyboy    }
418fee3b689Sstretchyboy
419fee3b689Sstretchyboy    /**
420fee3b689Sstretchyboy     * fetch the next row as assocative array
421fee3b689Sstretchyboy     */
422aa81d781SKlap-in    public function res_fetch_assoc($res) {
423aa81d781SKlap-in        return $this->adapter->res_fetch_assoc($res);
424fee3b689Sstretchyboy    }
425fee3b689Sstretchyboy
426fee3b689Sstretchyboy    /**
42778977d74SKlap-in     * Count the number of records in result
4283157674bSAndreas Gohr     *
429db58e525SKlap-in     * This function is really inperformant in PDO and should be avoided!
430fee3b689Sstretchyboy     */
431aa81d781SKlap-in    public function res2count($res) {
432aa81d781SKlap-in        return $this->adapter->res2count($res);
433fee3b689Sstretchyboy    }
43424a03f6cSstretchyboy
43524a03f6cSstretchyboy    /**
43624a03f6cSstretchyboy     * Count the number of records changed last time
43724a03f6cSstretchyboy     */
438*44685fc6SKlap-in    public function countChanges($res) {
439*44685fc6SKlap-in        return $this->adapter->countChanges($res);
440a1e6784eSAndreas Gohr    }
441a1e6784eSAndreas Gohr
442aa81d781SKlap-in}
443