xref: /plugin/sqlite/helper.php (revision 6c7ee3f2248930bb549b8d628e57c2ff3309ada5)
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
1287fa2c18Sstretchyboyif(!defined('DOKU_EXT_SQLITE')) define('DOKU_EXT_SQLITE', 'sqlite');
1387fa2c18Sstretchyboyif(!defined('DOKU_EXT_PDO')) define('DOKU_EXT_PDO', 'pdo');
14c137e95fSAndreas Gohrif(!defined('DOKU_EXT_NULL')) define('DOKU_EXT_NULL', 'null');
1587fa2c18Sstretchyboy
16aa81d781SKlap-inrequire_once(DOKU_PLUGIN.'sqlite/classes/adapter.php');
1787fa2c18Sstretchyboy
183e9ac593SGerrit Uitslag/**
193e9ac593SGerrit Uitslag * Class helper_plugin_sqlite
203e9ac593SGerrit Uitslag */
21a1e6784eSAndreas Gohrclass helper_plugin_sqlite extends DokuWiki_Plugin {
224b4b2db0SGerrit Uitslag    /** @var helper_plugin_sqlite_adapter_pdosqlite|helper_plugin_sqlite_adapter|\helper_plugin_sqlite_adapter_sqlite2|null  */
23*6c7ee3f2SAndreas Gohr    protected $adapter = null;
24aa81d781SKlap-in
253e9ac593SGerrit Uitslag    /**
26*6c7ee3f2SAndreas Gohr     * @return helper_plugin_sqlite_adapter_pdosqlite|helper_plugin_sqlite_adapter|\helper_plugin_sqlite_adapter_sqlite2|null
273e9ac593SGerrit Uitslag     */
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) {
45b0653a7eSAndreas Gohr            if($this->existsPDOSqlite() && empty($_ENV['SQLITE_SKIP_PDO'])) {
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) {
104aa81d781SKlap-in        $init = null; // set by initdb()
105c137e95fSAndreas Gohr        if( !$this->adapter or !$this->adapter->initdb($dbname, $init) ){
106c137e95fSAndreas Gohr            require_once(DOKU_PLUGIN.'sqlite/classes/adapter_null.php');
107c137e95fSAndreas Gohr            $this->adapter = new helper_plugin_sqlite_adapter_null();
108c137e95fSAndreas Gohr            return false;
109c137e95fSAndreas Gohr        }
110a1e6784eSAndreas Gohr
111a4680e7bSGerrit Uitslag        $this->create_function('GETACCESSLEVEL', array($this, '_getAccessLevel'), 1);
112a4680e7bSGerrit Uitslag
113aa81d781SKlap-in        return $this->_updatedb($init, $updatedir);
114a1e6784eSAndreas Gohr    }
115a1e6784eSAndreas Gohr
116a1e6784eSAndreas Gohr    /**
117a1e6784eSAndreas Gohr     * Return the current Database Version
118a1e6784eSAndreas Gohr     */
119aa81d781SKlap-in    private function _currentDBversion() {
120a1e6784eSAndreas Gohr        $sql = "SELECT val FROM opts WHERE opt = 'dbversion';";
121a1e6784eSAndreas Gohr        $res = $this->query($sql);
122a1e6784eSAndreas Gohr        if(!$res) return false;
123a1e6784eSAndreas Gohr        $row = $this->res2row($res, 0);
124a1e6784eSAndreas Gohr        return (int) $row['val'];
125a1e6784eSAndreas Gohr    }
126aa81d781SKlap-in
127a1e6784eSAndreas Gohr    /**
128a1e6784eSAndreas Gohr     * Update the database if needed
129a1e6784eSAndreas Gohr     *
130a1e6784eSAndreas Gohr     * @param bool   $init      - true if this is a new database to initialize
131a1e6784eSAndreas Gohr     * @param string $updatedir - Database update infos
132aa81d781SKlap-in     * @return bool
133a1e6784eSAndreas Gohr     */
13413896259SKlap-in    private function _updatedb($init, $updatedir) {
135a1e6784eSAndreas Gohr        if($init) {
1364d9093b4Sstretchyboy
137a1e6784eSAndreas Gohr            $current = 0;
138a1e6784eSAndreas Gohr        } else {
139a1e6784eSAndreas Gohr            $current = $this->_currentDBversion();
140a1e6784eSAndreas Gohr            if(!$current) {
141aa81d781SKlap-in                msg("SQLite: no DB version found. '".$this->adapter->getDbname()."' DB probably broken.", -1);
142a1e6784eSAndreas Gohr                return false;
143a1e6784eSAndreas Gohr            }
144a1e6784eSAndreas Gohr        }
145a1e6784eSAndreas Gohr
146a1e6784eSAndreas Gohr        // in case of init, add versioning table
147a1e6784eSAndreas Gohr        if($init) {
148a1e6784eSAndreas Gohr            if(!$this->_runupdatefile(dirname(__FILE__).'/db.sql', 0)) {
149aa81d781SKlap-in                msg("SQLite: '".$this->adapter->getDbname()."' database upgrade failed for version ", -1);
150a1e6784eSAndreas Gohr                return false;
151a1e6784eSAndreas Gohr            }
152a1e6784eSAndreas Gohr        }
153a1e6784eSAndreas Gohr
154a1e6784eSAndreas Gohr        $latest = (int) trim(io_readFile($updatedir.'/latest.version'));
155a1e6784eSAndreas Gohr
156a1e6784eSAndreas Gohr        // all up to date?
157a1e6784eSAndreas Gohr        if($current >= $latest) return true;
158a1e6784eSAndreas Gohr        for($i = $current + 1; $i <= $latest; $i++) {
159a1e6784eSAndreas Gohr            $file = sprintf($updatedir.'/update%04d.sql', $i);
160a1e6784eSAndreas Gohr            if(file_exists($file)) {
161a1e6784eSAndreas Gohr                if(!$this->_runupdatefile($file, $i)) {
162aa81d781SKlap-in                    msg("SQLite: '".$this->adapter->getDbname()."' database upgrade failed for version ".$i, -1);
163a1e6784eSAndreas Gohr                    return false;
164a1e6784eSAndreas Gohr                }
165*6c7ee3f2SAndreas Gohr            } else {
166*6c7ee3f2SAndreas Gohr                msg("SQLite: update file $file not found, skipped.", -1);
167a1e6784eSAndreas Gohr            }
168a1e6784eSAndreas Gohr        }
169a1e6784eSAndreas Gohr        return true;
170a1e6784eSAndreas Gohr    }
171a1e6784eSAndreas Gohr
172a1e6784eSAndreas Gohr    /**
173a1e6784eSAndreas Gohr     * Updates the database structure using the given file to
174a1e6784eSAndreas Gohr     * the given version.
175a1e6784eSAndreas Gohr     */
176aa81d781SKlap-in    private function _runupdatefile($file, $version) {
177*6c7ee3f2SAndreas Gohr        if(!file_exists($file)) {
178*6c7ee3f2SAndreas Gohr            msg("SQLite: Failed to find DB update file $file");
179*6c7ee3f2SAndreas Gohr            return false;
180*6c7ee3f2SAndreas Gohr        }
181a1e6784eSAndreas Gohr        $sql = io_readFile($file, false);
182a1e6784eSAndreas Gohr
183f10ea6c1SKlap-in        $sql = $this->SQLstring2array($sql);
184a1e6784eSAndreas Gohr        array_unshift($sql, 'BEGIN TRANSACTION');
185a1e6784eSAndreas Gohr        array_push($sql, "INSERT OR REPLACE INTO opts (val,opt) VALUES ($version,'dbversion')");
186a1e6784eSAndreas Gohr        array_push($sql, "COMMIT TRANSACTION");
187a1e6784eSAndreas Gohr
188f10ea6c1SKlap-in        if(!$this->doTransaction($sql)) {
189f10ea6c1SKlap-in            return false;
190f10ea6c1SKlap-in        }
191f10ea6c1SKlap-in        return ($version == $this->_currentDBversion());
192f10ea6c1SKlap-in    }
193f10ea6c1SKlap-in
194f10ea6c1SKlap-in    /**
195a4680e7bSGerrit Uitslag     * Callback checks the permissions for the current user
196a4680e7bSGerrit Uitslag     *
197a4680e7bSGerrit Uitslag     * This function is registered as a SQL function named GETACCESSLEVEL
198a4680e7bSGerrit Uitslag     *
199a4680e7bSGerrit Uitslag     * @param  string $pageid page ID (needs to be resolved and cleaned)
200a4680e7bSGerrit Uitslag     * @return int permission level
201a4680e7bSGerrit Uitslag     */
202a4680e7bSGerrit Uitslag    public function _getAccessLevel($pageid) {
203a4680e7bSGerrit Uitslag        static $aclcache = array();
204a4680e7bSGerrit Uitslag
205a4680e7bSGerrit Uitslag        if(isset($aclcache[$pageid])) {
206a4680e7bSGerrit Uitslag            return $aclcache[$pageid];
207a4680e7bSGerrit Uitslag        }
208a4680e7bSGerrit Uitslag
209a4680e7bSGerrit Uitslag        if(isHiddenPage($pageid)) {
210a4680e7bSGerrit Uitslag            $acl = AUTH_NONE;
211a4680e7bSGerrit Uitslag        } else {
212a4680e7bSGerrit Uitslag            $acl = auth_quickaclcheck($pageid);
213a4680e7bSGerrit Uitslag        }
214a4680e7bSGerrit Uitslag        $aclcache[$pageid] = $acl;
215a4680e7bSGerrit Uitslag        return $acl;
216a4680e7bSGerrit Uitslag    }
217a4680e7bSGerrit Uitslag
218a4680e7bSGerrit Uitslag    /**
219f10ea6c1SKlap-in     * Split sql queries on semicolons, unless when semicolons are quoted
220f10ea6c1SKlap-in     *
221f10ea6c1SKlap-in     * @param string $sql
222f10ea6c1SKlap-in     * @return array sql queries
223f10ea6c1SKlap-in     */
224f10ea6c1SKlap-in    public function SQLstring2array($sql) {
2253fb592daSAndreas Gohr        $statements = array();
2263fb592daSAndreas Gohr        $len = strlen($sql);
2273fb592daSAndreas Gohr
2283fb592daSAndreas Gohr        // Simple state machine to "parse" sql into single statements
2293fb592daSAndreas Gohr        $in_str = false;
2303fb592daSAndreas Gohr        $in_com = false;
2313fb592daSAndreas Gohr        $statement = '';
2323fb592daSAndreas Gohr        for($i=0; $i<$len; $i++){
2333fb592daSAndreas Gohr            $prev = $i ? $sql{$i-1} : "\n";
2343fb592daSAndreas Gohr            $char = $sql{$i};
2353fb592daSAndreas Gohr            $next = $sql{$i+1};
2363fb592daSAndreas Gohr
2373fb592daSAndreas Gohr            // in comment? ignore everything until line end
2383fb592daSAndreas Gohr            if($in_com){
2393fb592daSAndreas Gohr                if($char == "\n"){
2403fb592daSAndreas Gohr                    $in_com = false;
2413fb592daSAndreas Gohr                }
2423fb592daSAndreas Gohr                continue;
2433fb592daSAndreas Gohr            }
2443fb592daSAndreas Gohr
2453fb592daSAndreas Gohr            // handle strings
2463fb592daSAndreas Gohr            if($in_str){
2475922cb27SAndreas Gohr                if($char == "'"){
2485922cb27SAndreas Gohr                    if($next == "'"){
2495922cb27SAndreas Gohr                        // current char is an escape for the next
2503fb592daSAndreas Gohr                        $statement .= $char . $next;
2513fb592daSAndreas Gohr                        $i++;
2523fb592daSAndreas Gohr                        continue;
2535922cb27SAndreas Gohr                    }else{
2545922cb27SAndreas Gohr                        // end of string
2553fb592daSAndreas Gohr                        $statement .= $char;
2563fb592daSAndreas Gohr                        $in_str = false;
2573fb592daSAndreas Gohr                        continue;
2583fb592daSAndreas Gohr                    }
2595922cb27SAndreas Gohr                }
2603fb592daSAndreas Gohr                // still in string
2613fb592daSAndreas Gohr                $statement .= $char;
2623fb592daSAndreas Gohr                continue;
2633fb592daSAndreas Gohr            }
2643fb592daSAndreas Gohr
2653fb592daSAndreas Gohr            // new comment?
2663fb592daSAndreas Gohr            if($char == '-' && $next == '-' && $prev == "\n"){
2673fb592daSAndreas Gohr                $in_com = true;
2683fb592daSAndreas Gohr                continue;
2693fb592daSAndreas Gohr            }
2703fb592daSAndreas Gohr
2713fb592daSAndreas Gohr            // new string?
2725922cb27SAndreas Gohr            if($char == "'"){
2735922cb27SAndreas Gohr                $in_str = true;
2743fb592daSAndreas Gohr                $statement .= $char;
2753fb592daSAndreas Gohr                continue;
2763fb592daSAndreas Gohr            }
2773fb592daSAndreas Gohr
2783fb592daSAndreas Gohr            // the real delimiter
2793fb592daSAndreas Gohr            if($char == ';'){
2803fb592daSAndreas Gohr                $statements[] = trim($statement);
2813fb592daSAndreas Gohr                $statement = '';
2823fb592daSAndreas Gohr                continue;
2833fb592daSAndreas Gohr            }
2843fb592daSAndreas Gohr
2853fb592daSAndreas Gohr            // some standard query stuff
2863fb592daSAndreas Gohr            $statement .= $char;
2873fb592daSAndreas Gohr        }
2883fb592daSAndreas Gohr        if($statement) $statements[] = trim($statement);
2893fb592daSAndreas Gohr
2903fb592daSAndreas Gohr        return $statements;
291f10ea6c1SKlap-in    }
292f10ea6c1SKlap-in
293f10ea6c1SKlap-in    /**
294f10ea6c1SKlap-in     * @param array $sql queries without terminating semicolon
295f10ea6c1SKlap-in     * @param bool  $sqlpreparing
296f10ea6c1SKlap-in     * @return bool
297f10ea6c1SKlap-in     */
298f10ea6c1SKlap-in    public function doTransaction($sql, $sqlpreparing = true) {
299a1e6784eSAndreas Gohr        foreach($sql as $s) {
300a1e6784eSAndreas Gohr            $s = preg_replace('!^\s*--.*$!m', '', $s);
301a1e6784eSAndreas Gohr            $s = trim($s);
302a1e6784eSAndreas Gohr            if(!$s) continue;
303fd69a32cSAndreas Gohr
304f10ea6c1SKlap-in            if($sqlpreparing) {
305a1e6784eSAndreas Gohr                $res = $this->query("$s;");
306f10ea6c1SKlap-in            } else {
307f10ea6c1SKlap-in                $res = $this->adapter->executeQuery("$s;");
308f10ea6c1SKlap-in            }
309a1e6784eSAndreas Gohr            if($res === false) {
310f10ea6c1SKlap-in                //TODO check rollback for sqlite PDO
31113896259SKlap-in                if($this->adapter->getName() == DOKU_EXT_SQLITE) {
3121dc19626SKlap-in                    $this->query('ROLLBACK TRANSACTION');
313*6c7ee3f2SAndreas Gohr                } else {
314*6c7ee3f2SAndreas Gohr                    $err = $this->adapter->getDb()->errorInfo();
315*6c7ee3f2SAndreas Gohr                    msg($err[0].' '.$err[1].' '.$err[2].':<br /><pre>'.hsc($s).'</pre>', -1);
316a1e6784eSAndreas Gohr                }
31705f176edSstretchyboy                return false;
31805f176edSstretchyboy            }
319a1e6784eSAndreas Gohr        }
320f10ea6c1SKlap-in        return true;
321a1e6784eSAndreas Gohr    }
322a1e6784eSAndreas Gohr
323a34ef333SKlap-in    /**
324a34ef333SKlap-in     * Dump db into a file in meta directory
325a34ef333SKlap-in     *
326a34ef333SKlap-in     */
327a34ef333SKlap-in    public function dumpDatabase($dbname, $from = DOKU_EXT_SQLITE) {
328a34ef333SKlap-in        global $conf;
329a34ef333SKlap-in        $adapterDumpDb = null;
330a34ef333SKlap-in        //connect to desired database
331a34ef333SKlap-in        if($this->adapter->getName() == $from) {
332a34ef333SKlap-in            $adapterDumpDb =& $this->adapter;
333a34ef333SKlap-in        } else {
334a34ef333SKlap-in            if($from == DOKU_EXT_SQLITE) {
335a34ef333SKlap-in                //TODO test connecting to sqlite2 database
336a34ef333SKlap-in                if($this->existsSqlite2()) {
337a34ef333SKlap-in                    require_once(DOKU_PLUGIN.'sqlite/classes/adapter_sqlite2.php');
338a34ef333SKlap-in                    $adapterDumpDb = new helper_plugin_sqlite_adapter_sqlite2();
339a34ef333SKlap-in                } else {
340a34ef333SKlap-in                    msg('PHP Sqlite Extension(needed for sqlite2) not available, database "'.hsc($dbname).'" is not dumped to file.');
341a34ef333SKlap-in                    return false;
342a34ef333SKlap-in                }
343a34ef333SKlap-in            }
344a34ef333SKlap-in        }
345a34ef333SKlap-in        if($adapterDumpDb === null) {
346a34ef333SKlap-in            msg('No adapter loaded');
347a34ef333SKlap-in            return false;
348a34ef333SKlap-in        }
349a34ef333SKlap-in        $init = false;
350a34ef333SKlap-in        if(!$adapterDumpDb->initdb($dbname, $init)) {
351a34ef333SKlap-in            msg('Opening database fails.', -1);
352a34ef333SKlap-in            return false;
353a34ef333SKlap-in        }
354f10ea6c1SKlap-in
355a34ef333SKlap-in        $res    = $adapterDumpDb->query(array("SELECT name,sql FROM sqlite_master WHERE type='table'"));
356a34ef333SKlap-in        $tables = $adapterDumpDb->res2arr($res);
357a34ef333SKlap-in
358a34ef333SKlap-in        $filename = $conf['metadir'].'/dumpfile_'.$dbname.'.sql';
359a34ef333SKlap-in        if($fp = fopen($filename, 'w')) {
360a34ef333SKlap-in
361a34ef333SKlap-in            fwrite($fp, 'BEGIN TRANSACTION;'."\n");
362a34ef333SKlap-in
363a34ef333SKlap-in            foreach($tables as $table) {
364a34ef333SKlap-in
365a34ef333SKlap-in                fwrite($fp, $table['sql'].";\n");
366a34ef333SKlap-in
367a34ef333SKlap-in                $sql = "SELECT * FROM ".$table['name'];
368a34ef333SKlap-in                $res = $adapterDumpDb->query(array($sql));
369a34ef333SKlap-in
370a34ef333SKlap-in                while($row = $adapterDumpDb->res_fetch_array($res)) {
371a34ef333SKlap-in
372a34ef333SKlap-in                    $line = 'INSERT INTO '.$table['name'].' VALUES(';
373a34ef333SKlap-in                    foreach($row as $no_entry => $entry) {
374a34ef333SKlap-in                        if($no_entry !== 0) {
375a34ef333SKlap-in                            $line .= ',';
376a34ef333SKlap-in                        }
377a34ef333SKlap-in
378a34ef333SKlap-in                        if(is_null($entry)) {
379a34ef333SKlap-in                            $line .= 'NULL';
380a34ef333SKlap-in                        } elseif(!is_numeric($entry)) {
381a34ef333SKlap-in                            $line .= $adapterDumpDb->quote_string($entry);
382a34ef333SKlap-in                        } else {
383a34ef333SKlap-in                            //TODO depending on locale extra leading zeros are truncated e.g 1.300 (thousand three hunderd)-> 1.3
384a34ef333SKlap-in                            $line .= $entry;
385a34ef333SKlap-in                        }
386a34ef333SKlap-in                    }
387a34ef333SKlap-in                    $line .= ');'."\n";
388a34ef333SKlap-in
389a34ef333SKlap-in                    fwrite($fp, $line);
390a34ef333SKlap-in                }
391a34ef333SKlap-in            }
392a34ef333SKlap-in
393a34ef333SKlap-in            $res     = $adapterDumpDb->query(array("SELECT name,sql FROM sqlite_master WHERE type='index'"));
394a34ef333SKlap-in            $indexes = $adapterDumpDb->res2arr($res);
395a34ef333SKlap-in            foreach($indexes as $index) {
396a34ef333SKlap-in                fwrite($fp, $index['sql'].";\n");
397a34ef333SKlap-in            }
398a34ef333SKlap-in
399a34ef333SKlap-in            fwrite($fp, 'COMMIT;'."\n");
400a34ef333SKlap-in
401a34ef333SKlap-in            fclose($fp);
402a34ef333SKlap-in            return $filename;
403a34ef333SKlap-in        } else {
404a34ef333SKlap-in            msg('Dumping "'.hsc($dbname).'" has failed. Could not open '.$filename);
405a34ef333SKlap-in            return false;
406a34ef333SKlap-in        }
407a34ef333SKlap-in    }
408a34ef333SKlap-in
409a34ef333SKlap-in    /**
410a34ef333SKlap-in     * Read $dumpfile and try to add it to database.
411a34ef333SKlap-in     * A existing database is backuped first as e.g. dbname.copy2.sqlite3
412a34ef333SKlap-in     *
413a34ef333SKlap-in     * @param string $dbname
414a34ef333SKlap-in     * @param string $dumpfile
415a34ef333SKlap-in     * @return bool true on succes
416a34ef333SKlap-in     */
417a34ef333SKlap-in    public function fillDatabaseFromDump($dbname, $dumpfile) {
418a34ef333SKlap-in        global $conf;
419a34ef333SKlap-in        //backup existing stuff
420a34ef333SKlap-in        $dbf    = $conf['metadir'].'/'.$dbname;
421a34ef333SKlap-in        $dbext  = $this->adapter->getFileextension();
422a34ef333SKlap-in        $dbfile = $dbf.$dbext;
423a34ef333SKlap-in        if(@file_exists($dbfile)) {
424a34ef333SKlap-in
425a34ef333SKlap-in            $i            = 0;
426a34ef333SKlap-in            $backupdbfile = $dbfile;
427a34ef333SKlap-in            do {
428a34ef333SKlap-in                $i++;
429a34ef333SKlap-in                $backupdbfile = $dbf.".copy$i".$dbext;
430a34ef333SKlap-in            } while(@file_exists($backupdbfile));
431a34ef333SKlap-in
432a34ef333SKlap-in            io_rename($dbfile, $backupdbfile);
433a34ef333SKlap-in        }
434a34ef333SKlap-in
435a34ef333SKlap-in        $init = false;
436a34ef333SKlap-in        if(!$this->adapter->initdb($dbname, $init, $sqliteupgrade = true)) {
437a34ef333SKlap-in            msg('Initialize db fails');
438a34ef333SKlap-in            return false;
439a34ef333SKlap-in        }
440a34ef333SKlap-in
441a34ef333SKlap-in        $sql = io_readFile($dumpfile, false);
442a34ef333SKlap-in        $sql = $this->SQLstring2array($sql);
443a34ef333SKlap-in
444a34ef333SKlap-in        //skip preparing, because it interprets question marks as placeholders.
445a34ef333SKlap-in        return $this->doTransaction($sql, $sqlpreparing = false);
446a34ef333SKlap-in    }
447f10ea6c1SKlap-in
448a1e6784eSAndreas Gohr    /**
4493ae3f79eSKlap-in     * Registers a User Defined Function for use in SQL statements
4503ae3f79eSKlap-in     */
451aa81d781SKlap-in    public function create_function($function_name, $callback, $num_args) {
452aa81d781SKlap-in        $this->adapter->create_function($function_name, $callback, $num_args);
4533ae3f79eSKlap-in    }
4543ae3f79eSKlap-in
4553ae3f79eSKlap-in    /**
456a1e6784eSAndreas Gohr     * Execute a query with the given parameters.
457a1e6784eSAndreas Gohr     *
458a1e6784eSAndreas Gohr     * Takes care of escaping
459a1e6784eSAndreas Gohr     *
460a2a82480SAndreas Gohr     *
461a2a82480SAndreas Gohr     * @param string ...$args - the arguments of query(), the first is the sql and others are values
462aa81d781SKlap-in     * @return bool|\SQLiteResult
463a1e6784eSAndreas Gohr     */
464aa81d781SKlap-in    public function query() {
465a1e6784eSAndreas Gohr        // get function arguments
466a1e6784eSAndreas Gohr        $args = func_get_args();
467a1e6784eSAndreas Gohr
468aa81d781SKlap-in        return $this->adapter->query($args);
46987fa2c18Sstretchyboy    }
470a1e6784eSAndreas Gohr
471a1e6784eSAndreas Gohr    /**
472a1e6784eSAndreas Gohr     * Join the given values and quote them for SQL insertion
473a1e6784eSAndreas Gohr     */
474aa81d781SKlap-in    public function quote_and_join($vals, $sep = ',') {
475aa81d781SKlap-in        return $this->adapter->quote_and_join($vals, $sep);
476a1e6784eSAndreas Gohr    }
477a1e6784eSAndreas Gohr
478a1e6784eSAndreas Gohr    /**
479a1e6784eSAndreas Gohr     * Run sqlite_escape_string() on the given string and surround it
480a1e6784eSAndreas Gohr     * with quotes
481a1e6784eSAndreas Gohr     */
482aa81d781SKlap-in    public function quote_string($string) {
483aa81d781SKlap-in        return $this->adapter->quote_string($string);
484a1e6784eSAndreas Gohr    }
485a1e6784eSAndreas Gohr
486b5b947d7SAndreas Gohr    /**
487fee3b689Sstretchyboy     * Escape string for sql
488fee3b689Sstretchyboy     */
489aa81d781SKlap-in    public function escape_string($str) {
490aa81d781SKlap-in        return $this->adapter->escape_string($str);
491ff97cc8fSstretchyboy    }
492ff97cc8fSstretchyboy
493ff97cc8fSstretchyboy    /**
494b122d121SAndreas Gohr     * Closes the result set (and it's cursors)
495b122d121SAndreas Gohr     *
496b122d121SAndreas Gohr     * If you're doing SELECT queries inside a TRANSACTION, be sure to call this
497b122d121SAndreas Gohr     * function on all your results sets, before COMMITing the transaction.
498b122d121SAndreas Gohr     *
4994b4b2db0SGerrit Uitslag     * Also required when not all rows of a result are fetched
5004b4b2db0SGerrit Uitslag     *
501b122d121SAndreas Gohr     * @param $res
502b122d121SAndreas Gohr     * @return bool
503b122d121SAndreas Gohr     */
504b122d121SAndreas Gohr    public function res_close($res){
505b122d121SAndreas Gohr        return $this->adapter->res_close($res);
506b122d121SAndreas Gohr    }
507b122d121SAndreas Gohr
508b122d121SAndreas Gohr    /**
509aa81d781SKlap-in     * Returns a complete result set as array
510ff97cc8fSstretchyboy     */
511ef383ac5SKlap-in    public function res2arr($res, $assoc = true) {
512ef383ac5SKlap-in        return $this->adapter->res2arr($res, $assoc);
513b5b947d7SAndreas Gohr    }
514b5b947d7SAndreas Gohr
515b5b947d7SAndreas Gohr    /**
516aa81d781SKlap-in     * Return the wanted row from a given result set as
517aa81d781SKlap-in     * associative array
518b5b947d7SAndreas Gohr     */
519aa81d781SKlap-in    public function res2row($res, $rownum = 0) {
520aa81d781SKlap-in        return $this->adapter->res2row($res, $rownum);
521b5b947d7SAndreas Gohr    }
522b5b947d7SAndreas Gohr
523e7112ccbSAdrian Lang    /**
52444685fc6SKlap-in     * Return the first value from the next row.
525e7112ccbSAdrian Lang     */
526aa81d781SKlap-in    public function res2single($res) {
527aa81d781SKlap-in        return $this->adapter->res2single($res);
528e7112ccbSAdrian Lang    }
529fee3b689Sstretchyboy
530fee3b689Sstretchyboy    /**
531fee3b689Sstretchyboy     * fetch the next row as zero indexed array
532fee3b689Sstretchyboy     */
533aa81d781SKlap-in    public function res_fetch_array($res) {
534aa81d781SKlap-in        return $this->adapter->res_fetch_array($res);
53587fa2c18Sstretchyboy    }
536fee3b689Sstretchyboy
537fee3b689Sstretchyboy    /**
538fee3b689Sstretchyboy     * fetch the next row as assocative array
539fee3b689Sstretchyboy     */
540aa81d781SKlap-in    public function res_fetch_assoc($res) {
541aa81d781SKlap-in        return $this->adapter->res_fetch_assoc($res);
542fee3b689Sstretchyboy    }
543fee3b689Sstretchyboy
544fee3b689Sstretchyboy    /**
54578977d74SKlap-in     * Count the number of records in result
5463157674bSAndreas Gohr     *
547db58e525SKlap-in     * This function is really inperformant in PDO and should be avoided!
548fee3b689Sstretchyboy     */
549aa81d781SKlap-in    public function res2count($res) {
550aa81d781SKlap-in        return $this->adapter->res2count($res);
551fee3b689Sstretchyboy    }
55224a03f6cSstretchyboy
55324a03f6cSstretchyboy    /**
55424a03f6cSstretchyboy     * Count the number of records changed last time
55524a03f6cSstretchyboy     */
55644685fc6SKlap-in    public function countChanges($res) {
55744685fc6SKlap-in        return $this->adapter->countChanges($res);
558a1e6784eSAndreas Gohr    }
559a1e6784eSAndreas Gohr
560aa81d781SKlap-in}
561