MediaWiki  1.34.0
DatabaseSqlite.php
Go to the documentation of this file.
1 <?php
24 namespace Wikimedia\Rdbms;
25 
26 use NullLockManager;
27 use PDO;
28 use PDOException;
29 use Exception;
30 use LockManager;
31 use FSLockManager;
32 use RuntimeException;
33 use stdClass;
34 
38 class DatabaseSqlite extends Database {
40  protected $dbDir;
42  protected $dbPath;
44  protected $trxMode;
45 
49  protected $lastResultHandle;
50 
52  protected $conn;
53 
55  protected $lockMgr;
56 
58  private $sessionAttachedDbs = [];
59 
61  private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
62 
70  public function __construct( array $p ) {
71  if ( isset( $p['dbFilePath'] ) ) {
72  $this->dbPath = $p['dbFilePath'];
73  if ( !strlen( $p['dbname'] ) ) {
74  $p['dbname'] = self::generateDatabaseName( $this->dbPath );
75  }
76  } elseif ( isset( $p['dbDirectory'] ) ) {
77  $this->dbDir = $p['dbDirectory'];
78  }
79 
80  parent::__construct( $p );
81 
82  $this->trxMode = strtoupper( $p['trxMode'] ?? '' );
83 
84  $lockDirectory = $this->getLockFileDirectory();
85  if ( $lockDirectory !== null ) {
86  $this->lockMgr = new FSLockManager( [
87  'domain' => $this->getDomainID(),
88  'lockDirectory' => $lockDirectory
89  ] );
90  } else {
91  $this->lockMgr = new NullLockManager( [ 'domain' => $this->getDomainID() ] );
92  }
93  }
94 
95  protected static function getAttributes() {
96  return [ self::ATTR_DB_LEVEL_LOCKING => true ];
97  }
98 
108  public static function newStandaloneInstance( $filename, array $p = [] ) {
109  $p['dbFilePath'] = $filename;
110  $p['schema'] = null;
111  $p['tablePrefix'] = '';
113  $db = Database::factory( 'sqlite', $p );
114 
115  return $db;
116  }
117 
121  public function getType() {
122  return 'sqlite';
123  }
124 
125  protected function open( $server, $user, $pass, $dbName, $schema, $tablePrefix ) {
126  $this->close();
127 
128  // Note that for SQLite, $server, $user, and $pass are ignored
129 
130  if ( $schema !== null ) {
131  throw $this->newExceptionAfterConnectError( "Got schema '$schema'; not supported." );
132  }
133 
134  if ( $this->dbPath !== null ) {
136  } elseif ( $this->dbDir !== null ) {
137  $path = self::generateFileName( $this->dbDir, $dbName );
138  } else {
139  throw $this->newExceptionAfterConnectError( "DB path or directory required" );
140  }
141 
142  // Check if the database file already exists but is non-readable
143  if (
144  !self::isProcessMemoryPath( $path ) &&
145  file_exists( $path ) &&
146  !is_readable( $path )
147  ) {
148  throw $this->newExceptionAfterConnectError( 'SQLite database file is not readable' );
149  } elseif ( !in_array( $this->trxMode, self::$VALID_TRX_MODES, true ) ) {
150  throw $this->newExceptionAfterConnectError( "Got mode '{$this->trxMode}' for BEGIN" );
151  }
152 
153  $attributes = [];
154  if ( $this->getFlag( self::DBO_PERSISTENT ) ) {
155  // Persistent connections can avoid some schema index reading overhead.
156  // On the other hand, they can cause horrible contention with DBO_TRX.
157  if ( $this->getFlag( self::DBO_TRX ) || $this->getFlag( self::DBO_DEFAULT ) ) {
158  $this->connLogger->warning(
159  __METHOD__ . ": ignoring DBO_PERSISTENT due to DBO_TRX or DBO_DEFAULT",
160  $this->getLogContext()
161  );
162  } else {
163  $attributes[PDO::ATTR_PERSISTENT] = true;
164  }
165  }
166 
167  try {
168  // Open the database file, creating it if it does not yet exist
169  $this->conn = new PDO( "sqlite:$path", null, null, $attributes );
170  } catch ( PDOException $e ) {
171  throw $this->newExceptionAfterConnectError( $e->getMessage() );
172  }
173 
174  $this->currentDomain = new DatabaseDomain( $dbName, null, $tablePrefix );
175 
176  try {
177  $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_NO_RETRY;
178  // Enforce LIKE to be case sensitive, just like MySQL
179  $this->query( 'PRAGMA case_sensitive_like = 1', __METHOD__, $flags );
180  // Apply optimizations or requirements regarding fsync() usage
181  $sync = $this->connectionVariables['synchronous'] ?? null;
182  if ( in_array( $sync, [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ], true ) ) {
183  $this->query( "PRAGMA synchronous = $sync", __METHOD__, $flags );
184  }
186  } catch ( Exception $e ) {
187  throw $this->newExceptionAfterConnectError( $e->getMessage() );
188  }
189  }
190 
196  public function getDbFilePath() {
197  return $this->dbPath ?? self::generateFileName( $this->dbDir, $this->getDBname() );
198  }
199 
203  public function getLockFileDirectory() {
204  if ( $this->dbPath !== null && !self::isProcessMemoryPath( $this->dbPath ) ) {
205  return dirname( $this->dbPath ) . '/locks';
206  } elseif ( $this->dbDir !== null && !self::isProcessMemoryPath( $this->dbDir ) ) {
207  return $this->dbDir . '/locks';
208  }
209 
210  return null;
211  }
212 
217  protected function closeConnection() {
218  $this->conn = null;
219 
220  return true;
221  }
222 
230  public static function generateFileName( $dir, $dbName ) {
231  if ( $dir == '' ) {
232  throw new DBUnexpectedError( null, __CLASS__ . ": no DB directory specified" );
233  } elseif ( self::isProcessMemoryPath( $dir ) ) {
234  throw new DBUnexpectedError(
235  null,
236  __CLASS__ . ": cannot use process memory directory '$dir'"
237  );
238  } elseif ( !strlen( $dbName ) ) {
239  throw new DBUnexpectedError( null, __CLASS__ . ": no DB name specified" );
240  }
241 
242  return "$dir/$dbName.sqlite";
243  }
244 
249  private static function generateDatabaseName( $path ) {
250  if ( preg_match( '/^(:memory:$|file::memory:)/', $path ) ) {
251  // E.g. "file::memory:?cache=shared" => ":memory":
252  return ':memory:';
253  } elseif ( preg_match( '/^file::([^?]+)\?mode=memory(&|$)/', $path, $m ) ) {
254  // E.g. "file:memdb1?mode=memory" => ":memdb1:"
255  return ":{$m[1]}:";
256  } else {
257  // E.g. "/home/.../some_db.sqlite3" => "some_db"
258  return preg_replace( '/\.sqlite\d?$/', '', basename( $path ) );
259  }
260  }
261 
266  private static function isProcessMemoryPath( $path ) {
267  return preg_match( '/^(:memory:$|file:(:memory:|[^?]+\?mode=memory(&|$)))/', $path );
268  }
269 
274  static function getFulltextSearchModule() {
275  static $cachedResult = null;
276  if ( $cachedResult !== null ) {
277  return $cachedResult;
278  }
279  $cachedResult = false;
280  $table = 'dummy_search_test';
281 
282  $db = self::newStandaloneInstance( ':memory:' );
283  if ( $db->query( "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)", __METHOD__, true ) ) {
284  $cachedResult = 'FTS3';
285  }
286  $db->close();
287 
288  return $cachedResult;
289  }
290 
303  public function attachDatabase( $name, $file = false, $fname = __METHOD__ ) {
304  $file = is_string( $file ) ? $file : self::generateFileName( $this->dbDir, $name );
305  $encFile = $this->addQuotes( $file );
306 
307  return $this->query(
308  "ATTACH DATABASE $encFile AS $name",
309  $fname,
310  self::QUERY_IGNORE_DBO_TRX
311  );
312  }
313 
314  protected function isWriteQuery( $sql ) {
315  return parent::isWriteQuery( $sql ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql );
316  }
317 
318  protected function isTransactableQuery( $sql ) {
319  return parent::isTransactableQuery( $sql ) && !in_array(
320  $this->getQueryVerb( $sql ),
321  [ 'ATTACH', 'PRAGMA' ],
322  true
323  );
324  }
325 
332  protected function doQuery( $sql ) {
333  $res = $this->getBindingHandle()->query( $sql );
334  if ( $res === false ) {
335  return false;
336  }
337 
338  $resource = ResultWrapper::unwrap( $res );
339  $this->lastAffectedRowCount = $resource->rowCount();
340  $res = new ResultWrapper( $this, $resource->fetchAll() );
341 
342  return $res;
343  }
344 
348  function freeResult( $res ) {
349  if ( $res instanceof ResultWrapper ) {
350  $res->free();
351  }
352  }
353 
358  function fetchObject( $res ) {
359  $resource =& ResultWrapper::unwrap( $res );
360 
361  $cur = current( $resource );
362  if ( is_array( $cur ) ) {
363  next( $resource );
364  $obj = new stdClass;
365  foreach ( $cur as $k => $v ) {
366  if ( !is_numeric( $k ) ) {
367  $obj->$k = $v;
368  }
369  }
370 
371  return $obj;
372  }
373 
374  return false;
375  }
376 
381  function fetchRow( $res ) {
382  $resource =& ResultWrapper::unwrap( $res );
383  $cur = current( $resource );
384  if ( is_array( $cur ) ) {
385  next( $resource );
386 
387  return $cur;
388  }
389 
390  return false;
391  }
392 
399  function numRows( $res ) {
400  // false does not implement Countable
401  $resource = ResultWrapper::unwrap( $res );
402 
403  return is_array( $resource ) ? count( $resource ) : 0;
404  }
405 
410  function numFields( $res ) {
411  $resource = ResultWrapper::unwrap( $res );
412  if ( is_array( $resource ) && count( $resource ) > 0 ) {
413  // The size of the result array is twice the number of fields. (T67578)
414  return count( $resource[0] ) / 2;
415  } else {
416  // If the result is empty return 0
417  return 0;
418  }
419  }
420 
426  function fieldName( $res, $n ) {
427  $resource = ResultWrapper::unwrap( $res );
428  if ( is_array( $resource ) ) {
429  $keys = array_keys( $resource[0] );
430 
431  return $keys[$n];
432  }
433 
434  return false;
435  }
436 
437  protected function doSelectDomain( DatabaseDomain $domain ) {
438  if ( $domain->getSchema() !== null ) {
439  throw new DBExpectedError(
440  $this,
441  __CLASS__ . ": domain '{$domain->getId()}' has a schema component"
442  );
443  }
444 
445  $database = $domain->getDatabase();
446  // A null database means "don't care" so leave it as is and update the table prefix
447  if ( $database === null ) {
448  $this->currentDomain = new DatabaseDomain(
449  $this->currentDomain->getDatabase(),
450  null,
451  $domain->getTablePrefix()
452  );
453 
454  return true;
455  }
456 
457  if ( $database !== $this->getDBname() ) {
458  throw new DBExpectedError(
459  $this,
460  __CLASS__ . ": cannot change database (got '$database')"
461  );
462  }
463 
464  return true;
465  }
466 
474  function tableName( $name, $format = 'quoted' ) {
475  // table names starting with sqlite_ are reserved
476  if ( strpos( $name, 'sqlite_' ) === 0 ) {
477  return $name;
478  }
479 
480  return str_replace( '"', '', parent::tableName( $name, $format ) );
481  }
482 
488  function insertId() {
489  // PDO::lastInsertId yields a string :(
490  return intval( $this->getBindingHandle()->lastInsertId() );
491  }
492 
497  function dataSeek( $res, $row ) {
498  $resource =& ResultWrapper::unwrap( $res );
499  reset( $resource );
500  if ( $row > 0 ) {
501  for ( $i = 0; $i < $row; $i++ ) {
502  next( $resource );
503  }
504  }
505  }
506 
510  function lastError() {
511  if ( !is_object( $this->conn ) ) {
512  return "Cannot return last error, no db connection";
513  }
514  $e = $this->conn->errorInfo();
515 
516  return $e[2] ?? '';
517  }
518 
522  function lastErrno() {
523  if ( !is_object( $this->conn ) ) {
524  return "Cannot return last error, no db connection";
525  } else {
526  $info = $this->conn->errorInfo();
527 
528  return $info[1];
529  }
530  }
531 
535  protected function fetchAffectedRowCount() {
537  }
538 
539  function tableExists( $table, $fname = __METHOD__ ) {
540  $tableRaw = $this->tableName( $table, 'raw' );
541  if ( isset( $this->sessionTempTables[$tableRaw] ) ) {
542  return true; // already known to exist
543  }
544 
545  $encTable = $this->addQuotes( $tableRaw );
546  $res = $this->query(
547  "SELECT 1 FROM sqlite_master WHERE type='table' AND name=$encTable",
548  __METHOD__,
549  self::QUERY_IGNORE_DBO_TRX
550  );
551 
552  return $res->numRows() ? true : false;
553  }
554 
565  function indexInfo( $table, $index, $fname = __METHOD__ ) {
566  $sql = 'PRAGMA index_info(' . $this->addQuotes( $this->indexName( $index ) ) . ')';
567  $res = $this->query( $sql, $fname, self::QUERY_IGNORE_DBO_TRX );
568  if ( !$res || $res->numRows() == 0 ) {
569  return false;
570  }
571  $info = [];
572  foreach ( $res as $row ) {
573  $info[] = $row->name;
574  }
575 
576  return $info;
577  }
578 
585  function indexUnique( $table, $index, $fname = __METHOD__ ) {
586  $row = $this->selectRow( 'sqlite_master', '*',
587  [
588  'type' => 'index',
589  'name' => $this->indexName( $index ),
590  ], $fname );
591  if ( !$row || !isset( $row->sql ) ) {
592  return null;
593  }
594 
595  // $row->sql will be of the form CREATE [UNIQUE] INDEX ...
596  $indexPos = strpos( $row->sql, 'INDEX' );
597  if ( $indexPos === false ) {
598  return null;
599  }
600  $firstPart = substr( $row->sql, 0, $indexPos );
601  $options = explode( ' ', $firstPart );
602 
603  return in_array( 'UNIQUE', $options );
604  }
605 
606  protected function makeSelectOptions( array $options ) {
607  // Remove problematic options that the base implementation converts to SQL
608  foreach ( $options as $k => $v ) {
609  if ( is_numeric( $k ) && ( $v === 'FOR UPDATE' || $v === 'LOCK IN SHARE MODE' ) ) {
610  $options[$k] = '';
611  }
612  }
613 
614  return parent::makeSelectOptions( $options );
615  }
616 
621  protected function makeUpdateOptionsArray( $options ) {
622  $options = parent::makeUpdateOptionsArray( $options );
623  $options = self::fixIgnore( $options );
624 
625  return $options;
626  }
627 
632  static function fixIgnore( $options ) {
633  # SQLite uses OR IGNORE not just IGNORE
634  foreach ( $options as $k => $v ) {
635  if ( $v == 'IGNORE' ) {
636  $options[$k] = 'OR IGNORE';
637  }
638  }
639 
640  return $options;
641  }
642 
647  function makeInsertOptions( $options ) {
648  $options = self::fixIgnore( $options );
649 
650  return parent::makeInsertOptions( $options );
651  }
652 
661  function insert( $table, $a, $fname = __METHOD__, $options = [] ) {
662  if ( !count( $a ) ) {
663  return true;
664  }
665 
666  # SQLite can't handle multi-row inserts, so divide up into multiple single-row inserts
667  if ( isset( $a[0] ) && is_array( $a[0] ) ) {
668  $affectedRowCount = 0;
669  try {
670  $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
671  foreach ( $a as $v ) {
672  parent::insert( $table, $v, "$fname/multi-row", $options );
673  $affectedRowCount += $this->affectedRows();
674  }
675  $this->endAtomic( $fname );
676  } catch ( Exception $e ) {
677  $this->cancelAtomic( $fname );
678  throw $e;
679  }
680  $this->affectedRowCount = $affectedRowCount;
681  } else {
682  parent::insert( $table, $a, "$fname/single-row", $options );
683  }
684 
685  return true;
686  }
687 
694  function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
695  if ( !count( $rows ) ) {
696  return;
697  }
698 
699  # SQLite can't handle multi-row replaces, so divide up into multiple single-row queries
700  if ( isset( $rows[0] ) && is_array( $rows[0] ) ) {
701  $affectedRowCount = 0;
702  try {
703  $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
704  foreach ( $rows as $v ) {
705  $this->nativeReplace( $table, $v, "$fname/multi-row" );
706  $affectedRowCount += $this->affectedRows();
707  }
708  $this->endAtomic( $fname );
709  } catch ( Exception $e ) {
710  $this->cancelAtomic( $fname );
711  throw $e;
712  }
713  $this->affectedRowCount = $affectedRowCount;
714  } else {
715  $this->nativeReplace( $table, $rows, "$fname/single-row" );
716  }
717  }
718 
727  function textFieldSize( $table, $field ) {
728  return -1;
729  }
730 
735  return false;
736  }
737 
743  function unionQueries( $sqls, $all ) {
744  $glue = $all ? ' UNION ALL ' : ' UNION ';
745 
746  return implode( $glue, $sqls );
747  }
748 
752  function wasDeadlock() {
753  return $this->lastErrno() == 5; // SQLITE_BUSY
754  }
755 
759  function wasReadOnlyError() {
760  return $this->lastErrno() == 8; // SQLITE_READONLY;
761  }
762 
763  public function wasConnectionError( $errno ) {
764  return $errno == 17; // SQLITE_SCHEMA;
765  }
766 
767  protected function wasKnownStatementRollbackError() {
768  // ON CONFLICT ROLLBACK clauses make it so that SQLITE_CONSTRAINT error is
769  // ambiguous with regard to whether it implies a ROLLBACK or an ABORT happened.
770  // https://sqlite.org/lang_createtable.html#uniqueconst
771  // https://sqlite.org/lang_conflict.html
772  return false;
773  }
774 
775  public function serverIsReadOnly() {
776  $this->assertHasConnectionHandle();
777 
778  $path = $this->getDbFilePath();
779 
780  return ( !self::isProcessMemoryPath( $path ) && !is_writable( $path ) );
781  }
782 
786  public function getSoftwareLink() {
787  return "[{{int:version-db-sqlite-url}} SQLite]";
788  }
789 
793  function getServerVersion() {
794  $ver = $this->getBindingHandle()->getAttribute( PDO::ATTR_SERVER_VERSION );
795 
796  return $ver;
797  }
798 
807  function fieldInfo( $table, $field ) {
808  $tableName = $this->tableName( $table );
809  $sql = 'PRAGMA table_info(' . $this->addQuotes( $tableName ) . ')';
810  $res = $this->query( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
811  foreach ( $res as $row ) {
812  if ( $row->name == $field ) {
813  return new SQLiteField( $row, $tableName );
814  }
815  }
816 
817  return false;
818  }
819 
820  protected function doBegin( $fname = '' ) {
821  if ( $this->trxMode != '' ) {
822  $this->query( "BEGIN {$this->trxMode}", $fname );
823  } else {
824  $this->query( 'BEGIN', $fname );
825  }
826  }
827 
832  function strencode( $s ) {
833  return substr( $this->addQuotes( $s ), 1, -1 );
834  }
835 
840  function encodeBlob( $b ) {
841  return new Blob( $b );
842  }
843 
848  function decodeBlob( $b ) {
849  if ( $b instanceof Blob ) {
850  $b = $b->fetch();
851  }
852 
853  return $b;
854  }
855 
860  function addQuotes( $s ) {
861  if ( $s instanceof Blob ) {
862  return "x'" . bin2hex( $s->fetch() ) . "'";
863  } elseif ( is_bool( $s ) ) {
864  return (int)$s;
865  } elseif ( strpos( (string)$s, "\0" ) !== false ) {
866  // SQLite doesn't support \0 in strings, so use the hex representation as a workaround.
867  // This is a known limitation of SQLite's mprintf function which PDO
868  // should work around, but doesn't. I have reported this to php.net as bug #63419:
869  // https://bugs.php.net/bug.php?id=63419
870  // There was already a similar report for SQLite3::escapeString, bug #62361:
871  // https://bugs.php.net/bug.php?id=62361
872  // There is an additional bug regarding sorting this data after insert
873  // on older versions of sqlite shipped with ubuntu 12.04
874  // https://phabricator.wikimedia.org/T74367
875  $this->queryLogger->debug(
876  __FUNCTION__ .
877  ': Quoting value containing null byte. ' .
878  'For consistency all binary data should have been ' .
879  'first processed with self::encodeBlob()'
880  );
881  return "x'" . bin2hex( (string)$s ) . "'";
882  } else {
883  return $this->getBindingHandle()->quote( (string)$s );
884  }
885  }
886 
887  public function buildSubstring( $input, $startPosition, $length = null ) {
888  $this->assertBuildSubstringParams( $startPosition, $length );
889  $params = [ $input, $startPosition ];
890  if ( $length !== null ) {
891  $params[] = $length;
892  }
893  return 'SUBSTR(' . implode( ',', $params ) . ')';
894  }
895 
901  public function buildStringCast( $field ) {
902  return 'CAST ( ' . $field . ' AS TEXT )';
903  }
904 
910  public function deadlockLoop( /*...*/ ) {
911  $args = func_get_args();
912  $function = array_shift( $args );
913 
914  return $function( ...$args );
915  }
916 
921  protected function replaceVars( $s ) {
922  $s = parent::replaceVars( $s );
923  if ( preg_match( '/^\s*(CREATE|ALTER) TABLE/i', $s ) ) {
924  // CREATE TABLE hacks to allow schema file sharing with MySQL
925 
926  // binary/varbinary column type -> blob
927  $s = preg_replace( '/\b(var)?binary(\(\d+\))/i', 'BLOB', $s );
928  // no such thing as unsigned
929  $s = preg_replace( '/\b(un)?signed\b/i', '', $s );
930  // INT -> INTEGER
931  $s = preg_replace( '/\b(tiny|small|medium|big|)int(\s*\(\s*\d+\s*\)|\b)/i', 'INTEGER', $s );
932  // floating point types -> REAL
933  $s = preg_replace(
934  '/\b(float|double(\s+precision)?)(\s*\(\s*\d+\s*(,\s*\d+\s*)?\)|\b)/i',
935  'REAL',
936  $s
937  );
938  // varchar -> TEXT
939  $s = preg_replace( '/\b(var)?char\s*\(.*?\)/i', 'TEXT', $s );
940  // TEXT normalization
941  $s = preg_replace( '/\b(tiny|medium|long)text\b/i', 'TEXT', $s );
942  // BLOB normalization
943  $s = preg_replace( '/\b(tiny|small|medium|long|)blob\b/i', 'BLOB', $s );
944  // BOOL -> INTEGER
945  $s = preg_replace( '/\bbool(ean)?\b/i', 'INTEGER', $s );
946  // DATETIME -> TEXT
947  $s = preg_replace( '/\b(datetime|timestamp)\b/i', 'TEXT', $s );
948  // No ENUM type
949  $s = preg_replace( '/\benum\s*\([^)]*\)/i', 'TEXT', $s );
950  // binary collation type -> nothing
951  $s = preg_replace( '/\bbinary\b/i', '', $s );
952  // auto_increment -> autoincrement
953  $s = preg_replace( '/\bauto_increment\b/i', 'AUTOINCREMENT', $s );
954  // No explicit options
955  $s = preg_replace( '/\)[^);]*(;?)\s*$/', ')\1', $s );
956  // AUTOINCREMENT should immedidately follow PRIMARY KEY
957  $s = preg_replace( '/primary key (.*?) autoincrement/i', 'PRIMARY KEY AUTOINCREMENT $1', $s );
958  } elseif ( preg_match( '/^\s*CREATE (\s*(?:UNIQUE|FULLTEXT)\s+)?INDEX/i', $s ) ) {
959  // No truncated indexes
960  $s = preg_replace( '/\(\d+\)/', '', $s );
961  // No FULLTEXT
962  $s = preg_replace( '/\bfulltext\b/i', '', $s );
963  } elseif ( preg_match( '/^\s*DROP INDEX/i', $s ) ) {
964  // DROP INDEX is database-wide, not table-specific, so no ON <table> clause.
965  $s = preg_replace( '/\sON\s+[^\s]*/i', '', $s );
966  } elseif ( preg_match( '/^\s*INSERT IGNORE\b/i', $s ) ) {
967  // INSERT IGNORE --> INSERT OR IGNORE
968  $s = preg_replace( '/^\s*INSERT IGNORE\b/i', 'INSERT OR IGNORE', $s );
969  }
970 
971  return $s;
972  }
973 
974  public function lock( $lockName, $method, $timeout = 5 ) {
975  $status = $this->lockMgr->lock( [ $lockName ], LockManager::LOCK_EX, $timeout );
976  if (
977  $this->lockMgr instanceof FSLockManager &&
978  $status->hasMessage( 'lockmanager-fail-openlock' )
979  ) {
980  throw new DBError( $this, "Cannot create directory \"{$this->getLockFileDirectory()}\"" );
981  }
982 
983  return $status->isOK();
984  }
985 
986  public function unlock( $lockName, $method ) {
987  return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isGood();
988  }
989 
996  function buildConcat( $stringList ) {
997  return '(' . implode( ') || (', $stringList ) . ')';
998  }
999 
1000  public function buildGroupConcatField(
1001  $delim, $table, $field, $conds = '', $join_conds = []
1002  ) {
1003  $fld = "group_concat($field," . $this->addQuotes( $delim ) . ')';
1004 
1005  return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')';
1006  }
1007 
1016  function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = __METHOD__ ) {
1017  $res = $this->query( "SELECT sql FROM sqlite_master WHERE tbl_name=" .
1018  $this->addQuotes( $oldName ) . " AND type='table'", $fname );
1019  $obj = $this->fetchObject( $res );
1020  if ( !$obj ) {
1021  throw new RuntimeException( "Couldn't retrieve structure for table $oldName" );
1022  }
1023  $sql = $obj->sql;
1024  $sql = preg_replace(
1025  '/(?<=\W)"?' .
1026  preg_quote( trim( $this->addIdentifierQuotes( $oldName ), '"' ), '/' ) .
1027  '"?(?=\W)/',
1028  $this->addIdentifierQuotes( $newName ),
1029  $sql,
1030  1
1031  );
1032  if ( $temporary ) {
1033  if ( preg_match( '/^\\s*CREATE\\s+VIRTUAL\\s+TABLE\b/i', $sql ) ) {
1034  $this->queryLogger->debug(
1035  "Table $oldName is virtual, can't create a temporary duplicate.\n" );
1036  } else {
1037  $sql = str_replace( 'CREATE TABLE', 'CREATE TEMPORARY TABLE', $sql );
1038  }
1039  }
1040 
1041  $res = $this->query( $sql, $fname, self::QUERY_PSEUDO_PERMANENT );
1042 
1043  // Take over indexes
1044  $indexList = $this->query( 'PRAGMA INDEX_LIST(' . $this->addQuotes( $oldName ) . ')' );
1045  foreach ( $indexList as $index ) {
1046  if ( strpos( $index->name, 'sqlite_autoindex' ) === 0 ) {
1047  continue;
1048  }
1049 
1050  if ( $index->unique ) {
1051  $sql = 'CREATE UNIQUE INDEX';
1052  } else {
1053  $sql = 'CREATE INDEX';
1054  }
1055  // Try to come up with a new index name, given indexes have database scope in SQLite
1056  $indexName = $newName . '_' . $index->name;
1057  $sql .= ' ' . $indexName . ' ON ' . $newName;
1058 
1059  $indexInfo = $this->query( 'PRAGMA INDEX_INFO(' . $this->addQuotes( $index->name ) . ')' );
1060  $fields = [];
1061  foreach ( $indexInfo as $indexInfoRow ) {
1062  $fields[$indexInfoRow->seqno] = $indexInfoRow->name;
1063  }
1064 
1065  $sql .= '(' . implode( ',', $fields ) . ')';
1066 
1067  $this->query( $sql );
1068  }
1069 
1070  return $res;
1071  }
1072 
1081  function listTables( $prefix = null, $fname = __METHOD__ ) {
1082  $result = $this->select(
1083  'sqlite_master',
1084  'name',
1085  "type='table'"
1086  );
1087 
1088  $endArray = [];
1089 
1090  foreach ( $result as $table ) {
1091  $vars = get_object_vars( $table );
1092  $table = array_pop( $vars );
1093 
1094  if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
1095  if ( strpos( $table, 'sqlite_' ) !== 0 ) {
1096  $endArray[] = $table;
1097  }
1098  }
1099  }
1100 
1101  return $endArray;
1102  }
1103 
1112  public function dropTable( $tableName, $fName = __METHOD__ ) {
1113  if ( !$this->tableExists( $tableName, $fName ) ) {
1114  return false;
1115  }
1116  $sql = "DROP TABLE " . $this->tableName( $tableName );
1117 
1118  return $this->query( $sql, $fName, self::QUERY_IGNORE_DBO_TRX );
1119  }
1120 
1121  public function setTableAliases( array $aliases ) {
1122  parent::setTableAliases( $aliases );
1123  if ( $this->isOpen() ) {
1125  }
1126  }
1127 
1131  private function attachDatabasesFromTableAliases() {
1132  foreach ( $this->tableAliases as $params ) {
1133  if (
1134  $params['dbname'] !== $this->getDBname() &&
1135  !isset( $this->sessionAttachedDbs[$params['dbname']] )
1136  ) {
1137  $this->attachDatabase( $params['dbname'] );
1138  $this->sessionAttachedDbs[$params['dbname']] = true;
1139  }
1140  }
1141  }
1142 
1143  public function resetSequenceForTable( $table, $fname = __METHOD__ ) {
1144  $encTable = $this->addIdentifierQuotes( 'sqlite_sequence' );
1145  $encName = $this->addQuotes( $this->tableName( $table, 'raw' ) );
1146  $this->query(
1147  "DELETE FROM $encTable WHERE name = $encName",
1148  $fname,
1149  self::QUERY_IGNORE_DBO_TRX
1150  );
1151  }
1152 
1153  public function databasesAreIndependent() {
1154  return true;
1155  }
1156 
1157  protected function doHandleSessionLossPreconnect() {
1158  $this->sessionAttachedDbs = [];
1159  }
1160 
1164  protected function getBindingHandle() {
1165  return parent::getBindingHandle();
1166  }
1167 }
1168 
1172 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:44
Wikimedia\Rdbms\DatabaseSqlite\fieldInfo
fieldInfo( $table, $field)
Get information about a given field Returns false if the field does not exist.
Definition: DatabaseSqlite.php:807
Wikimedia\Rdbms\DatabaseSqlite\$lockMgr
FSLockManager $lockMgr
(hopefully on the same server as the DB)
Definition: DatabaseSqlite.php:55
LockManager
Class for handling resource locking.
Definition: LockManager.php:47
Wikimedia\Rdbms\DatabaseSqlite\getBindingHandle
getBindingHandle()
Definition: DatabaseSqlite.php:1164
Wikimedia\Rdbms\DatabaseSqlite\addQuotes
addQuotes( $s)
Definition: DatabaseSqlite.php:860
Wikimedia\Rdbms\DatabaseSqlite\fetchRow
fetchRow( $res)
Definition: DatabaseSqlite.php:381
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:49
Wikimedia\Rdbms\DatabaseSqlite\doHandleSessionLossPreconnect
doHandleSessionLossPreconnect()
Reset any additional subclass trx* and session* fields.
Definition: DatabaseSqlite.php:1157
Wikimedia\Rdbms\DatabaseSqlite
Definition: DatabaseSqlite.php:38
Wikimedia\Rdbms\DatabaseSqlite\wasKnownStatementRollbackError
wasKnownStatementRollbackError()
Definition: DatabaseSqlite.php:767
Wikimedia\Rdbms\DatabaseSqlite\listTables
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
Definition: DatabaseSqlite.php:1081
FSLockManager
Simple version of LockManager based on using FS lock files.
Definition: FSLockManager.php:36
Wikimedia\Rdbms\DatabaseSqlite\unlock
unlock( $lockName, $method)
Release a lock.
Definition: DatabaseSqlite.php:986
Wikimedia\Rdbms\Database\getDomainID
getDomainID()
Return the currently selected domain ID.
Definition: Database.php:790
Wikimedia\Rdbms\DatabaseSqlite\open
open( $server, $user, $pass, $dbName, $schema, $tablePrefix)
Open a new connection to the database (closing any existing one)
Definition: DatabaseSqlite.php:125
Wikimedia\Rdbms\Database\assertHasConnectionHandle
assertHasConnectionHandle()
Make sure there is an open connection handle (alive or not) as a sanity check.
Definition: Database.php:954
Wikimedia\Rdbms\DatabaseSqlite\attachDatabasesFromTableAliases
attachDatabasesFromTableAliases()
Issue ATTATCH statements for all unattached foreign DBs in table aliases.
Definition: DatabaseSqlite.php:1131
Wikimedia\Rdbms\Database\nativeReplace
nativeReplace( $table, $rows, $fname)
REPLACE query wrapper for MySQL and SQLite, which have a native REPLACE statement.
Definition: Database.php:2903
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:370
true
return true
Definition: router.php:92
Wikimedia\Rdbms\DatabaseSqlite\unionSupportsOrderAndLimit
unionSupportsOrderAndLimit()
Definition: DatabaseSqlite.php:734
Wikimedia\Rdbms\DatabaseSqlite\databasesAreIndependent
databasesAreIndependent()
Returns true if DBs are assumed to be on potentially different servers.
Definition: DatabaseSqlite.php:1153
Wikimedia\Rdbms\DatabaseSqlite\isProcessMemoryPath
static isProcessMemoryPath( $path)
Definition: DatabaseSqlite.php:266
Wikimedia\Rdbms\DatabaseSqlite\getLockFileDirectory
getLockFileDirectory()
Definition: DatabaseSqlite.php:203
Wikimedia\Rdbms\Database\endAtomic
endAtomic( $fname=__METHOD__)
Ends an atomic section of SQL statements.
Definition: Database.php:3842
Wikimedia\Rdbms\Database\indexName
indexName( $index)
Allows for index remapping in queries where this is not consistent across DBMS.
Definition: Database.php:2726
Wikimedia\Rdbms\DatabaseDomain\getTablePrefix
getTablePrefix()
Definition: DatabaseDomain.php:189
Wikimedia\Rdbms\DatabaseSqlite\fetchAffectedRowCount
fetchAffectedRowCount()
Definition: DatabaseSqlite.php:535
Wikimedia\Rdbms\DatabaseSqlite\replace
replace( $table, $uniqueIndexes, $rows, $fname=__METHOD__)
Definition: DatabaseSqlite.php:694
Wikimedia\Rdbms\DatabaseSqlite\encodeBlob
encodeBlob( $b)
Definition: DatabaseSqlite.php:840
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:1121
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
$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:510
Wikimedia\Rdbms\DatabaseSqlite\getServerVersion
getServerVersion()
Definition: DatabaseSqlite.php:793
$s
$s
Definition: mergeMessageFileList.php:185
Wikimedia\Rdbms\DatabaseSqlite\dataSeek
dataSeek( $res, $row)
Definition: DatabaseSqlite.php:497
Wikimedia\Rdbms\DatabaseSqlite\strencode
strencode( $s)
Definition: DatabaseSqlite.php:832
Wikimedia\Rdbms\DatabaseSqlite\$lastResultHandle
resource $lastResultHandle
Definition: DatabaseSqlite.php:49
Wikimedia\Rdbms\DatabaseDomain\getDatabase
getDatabase()
Definition: DatabaseDomain.php:175
Wikimedia\Rdbms\DatabaseSqlite\buildSubstring
buildSubstring( $input, $startPosition, $length=null)
Definition: DatabaseSqlite.php:887
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:217
$res
$res
Definition: testCompression.php:52
Wikimedia\Rdbms\Database\cancelAtomic
cancelAtomic( $fname=__METHOD__, AtomicSectionIdentifier $sectionId=null)
Cancel an atomic section of SQL statements.
Definition: Database.php:3876
Wikimedia\Rdbms\Database\getFlag
getFlag( $flag)
Returns a boolean whether the flag $flag is set for this connection.
Definition: Database.php:786
Wikimedia\Rdbms\DBError
Database error base class.
Definition: DBError.php:30
Wikimedia\Rdbms\DatabaseSqlite\buildStringCast
buildStringCast( $field)
Definition: DatabaseSqlite.php:901
Wikimedia\Rdbms\DatabaseSqlite\makeInsertOptions
makeInsertOptions( $options)
Definition: DatabaseSqlite.php:647
DBO_TRX
const DBO_TRX
Definition: defines.php:12
Wikimedia\Rdbms\DatabaseSqlite\unionQueries
unionQueries( $sqls, $all)
Definition: DatabaseSqlite.php:743
Wikimedia\Rdbms\Database\close
close( $fname=__METHOD__, $owner=null)
Close the database connection.
Definition: Database.php:876
Wikimedia\Rdbms\Database\$affectedRowCount
integer null $affectedRowCount
Rows affected by the last query to query() or its CRUD wrappers.
Definition: Database.php:164
Wikimedia\Rdbms\DatabaseSqlite\$lastAffectedRowCount
int $lastAffectedRowCount
The number of rows affected as an integer.
Definition: DatabaseSqlite.php:47
Wikimedia\Rdbms\Database\assertBuildSubstringParams
assertBuildSubstringParams( $startPosition, $length)
Check type and bounds for parameters to self::buildSubstring()
Definition: Database.php:2339
NullLockManager
Simple version of LockManager that only does lock reference counting.
Definition: NullLockManager.php:28
Wikimedia\Rdbms\Database\startAtomic
startAtomic( $fname=__METHOD__, $cancelable=self::ATOMIC_NOT_CANCELABLE)
Begin an atomic section of SQL statements.
Definition: Database.php:3812
Wikimedia\Rdbms\DatabaseSqlite\wasDeadlock
wasDeadlock()
Definition: DatabaseSqlite.php:752
Wikimedia\Rdbms\DatabaseSqlite\generateFileName
static generateFileName( $dir, $dbName)
Generates a database file name.
Definition: DatabaseSqlite.php:230
Wikimedia\Rdbms\DatabaseSqlite\doBegin
doBegin( $fname='')
Issues the BEGIN command to the database server.
Definition: DatabaseSqlite.php:820
Wikimedia\Rdbms\DatabaseSqlite\$conn
PDO $conn
Definition: DatabaseSqlite.php:52
Wikimedia\Rdbms\DatabaseSqlite\resetSequenceForTable
resetSequenceForTable( $table, $fname=__METHOD__)
Definition: DatabaseSqlite.php:1143
Wikimedia\Rdbms\DatabaseSqlite\fixIgnore
static fixIgnore( $options)
Definition: DatabaseSqlite.php:632
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.
Definition: Database.php:1810
Wikimedia\Rdbms\Database\$user
string $user
User that this instance is currently connected under the name of.
Definition: Database.php:77
Wikimedia\Rdbms\DatabaseSqlite\tableExists
tableExists( $table, $fname=__METHOD__)
Query whether a given table exists.
Definition: DatabaseSqlite.php:539
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:196
Wikimedia\Rdbms\DatabaseSqlite\numRows
numRows( $res)
The PDO::Statement class implements the array interface so count() will work.
Definition: DatabaseSqlite.php:399
Wikimedia\Rdbms\DatabaseSqlite\replaceVars
replaceVars( $s)
Definition: DatabaseSqlite.php:921
Wikimedia\Rdbms\DatabaseSqlite\deadlockLoop
deadlockLoop()
No-op version of deadlockLoop.
Definition: DatabaseSqlite.php:910
Wikimedia\Rdbms\DatabaseSqlite\fieldName
fieldName( $res, $n)
Definition: DatabaseSqlite.php:426
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:1893
Wikimedia\Rdbms\DatabaseSqlite\lock
lock( $lockName, $method, $timeout=5)
Acquire a named lock.
Definition: DatabaseSqlite.php:974
Wikimedia\Rdbms\DatabaseSqlite\fetchObject
fetchObject( $res)
Definition: DatabaseSqlite.php:358
Wikimedia\Rdbms\Database\getLogContext
getLogContext(array $extras=[])
Create a log context to pass to PSR-3 logger functions.
Definition: Database.php:865
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:332
Wikimedia\Rdbms\DatabaseSqlite\$dbDir
string null $dbDir
Directory for SQLite database files listed under their DB name.
Definition: DatabaseSqlite.php:40
Wikimedia\Rdbms\DatabaseSqlite\getAttributes
static getAttributes()
Definition: DatabaseSqlite.php:95
Wikimedia\Rdbms\DatabaseSqlite\getType
getType()
Definition: DatabaseSqlite.php:121
Wikimedia\Rdbms\DatabaseSqlite\buildGroupConcatField
buildGroupConcatField( $delim, $table, $field, $conds='', $join_conds=[])
Build a GROUP_CONCAT or equivalent statement for a query.
Definition: DatabaseSqlite.php:1000
Wikimedia\Rdbms\DatabaseSqlite\attachDatabase
attachDatabase( $name, $file=false, $fname=__METHOD__)
Attaches external database to the connection handle.
Definition: DatabaseSqlite.php:303
Wikimedia\Rdbms\DBUnexpectedError
Definition: DBUnexpectedError.php:27
Wikimedia\Rdbms\DatabaseSqlite\isTransactableQuery
isTransactableQuery( $sql)
Determine whether a SQL statement is sensitive to isolation level.
Definition: DatabaseSqlite.php:318
Wikimedia\Rdbms\DatabaseSqlite\insert
insert( $table, $a, $fname=__METHOD__, $options=[])
Based on generic method (parent) with some prior SQLite-sepcific adjustments.
Definition: DatabaseSqlite.php:661
Wikimedia\Rdbms\DatabaseSqlite\generateDatabaseName
static generateDatabaseName( $path)
Definition: DatabaseSqlite.php:249
Wikimedia\Rdbms\DatabaseSqlite\newStandaloneInstance
static newStandaloneInstance( $filename, array $p=[])
Definition: DatabaseSqlite.php:108
Wikimedia\Rdbms\Database\addIdentifierQuotes
addIdentifierQuotes( $s)
Escape a SQL identifier (e.g.
Definition: Database.php:2747
$args
if( $line===false) $args
Definition: cdb.php:64
Wikimedia\Rdbms\DatabaseSqlite\getFulltextSearchModule
static getFulltextSearchModule()
Returns version of currently supported SQLite fulltext search module or false if none present.
Definition: DatabaseSqlite.php:274
Wikimedia\Rdbms\Database\getQueryVerb
getQueryVerb( $sql)
Definition: Database.php:1057
$status
return $status
Definition: SyntaxHighlight.php:347
Wikimedia\Rdbms\DatabaseSqlite\$dbPath
string null $dbPath
Explicit path for the SQLite database file.
Definition: DatabaseSqlite.php:42
Wikimedia\Rdbms\DatabaseSqlite\makeUpdateOptionsArray
makeUpdateOptionsArray( $options)
Definition: DatabaseSqlite.php:621
Wikimedia\Rdbms\DatabaseSqlite\getSoftwareLink
getSoftwareLink()
Definition: DatabaseSqlite.php:786
Wikimedia\Rdbms\Database\newExceptionAfterConnectError
newExceptionAfterConnectError( $error)
Definition: Database.php:1613
Wikimedia\Rdbms\DatabaseSqlite\insertId
insertId()
This must be called after nextSequenceVal.
Definition: DatabaseSqlite.php:488
Wikimedia\Rdbms\DBExpectedError
Base class for the more common types of database errors.
Definition: DBExpectedError.php:32
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:348
Wikimedia\Rdbms\DatabaseSqlite\lastErrno
lastErrno()
Definition: DatabaseSqlite.php:522
$path
$path
Definition: NoLocalSettings.php:25
Wikimedia\Rdbms\DatabaseDomain\getSchema
getSchema()
Definition: DatabaseDomain.php:182
Wikimedia\Rdbms\DatabaseSqlite\indexUnique
indexUnique( $table, $index, $fname=__METHOD__)
Definition: DatabaseSqlite.php:585
Wikimedia\Rdbms\DatabaseSqlite\wasReadOnlyError
wasReadOnlyError()
Definition: DatabaseSqlite.php:759
Wikimedia\Rdbms\Database\$server
string $server
Server that this instance is currently connected to.
Definition: Database.php:75
$keys
$keys
Definition: testCompression.php:67
Wikimedia\Rdbms\Database\isOpen
isOpen()
Definition: Database.php:739
Wikimedia\Rdbms\DatabaseSqlite\doSelectDomain
doSelectDomain(DatabaseDomain $domain)
Definition: DatabaseSqlite.php:437
Wikimedia\Rdbms\Database\$flags
int $flags
Current bit field of class DBO_* constants.
Definition: Database.php:92
Wikimedia\Rdbms\DatabaseSqlite\buildConcat
buildConcat( $stringList)
Build a concatenation list to feed into a SQL query.
Definition: DatabaseSqlite.php:996
Wikimedia\Rdbms\Database\select
select( $table, $vars, $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
Execute a SELECT query constructed using the various parameters provided.
Definition: Database.php:1802
Wikimedia\Rdbms\DatabaseSqlite\isWriteQuery
isWriteQuery( $sql)
Determine whether a query writes to the DB.
Definition: DatabaseSqlite.php:314
Wikimedia\Rdbms\Database\affectedRows
affectedRows()
Get the number of rows affected by the last write query.
Definition: Database.php:4250
Wikimedia\Rdbms\DatabaseSqlite\wasConnectionError
wasConnectionError( $errno)
Do not use this method outside of Database/DBError classes.
Definition: DatabaseSqlite.php:763
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:70
Wikimedia\Rdbms\DatabaseSqlite\__construct
__construct(array $p)
Additional params include:
Definition: DatabaseSqlite.php:70
Wikimedia\Rdbms\DatabaseSqlite\decodeBlob
decodeBlob( $b)
Definition: DatabaseSqlite.php:848
DBO_DEFAULT
const DBO_DEFAULT
Definition: defines.php:13
Wikimedia\Rdbms\DatabaseSqlite\dropTable
dropTable( $tableName, $fName=__METHOD__)
Override due to no CASCADE support.
Definition: DatabaseSqlite.php:1112
Wikimedia\Rdbms\ResultWrapper\unwrap
static & unwrap(&$res)
Get the underlying RDBMS driver-specific result resource.
Definition: ResultWrapper.php:59
Wikimedia\Rdbms\Database\query
query( $sql, $fname=__METHOD__, $flags=0)
Run an SQL query and return the result.
Definition: Database.php:1141
Wikimedia\Rdbms\DatabaseSqlite\serverIsReadOnly
serverIsReadOnly()
Definition: DatabaseSqlite.php:775
Wikimedia\Rdbms\DatabaseSqlite\duplicateTableStructure
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Definition: DatabaseSqlite.php:1016
Wikimedia\Rdbms\DatabaseSqlite\numFields
numFields( $res)
Definition: DatabaseSqlite.php:410
Wikimedia\Rdbms\DatabaseSqlite\tableName
tableName( $name, $format='quoted')
Use MySQL's naming (accounts for prefix etc) but remove surrounding backticks.
Definition: DatabaseSqlite.php:474
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:565
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:727
Wikimedia\Rdbms\Database\getDBname
getDBname()
Get the current DB name.
Definition: Database.php:2399
Wikimedia\Rdbms\Blob
Definition: Blob.php:5
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:606