MediaWiki  master
DatabaseSqlite.php
Go to the documentation of this file.
1 <?php
24 namespace Wikimedia\Rdbms;
25 
26 use FSLockManager;
27 use LockManager;
28 use NullLockManager;
29 use PDO;
30 use PDOException;
31 use RuntimeException;
32 use stdClass;
33 
37 class DatabaseSqlite extends Database {
39  protected $dbDir;
41  protected $dbPath;
43  protected $trxMode;
44 
47 
49  protected $conn;
50 
52  protected $lockMgr;
53 
55  private $version;
56 
58  private $sessionAttachedDbs = [];
59 
61  private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
62 
64  private static $VALID_PRAGMAS = [
65  // Optimizations or requirements regarding fsync() usage
66  'synchronous' => [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ],
67  // Optimizations for TEMPORARY tables
68  'temp_store' => [ 'FILE', 'MEMORY' ]
69  ];
70 
78  public function __construct( array $params ) {
79  if ( isset( $params['dbFilePath'] ) ) {
80  $this->dbPath = $params['dbFilePath'];
81  if ( !strlen( $params['dbname'] ) ) {
82  $params['dbname'] = self::generateDatabaseName( $this->dbPath );
83  }
84  } elseif ( isset( $params['dbDirectory'] ) ) {
85  $this->dbDir = $params['dbDirectory'];
86  }
87 
88  parent::__construct( $params );
89 
90  $this->trxMode = strtoupper( $params['trxMode'] ?? '' );
91 
92  $lockDirectory = $this->getLockFileDirectory();
93  if ( $lockDirectory !== null ) {
94  $this->lockMgr = new FSLockManager( [
95  'domain' => $this->getDomainID(),
96  'lockDirectory' => $lockDirectory
97  ] );
98  } else {
99  $this->lockMgr = new NullLockManager( [ 'domain' => $this->getDomainID() ] );
100  }
101  }
102 
103  protected static function getAttributes() {
104  return [
105  self::ATTR_DB_IS_FILE => true,
106  self::ATTR_DB_LEVEL_LOCKING => true
107  ];
108  }
109 
119  public static function newStandaloneInstance( $filename, array $p = [] ) {
120  $p['dbFilePath'] = $filename;
121  $p['schema'] = null;
122  $p['tablePrefix'] = '';
124  $db = Database::factory( 'sqlite', $p );
125 
126  return $db;
127  }
128 
132  public function getType() {
133  return 'sqlite';
134  }
135 
136  protected function open( $server, $user, $password, $db, $schema, $tablePrefix ) {
137  $this->close( __METHOD__ );
138 
139  // Note that for SQLite, $server, $user, and $pass are ignored
140 
141  if ( $schema !== null ) {
142  throw $this->newExceptionAfterConnectError( "Got schema '$schema'; not supported." );
143  }
144 
145  if ( $this->dbPath !== null ) {
147  } elseif ( $this->dbDir !== null ) {
148  $path = self::generateFileName( $this->dbDir, $db );
149  } else {
150  throw $this->newExceptionAfterConnectError( "DB path or directory required" );
151  }
152 
153  // Check if the database file already exists but is non-readable
154  if ( !self::isProcessMemoryPath( $path ) && is_file( $path ) && !is_readable( $path ) ) {
155  throw $this->newExceptionAfterConnectError( 'SQLite database file is not readable' );
156  } elseif ( !in_array( $this->trxMode, self::$VALID_TRX_MODES, true ) ) {
157  throw $this->newExceptionAfterConnectError( "Got mode '{$this->trxMode}' for BEGIN" );
158  }
159 
160  $attributes = [];
161  if ( $this->getFlag( self::DBO_PERSISTENT ) ) {
162  // Persistent connections can avoid some schema index reading overhead.
163  // On the other hand, they can cause horrible contention with DBO_TRX.
164  if ( $this->getFlag( self::DBO_TRX ) || $this->getFlag( self::DBO_DEFAULT ) ) {
165  $this->connLogger->warning(
166  __METHOD__ . ": ignoring DBO_PERSISTENT due to DBO_TRX or DBO_DEFAULT",
167  $this->getLogContext()
168  );
169  } else {
170  $attributes[PDO::ATTR_PERSISTENT] = true;
171  }
172  }
173 
174  try {
175  // Open the database file, creating it if it does not yet exist
176  $this->conn = new PDO( "sqlite:$path", null, null, $attributes );
177  } catch ( PDOException $e ) {
178  throw $this->newExceptionAfterConnectError( $e->getMessage() );
179  }
180 
181  $this->currentDomain = new DatabaseDomain( $db, null, $tablePrefix );
182 
183  try {
184  $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_NO_RETRY;
185  // Enforce LIKE to be case sensitive, just like MySQL
186  $this->query( 'PRAGMA case_sensitive_like = 1', __METHOD__, $flags );
187  // Set any connection-level custom PRAGMA options
188  $pragmas = array_intersect_key( $this->connectionVariables, self::$VALID_PRAGMAS );
189  $pragmas += $this->getDefaultPragmas();
190  foreach ( $pragmas as $name => $value ) {
191  $allowed = self::$VALID_PRAGMAS[$name];
192  if ( in_array( $value, $allowed, true ) ) {
193  $this->query( "PRAGMA $name = $value", __METHOD__, $flags );
194  }
195  }
197  } catch ( RuntimeException $e ) {
198  throw $this->newExceptionAfterConnectError( $e->getMessage() );
199  }
200  }
201 
205  private function getDefaultPragmas() {
206  $variables = [];
207 
208  if ( !$this->cliMode ) {
209  $variables['temp_store'] = 'MEMORY';
210  }
211 
212  return $variables;
213  }
214 
220  public function getDbFilePath() {
221  return $this->dbPath ?? self::generateFileName( $this->dbDir, $this->getDBname() );
222  }
223 
227  public function getLockFileDirectory() {
228  if ( $this->dbPath !== null && !self::isProcessMemoryPath( $this->dbPath ) ) {
229  return dirname( $this->dbPath ) . '/locks';
230  } elseif ( $this->dbDir !== null && !self::isProcessMemoryPath( $this->dbDir ) ) {
231  return $this->dbDir . '/locks';
232  }
233 
234  return null;
235  }
236 
241  protected function closeConnection() {
242  $this->conn = null;
243 
244  return true;
245  }
246 
254  public static function generateFileName( $dir, $dbName ) {
255  if ( $dir == '' ) {
256  throw new DBUnexpectedError( null, __CLASS__ . ": no DB directory specified" );
257  } elseif ( self::isProcessMemoryPath( $dir ) ) {
258  throw new DBUnexpectedError(
259  null,
260  __CLASS__ . ": cannot use process memory directory '$dir'"
261  );
262  } elseif ( !strlen( $dbName ) ) {
263  throw new DBUnexpectedError( null, __CLASS__ . ": no DB name specified" );
264  }
265 
266  return "$dir/$dbName.sqlite";
267  }
268 
273  private static function generateDatabaseName( $path ) {
274  if ( preg_match( '/^(:memory:$|file::memory:)/', $path ) ) {
275  // E.g. "file::memory:?cache=shared" => ":memory":
276  return ':memory:';
277  } elseif ( preg_match( '/^file::([^?]+)\?mode=memory(&|$)/', $path, $m ) ) {
278  // E.g. "file:memdb1?mode=memory" => ":memdb1:"
279  return ":{$m[1]}:";
280  } else {
281  // E.g. "/home/.../some_db.sqlite3" => "some_db"
282  return preg_replace( '/\.sqlite\d?$/', '', basename( $path ) );
283  }
284  }
285 
290  private static function isProcessMemoryPath( $path ) {
291  return preg_match( '/^(:memory:$|file:(:memory:|[^?]+\?mode=memory(&|$)))/', $path );
292  }
293 
298  public static function getFulltextSearchModule() {
299  static $cachedResult = null;
300  if ( $cachedResult !== null ) {
301  return $cachedResult;
302  }
303  $cachedResult = false;
304  $table = 'dummy_search_test';
305 
306  $db = self::newStandaloneInstance( ':memory:' );
307  if ( $db->query(
308  "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)",
309  __METHOD__,
310  IDatabase::QUERY_SILENCE_ERRORS
311  ) ) {
312  $cachedResult = 'FTS3';
313  }
314  $db->close( __METHOD__ );
315 
316  return $cachedResult;
317  }
318 
331  public function attachDatabase( $name, $file = false, $fname = __METHOD__ ) {
332  $file = is_string( $file ) ? $file : self::generateFileName( $this->dbDir, $name );
333  $encFile = $this->addQuotes( $file );
334 
335  return $this->query(
336  "ATTACH DATABASE $encFile AS $name",
337  $fname,
338  self::QUERY_IGNORE_DBO_TRX
339  );
340  }
341 
342  protected function isWriteQuery( $sql, $flags ) {
343  return parent::isWriteQuery( $sql, $flags ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql );
344  }
345 
346  protected function isTransactableQuery( $sql ) {
347  return parent::isTransactableQuery( $sql ) && !in_array(
348  $this->getQueryVerb( $sql ),
349  [ 'ATTACH', 'PRAGMA' ],
350  true
351  );
352  }
353 
360  protected function doQuery( $sql ) {
361  $res = $this->getBindingHandle()->query( $sql );
362  if ( $res === false ) {
363  return false;
364  }
365 
366  $resource = ResultWrapper::unwrap( $res );
367  $this->lastAffectedRowCount = $resource->rowCount();
368  $res = new ResultWrapper( $this, $resource->fetchAll() );
369 
370  return $res;
371  }
372 
376  public function freeResult( $res ) {
377  if ( $res instanceof ResultWrapper ) {
378  $res->free();
379  }
380  }
381 
386  public function fetchObject( $res ) {
387  $resource =& ResultWrapper::unwrap( $res );
388 
389  $cur = current( $resource );
390  if ( is_array( $cur ) ) {
391  next( $resource );
392  $obj = (object)[];
393  foreach ( $cur as $k => $v ) {
394  if ( !is_numeric( $k ) ) {
395  $obj->$k = $v;
396  }
397  }
398 
399  return $obj;
400  }
401 
402  return false;
403  }
404 
409  public function fetchRow( $res ) {
410  $resource =& ResultWrapper::unwrap( $res );
411  $cur = current( $resource );
412  if ( is_array( $cur ) ) {
413  next( $resource );
414 
415  return $cur;
416  }
417 
418  return false;
419  }
420 
427  public function numRows( $res ) {
428  // false does not implement Countable
429  $resource = ResultWrapper::unwrap( $res );
430 
431  return is_array( $resource ) ? count( $resource ) : 0;
432  }
433 
438  public function numFields( $res ) {
439  $resource = ResultWrapper::unwrap( $res );
440  if ( is_array( $resource ) && count( $resource ) > 0 ) {
441  // The size of the result array is twice the number of fields. (T67578)
442  return count( $resource[0] ) / 2;
443  } else {
444  // If the result is empty return 0
445  return 0;
446  }
447  }
448 
454  public function fieldName( $res, $n ) {
455  $resource = ResultWrapper::unwrap( $res );
456  if ( is_array( $resource ) ) {
457  $keys = array_keys( $resource[0] );
458 
459  return $keys[$n];
460  }
461 
462  return false;
463  }
464 
465  protected function doSelectDomain( DatabaseDomain $domain ) {
466  if ( $domain->getSchema() !== null ) {
467  throw new DBExpectedError(
468  $this,
469  __CLASS__ . ": domain '{$domain->getId()}' has a schema component"
470  );
471  }
472 
473  $database = $domain->getDatabase();
474  // A null database means "don't care" so leave it as is and update the table prefix
475  if ( $database === null ) {
476  $this->currentDomain = new DatabaseDomain(
477  $this->currentDomain->getDatabase(),
478  null,
479  $domain->getTablePrefix()
480  );
481 
482  return true;
483  }
484 
485  if ( $database !== $this->getDBname() ) {
486  throw new DBExpectedError(
487  $this,
488  __CLASS__ . ": cannot change database (got '$database')"
489  );
490  }
491 
492  return true;
493  }
494 
502  public function tableName( $name, $format = 'quoted' ) {
503  // table names starting with sqlite_ are reserved
504  if ( strpos( $name, 'sqlite_' ) === 0 ) {
505  return $name;
506  }
507 
508  return str_replace( '"', '', parent::tableName( $name, $format ) );
509  }
510 
516  public function insertId() {
517  // PDO::lastInsertId yields a string :(
518  return intval( $this->getBindingHandle()->lastInsertId() );
519  }
520 
525  public function dataSeek( $res, $row ) {
526  $resource =& ResultWrapper::unwrap( $res );
527  reset( $resource );
528  if ( $row > 0 ) {
529  for ( $i = 0; $i < $row; $i++ ) {
530  next( $resource );
531  }
532  }
533  }
534 
538  public function lastError() {
539  if ( !is_object( $this->conn ) ) {
540  return "Cannot return last error, no db connection";
541  }
542  $e = $this->conn->errorInfo();
543 
544  return $e[2] ?? '';
545  }
546 
550  public function lastErrno() {
551  if ( !is_object( $this->conn ) ) {
552  return "Cannot return last error, no db connection";
553  } else {
554  $info = $this->conn->errorInfo();
555 
556  return $info[1];
557  }
558  }
559 
563  protected function fetchAffectedRowCount() {
565  }
566 
567  public function tableExists( $table, $fname = __METHOD__ ) {
568  $tableRaw = $this->tableName( $table, 'raw' );
569  if ( isset( $this->sessionTempTables[$tableRaw] ) ) {
570  return true; // already known to exist
571  }
572 
573  $encTable = $this->addQuotes( $tableRaw );
574  $res = $this->query(
575  "SELECT 1 FROM sqlite_master WHERE type='table' AND name=$encTable",
576  __METHOD__,
577  self::QUERY_IGNORE_DBO_TRX
578  );
579 
580  return $res->numRows() ? true : false;
581  }
582 
593  public function indexInfo( $table, $index, $fname = __METHOD__ ) {
594  $sql = 'PRAGMA index_info(' . $this->addQuotes( $this->indexName( $index ) ) . ')';
595  $res = $this->query( $sql, $fname, self::QUERY_IGNORE_DBO_TRX );
596  if ( !$res || $res->numRows() == 0 ) {
597  return false;
598  }
599  $info = [];
600  foreach ( $res as $row ) {
601  $info[] = $row->name;
602  }
603 
604  return $info;
605  }
606 
613  public function indexUnique( $table, $index, $fname = __METHOD__ ) {
614  $row = $this->selectRow( 'sqlite_master', '*',
615  [
616  'type' => 'index',
617  'name' => $this->indexName( $index ),
618  ], $fname );
619  if ( !$row || !isset( $row->sql ) ) {
620  return null;
621  }
622 
623  // $row->sql will be of the form CREATE [UNIQUE] INDEX ...
624  $indexPos = strpos( $row->sql, 'INDEX' );
625  if ( $indexPos === false ) {
626  return null;
627  }
628  $firstPart = substr( $row->sql, 0, $indexPos );
629  $options = explode( ' ', $firstPart );
630 
631  return in_array( 'UNIQUE', $options );
632  }
633 
634  protected function makeSelectOptions( array $options ) {
635  // Remove problematic options that the base implementation converts to SQL
636  foreach ( $options as $k => $v ) {
637  if ( is_numeric( $k ) && ( $v === 'FOR UPDATE' || $v === 'LOCK IN SHARE MODE' ) ) {
638  $options[$k] = '';
639  }
640  }
641 
642  return parent::makeSelectOptions( $options );
643  }
644 
649  protected function makeUpdateOptionsArray( $options ) {
650  $options = parent::makeUpdateOptionsArray( $options );
651  $options = $this->rewriteIgnoreKeyword( $options );
652 
653  return $options;
654  }
655 
660  private function rewriteIgnoreKeyword( $options ) {
661  # SQLite uses OR IGNORE not just IGNORE
662  foreach ( $options as $k => $v ) {
663  if ( $v == 'IGNORE' ) {
664  $options[$k] = 'OR IGNORE';
665  }
666  }
667 
668  return $options;
669  }
670 
672  return [ 'INSERT OR IGNORE INTO', '' ];
673  }
674 
675  protected function doReplace( $table, array $uniqueKey, array $rows, $fname ) {
676  $encTable = $this->tableName( $table );
677  list( $sqlColumns, $sqlTuples ) = $this->makeInsertLists( $rows );
678  // https://sqlite.org/lang_insert.html
679  $this->query( "REPLACE INTO $encTable ($sqlColumns) VALUES $sqlTuples", $fname );
680  }
681 
690  public function textFieldSize( $table, $field ) {
691  return -1;
692  }
693 
697  public function unionSupportsOrderAndLimit() {
698  return false;
699  }
700 
706  public function unionQueries( $sqls, $all ) {
707  $glue = $all ? ' UNION ALL ' : ' UNION ';
708 
709  return implode( $glue, $sqls );
710  }
711 
715  public function wasDeadlock() {
716  return $this->lastErrno() == 5; // SQLITE_BUSY
717  }
718 
722  public function wasReadOnlyError() {
723  return $this->lastErrno() == 8; // SQLITE_READONLY;
724  }
725 
726  public function wasConnectionError( $errno ) {
727  return $errno == 17; // SQLITE_SCHEMA;
728  }
729 
730  protected function wasKnownStatementRollbackError() {
731  // ON CONFLICT ROLLBACK clauses make it so that SQLITE_CONSTRAINT error is
732  // ambiguous with regard to whether it implies a ROLLBACK or an ABORT happened.
733  // https://sqlite.org/lang_createtable.html#uniqueconst
734  // https://sqlite.org/lang_conflict.html
735  return false;
736  }
737 
738  public function getTopologyBasedServerId() {
739  // Sqlite topologies trivially consist of single master server for the dataset
740  return 0;
741  }
742 
743  public function serverIsReadOnly() {
744  $this->assertHasConnectionHandle();
745 
746  $path = $this->getDbFilePath();
747 
748  return ( !self::isProcessMemoryPath( $path ) && !is_writable( $path ) );
749  }
750 
754  public function getSoftwareLink() {
755  return "[{{int:version-db-sqlite-url}} SQLite]";
756  }
757 
761  public function getServerVersion() {
762  if ( $this->version === null ) {
763  $this->version = $this->getBindingHandle()->getAttribute( PDO::ATTR_SERVER_VERSION );
764  }
765 
766  return $this->version;
767  }
768 
777  public function fieldInfo( $table, $field ) {
778  $tableName = $this->tableName( $table );
779  $sql = 'PRAGMA table_info(' . $this->addQuotes( $tableName ) . ')';
780  $res = $this->query( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
781  foreach ( $res as $row ) {
782  if ( $row->name == $field ) {
783  return new SQLiteField( $row, $tableName );
784  }
785  }
786 
787  return false;
788  }
789 
790  protected function doBegin( $fname = '' ) {
791  if ( $this->trxMode != '' ) {
792  $this->query( "BEGIN {$this->trxMode}", $fname );
793  } else {
794  $this->query( 'BEGIN', $fname );
795  }
796  }
797 
802  public function strencode( $s ) {
803  return substr( $this->addQuotes( $s ), 1, -1 );
804  }
805 
810  public function encodeBlob( $b ) {
811  return new Blob( $b );
812  }
813 
818  public function decodeBlob( $b ) {
819  if ( $b instanceof Blob ) {
820  $b = $b->fetch();
821  }
822 
823  return $b;
824  }
825 
830  public function addQuotes( $s ) {
831  if ( $s instanceof Blob ) {
832  return "x'" . bin2hex( $s->fetch() ) . "'";
833  } elseif ( is_bool( $s ) ) {
834  return (string)(int)$s;
835  } elseif ( is_int( $s ) ) {
836  return (string)$s;
837  } elseif ( strpos( (string)$s, "\0" ) !== false ) {
838  // SQLite doesn't support \0 in strings, so use the hex representation as a workaround.
839  // This is a known limitation of SQLite's mprintf function which PDO
840  // should work around, but doesn't. I have reported this to php.net as bug #63419:
841  // https://bugs.php.net/bug.php?id=63419
842  // There was already a similar report for SQLite3::escapeString, bug #62361:
843  // https://bugs.php.net/bug.php?id=62361
844  // There is an additional bug regarding sorting this data after insert
845  // on older versions of sqlite shipped with ubuntu 12.04
846  // https://phabricator.wikimedia.org/T74367
847  $this->queryLogger->debug(
848  __FUNCTION__ .
849  ': Quoting value containing null byte. ' .
850  'For consistency all binary data should have been ' .
851  'first processed with self::encodeBlob()'
852  );
853  return "x'" . bin2hex( (string)$s ) . "'";
854  } else {
855  return $this->getBindingHandle()->quote( (string)$s );
856  }
857  }
858 
859  public function buildSubstring( $input, $startPosition, $length = null ) {
860  $this->assertBuildSubstringParams( $startPosition, $length );
861  $params = [ $input, $startPosition ];
862  if ( $length !== null ) {
863  $params[] = $length;
864  }
865  return 'SUBSTR(' . implode( ',', $params ) . ')';
866  }
867 
873  public function buildStringCast( $field ) {
874  return 'CAST ( ' . $field . ' AS TEXT )';
875  }
876 
883  public function deadlockLoop( ...$args ) {
884  $function = array_shift( $args );
885 
886  return $function( ...$args );
887  }
888 
893  protected function replaceVars( $s ) {
894  $s = parent::replaceVars( $s );
895  if ( preg_match( '/^\s*(CREATE|ALTER) TABLE/i', $s ) ) {
896  // CREATE TABLE hacks to allow schema file sharing with MySQL
897 
898  // binary/varbinary column type -> blob
899  $s = preg_replace( '/\b(var)?binary(\‍(\d+\‍))/i', 'BLOB', $s );
900  // no such thing as unsigned
901  $s = preg_replace( '/\b(un)?signed\b/i', '', $s );
902  // INT -> INTEGER
903  $s = preg_replace( '/\b(tiny|small|medium|big|)int(\s*\‍(\s*\d+\s*\‍)|\b)/i', 'INTEGER', $s );
904  // floating point types -> REAL
905  $s = preg_replace(
906  '/\b(float|double(\s+precision)?)(\s*\‍(\s*\d+\s*(,\s*\d+\s*)?\‍)|\b)/i',
907  'REAL',
908  $s
909  );
910  // varchar -> TEXT
911  $s = preg_replace( '/\b(var)?char\s*\‍(.*?\‍)/i', 'TEXT', $s );
912  // TEXT normalization
913  $s = preg_replace( '/\b(tiny|medium|long)text\b/i', 'TEXT', $s );
914  // BLOB normalization
915  $s = preg_replace( '/\b(tiny|small|medium|long|)blob\b/i', 'BLOB', $s );
916  // BOOL -> INTEGER
917  $s = preg_replace( '/\bbool(ean)?\b/i', 'INTEGER', $s );
918  // DATETIME -> TEXT
919  $s = preg_replace( '/\b(datetime|timestamp)\b/i', 'TEXT', $s );
920  // No ENUM type
921  $s = preg_replace( '/\benum\s*\‍([^)]*\‍)/i', 'TEXT', $s );
922  // binary collation type -> nothing
923  $s = preg_replace( '/\bbinary\b/i', '', $s );
924  // auto_increment -> autoincrement
925  $s = preg_replace( '/\bauto_increment\b/i', 'AUTOINCREMENT', $s );
926  // No explicit options
927  $s = preg_replace( '/\‍)[^);]*(;?)\s*$/', ')\1', $s );
928  // AUTOINCREMENT should immedidately follow PRIMARY KEY
929  $s = preg_replace( '/primary key (.*?) autoincrement/i', 'PRIMARY KEY AUTOINCREMENT $1', $s );
930  } elseif ( preg_match( '/^\s*CREATE (\s*(?:UNIQUE|FULLTEXT)\s+)?INDEX/i', $s ) ) {
931  // No truncated indexes
932  $s = preg_replace( '/\‍(\d+\‍)/', '', $s );
933  // No FULLTEXT
934  $s = preg_replace( '/\bfulltext\b/i', '', $s );
935  } elseif ( preg_match( '/^\s*DROP INDEX/i', $s ) ) {
936  // DROP INDEX is database-wide, not table-specific, so no ON <table> clause.
937  $s = preg_replace( '/\sON\s+[^\s]*/i', '', $s );
938  } elseif ( preg_match( '/^\s*INSERT IGNORE\b/i', $s ) ) {
939  // INSERT IGNORE --> INSERT OR IGNORE
940  $s = preg_replace( '/^\s*INSERT IGNORE\b/i', 'INSERT OR IGNORE', $s );
941  }
942 
943  return $s;
944  }
945 
946  public function lock( $lockName, $method, $timeout = 5 ) {
947  $status = $this->lockMgr->lock( [ $lockName ], LockManager::LOCK_EX, $timeout );
948  if (
949  $this->lockMgr instanceof FSLockManager &&
950  $status->hasMessage( 'lockmanager-fail-openlock' )
951  ) {
952  throw new DBError( $this, "Cannot create directory \"{$this->getLockFileDirectory()}\"" );
953  }
954 
955  return $status->isOK();
956  }
957 
958  public function unlock( $lockName, $method ) {
959  return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isGood();
960  }
961 
968  public function buildConcat( $stringList ) {
969  return '(' . implode( ') || (', $stringList ) . ')';
970  }
971 
972  public function buildGroupConcatField(
973  $delim, $table, $field, $conds = '', $join_conds = []
974  ) {
975  $fld = "group_concat($field," . $this->addQuotes( $delim ) . ')';
976 
977  return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')';
978  }
979 
980  public function buildGreatest( $fields, $values ) {
981  return $this->buildSuperlative( 'MAX', $fields, $values );
982  }
983 
984  public function buildLeast( $fields, $values ) {
985  return $this->buildSuperlative( 'MIN', $fields, $values );
986  }
987 
996  public function duplicateTableStructure(
997  $oldName, $newName, $temporary = false, $fname = __METHOD__
998  ) {
999  $queryFlags = self::QUERY_PSEUDO_PERMANENT | self::QUERY_IGNORE_DBO_TRX;
1000 
1001  $res = $this->query(
1002  "SELECT sql FROM sqlite_master WHERE tbl_name=" .
1003  $this->addQuotes( $oldName ) . " AND type='table'",
1004  $fname,
1005  $queryFlags
1006  );
1007  $obj = $this->fetchObject( $res );
1008  if ( !$obj ) {
1009  throw new RuntimeException( "Couldn't retrieve structure for table $oldName" );
1010  }
1011  $sql = $obj->sql;
1012  $sql = preg_replace(
1013  '/(?<=\W)"?' .
1014  preg_quote( trim( $this->addIdentifierQuotes( $oldName ), '"' ), '/' ) .
1015  '"?(?=\W)/',
1016  $this->addIdentifierQuotes( $newName ),
1017  $sql,
1018  1
1019  );
1020  if ( $temporary ) {
1021  if ( preg_match( '/^\\s*CREATE\\s+VIRTUAL\\s+TABLE\b/i', $sql ) ) {
1022  $this->queryLogger->debug(
1023  "Table $oldName is virtual, can't create a temporary duplicate." );
1024  } else {
1025  $sql = str_replace( 'CREATE TABLE', 'CREATE TEMPORARY TABLE', $sql );
1026  }
1027  }
1028 
1029  // @phan-suppress-next-line SecurityCheck-SQLInjection SQL is taken from database
1030  $res = $this->query( $sql, $fname, $queryFlags );
1031 
1032  // Take over indexes
1033  $indexList = $this->query(
1034  'PRAGMA INDEX_LIST(' . $this->addQuotes( $oldName ) . ')',
1035  $fname,
1036  $queryFlags
1037  );
1038  foreach ( $indexList as $index ) {
1039  if ( strpos( $index->name, 'sqlite_autoindex' ) === 0 ) {
1040  continue;
1041  }
1042 
1043  if ( $index->unique ) {
1044  $sqlIndex = 'CREATE UNIQUE INDEX';
1045  } else {
1046  $sqlIndex = 'CREATE INDEX';
1047  }
1048  // Try to come up with a new index name, given indexes have database scope in SQLite
1049  $indexName = $newName . '_' . $index->name;
1050  $sqlIndex .= ' ' . $this->addIdentifierQuotes( $indexName ) .
1051  ' ON ' . $this->addIdentifierQuotes( $newName );
1052 
1053  $indexInfo = $this->query(
1054  'PRAGMA INDEX_INFO(' . $this->addQuotes( $index->name ) . ')',
1055  $fname,
1056  $queryFlags
1057  );
1058  $fields = [];
1059  foreach ( $indexInfo as $indexInfoRow ) {
1060  $fields[$indexInfoRow->seqno] = $this->addQuotes( $indexInfoRow->name );
1061  }
1062 
1063  $sqlIndex .= '(' . implode( ',', $fields ) . ')';
1064 
1065  // @phan-suppress-next-line SecurityCheck-SQLInjection implode does not ignore taint from keys T270942
1066  $this->query( $sqlIndex, __METHOD__ );
1067  }
1068 
1069  return $res;
1070  }
1071 
1080  public function listTables( $prefix = null, $fname = __METHOD__ ) {
1081  $result = $this->query(
1082  "SELECT name FROM sqlite_master WHERE type = 'table'",
1083  $fname,
1084  self::QUERY_IGNORE_DBO_TRX
1085  );
1086 
1087  $endArray = [];
1088 
1089  foreach ( $result as $table ) {
1090  $vars = get_object_vars( $table );
1091  $table = array_pop( $vars );
1092 
1093  if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
1094  if ( strpos( $table, 'sqlite_' ) !== 0 ) {
1095  $endArray[] = $table;
1096  }
1097  }
1098  }
1099 
1100  return $endArray;
1101  }
1102 
1103  public function dropTable( $table, $fname = __METHOD__ ) {
1104  if ( !$this->tableExists( $table, $fname ) ) {
1105  return false;
1106  }
1107 
1108  // No CASCADE support; https://www.sqlite.org/lang_droptable.html
1109  $sql = "DROP TABLE " . $this->tableName( $table );
1110  $this->query( $sql, $fname, self::QUERY_IGNORE_DBO_TRX );
1111 
1112  return true;
1113  }
1114 
1115  protected function doTruncate( array $tables, $fname ) {
1116  $this->startAtomic( $fname );
1117 
1118  $encSeqNames = [];
1119  foreach ( $tables as $table ) {
1120  // Use "truncate" optimization; https://www.sqlite.org/lang_delete.html
1121  $sql = "DELETE FROM " . $this->tableName( $table );
1122  $this->query( $sql, $fname, self::QUERY_CHANGE_SCHEMA );
1123 
1124  $encSeqNames[] = $this->addQuotes( $this->tableName( $table, 'raw' ) );
1125  }
1126 
1127  $encMasterTable = $this->addIdentifierQuotes( 'sqlite_sequence' );
1128  $this->query(
1129  "DELETE FROM $encMasterTable WHERE name IN(" . implode( ',', $encSeqNames ) . ")",
1130  $fname,
1131  self::QUERY_CHANGE_SCHEMA
1132  );
1133 
1134  $this->endAtomic( $fname );
1135  }
1136 
1137  public function setTableAliases( array $aliases ) {
1138  parent::setTableAliases( $aliases );
1139  if ( $this->isOpen() ) {
1141  }
1142  }
1143 
1147  private function attachDatabasesFromTableAliases() {
1148  foreach ( $this->tableAliases as $params ) {
1149  if (
1150  $params['dbname'] !== $this->getDBname() &&
1151  !isset( $this->sessionAttachedDbs[$params['dbname']] )
1152  ) {
1153  $this->attachDatabase( $params['dbname'], false, __METHOD__ );
1154  $this->sessionAttachedDbs[$params['dbname']] = true;
1155  }
1156  }
1157  }
1158 
1159  public function databasesAreIndependent() {
1160  return true;
1161  }
1162 
1163  protected function doHandleSessionLossPreconnect() {
1164  $this->sessionAttachedDbs = [];
1165  }
1166 
1170  protected function getBindingHandle() {
1171  return parent::getBindingHandle();
1172  }
1173 }
1174 
1178 class_alias( DatabaseSqlite::class, 'DatabaseSqlite' );
DBO_PERSISTENT
const DBO_PERSISTENT
Definition: defines.php:14
Wikimedia\Rdbms\SQLiteField
Definition: SQLiteField.php:5
Wikimedia\Rdbms\DatabaseSqlite\$trxMode
string $trxMode
Transaction mode.
Definition: DatabaseSqlite.php:43
Wikimedia\Rdbms\DatabaseSqlite\fieldInfo
fieldInfo( $table, $field)
Get information about a given field Returns false if the field does not exist.
Definition: DatabaseSqlite.php:777
Wikimedia\Rdbms\DatabaseSqlite\$lockMgr
FSLockManager $lockMgr
(hopefully on the same server as the DB)
Definition: DatabaseSqlite.php:52
LockManager
Class for handling resource locking.
Definition: LockManager.php:48
Wikimedia\Rdbms\DatabaseSqlite\getBindingHandle
getBindingHandle()
Definition: DatabaseSqlite.php:1170
Wikimedia\Rdbms\DatabaseSqlite\addQuotes
addQuotes( $s)
Definition: DatabaseSqlite.php:830
Wikimedia\Rdbms\DatabaseSqlite\$VALID_PRAGMAS
static string[][] $VALID_PRAGMAS
Definition: DatabaseSqlite.php:64
Wikimedia\Rdbms\DatabaseSqlite\fetchRow
fetchRow( $res)
Definition: DatabaseSqlite.php:409
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:52
Wikimedia\Rdbms\DatabaseSqlite\doHandleSessionLossPreconnect
doHandleSessionLossPreconnect()
Reset any additional subclass trx* and session* fields.
Definition: DatabaseSqlite.php:1163
Wikimedia\Rdbms\DatabaseSqlite
Definition: DatabaseSqlite.php:37
Wikimedia\Rdbms\DatabaseSqlite\wasKnownStatementRollbackError
wasKnownStatementRollbackError()
Definition: DatabaseSqlite.php:730
Wikimedia\Rdbms\DatabaseSqlite\listTables
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
Definition: DatabaseSqlite.php:1080
FSLockManager
Simple version of LockManager based on using FS lock files.
Definition: FSLockManager.php:36
Wikimedia\Rdbms\DatabaseSqlite\deadlockLoop
deadlockLoop(... $args)
No-op version of deadlockLoop.
Definition: DatabaseSqlite.php:883
Wikimedia\Rdbms\DatabaseSqlite\unlock
unlock( $lockName, $method)
Release a lock.Named locks are not related to transactionsName of lock to release Name of the calling...
Definition: DatabaseSqlite.php:958
Wikimedia\Rdbms\Database\getDomainID
getDomainID()
Return the currently selected domain ID.
Definition: Database.php:863
Wikimedia\Rdbms\DatabaseSqlite\makeInsertNonConflictingVerbAndOptions
makeInsertNonConflictingVerbAndOptions()
Definition: DatabaseSqlite.php:671
Wikimedia\Rdbms\Database\assertHasConnectionHandle
assertHasConnectionHandle()
Make sure there is an open connection handle (alive or not) as a sanity check.
Definition: Database.php:1032
Wikimedia\Rdbms\DatabaseSqlite\attachDatabasesFromTableAliases
attachDatabasesFromTableAliases()
Issue ATTATCH statements for all unattached foreign DBs in table aliases.
Definition: DatabaseSqlite.php:1147
Wikimedia\Rdbms\Database\factory
static factory( $type, $params=[], $connect=self::NEW_CONNECTED)
Construct a Database subclass instance given a database type and parameters.
Definition: Database.php:436
true
return true
Definition: router.php:90
Wikimedia\Rdbms\DatabaseSqlite\unionSupportsOrderAndLimit
unionSupportsOrderAndLimit()
Definition: DatabaseSqlite.php:697
Wikimedia\Rdbms\DatabaseSqlite\$version
string null $version
Definition: DatabaseSqlite.php:55
Wikimedia\Rdbms\DatabaseSqlite\databasesAreIndependent
databasesAreIndependent()
Returns true if DBs are assumed to be on potentially different servers.In systems like mysql/mariadb,...
Definition: DatabaseSqlite.php:1159
Wikimedia\Rdbms\DatabaseSqlite\isProcessMemoryPath
static isProcessMemoryPath( $path)
Definition: DatabaseSqlite.php:290
Wikimedia\Rdbms\DatabaseSqlite\buildLeast
buildLeast( $fields, $values)
Build a LEAST function statement comparing columns/values.Integer and float values in $values will no...
Definition: DatabaseSqlite.php:984
Wikimedia\Rdbms\DatabaseSqlite\getLockFileDirectory
getLockFileDirectory()
Definition: DatabaseSqlite.php:227
Wikimedia\Rdbms\Database\endAtomic
endAtomic( $fname=__METHOD__)
Ends an atomic section of SQL statements.
Definition: Database.php:4495
Wikimedia\Rdbms\Database\indexName
indexName( $index)
Allows for index remapping in queries where this is not consistent across DBMS.
Definition: Database.php:3187
Wikimedia\Rdbms\DatabaseSqlite\getTopologyBasedServerId
getTopologyBasedServerId()
Get a non-recycled ID that uniquely identifies this server within the replication topology.
Definition: DatabaseSqlite.php:738
Wikimedia\Rdbms\DatabaseDomain\getTablePrefix
getTablePrefix()
Definition: DatabaseDomain.php:193
Wikimedia\Rdbms\DatabaseSqlite\fetchAffectedRowCount
fetchAffectedRowCount()
Definition: DatabaseSqlite.php:563
Wikimedia\Rdbms\DatabaseSqlite\doTruncate
doTruncate(array $tables, $fname)
Definition: DatabaseSqlite.php:1115
Wikimedia\Rdbms\DatabaseSqlite\encodeBlob
encodeBlob( $b)
Definition: DatabaseSqlite.php:810
Wikimedia\Rdbms\DatabaseSqlite\setTableAliases
setTableAliases(array $aliases)
Make certain table names use their own database, schema, and table prefix when passed into SQL querie...
Definition: DatabaseSqlite.php:1137
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
Wikimedia\Rdbms\Database\$server
string null $server
Server that this instance is currently connected to.
Definition: Database.php:83
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
Wikimedia\Rdbms\DatabaseSqlite\lastError
lastError()
Definition: DatabaseSqlite.php:538
Wikimedia\Rdbms\DatabaseSqlite\getServerVersion
getServerVersion()
Definition: DatabaseSqlite.php:761
Wikimedia\Rdbms\DatabaseSqlite\open
open( $server, $user, $password, $db, $schema, $tablePrefix)
Open a new connection to the database (closing any existing one)
Definition: DatabaseSqlite.php:136
Wikimedia\Rdbms\DatabaseSqlite\dataSeek
dataSeek( $res, $row)
Definition: DatabaseSqlite.php:525
Wikimedia\Rdbms\DatabaseSqlite\strencode
strencode( $s)
Definition: DatabaseSqlite.php:802
Wikimedia\Rdbms\DatabaseDomain\getDatabase
getDatabase()
Definition: DatabaseDomain.php:179
Wikimedia\Rdbms\DatabaseSqlite\buildSubstring
buildSubstring( $input, $startPosition, $length=null)
Stability: stableto override
Definition: DatabaseSqlite.php:859
Wikimedia\Rdbms\ResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: ResultWrapper.php:23
Wikimedia\Rdbms\DatabaseSqlite\closeConnection
closeConnection()
Does not actually close the connection, just destroys the reference for GC to do its work.
Definition: DatabaseSqlite.php:241
Wikimedia\Rdbms\DatabaseSqlite\isWriteQuery
isWriteQuery( $sql, $flags)
Determine whether a query writes to the DB.
Definition: DatabaseSqlite.php:342
$res
$res
Definition: testCompression.php:57
Wikimedia\Rdbms\DatabaseSqlite\dropTable
dropTable( $table, $fname=__METHOD__)
Delete a table.
Definition: DatabaseSqlite.php:1103
Wikimedia\Rdbms\Database\getFlag
getFlag( $flag)
Returns a boolean whether the flag $flag is set for this connection.
Definition: Database.php:859
Wikimedia\Rdbms\DBError
Database error base class @newable.
Definition: DBError.php:32
Wikimedia\Rdbms\DatabaseSqlite\buildStringCast
buildStringCast( $field)
Definition: DatabaseSqlite.php:873
DBO_TRX
const DBO_TRX
Definition: defines.php:12
Wikimedia\Rdbms\DatabaseSqlite\unionQueries
unionQueries( $sqls, $all)
Definition: DatabaseSqlite.php:706
Wikimedia\Rdbms\DatabaseSqlite\doReplace
doReplace( $table, array $uniqueKey, array $rows, $fname)
Definition: DatabaseSqlite.php:675
Wikimedia\Rdbms\Database\close
close( $fname=__METHOD__, $owner=null)
Close the database connection.
Definition: Database.php:953
Wikimedia\Rdbms\DatabaseSqlite\$lastAffectedRowCount
int $lastAffectedRowCount
The number of rows affected as an integer.
Definition: DatabaseSqlite.php:46
Wikimedia\Rdbms\Database\assertBuildSubstringParams
assertBuildSubstringParams( $startPosition, $length)
Check type and bounds for parameters to self::buildSubstring()
Definition: Database.php:2757
NullLockManager
Simple version of LockManager that only does lock reference counting.
Definition: NullLockManager.php:28
Wikimedia\Rdbms\DatabaseSqlite\buildGreatest
buildGreatest( $fields, $values)
Build a GREATEST function statement comparing columns/values.Integer and float values in $values will...
Definition: DatabaseSqlite.php:980
Wikimedia\Rdbms\Database\startAtomic
startAtomic( $fname=__METHOD__, $cancelable=self::ATOMIC_NOT_CANCELABLE)
Begin an atomic section of SQL statements.
Definition: Database.php:4433
Wikimedia\Rdbms\DatabaseSqlite\wasDeadlock
wasDeadlock()
Definition: DatabaseSqlite.php:715
Wikimedia\Rdbms\DatabaseSqlite\generateFileName
static generateFileName( $dir, $dbName)
Generates a database file name.
Definition: DatabaseSqlite.php:254
Wikimedia\Rdbms\DatabaseSqlite\doBegin
doBegin( $fname='')
Issues the BEGIN command to the database server.
Definition: DatabaseSqlite.php:790
Wikimedia\Rdbms\DatabaseSqlite\$conn
PDO $conn
Definition: DatabaseSqlite.php:49
Wikimedia\Rdbms\Database\selectSQLText
selectSQLText( $table, $vars, $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
Take the same arguments as IDatabase::select() and return the SQL it would use.This can be useful for...
Definition: Database.php:1977
Wikimedia\Rdbms\Database\makeInsertLists
makeInsertLists(array $rows)
Make SQL lists of columns, row tuples for INSERT/VALUES expressions.
Definition: Database.php:2446
$args
if( $line===false) $args
Definition: mcc.php:124
Wikimedia\Rdbms\DatabaseSqlite\tableExists
tableExists( $table, $fname=__METHOD__)
Query whether a given table exists.
Definition: DatabaseSqlite.php:567
Wikimedia\Rdbms\DatabaseSqlite\$VALID_TRX_MODES
static string[] $VALID_TRX_MODES
See https://www.sqlite.org/lang_transaction.html.
Definition: DatabaseSqlite.php:61
Wikimedia\Rdbms\DatabaseSqlite\getDbFilePath
getDbFilePath()
Definition: DatabaseSqlite.php:220
Wikimedia\Rdbms\DatabaseSqlite\numRows
numRows( $res)
The PDO::Statement class implements the array interface so count() will work.
Definition: DatabaseSqlite.php:427
Wikimedia\Rdbms\DatabaseSqlite\replaceVars
replaceVars( $s)
Definition: DatabaseSqlite.php:893
Wikimedia\Rdbms\DatabaseSqlite\fieldName
fieldName( $res, $n)
Definition: DatabaseSqlite.php:454
Wikimedia\Rdbms\Database\selectRow
selectRow( $table, $vars, $conds, $fname=__METHOD__, $options=[], $join_conds=[])
Wrapper to IDatabase::select() that only fetches one row (via LIMIT)
Definition: Database.php:2064
Wikimedia\Rdbms\Database\buildSuperlative
buildSuperlative( $sqlfunc, $fields, $values)
Build a superlative function statement comparing columns/values.
Definition: Database.php:2705
Wikimedia\Rdbms\DatabaseSqlite\lock
lock( $lockName, $method, $timeout=5)
Acquire a named lock.Named locks are not related to transactionsName of lock to aquire Name of the ca...
Definition: DatabaseSqlite.php:946
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
Wikimedia\Rdbms\DatabaseSqlite\fetchObject
fetchObject( $res)
Definition: DatabaseSqlite.php:386
Wikimedia\Rdbms\Database\getLogContext
getLogContext(array $extras=[])
Create a log context to pass to PSR-3 logger functions.
Definition: Database.php:942
Wikimedia\Rdbms\DatabaseSqlite\doQuery
doQuery( $sql)
SQLite doesn't allow buffered results or data seeking etc, so we'll use fetchAll as the result.
Definition: DatabaseSqlite.php:360
Wikimedia\Rdbms\DatabaseSqlite\$dbDir
string null $dbDir
Directory for SQLite database files listed under their DB name.
Definition: DatabaseSqlite.php:39
Wikimedia\Rdbms\DatabaseSqlite\getAttributes
static getAttributes()
Definition: DatabaseSqlite.php:103
Wikimedia\Rdbms\Database\query
query( $sql, $fname=__METHOD__, $flags=self::QUERY_NORMAL)
Run an SQL query and return the result.
Definition: Database.php:1272
Wikimedia\Rdbms\DatabaseSqlite\getType
getType()
Definition: DatabaseSqlite.php:132
Wikimedia\Rdbms\DatabaseSqlite\buildGroupConcatField
buildGroupConcatField( $delim, $table, $field, $conds='', $join_conds=[])
Build a GROUP_CONCAT or equivalent statement for a query.This is useful for combining a field for sev...
Definition: DatabaseSqlite.php:972
Wikimedia\Rdbms\Database\$user
string null $user
User that this instance is currently connected under the name of.
Definition: Database.php:85
Wikimedia\Rdbms\DatabaseSqlite\attachDatabase
attachDatabase( $name, $file=false, $fname=__METHOD__)
Attaches external database to the connection handle.
Definition: DatabaseSqlite.php:331
Wikimedia\Rdbms\DBUnexpectedError
@newable
Definition: DBUnexpectedError.php:29
Wikimedia\Rdbms\DatabaseSqlite\isTransactableQuery
isTransactableQuery( $sql)
Determine whether a SQL statement is sensitive to isolation level.
Definition: DatabaseSqlite.php:346
Wikimedia\Rdbms\DatabaseSqlite\generateDatabaseName
static generateDatabaseName( $path)
Definition: DatabaseSqlite.php:273
Wikimedia\Rdbms\DatabaseSqlite\newStandaloneInstance
static newStandaloneInstance( $filename, array $p=[])
Definition: DatabaseSqlite.php:119
Wikimedia\Rdbms\Database\addIdentifierQuotes
addIdentifierQuotes( $s)
Escape a SQL identifier (e.g.table, column, database) for use in a SQL queryDepending on the database...
Definition: Database.php:3214
Wikimedia\Rdbms\DatabaseSqlite\getFulltextSearchModule
static getFulltextSearchModule()
Returns version of currently supported SQLite fulltext search module or false if none present.
Definition: DatabaseSqlite.php:298
Wikimedia\Rdbms\Database\getQueryVerb
getQueryVerb( $sql)
Definition: Database.php:1142
Wikimedia\Rdbms\DatabaseSqlite\$dbPath
string null $dbPath
Explicit path for the SQLite database file.
Definition: DatabaseSqlite.php:41
Wikimedia\Rdbms\DatabaseSqlite\makeUpdateOptionsArray
makeUpdateOptionsArray( $options)
Definition: DatabaseSqlite.php:649
Wikimedia\Rdbms\DatabaseSqlite\getSoftwareLink
getSoftwareLink()
Definition: DatabaseSqlite.php:754
Wikimedia\Rdbms\Database\newExceptionAfterConnectError
newExceptionAfterConnectError( $error)
Definition: Database.php:1768
Wikimedia\Rdbms\DatabaseSqlite\insertId
insertId()
This must be called after nextSequenceVal.
Definition: DatabaseSqlite.php:516
Wikimedia\Rdbms\DBExpectedError
Base class for the more common types of database errors.
Definition: DBExpectedError.php:34
Wikimedia\Rdbms\DatabaseSqlite\$sessionAttachedDbs
array $sessionAttachedDbs
List of shared database already attached to this connection.
Definition: DatabaseSqlite.php:58
Wikimedia\Rdbms\DatabaseSqlite\freeResult
freeResult( $res)
Definition: DatabaseSqlite.php:376
Wikimedia\Rdbms\DatabaseSqlite\lastErrno
lastErrno()
Definition: DatabaseSqlite.php:550
$path
$path
Definition: NoLocalSettings.php:25
Wikimedia\Rdbms\DatabaseDomain\getSchema
getSchema()
Definition: DatabaseDomain.php:186
Wikimedia\Rdbms\DatabaseSqlite\indexUnique
indexUnique( $table, $index, $fname=__METHOD__)
Definition: DatabaseSqlite.php:613
Wikimedia\Rdbms\DatabaseSqlite\wasReadOnlyError
wasReadOnlyError()
Definition: DatabaseSqlite.php:722
$keys
$keys
Definition: testCompression.php:72
Wikimedia\Rdbms\Database\isOpen
isOpen()
Definition: Database.php:812
Wikimedia\Rdbms\DatabaseSqlite\doSelectDomain
doSelectDomain(DatabaseDomain $domain)
Definition: DatabaseSqlite.php:465
Wikimedia\Rdbms\Database\$flags
int $flags
Current bit field of class DBO_* constants.
Definition: Database.php:106
Wikimedia\Rdbms\DatabaseSqlite\__construct
__construct(array $params)
Additional params include:
Definition: DatabaseSqlite.php:78
Wikimedia\Rdbms\DatabaseSqlite\buildConcat
buildConcat( $stringList)
Build a concatenation list to feed into a SQL query.
Definition: DatabaseSqlite.php:968
Wikimedia\Rdbms\Database\$password
string null $password
Password used to establish the current connection.
Definition: Database.php:87
Wikimedia\Rdbms\DatabaseSqlite\wasConnectionError
wasConnectionError( $errno)
Do not use this method outside of Database/DBError classes.
Definition: DatabaseSqlite.php:726
Wikimedia\Rdbms\DatabaseDomain
Class to handle database/schema/prefix specifications for IDatabase.
Definition: DatabaseDomain.php:40
LockManager\LOCK_EX
const LOCK_EX
Definition: LockManager.php:71
Wikimedia\Rdbms\DatabaseSqlite\decodeBlob
decodeBlob( $b)
Definition: DatabaseSqlite.php:818
DBO_DEFAULT
const DBO_DEFAULT
Definition: defines.php:13
Wikimedia\Rdbms\ResultWrapper\unwrap
static & unwrap(&$res)
Get the underlying RDBMS driver-specific result resource.
Definition: ResultWrapper.php:59
Wikimedia\Rdbms\DatabaseSqlite\getDefaultPragmas
getDefaultPragmas()
Definition: DatabaseSqlite.php:205
Wikimedia\Rdbms\DatabaseSqlite\serverIsReadOnly
serverIsReadOnly()
bool Whether the DB is marked as read-only server-side 1.28Stability: stableto override
Definition: DatabaseSqlite.php:743
Wikimedia\Rdbms\DatabaseSqlite\duplicateTableStructure
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Definition: DatabaseSqlite.php:996
Wikimedia\Rdbms\DatabaseSqlite\numFields
numFields( $res)
Definition: DatabaseSqlite.php:438
Wikimedia\Rdbms\DatabaseSqlite\tableName
tableName( $name, $format='quoted')
Use MySQL's naming (accounts for prefix etc) but remove surrounding backticks.
Definition: DatabaseSqlite.php:502
Wikimedia\Rdbms\DatabaseSqlite\rewriteIgnoreKeyword
rewriteIgnoreKeyword( $options)
Definition: DatabaseSqlite.php:660
Wikimedia\Rdbms\DatabaseSqlite\indexInfo
indexInfo( $table, $index, $fname=__METHOD__)
Returns information about an index Returns false if the index does not exist.
Definition: DatabaseSqlite.php:593
Wikimedia\Rdbms\DatabaseSqlite\textFieldSize
textFieldSize( $table, $field)
Returns the size of a text field, or -1 for "unlimited" In SQLite this is SQLITE_MAX_LENGTH,...
Definition: DatabaseSqlite.php:690
Wikimedia\Rdbms\Database\getDBname
getDBname()
Get the current database name; null if there isn't one.
Definition: Database.php:2867
Wikimedia\Rdbms\Blob
@newable
Definition: Blob.php:9
Wikimedia\Rdbms\DatabaseSqlite\makeSelectOptions
makeSelectOptions(array $options)
Returns an optional USE INDEX clause to go after the table, and a string to go at the end of the quer...
Definition: DatabaseSqlite.php:634