[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/dml/ -> sqlite3_pdo_moodle_database.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Experimental pdo database class.
  19   *
  20   * @package    core_dml
  21   * @copyright  2008 Andrei Bautu
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  require_once (__DIR__.'/pdo_moodle_database.php');
  28  
  29  /**
  30   * Experimental pdo database class
  31   *
  32   * @package    core_dml
  33   * @copyright  2008 Andrei Bautu
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class sqlite3_pdo_moodle_database extends pdo_moodle_database {
  37      protected $database_file_extension = '.sq3.php';
  38      /**
  39       * Detects if all needed PHP stuff installed.
  40       * Note: can be used before connect()
  41       * @return mixed true if ok, string if something
  42       */
  43      public function driver_installed() {
  44          if (!extension_loaded('pdo_sqlite') || !extension_loaded('pdo')){
  45              return get_string('sqliteextensionisnotpresentinphp', 'install');
  46          }
  47          return true;
  48      }
  49  
  50      /**
  51       * Returns database family type - describes SQL dialect
  52       * Note: can be used before connect()
  53       * @return string db family name (mysql, postgres, mssql, oracle, etc.)
  54       */
  55      public function get_dbfamily() {
  56          return 'sqlite';
  57      }
  58  
  59      /**
  60       * Returns more specific database driver type
  61       * Note: can be used before connect()
  62       * @return string db type mysqli, pgsql, oci, mssql, sqlsrv
  63       */
  64      protected function get_dbtype() {
  65          return 'sqlite3';
  66      }
  67  
  68      protected function configure_dbconnection() {
  69          // try to protect database file against web access;
  70          // this is required in case that the moodledata folder is web accessible and
  71          // .htaccess is not in place; requires that the database file extension is php
  72          $this->pdb->exec('CREATE TABLE IF NOT EXISTS "<?php die?>" (id int)');
  73          $this->pdb->exec('PRAGMA synchronous=OFF');
  74          $this->pdb->exec('PRAGMA short_column_names=1');
  75          $this->pdb->exec('PRAGMA encoding="UTF-8"');
  76          $this->pdb->exec('PRAGMA case_sensitive_like=0');
  77          $this->pdb->exec('PRAGMA locking_mode=NORMAL');
  78      }
  79  
  80      /**
  81       * Attempt to create the database
  82       * @param string $dbhost
  83       * @param string $dbuser
  84       * @param string $dbpass
  85       * @param string $dbname
  86       *
  87       * @return bool success
  88       */
  89      public function create_database($dbhost, $dbuser, $dbpass, $dbname, array $dboptions=null) {
  90          global $CFG;
  91  
  92          $this->dbhost = $dbhost;
  93          $this->dbuser = $dbuser;
  94          $this->dbpass = $dbpass;
  95          $this->dbname = $dbname;
  96          $filepath = $this->get_dbfilepath();
  97          $dirpath = dirname($filepath);
  98          @mkdir($dirpath, $CFG->directorypermissions, true);
  99          return touch($filepath);
 100      }
 101  
 102      /**
 103       * Returns the driver-dependent DSN for PDO based on members stored by connect.
 104       * Must be called after connect (or after $dbname, $dbhost, etc. members have been set).
 105       * @return string driver-dependent DSN
 106       */
 107      protected function get_dsn() {
 108          return 'sqlite:'.$this->get_dbfilepath();
 109      }
 110  
 111      /**
 112       * Returns the file path for the database file, computed from dbname and/or dboptions.
 113       * If dboptions['file'] is set, then it is used (use :memory: for in memory database);
 114       * else if dboptions['path'] is set, then the file will be <dboptions path>/<dbname>.sq3.php;
 115       * else if dbhost is set and not localhost, then the file will be <dbhost>/<dbname>.sq3.php;
 116       * else the file will be <moodle data path>/<dbname>.sq3.php
 117       * @return string file path to the SQLite database;
 118       */
 119      public function get_dbfilepath() {
 120          global $CFG;
 121          if (!empty($this->dboptions['file'])) {
 122              return $this->dboptions['file'];
 123          }
 124          if ($this->dbhost && $this->dbhost != 'localhost') {
 125              $path = $this->dbhost;
 126          } else {
 127              $path = $CFG->dataroot;
 128          }
 129          $path = rtrim($path, '\\/').'/';
 130          if (!empty($this->dbuser)) {
 131              $path .= $this->dbuser.'_';
 132          }
 133          $path .= $this->dbname.'_'.md5($this->dbpass).$this->database_file_extension;
 134          return $path;
 135      }
 136  
 137      /**
 138       * Return tables in database WITHOUT current prefix.
 139       * @param bool $usecache if true, returns list of cached tables.
 140       * @return array of table names in lowercase and without prefix
 141       */
 142      public function get_tables($usecache=true) {
 143          $tables = array();
 144  
 145          $sql = 'SELECT name FROM sqlite_master WHERE type="table" UNION ALL SELECT name FROM sqlite_temp_master WHERE type="table" ORDER BY name';
 146          if ($this->debug) {
 147              $this->debug_query($sql);
 148          }
 149          $rstables = $this->pdb->query($sql);
 150          foreach ($rstables as $table) {
 151              $table = $table['name'];
 152              $table = strtolower($table);
 153              if ($this->prefix !== false && $this->prefix !== '') {
 154                  if (strpos($table, $this->prefix) !== 0) {
 155                      continue;
 156                  }
 157                  $table = substr($table, strlen($this->prefix));
 158              }
 159              $tables[$table] = $table;
 160          }
 161          return $tables;
 162      }
 163  
 164      /**
 165       * Return table indexes - everything lowercased
 166       * @param string $table The table we want to get indexes from.
 167       * @return array of arrays
 168       */
 169      public function get_indexes($table) {
 170          $indexes = array();
 171          $sql = 'PRAGMA index_list('.$this->prefix.$table.')';
 172          if ($this->debug) {
 173              $this->debug_query($sql);
 174          }
 175          $rsindexes = $this->pdb->query($sql);
 176          foreach($rsindexes as $index) {
 177              $unique = (boolean)$index['unique'];
 178              $index = $index['name'];
 179              $sql = 'PRAGMA index_info("'.$index.'")';
 180              if ($this->debug) {
 181                  $this->debug_query($sql);
 182              }
 183              $rscolumns = $this->pdb->query($sql);
 184              $columns = array();
 185              foreach($rscolumns as $row) {
 186                  $columns[] = strtolower($row['name']);
 187              }
 188              $index = strtolower($index);
 189              $indexes[$index]['unique'] = $unique;
 190              $indexes[$index]['columns'] = $columns;
 191          }
 192          return $indexes;
 193      }
 194  
 195      /**
 196       * Returns detailed information about columns in table. This information is cached internally.
 197       * @param string $table name
 198       * @param bool $usecache
 199       * @return array array of database_column_info objects indexed with column names
 200       */
 201      public function get_columns($table, $usecache=true) {
 202  
 203          if ($usecache) {
 204              if ($this->temptables->is_temptable($table)) {
 205                  if ($data = $this->get_temp_tables_cache()->get($table)) {
 206                      return $data;
 207                  }
 208              } else {
 209                  if ($data = $this->get_metacache()->get($table)) {
 210                      return $data;
 211                  }
 212              }
 213          }
 214  
 215          $structure = array();
 216  
 217          // get table's CREATE TABLE command (we'll need it for autoincrement fields)
 218          $sql = 'SELECT sql FROM sqlite_master WHERE type="table" AND tbl_name="'.$this->prefix.$table.'"';
 219          if ($this->debug) {
 220              $this->debug_query($sql);
 221          }
 222          $createsql = $this->pdb->query($sql)->fetch();
 223          if (!$createsql) {
 224              return false;
 225          }
 226          $createsql = $createsql['sql'];
 227  
 228          $sql = 'PRAGMA table_info("'. $this->prefix.$table.'")';
 229          if ($this->debug) {
 230              $this->debug_query($sql);
 231          }
 232          $rscolumns = $this->pdb->query($sql);
 233          foreach ($rscolumns as $row) {
 234              $columninfo = array(
 235                  'name' => strtolower($row['name']), // colum names must be lowercase
 236                  'not_null' =>(boolean)$row['notnull'],
 237                  'primary_key' => (boolean)$row['pk'],
 238                  'has_default' => !is_null($row['dflt_value']),
 239                  'default_value' => $row['dflt_value'],
 240                  'auto_increment' => false,
 241                  'binary' => false,
 242                  //'unsigned' => false,
 243              );
 244              $type = explode('(', $row['type']);
 245              $columninfo['type'] = strtolower($type[0]);
 246              if (count($type) > 1) {
 247                  $size = explode(',', trim($type[1], ')'));
 248                  $columninfo['max_length'] = $size[0];
 249                  if (count($size) > 1) {
 250                      $columninfo['scale'] = $size[1];
 251                  }
 252              }
 253              // SQLite does not have a fixed set of datatypes (ie. it accepts any string as
 254              // datatype in the CREATE TABLE command. We try to guess which type is used here
 255              switch(substr($columninfo['type'], 0, 3)) {
 256                  case 'int': // int integer
 257                      if ($columninfo['primary_key'] && preg_match('/'.$columninfo['name'].'\W+integer\W+primary\W+key\W+autoincrement/im', $createsql)) {
 258                          $columninfo['meta_type'] = 'R';
 259                          $columninfo['auto_increment'] = true;
 260                      } else {
 261                          $columninfo['meta_type'] = 'I';
 262                      }
 263                      break;
 264                  case 'num': // number numeric
 265                  case 'rea': // real
 266                  case 'dou': // double
 267                  case 'flo': // float
 268                      $columninfo['meta_type'] = 'N';
 269                      break;
 270                  case 'var': // varchar
 271                  case 'cha': // char
 272                      $columninfo['meta_type'] = 'C';
 273                      break;
 274                  case 'enu': // enums
 275                      $columninfo['meta_type'] = 'C';
 276                      break;
 277                  case 'tex': // text
 278                  case 'clo': // clob
 279                      $columninfo['meta_type'] = 'X';
 280                      break;
 281                  case 'blo': // blob
 282                  case 'non': // none
 283                      $columninfo['meta_type'] = 'B';
 284                      $columninfo['binary'] = true;
 285                      break;
 286                  case 'boo': // boolean
 287                  case 'bit': // bit
 288                  case 'log': // logical
 289                      $columninfo['meta_type'] = 'L';
 290                      $columninfo['max_length'] = 1;
 291                      break;
 292                  case 'tim': // timestamp
 293                      $columninfo['meta_type'] = 'T';
 294                      break;
 295                  case 'dat': // date datetime
 296                      $columninfo['meta_type'] = 'D';
 297                      break;
 298              }
 299              if ($columninfo['has_default'] && ($columninfo['meta_type'] == 'X' || $columninfo['meta_type']== 'C')) {
 300                  // trim extra quotes from text default values
 301                  $columninfo['default_value'] = substr($columninfo['default_value'], 1, -1);
 302              }
 303              $structure[$columninfo['name']] = new database_column_info($columninfo);
 304          }
 305  
 306          if ($usecache) {
 307              if ($this->temptables->is_temptable($table)) {
 308                  $this->get_temp_tables_cache()->set($table, $structure);
 309              } else {
 310                  $this->get_metacache()->set($table, $structure);
 311              }
 312          }
 313  
 314          return $structure;
 315      }
 316  
 317      /**
 318       * Normalise values based in RDBMS dependencies (booleans, LOBs...)
 319       *
 320       * @param database_column_info $column column metadata corresponding with the value we are going to normalise
 321       * @param mixed $value value we are going to normalise
 322       * @return mixed the normalised value
 323       */
 324      protected function normalise_value($column, $value) {
 325          return $value;
 326      }
 327  
 328      /**
 329       * Returns the sql statement with clauses to append used to limit a recordset range.
 330       * @param string $sql the SQL statement to limit.
 331       * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
 332       * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
 333       * @return string the SQL statement with limiting clauses
 334       */
 335      protected function get_limit_clauses($sql, $limitfrom=0, $limitnum=0) {
 336          if ($limitnum) {
 337              $sql .= ' LIMIT '.$limitnum;
 338              if ($limitfrom) {
 339                  $sql .= ' OFFSET '.$limitfrom;
 340              }
 341          }
 342          return $sql;
 343      }
 344  
 345      /**
 346       * Delete the records from a table where all the given conditions met.
 347       * If conditions not specified, table is truncated.
 348       *
 349       * @param string $table the table to delete from.
 350       * @param array $conditions optional array $fieldname=>requestedvalue with AND in between
 351       * @return returns success.
 352       */
 353      public function delete_records($table, array $conditions=null) {
 354          if (is_null($conditions)) {
 355              return $this->execute("DELETE FROM {{$table}}");
 356          }
 357          list($select, $params) = $this->where_clause($table, $conditions);
 358          return $this->delete_records_select($table, $select, $params);
 359      }
 360  
 361      /**
 362       * Returns the proper SQL to do CONCAT between the elements passed
 363       * Can take many parameters
 364       *
 365       * @param string $element
 366       * @return string
 367       */
 368      public function sql_concat() {
 369          $elements = func_get_args();
 370          return implode('||', $elements);
 371      }
 372  
 373      /**
 374       * Returns the proper SQL to do CONCAT between the elements passed
 375       * with a given separator
 376       *
 377       * @param string $separator
 378       * @param array  $elements
 379       * @return string
 380       */
 381      public function sql_concat_join($separator="' '", $elements=array()) {
 382          // Intersperse $elements in the array.
 383          // Add items to the array on the fly, walking it
 384          // _backwards_ splicing the elements in. The loop definition
 385          // should skip first and last positions.
 386          for ($n=count($elements)-1; $n > 0; $n--) {
 387              array_splice($elements, $n, 0, $separator);
 388          }
 389          return implode('||', $elements);
 390      }
 391  
 392      /**
 393       * Returns the SQL text to be used in order to perform one bitwise XOR operation
 394       * between 2 integers.
 395       *
 396       * @param integer int1 first integer in the operation
 397       * @param integer int2 second integer in the operation
 398       * @return string the piece of SQL code to be used in your statement.
 399       */
 400      public function sql_bitxor($int1, $int2) {
 401          return '( ~' . $this->sql_bitand($int1, $int2) . ' & ' . $this->sql_bitor($int1, $int2) . ')';
 402      }
 403  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1