xref: /plugin/sqlite/helper.php (revision 3a56750b42e05745f84fd97217f7133805e622eb)
1a1e6784eSAndreas Gohr<?php
28da7d805SAndreas Gohr
38da7d805SAndreas Gohr/**
48da7d805SAndreas Gohr * @noinspection SqlNoDataSourceInspection
58da7d805SAndreas Gohr * @noinspection SqlDialectInspection
68da7d805SAndreas Gohr * @noinspection PhpComposerExtensionStubsInspection
78da7d805SAndreas Gohr */
88da7d805SAndreas Gohr
98da7d805SAndreas Gohruse dokuwiki\plugin\sqlite\SQLiteDB;
108da7d805SAndreas Gohruse dokuwiki\plugin\sqlite\Tools;
118da7d805SAndreas Gohr
128da7d805SAndreas Gohr
13a1e6784eSAndreas Gohr/**
14a1e6784eSAndreas Gohr * DokuWiki Plugin sqlite (Helper Component)
15a1e6784eSAndreas Gohr *
16a1e6784eSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
17a1e6784eSAndreas Gohr * @author  Andreas Gohr <gohr@cosmocode.de>
188da7d805SAndreas Gohr * @deprecated 2023-03-15
19a1e6784eSAndreas Gohr */
208da7d805SAndreas Gohrclass helper_plugin_sqlite extends DokuWiki_Plugin
218da7d805SAndreas Gohr{
228da7d805SAndreas Gohr    /** @var SQLiteDB|null */
236c7ee3f2SAndreas Gohr    protected $adapter = null;
24aa81d781SKlap-in
258da7d805SAndreas Gohr    /** @var array result cache */
268da7d805SAndreas Gohr    protected $data;
278da7d805SAndreas Gohr
283e9ac593SGerrit Uitslag    /**
298da7d805SAndreas Gohr     * constructor
303e9ac593SGerrit Uitslag     */
318da7d805SAndreas Gohr    public function __construct()
328da7d805SAndreas Gohr    {
338da7d805SAndreas Gohr        if (!$this->existsPDOSqlite()) {
348da7d805SAndreas Gohr            msg('PDO SQLite support missing in this PHP install - The sqlite plugin will not work', -1);
358da7d805SAndreas Gohr        }
368da7d805SAndreas Gohr    }
378da7d805SAndreas Gohr
388da7d805SAndreas Gohr    /**
398da7d805SAndreas Gohr     * Get the current Adapter
408da7d805SAndreas Gohr     * @return SQLiteDB|null
418da7d805SAndreas Gohr     */
428da7d805SAndreas Gohr    public function getAdapter()
438da7d805SAndreas Gohr    {
44ca2f2adaSKlap-in        return $this->adapter;
45ca2f2adaSKlap-in    }
46ca2f2adaSKlap-in
47a1e6784eSAndreas Gohr    /**
48aa81d781SKlap-in     * Keep separate instances for every call to keep database connections
49aa81d781SKlap-in     */
508da7d805SAndreas Gohr    public function isSingleton()
518da7d805SAndreas Gohr    {
52aa81d781SKlap-in        return false;
53aa81d781SKlap-in    }
54aa81d781SKlap-in
55aa81d781SKlap-in    /**
56aa81d781SKlap-in     * check availabilty of PHP PDO sqlite3
57aa81d781SKlap-in     */
588da7d805SAndreas Gohr    public function existsPDOSqlite()
598da7d805SAndreas Gohr    {
6087fa2c18Sstretchyboy        if (class_exists('pdo')) {
618da7d805SAndreas Gohr            return in_array('sqlite', \PDO::getAvailableDrivers());
627ed6069fSAdrian Lang        }
63aa81d781SKlap-in        return false;
64a1e6784eSAndreas Gohr    }
65a1e6784eSAndreas Gohr
66a1e6784eSAndreas Gohr    /**
67a1e6784eSAndreas Gohr     * Initializes and opens the database
68a1e6784eSAndreas Gohr     *
69a1e6784eSAndreas Gohr     * Needs to be called right after loading this helper plugin
70aa81d781SKlap-in     *
71aa81d781SKlap-in     * @param string $dbname
72aa81d781SKlap-in     * @param string $updatedir - Database update infos
73aa81d781SKlap-in     * @return bool
74a1e6784eSAndreas Gohr     */
758da7d805SAndreas Gohr    public function init($dbname, $updatedir)
768da7d805SAndreas Gohr    {
77*3a56750bSAndreas Gohr        dbg_deprecated(SQLiteDB::class);
78*3a56750bSAndreas Gohr
798da7d805SAndreas Gohr        try {
808da7d805SAndreas Gohr            $this->adapter = new SQLiteDB($dbname, $updatedir, $this);
818da7d805SAndreas Gohr        } catch (Exception $e) {
828da7d805SAndreas Gohr            msg('SQLite: ' . $e->getMessage(), -1);
83c137e95fSAndreas Gohr            return false;
84c137e95fSAndreas Gohr        }
85a1e6784eSAndreas Gohr        return true;
86a1e6784eSAndreas Gohr    }
87a1e6784eSAndreas Gohr
88a1e6784eSAndreas Gohr    /**
898da7d805SAndreas Gohr     * This is called from the adapter itself for backwards compatibility
908da7d805SAndreas Gohr     *
918da7d805SAndreas Gohr     * @param SQLiteDB $adapter
928da7d805SAndreas Gohr     * @return void
93a1e6784eSAndreas Gohr     */
948da7d805SAndreas Gohr    function setAdapter($adapter)
958da7d805SAndreas Gohr    {
968da7d805SAndreas Gohr        $this->adapter = $adapter;
97a34ef333SKlap-in    }
98f10ea6c1SKlap-in
99a1e6784eSAndreas Gohr    /**
1003ae3f79eSKlap-in     * Registers a User Defined Function for use in SQL statements
1013ae3f79eSKlap-in     */
1028da7d805SAndreas Gohr    public function create_function($function_name, $callback, $num_args)
1038da7d805SAndreas Gohr    {
1048da7d805SAndreas Gohr        $this->adapter->pdo()->sqliteCreateFunction($function_name, $callback, $num_args);
1053ae3f79eSKlap-in    }
1063ae3f79eSKlap-in
1078da7d805SAndreas Gohr    // region query and result handling functions
1088da7d805SAndreas Gohr
1093ae3f79eSKlap-in    /**
110e7b0736cSAndreas Gohr     * Convenience function to run an INSERT OR REPLACE operation
111e7b0736cSAndreas Gohr     *
112e7b0736cSAndreas Gohr     * The function takes a key-value array with the column names in the key and the actual value in the value,
113e7b0736cSAndreas Gohr     * build the appropriate query and executes it.
114e7b0736cSAndreas Gohr     *
115e7b0736cSAndreas Gohr     * @param string $table the table the entry should be saved to (will not be escaped)
116e7b0736cSAndreas Gohr     * @param array $entry A simple key-value pair array (only values will be escaped)
1178da7d805SAndreas Gohr     * @return bool
118e7b0736cSAndreas Gohr     */
1198da7d805SAndreas Gohr    public function storeEntry($table, $entry)
1208da7d805SAndreas Gohr    {
1218da7d805SAndreas Gohr        try {
1228da7d805SAndreas Gohr            $this->adapter->saveRecord($table, $entry);
1238da7d805SAndreas Gohr        } catch (\Exception $e) {
1248da7d805SAndreas Gohr            msg('SQLite: ' . $e->getMessage(), -1);
1258da7d805SAndreas Gohr            return false;
126e7b0736cSAndreas Gohr        }
127e7b0736cSAndreas Gohr
1288da7d805SAndreas Gohr        return true;
1298da7d805SAndreas Gohr    }
130e7b0736cSAndreas Gohr
131e7b0736cSAndreas Gohr    /**
132a1e6784eSAndreas Gohr     * Execute a query with the given parameters.
133a1e6784eSAndreas Gohr     *
134a1e6784eSAndreas Gohr     * Takes care of escaping
135a1e6784eSAndreas Gohr     *
136a2a82480SAndreas Gohr     *
137a2a82480SAndreas Gohr     * @param string ...$args - the arguments of query(), the first is the sql and others are values
138a1e6784eSAndreas Gohr     */
1398da7d805SAndreas Gohr    public function query()
1408da7d805SAndreas Gohr    {
141a1e6784eSAndreas Gohr        // get function arguments
142a1e6784eSAndreas Gohr        $args = func_get_args();
1438da7d805SAndreas Gohr        $sql = array_shift($args);
144a1e6784eSAndreas Gohr
1458da7d805SAndreas Gohr        try {
1468da7d805SAndreas Gohr            return $this->adapter->query($sql, $args);
1478da7d805SAndreas Gohr        } catch (\Exception $e) {
1488da7d805SAndreas Gohr            msg('SQLite: ' . $e->getMessage(), -1);
1498da7d805SAndreas Gohr            return false;
1508da7d805SAndreas Gohr        }
15187fa2c18Sstretchyboy    }
152a1e6784eSAndreas Gohr
153ff97cc8fSstretchyboy
154ff97cc8fSstretchyboy    /**
155b122d121SAndreas Gohr     * Closes the result set (and it's cursors)
156b122d121SAndreas Gohr     *
157b122d121SAndreas Gohr     * If you're doing SELECT queries inside a TRANSACTION, be sure to call this
158b122d121SAndreas Gohr     * function on all your results sets, before COMMITing the transaction.
159b122d121SAndreas Gohr     *
1604b4b2db0SGerrit Uitslag     * Also required when not all rows of a result are fetched
1614b4b2db0SGerrit Uitslag     *
1628da7d805SAndreas Gohr     * @param \PDOStatement $res
163b122d121SAndreas Gohr     * @return bool
164b122d121SAndreas Gohr     */
1658da7d805SAndreas Gohr    public function res_close($res)
1668da7d805SAndreas Gohr    {
1678da7d805SAndreas Gohr        if (!$res) return false;
1688da7d805SAndreas Gohr
1698da7d805SAndreas Gohr        return $res->closeCursor();
170b122d121SAndreas Gohr    }
171b122d121SAndreas Gohr
172b122d121SAndreas Gohr    /**
173aa81d781SKlap-in     * Returns a complete result set as array
1748da7d805SAndreas Gohr     *
1758da7d805SAndreas Gohr     * @param \PDOStatement $res
1768da7d805SAndreas Gohr     * @return array
177ff97cc8fSstretchyboy     */
1788da7d805SAndreas Gohr    public function res2arr($res, $assoc = true)
1798da7d805SAndreas Gohr    {
1808da7d805SAndreas Gohr        if (!$res) return [];
1818da7d805SAndreas Gohr
1828da7d805SAndreas Gohr        // this is a bullshit workaround for having res2arr and res2count work on one result
1838da7d805SAndreas Gohr        if (!$this->data) {
1848da7d805SAndreas Gohr            $mode = $assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM;
1858da7d805SAndreas Gohr            $this->data = $res->fetchAll($mode);
1868da7d805SAndreas Gohr        }
1878da7d805SAndreas Gohr        return $this->data;
188b5b947d7SAndreas Gohr    }
189b5b947d7SAndreas Gohr
190b5b947d7SAndreas Gohr    /**
1918da7d805SAndreas Gohr     * Return the next row from the result set as associative array
1928da7d805SAndreas Gohr     *
1938da7d805SAndreas Gohr     * @param \PDOStatement $res
1948da7d805SAndreas Gohr     * @param int $rownum will be ignored
195b5b947d7SAndreas Gohr     */
1968da7d805SAndreas Gohr    public function res2row($res, $rownum = 0)
1978da7d805SAndreas Gohr    {
1988da7d805SAndreas Gohr        if (!$res) return false;
1998da7d805SAndreas Gohr
2008da7d805SAndreas Gohr        return $res->fetch(\PDO::FETCH_ASSOC);
201b5b947d7SAndreas Gohr    }
202b5b947d7SAndreas Gohr
203e7112ccbSAdrian Lang    /**
20444685fc6SKlap-in     * Return the first value from the next row.
2058da7d805SAndreas Gohr     *
2068da7d805SAndreas Gohr     * @param \PDOStatement $res
2078da7d805SAndreas Gohr     * @return mixed
208e7112ccbSAdrian Lang     */
2098da7d805SAndreas Gohr    public function res2single($res)
2108da7d805SAndreas Gohr    {
2118da7d805SAndreas Gohr        if (!$res) return false;
2128da7d805SAndreas Gohr
2138da7d805SAndreas Gohr        $data = $res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_ABS, 0);
2148da7d805SAndreas Gohr        if (empty($data)) {
2158da7d805SAndreas Gohr            return false;
2168da7d805SAndreas Gohr        }
2178da7d805SAndreas Gohr        return $data[0];
218e7112ccbSAdrian Lang    }
219fee3b689Sstretchyboy
220fee3b689Sstretchyboy    /**
221fee3b689Sstretchyboy     * fetch the next row as zero indexed array
2228da7d805SAndreas Gohr     *
2238da7d805SAndreas Gohr     * @param \PDOStatement $res
2248da7d805SAndreas Gohr     * @return array|bool
225fee3b689Sstretchyboy     */
2268da7d805SAndreas Gohr    public function res_fetch_array($res)
2278da7d805SAndreas Gohr    {
2288da7d805SAndreas Gohr        if (!$res) return false;
2298da7d805SAndreas Gohr
2308da7d805SAndreas Gohr        return $res->fetch(PDO::FETCH_NUM);
23187fa2c18Sstretchyboy    }
232fee3b689Sstretchyboy
233fee3b689Sstretchyboy    /**
234fee3b689Sstretchyboy     * fetch the next row as assocative array
2358da7d805SAndreas Gohr     *
2368da7d805SAndreas Gohr     * @param \PDOStatement $res
2378da7d805SAndreas Gohr     * @return array|bool
238fee3b689Sstretchyboy     */
2398da7d805SAndreas Gohr    public function res_fetch_assoc($res)
2408da7d805SAndreas Gohr    {
2418da7d805SAndreas Gohr        if (!$res) return false;
2428da7d805SAndreas Gohr
2438da7d805SAndreas Gohr        return $res->fetch(PDO::FETCH_ASSOC);
244fee3b689Sstretchyboy    }
245fee3b689Sstretchyboy
246fee3b689Sstretchyboy    /**
24778977d74SKlap-in     * Count the number of records in result
2483157674bSAndreas Gohr     *
249db58e525SKlap-in     * This function is really inperformant in PDO and should be avoided!
2508da7d805SAndreas Gohr     *
2518da7d805SAndreas Gohr     * @param \PDOStatement $res
2528da7d805SAndreas Gohr     * @return int
253fee3b689Sstretchyboy     */
2548da7d805SAndreas Gohr    public function res2count($res)
2558da7d805SAndreas Gohr    {
2568da7d805SAndreas Gohr        if (!$res) return 0;
2578da7d805SAndreas Gohr
2588da7d805SAndreas Gohr        // this is a bullshit workaround for having res2arr and res2count work on one result
2598da7d805SAndreas Gohr        if (!$this->data) {
2608da7d805SAndreas Gohr            $this->data = $this->res2arr($res);
2618da7d805SAndreas Gohr        }
2628da7d805SAndreas Gohr
2638da7d805SAndreas Gohr        return count($this->data);
264fee3b689Sstretchyboy    }
26524a03f6cSstretchyboy
26624a03f6cSstretchyboy    /**
26724a03f6cSstretchyboy     * Count the number of records changed last time
2688da7d805SAndreas Gohr     *
2698da7d805SAndreas Gohr     * @param \PDOStatement $res
2708da7d805SAndreas Gohr     * @return int
27124a03f6cSstretchyboy     */
2728da7d805SAndreas Gohr    public function countChanges($res)
2738da7d805SAndreas Gohr    {
2748da7d805SAndreas Gohr        if (!$res) return 0;
2758da7d805SAndreas Gohr
2768da7d805SAndreas Gohr        return $res->rowCount();
277a1e6784eSAndreas Gohr    }
278a1e6784eSAndreas Gohr
2798da7d805SAndreas Gohr    // endregion
2808da7d805SAndreas Gohr
2818da7d805SAndreas Gohr    // region quoting/escaping functions
2828da7d805SAndreas Gohr
2838da7d805SAndreas Gohr    /**
2848da7d805SAndreas Gohr     * Join the given values and quote them for SQL insertion
2858da7d805SAndreas Gohr     */
2868da7d805SAndreas Gohr    public function quote_and_join($vals, $sep = ',')
2878da7d805SAndreas Gohr    {
2888da7d805SAndreas Gohr        $vals = array_map([$this->adapter->pdo(), 'quote'], $vals);
2898da7d805SAndreas Gohr        return join($sep, $vals);
2908da7d805SAndreas Gohr    }
2918da7d805SAndreas Gohr
2928da7d805SAndreas Gohr    /**
2938da7d805SAndreas Gohr     * Quotes a string, by escaping it and adding quotes
2948da7d805SAndreas Gohr     */
2958da7d805SAndreas Gohr    public function quote_string($string)
2968da7d805SAndreas Gohr    {
2978da7d805SAndreas Gohr        return $this->adapter->pdo()->quote($string);
2988da7d805SAndreas Gohr    }
2998da7d805SAndreas Gohr
3008da7d805SAndreas Gohr    /**
3018da7d805SAndreas Gohr     * Similar to quote_string, but without the quotes, useful to construct LIKE patterns
3028da7d805SAndreas Gohr     */
3038da7d805SAndreas Gohr    public function escape_string($str)
3048da7d805SAndreas Gohr    {
3058da7d805SAndreas Gohr        return trim($this->adapter->pdo()->quote($str), "'");
3068da7d805SAndreas Gohr    }
3078da7d805SAndreas Gohr
3088da7d805SAndreas Gohr    // endregion
3098da7d805SAndreas Gohr
3108da7d805SAndreas Gohr    // region speciality functions
3118da7d805SAndreas Gohr
3128da7d805SAndreas Gohr    /**
3138da7d805SAndreas Gohr     * Split sql queries on semicolons, unless when semicolons are quoted
3148da7d805SAndreas Gohr     *
3158da7d805SAndreas Gohr     * Usually you don't need this. It's only really needed if you need individual results for
3168da7d805SAndreas Gohr     * multiple queries. For example in the admin interface.
3178da7d805SAndreas Gohr     *
3188da7d805SAndreas Gohr     * @param string $sql
3198da7d805SAndreas Gohr     * @return array sql queries
3208da7d805SAndreas Gohr     * @deprecated
3218da7d805SAndreas Gohr     */
3228da7d805SAndreas Gohr    public function SQLstring2array($sql)
3238da7d805SAndreas Gohr    {
3248da7d805SAndreas Gohr        dbg_deprecated(Tools::class . '::SQLstring2array');
3258da7d805SAndreas Gohr        return Tools::SQLstring2array($sql);
3268da7d805SAndreas Gohr    }
3278da7d805SAndreas Gohr
3288da7d805SAndreas Gohr    /**
3298da7d805SAndreas Gohr     * @deprecated needs to be fixed in stuct and structpublish
3308da7d805SAndreas Gohr     */
3318da7d805SAndreas Gohr    public function doTransaction($sql, $sqlpreparing = true) {
3328da7d805SAndreas Gohr        throw new \Exception(
3338da7d805SAndreas Gohr            'This method seems to never have done what it suggests. Please use the query() function instead.'
3348da7d805SAndreas Gohr        );
3358da7d805SAndreas Gohr    }
3368da7d805SAndreas Gohr
3378da7d805SAndreas Gohr    // endregion
338aa81d781SKlap-in}
339