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