1<?php 2 3/** 4 * @noinspection SqlNoDataSourceInspection 5 * @noinspection SqlDialectInspection 6 * @noinspection PhpComposerExtensionStubsInspection 7 */ 8 9use dokuwiki\plugin\sqlite\SQLiteDB; 10use dokuwiki\plugin\sqlite\Tools; 11 12 13 14/** 15 * For compatibility with previous adapter implementation. 16 */ 17if(!defined('DOKU_EXT_PDO')) define('DOKU_EXT_PDO', 'pdo'); 18class helper_plugin_sqlite_adapter_dummy 19{ 20 public function getName() { 21 return DOKU_EXT_PDO; 22 } 23 24 public function setUseNativeAlter($set) {} 25} 26 27/** 28 * DokuWiki Plugin sqlite (Helper Component) 29 * 30 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 31 * @author Andreas Gohr <gohr@cosmocode.de> 32 * @deprecated 2023-03-15 33 */ 34class helper_plugin_sqlite extends DokuWiki_Plugin 35{ 36 /** @var SQLiteDB|null */ 37 protected $adapter = null; 38 39 /** @var array result cache */ 40 protected $data; 41 42 /** 43 * constructor 44 */ 45 public function __construct() 46 { 47 if (!$this->existsPDOSqlite()) { 48 msg('PDO SQLite support missing in this PHP install - The sqlite plugin will not work', -1); 49 } 50 $this->adapter = new helper_plugin_sqlite_adapter_dummy(); 51 } 52 53 /** 54 * Get the current Adapter 55 * @return SQLiteDB|null 56 */ 57 public function getAdapter() 58 { 59 return $this->adapter; 60 } 61 62 /** 63 * Keep separate instances for every call to keep database connections 64 */ 65 public function isSingleton() 66 { 67 return false; 68 } 69 70 /** 71 * check availabilty of PHP PDO sqlite3 72 */ 73 public function existsPDOSqlite() 74 { 75 if (class_exists('pdo')) { 76 return in_array('sqlite', \PDO::getAvailableDrivers()); 77 } 78 return false; 79 } 80 81 /** 82 * Initializes and opens the database 83 * 84 * Needs to be called right after loading this helper plugin 85 * 86 * @param string $dbname 87 * @param string $updatedir - Database update infos 88 * @return bool 89 */ 90 public function init($dbname, $updatedir) 91 { 92 if(!defined('DOKU_UNITTEST')) { // for now we don't want to trigger the deprecation warning in the tests 93 dbg_deprecated(SQLiteDB::class); 94 } 95 96 try { 97 $this->adapter = new SQLiteDB($dbname, $updatedir, $this); 98 } catch (Exception $e) { 99 msg('SQLite: ' . $e->getMessage(), -1); 100 return false; 101 } 102 return true; 103 } 104 105 /** 106 * This is called from the adapter itself for backwards compatibility 107 * 108 * @param SQLiteDB $adapter 109 * @return void 110 */ 111 function setAdapter($adapter) 112 { 113 $this->adapter = $adapter; 114 } 115 116 /** 117 * Registers a User Defined Function for use in SQL statements 118 */ 119 public function create_function($function_name, $callback, $num_args) 120 { 121 $this->adapter->pdo()->sqliteCreateFunction($function_name, $callback, $num_args); 122 } 123 124 // region query and result handling functions 125 126 /** 127 * Convenience function to run an INSERT OR REPLACE operation 128 * 129 * The function takes a key-value array with the column names in the key and the actual value in the value, 130 * build the appropriate query and executes it. 131 * 132 * @param string $table the table the entry should be saved to (will not be escaped) 133 * @param array $entry A simple key-value pair array (only values will be escaped) 134 * @return bool 135 */ 136 public function storeEntry($table, $entry) 137 { 138 try { 139 $this->adapter->saveRecord($table, $entry); 140 } catch (\Exception $e) { 141 msg('SQLite: ' . $e->getMessage(), -1); 142 return false; 143 } 144 145 return true; 146 } 147 148 /** 149 * Execute a query with the given parameters. 150 * 151 * Takes care of escaping 152 * 153 * 154 * @param string ...$args - the arguments of query(), the first is the sql and others are values 155 */ 156 public function query() 157 { 158 // get function arguments 159 $args = func_get_args(); 160 $sql = array_shift($args); 161 162 try { 163 return $this->adapter->query($sql, $args); 164 } catch (\Exception $e) { 165 msg('SQLite: ' . $e->getMessage(), -1); 166 return false; 167 } 168 } 169 170 171 /** 172 * Closes the result set (and it's cursors) 173 * 174 * If you're doing SELECT queries inside a TRANSACTION, be sure to call this 175 * function on all your results sets, before COMMITing the transaction. 176 * 177 * Also required when not all rows of a result are fetched 178 * 179 * @param \PDOStatement $res 180 * @return bool 181 */ 182 public function res_close($res) 183 { 184 if (!$res) return false; 185 186 return $res->closeCursor(); 187 } 188 189 /** 190 * Returns a complete result set as array 191 * 192 * @param \PDOStatement $res 193 * @return array 194 */ 195 public function res2arr($res, $assoc = true) 196 { 197 if (!$res) return []; 198 199 // this is a bullshit workaround for having res2arr and res2count work on one result 200 if (!$this->data) { 201 $mode = $assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM; 202 $this->data = $res->fetchAll($mode); 203 } 204 return $this->data; 205 } 206 207 /** 208 * Return the next row from the result set as associative array 209 * 210 * @param \PDOStatement $res 211 * @param int $rownum will be ignored 212 */ 213 public function res2row($res, $rownum = 0) 214 { 215 if (!$res) return false; 216 217 return $res->fetch(\PDO::FETCH_ASSOC); 218 } 219 220 /** 221 * Return the first value from the next row. 222 * 223 * @param \PDOStatement $res 224 * @return mixed 225 */ 226 public function res2single($res) 227 { 228 if (!$res) return false; 229 230 $data = $res->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_ABS, 0); 231 if (empty($data)) { 232 return false; 233 } 234 return $data[0]; 235 } 236 237 /** 238 * fetch the next row as zero indexed array 239 * 240 * @param \PDOStatement $res 241 * @return array|bool 242 */ 243 public function res_fetch_array($res) 244 { 245 if (!$res) return false; 246 247 return $res->fetch(PDO::FETCH_NUM); 248 } 249 250 /** 251 * fetch the next row as assocative array 252 * 253 * @param \PDOStatement $res 254 * @return array|bool 255 */ 256 public function res_fetch_assoc($res) 257 { 258 if (!$res) return false; 259 260 return $res->fetch(PDO::FETCH_ASSOC); 261 } 262 263 /** 264 * Count the number of records in result 265 * 266 * This function is really inperformant in PDO and should be avoided! 267 * 268 * @param \PDOStatement $res 269 * @return int 270 */ 271 public function res2count($res) 272 { 273 if (!$res) return 0; 274 275 // this is a bullshit workaround for having res2arr and res2count work on one result 276 if (!$this->data) { 277 $this->data = $this->res2arr($res); 278 } 279 280 return count($this->data); 281 } 282 283 /** 284 * Count the number of records changed last time 285 * 286 * @param \PDOStatement $res 287 * @return int 288 */ 289 public function countChanges($res) 290 { 291 if (!$res) return 0; 292 293 return $res->rowCount(); 294 } 295 296 // endregion 297 298 // region quoting/escaping functions 299 300 /** 301 * Join the given values and quote them for SQL insertion 302 */ 303 public function quote_and_join($vals, $sep = ',') 304 { 305 $vals = array_map([$this->adapter->pdo(), 'quote'], $vals); 306 return join($sep, $vals); 307 } 308 309 /** 310 * Quotes a string, by escaping it and adding quotes 311 */ 312 public function quote_string($string) 313 { 314 return $this->adapter->pdo()->quote($string); 315 } 316 317 /** 318 * Similar to quote_string, but without the quotes, useful to construct LIKE patterns 319 */ 320 public function escape_string($str) 321 { 322 return trim($this->adapter->pdo()->quote($str), "'"); 323 } 324 325 // endregion 326 327 // region speciality functions 328 329 /** 330 * Split sql queries on semicolons, unless when semicolons are quoted 331 * 332 * Usually you don't need this. It's only really needed if you need individual results for 333 * multiple queries. For example in the admin interface. 334 * 335 * @param string $sql 336 * @return array sql queries 337 * @deprecated 338 */ 339 public function SQLstring2array($sql) 340 { 341 if(!DOKU_UNITTEST) { // for now we don't want to trigger the deprecation warning in the tests 342 dbg_deprecated(Tools::class . '::SQLstring2array'); 343 } 344 return Tools::SQLstring2array($sql); 345 } 346 347 /** 348 * @deprecated needs to be fixed in stuct and structpublish 349 */ 350 public function doTransaction($sql, $sqlpreparing = true) { 351 throw new \Exception( 352 'This method seems to never have done what it suggests. Please use the query() function instead.' 353 ); 354 } 355 356 // endregion 357} 358