1a1e6784eSAndreas Gohr<?php 2*8da7d805SAndreas Gohr 3*8da7d805SAndreas Gohr/** 4*8da7d805SAndreas Gohr * @noinspection SqlNoDataSourceInspection 5*8da7d805SAndreas Gohr * @noinspection SqlDialectInspection 6*8da7d805SAndreas Gohr * @noinspection PhpComposerExtensionStubsInspection 7*8da7d805SAndreas Gohr */ 8*8da7d805SAndreas Gohr 9*8da7d805SAndreas Gohruse dokuwiki\plugin\sqlite\SQLiteDB; 10*8da7d805SAndreas Gohruse dokuwiki\plugin\sqlite\Tools; 11*8da7d805SAndreas Gohr 12*8da7d805SAndreas 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> 18*8da7d805SAndreas Gohr * @deprecated 2023-03-15 19a1e6784eSAndreas Gohr */ 20*8da7d805SAndreas Gohrclass helper_plugin_sqlite extends DokuWiki_Plugin 21*8da7d805SAndreas Gohr{ 22*8da7d805SAndreas Gohr /** @var SQLiteDB|null */ 236c7ee3f2SAndreas Gohr protected $adapter = null; 24aa81d781SKlap-in 25*8da7d805SAndreas Gohr /** @var array result cache */ 26*8da7d805SAndreas Gohr protected $data; 27*8da7d805SAndreas Gohr 283e9ac593SGerrit Uitslag /** 29*8da7d805SAndreas Gohr * constructor 303e9ac593SGerrit Uitslag */ 31*8da7d805SAndreas Gohr public function __construct() 32*8da7d805SAndreas Gohr { 33*8da7d805SAndreas Gohr dbg_deprecated(SQLiteDB::class); 34*8da7d805SAndreas Gohr 35*8da7d805SAndreas Gohr if (!$this->existsPDOSqlite()) { 36*8da7d805SAndreas Gohr msg('PDO SQLite support missing in this PHP install - The sqlite plugin will not work', -1); 37*8da7d805SAndreas Gohr } 38*8da7d805SAndreas Gohr } 39*8da7d805SAndreas Gohr 40*8da7d805SAndreas Gohr /** 41*8da7d805SAndreas Gohr * Get the current Adapter 42*8da7d805SAndreas Gohr * @return SQLiteDB|null 43*8da7d805SAndreas Gohr */ 44*8da7d805SAndreas Gohr public function getAdapter() 45*8da7d805SAndreas Gohr { 46ca2f2adaSKlap-in return $this->adapter; 47ca2f2adaSKlap-in } 48ca2f2adaSKlap-in 49a1e6784eSAndreas Gohr /** 50aa81d781SKlap-in * Keep separate instances for every call to keep database connections 51aa81d781SKlap-in */ 52*8da7d805SAndreas Gohr public function isSingleton() 53*8da7d805SAndreas Gohr { 54aa81d781SKlap-in return false; 55aa81d781SKlap-in } 56aa81d781SKlap-in 57aa81d781SKlap-in /** 58aa81d781SKlap-in * check availabilty of PHP PDO sqlite3 59aa81d781SKlap-in */ 60*8da7d805SAndreas Gohr public function existsPDOSqlite() 61*8da7d805SAndreas Gohr { 6287fa2c18Sstretchyboy if (class_exists('pdo')) { 63*8da7d805SAndreas Gohr return in_array('sqlite', \PDO::getAvailableDrivers()); 647ed6069fSAdrian Lang } 65aa81d781SKlap-in return false; 66a1e6784eSAndreas Gohr } 67a1e6784eSAndreas Gohr 68a1e6784eSAndreas Gohr /** 69a1e6784eSAndreas Gohr * Initializes and opens the database 70a1e6784eSAndreas Gohr * 71a1e6784eSAndreas Gohr * Needs to be called right after loading this helper plugin 72aa81d781SKlap-in * 73aa81d781SKlap-in * @param string $dbname 74aa81d781SKlap-in * @param string $updatedir - Database update infos 75aa81d781SKlap-in * @return bool 76a1e6784eSAndreas Gohr */ 77*8da7d805SAndreas Gohr public function init($dbname, $updatedir) 78*8da7d805SAndreas Gohr { 79*8da7d805SAndreas Gohr try { 80*8da7d805SAndreas Gohr $this->adapter = new SQLiteDB($dbname, $updatedir, $this); 81*8da7d805SAndreas Gohr } catch (Exception $e) { 82*8da7d805SAndreas Gohr msg('SQLite: ' . $e->getMessage(), -1); 83c137e95fSAndreas Gohr return false; 84c137e95fSAndreas Gohr } 85a1e6784eSAndreas Gohr return true; 86a1e6784eSAndreas Gohr } 87a1e6784eSAndreas Gohr 88a1e6784eSAndreas Gohr /** 89*8da7d805SAndreas Gohr * This is called from the adapter itself for backwards compatibility 90*8da7d805SAndreas Gohr * 91*8da7d805SAndreas Gohr * @param SQLiteDB $adapter 92*8da7d805SAndreas Gohr * @return void 93a1e6784eSAndreas Gohr */ 94*8da7d805SAndreas Gohr function setAdapter($adapter) 95*8da7d805SAndreas Gohr { 96*8da7d805SAndreas Gohr $this->adapter = $adapter; 97a34ef333SKlap-in } 98f10ea6c1SKlap-in 99a1e6784eSAndreas Gohr /** 1003ae3f79eSKlap-in * Registers a User Defined Function for use in SQL statements 1013ae3f79eSKlap-in */ 102*8da7d805SAndreas Gohr public function create_function($function_name, $callback, $num_args) 103*8da7d805SAndreas Gohr { 104*8da7d805SAndreas Gohr $this->adapter->pdo()->sqliteCreateFunction($function_name, $callback, $num_args); 1053ae3f79eSKlap-in } 1063ae3f79eSKlap-in 107*8da7d805SAndreas Gohr // region query and result handling functions 108*8da7d805SAndreas 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) 117*8da7d805SAndreas Gohr * @return bool 118e7b0736cSAndreas Gohr */ 119*8da7d805SAndreas Gohr public function storeEntry($table, $entry) 120*8da7d805SAndreas Gohr { 121*8da7d805SAndreas Gohr try { 122*8da7d805SAndreas Gohr $this->adapter->saveRecord($table, $entry); 123*8da7d805SAndreas Gohr } catch (\Exception $e) { 124*8da7d805SAndreas Gohr msg('SQLite: ' . $e->getMessage(), -1); 125*8da7d805SAndreas Gohr return false; 126e7b0736cSAndreas Gohr } 127e7b0736cSAndreas Gohr 128*8da7d805SAndreas Gohr return true; 129*8da7d805SAndreas 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 */ 139*8da7d805SAndreas Gohr public function query() 140*8da7d805SAndreas Gohr { 141a1e6784eSAndreas Gohr // get function arguments 142a1e6784eSAndreas Gohr $args = func_get_args(); 143*8da7d805SAndreas Gohr $sql = array_shift($args); 144a1e6784eSAndreas Gohr 145*8da7d805SAndreas Gohr try { 146*8da7d805SAndreas Gohr return $this->adapter->query($sql, $args); 147*8da7d805SAndreas Gohr } catch (\Exception $e) { 148*8da7d805SAndreas Gohr msg('SQLite: ' . $e->getMessage(), -1); 149*8da7d805SAndreas Gohr return false; 150*8da7d805SAndreas 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 * 162*8da7d805SAndreas Gohr * @param \PDOStatement $res 163b122d121SAndreas Gohr * @return bool 164b122d121SAndreas Gohr */ 165*8da7d805SAndreas Gohr public function res_close($res) 166*8da7d805SAndreas Gohr { 167*8da7d805SAndreas Gohr if (!$res) return false; 168*8da7d805SAndreas Gohr 169*8da7d805SAndreas Gohr return $res->closeCursor(); 170b122d121SAndreas Gohr } 171b122d121SAndreas Gohr 172b122d121SAndreas Gohr /** 173aa81d781SKlap-in * Returns a complete result set as array 174*8da7d805SAndreas Gohr * 175*8da7d805SAndreas Gohr * @param \PDOStatement $res 176*8da7d805SAndreas Gohr * @return array 177ff97cc8fSstretchyboy */ 178*8da7d805SAndreas Gohr public function res2arr($res, $assoc = true) 179*8da7d805SAndreas Gohr { 180*8da7d805SAndreas Gohr if (!$res) return []; 181*8da7d805SAndreas Gohr 182*8da7d805SAndreas Gohr // this is a bullshit workaround for having res2arr and res2count work on one result 183*8da7d805SAndreas Gohr if (!$this->data) { 184*8da7d805SAndreas Gohr $mode = $assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM; 185*8da7d805SAndreas Gohr $this->data = $res->fetchAll($mode); 186*8da7d805SAndreas Gohr } 187*8da7d805SAndreas Gohr return $this->data; 188b5b947d7SAndreas Gohr } 189b5b947d7SAndreas Gohr 190b5b947d7SAndreas Gohr /** 191*8da7d805SAndreas Gohr * Return the next row from the result set as associative array 192*8da7d805SAndreas Gohr * 193*8da7d805SAndreas Gohr * @param \PDOStatement $res 194*8da7d805SAndreas Gohr * @param int $rownum will be ignored 195b5b947d7SAndreas Gohr */ 196*8da7d805SAndreas Gohr public function res2row($res, $rownum = 0) 197*8da7d805SAndreas Gohr { 198*8da7d805SAndreas Gohr if (!$res) return false; 199*8da7d805SAndreas Gohr 200*8da7d805SAndreas Gohr return $res->fetch(\PDO::FETCH_ASSOC); 201b5b947d7SAndreas Gohr } 202b5b947d7SAndreas Gohr 203e7112ccbSAdrian Lang /** 20444685fc6SKlap-in * Return the first value from the next row. 205*8da7d805SAndreas Gohr * 206*8da7d805SAndreas Gohr * @param \PDOStatement $res 207*8da7d805SAndreas Gohr * @return mixed 208e7112ccbSAdrian Lang */ 209*8da7d805SAndreas Gohr public function res2single($res) 210*8da7d805SAndreas Gohr { 211*8da7d805SAndreas Gohr if (!$res) return false; 212*8da7d805SAndreas Gohr 213*8da7d805SAndreas Gohr $data = $res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_ABS, 0); 214*8da7d805SAndreas Gohr if (empty($data)) { 215*8da7d805SAndreas Gohr return false; 216*8da7d805SAndreas Gohr } 217*8da7d805SAndreas Gohr return $data[0]; 218e7112ccbSAdrian Lang } 219fee3b689Sstretchyboy 220fee3b689Sstretchyboy /** 221fee3b689Sstretchyboy * fetch the next row as zero indexed array 222*8da7d805SAndreas Gohr * 223*8da7d805SAndreas Gohr * @param \PDOStatement $res 224*8da7d805SAndreas Gohr * @return array|bool 225fee3b689Sstretchyboy */ 226*8da7d805SAndreas Gohr public function res_fetch_array($res) 227*8da7d805SAndreas Gohr { 228*8da7d805SAndreas Gohr if (!$res) return false; 229*8da7d805SAndreas Gohr 230*8da7d805SAndreas Gohr return $res->fetch(PDO::FETCH_NUM); 23187fa2c18Sstretchyboy } 232fee3b689Sstretchyboy 233fee3b689Sstretchyboy /** 234fee3b689Sstretchyboy * fetch the next row as assocative array 235*8da7d805SAndreas Gohr * 236*8da7d805SAndreas Gohr * @param \PDOStatement $res 237*8da7d805SAndreas Gohr * @return array|bool 238fee3b689Sstretchyboy */ 239*8da7d805SAndreas Gohr public function res_fetch_assoc($res) 240*8da7d805SAndreas Gohr { 241*8da7d805SAndreas Gohr if (!$res) return false; 242*8da7d805SAndreas Gohr 243*8da7d805SAndreas 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! 250*8da7d805SAndreas Gohr * 251*8da7d805SAndreas Gohr * @param \PDOStatement $res 252*8da7d805SAndreas Gohr * @return int 253fee3b689Sstretchyboy */ 254*8da7d805SAndreas Gohr public function res2count($res) 255*8da7d805SAndreas Gohr { 256*8da7d805SAndreas Gohr if (!$res) return 0; 257*8da7d805SAndreas Gohr 258*8da7d805SAndreas Gohr // this is a bullshit workaround for having res2arr and res2count work on one result 259*8da7d805SAndreas Gohr if (!$this->data) { 260*8da7d805SAndreas Gohr $this->data = $this->res2arr($res); 261*8da7d805SAndreas Gohr } 262*8da7d805SAndreas Gohr 263*8da7d805SAndreas Gohr return count($this->data); 264fee3b689Sstretchyboy } 26524a03f6cSstretchyboy 26624a03f6cSstretchyboy /** 26724a03f6cSstretchyboy * Count the number of records changed last time 268*8da7d805SAndreas Gohr * 269*8da7d805SAndreas Gohr * @param \PDOStatement $res 270*8da7d805SAndreas Gohr * @return int 27124a03f6cSstretchyboy */ 272*8da7d805SAndreas Gohr public function countChanges($res) 273*8da7d805SAndreas Gohr { 274*8da7d805SAndreas Gohr if (!$res) return 0; 275*8da7d805SAndreas Gohr 276*8da7d805SAndreas Gohr return $res->rowCount(); 277a1e6784eSAndreas Gohr } 278a1e6784eSAndreas Gohr 279*8da7d805SAndreas Gohr // endregion 280*8da7d805SAndreas Gohr 281*8da7d805SAndreas Gohr // region quoting/escaping functions 282*8da7d805SAndreas Gohr 283*8da7d805SAndreas Gohr /** 284*8da7d805SAndreas Gohr * Join the given values and quote them for SQL insertion 285*8da7d805SAndreas Gohr */ 286*8da7d805SAndreas Gohr public function quote_and_join($vals, $sep = ',') 287*8da7d805SAndreas Gohr { 288*8da7d805SAndreas Gohr $vals = array_map([$this->adapter->pdo(), 'quote'], $vals); 289*8da7d805SAndreas Gohr return join($sep, $vals); 290*8da7d805SAndreas Gohr } 291*8da7d805SAndreas Gohr 292*8da7d805SAndreas Gohr /** 293*8da7d805SAndreas Gohr * Quotes a string, by escaping it and adding quotes 294*8da7d805SAndreas Gohr */ 295*8da7d805SAndreas Gohr public function quote_string($string) 296*8da7d805SAndreas Gohr { 297*8da7d805SAndreas Gohr return $this->adapter->pdo()->quote($string); 298*8da7d805SAndreas Gohr } 299*8da7d805SAndreas Gohr 300*8da7d805SAndreas Gohr /** 301*8da7d805SAndreas Gohr * Similar to quote_string, but without the quotes, useful to construct LIKE patterns 302*8da7d805SAndreas Gohr */ 303*8da7d805SAndreas Gohr public function escape_string($str) 304*8da7d805SAndreas Gohr { 305*8da7d805SAndreas Gohr return trim($this->adapter->pdo()->quote($str), "'"); 306*8da7d805SAndreas Gohr } 307*8da7d805SAndreas Gohr 308*8da7d805SAndreas Gohr // endregion 309*8da7d805SAndreas Gohr 310*8da7d805SAndreas Gohr // region speciality functions 311*8da7d805SAndreas Gohr 312*8da7d805SAndreas Gohr /** 313*8da7d805SAndreas Gohr * Split sql queries on semicolons, unless when semicolons are quoted 314*8da7d805SAndreas Gohr * 315*8da7d805SAndreas Gohr * Usually you don't need this. It's only really needed if you need individual results for 316*8da7d805SAndreas Gohr * multiple queries. For example in the admin interface. 317*8da7d805SAndreas Gohr * 318*8da7d805SAndreas Gohr * @param string $sql 319*8da7d805SAndreas Gohr * @return array sql queries 320*8da7d805SAndreas Gohr * @deprecated 321*8da7d805SAndreas Gohr */ 322*8da7d805SAndreas Gohr public function SQLstring2array($sql) 323*8da7d805SAndreas Gohr { 324*8da7d805SAndreas Gohr dbg_deprecated(Tools::class . '::SQLstring2array'); 325*8da7d805SAndreas Gohr return Tools::SQLstring2array($sql); 326*8da7d805SAndreas Gohr } 327*8da7d805SAndreas Gohr 328*8da7d805SAndreas Gohr /** 329*8da7d805SAndreas Gohr * @deprecated needs to be fixed in stuct and structpublish 330*8da7d805SAndreas Gohr */ 331*8da7d805SAndreas Gohr public function doTransaction($sql, $sqlpreparing = true) { 332*8da7d805SAndreas Gohr throw new \Exception( 333*8da7d805SAndreas Gohr 'This method seems to never have done what it suggests. Please use the query() function instead.' 334*8da7d805SAndreas Gohr ); 335*8da7d805SAndreas Gohr } 336*8da7d805SAndreas Gohr 337*8da7d805SAndreas Gohr // endregion 338aa81d781SKlap-in} 339