MediaWiki  master
DatabaseSqlite.php
Go to the documentation of this file.
1 <?php
24 namespace Wikimedia\Rdbms;
25 
26 use Exception;
27 use FSLockManager;
28 use LockManager;
29 use NullLockManager;
30 use PDO;
31 use PDOException;
32 use RuntimeException;
33 use stdClass;
34 
38 class DatabaseSqlite extends Database {
40  protected $dbDir;
42  protected $dbPath;
44  protected $trxMode;
45 
48 
50  protected $conn;
51 
53  protected $lockMgr;
54 
56  private $version;
57 
59  private $sessionAttachedDbs = [];
60 
62  private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
63 
71  public function __construct( array $params ) {
72  if ( isset( $params['dbFilePath'] ) ) {
73  $this->dbPath = $params['dbFilePath'];
74  if ( !strlen( $params['dbname'] ) ) {
75  $params['dbname'] = self::generateDatabaseName( $this->dbPath );
76  }
77  } elseif ( isset( $params['dbDirectory'] ) ) {
78  $this->dbDir = $params['dbDirectory'];
79  }
80 
81  parent::__construct( $params );
82 
83  $this->trxMode = strtoupper( $params['trxMode'] ?? '' );
84 
85  $lockDirectory = $this->getLockFileDirectory();
86  if ( $lockDirectory !== null ) {
87  $this->lockMgr = new FSLockManager( [
88  'domain' => $this->getDomainID(),
89  'lockDirectory' => $lockDirectory
90  ] );
91  } else {
92  $this->lockMgr = new NullLockManager( [ 'domain' => $this->getDomainID() ] );
93  }
94  }
95 
96  protected static function getAttributes() {
97  return [
98  self::ATTR_DB_IS_FILE => true,
99  self::ATTR_DB_LEVEL_LOCKING => true
100  ];
101  }
102 
112  public static function newStandaloneInstance( $filename, array $p = [] ) {
113  $p['dbFilePath'] = $filename;
114  $p['schema'] = null;
115  $p['tablePrefix'] = '';
117  $db = Database::factory( 'sqlite', $p );
118 
119  return $db;
120  }
121 
125  public function getType() {
126  return 'sqlite';
127  }
128 
129  protected function open( $server, $user, $pass, $dbName, $schema, $tablePrefix ) {
130  $this->close();
131 
132  // Note that for SQLite, $server, $user, and $pass are ignored
133 
134  if ( $schema !== null ) {
135  throw $this->newExceptionAfterConnectError( "Got schema '$schema'; not supported." );
136  }
137 
138  if ( $this->dbPath !== null ) {
140  } elseif ( $this->dbDir !== null ) {
141  $path = self::generateFileName( $this->dbDir, $dbName );
142  } else {
143  throw $this->newExceptionAfterConnectError( "DB path or directory required" );
144  }
145 
146  // Check if the database file already exists but is non-readable
147  if (
148  !self::isProcessMemoryPath( $path ) &&
149  file_exists( $path ) &&
150  !is_readable( $path )
151  ) {
152  throw $this->newExceptionAfterConnectError( 'SQLite database file is not readable' );
153  } elseif ( !in_array( $this->trxMode, self::$VALID_TRX_MODES, true ) ) {
154  throw $this->newExceptionAfterConnectError( "Got mode '{$this->trxMode}' for BEGIN" );
155  }
156 
157  $this->server = 'localhost';
158 
159  $attributes = [];
160  if ( $this->getFlag( self::DBO_PERSISTENT ) ) {
161  // Persistent connections can avoid some schema index reading overhead.
162  // On the other hand, they can cause horrible contention with DBO_TRX.
163  if ( $this->getFlag( self::DBO_TRX ) || $this->getFlag( self::DBO_DEFAULT ) ) {
164  $this->connLogger->warning(
165  __METHOD__ . ": ignoring DBO_PERSISTENT due to DBO_TRX or DBO_DEFAULT",
166  $this->getLogContext()
167  );
168  } else {
169  $attributes[PDO::ATTR_PERSISTENT] = true;
170  }
171  }
172 
173  try {
174  // Open the database file, creating it if it does not yet exist
175  $this->conn = new PDO( "sqlite:$path", null, null, $attributes );
176  } catch ( PDOException $e ) {
177  throw $this->newExceptionAfterConnectError( $e->getMessage() );
178  }
179 
180  $this->currentDomain = new DatabaseDomain( $dbName, null, $tablePrefix );
181 
182  try {
183  $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_NO_RETRY;
184  // Enforce LIKE to be case sensitive, just like MySQL
185  $this->query( 'PRAGMA case_sensitive_like = 1', __METHOD__, $flags );
186  // Apply optimizations or requirements regarding fsync() usage
187  $sync = $this->connectionVariables['synchronous'] ?? null;
188  if ( in_array( $sync, [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ], true ) ) {
189  $this->query( "PRAGMA synchronous = $sync", __METHOD__, $flags );
190  }
192  } catch ( Exception $e ) {
193  throw $this->newExceptionAfterConnectError( $e->getMessage() );
194  }
195  }
196 
202  public function getDbFilePath() {
203  return $this->dbPath ?? self::generateFileName( $this->dbDir, $this->getDBname() );
204  }
205 
209  public function getLockFileDirectory() {
210  if ( $this->dbPath !== null && !self::isProcessMemoryPath( $this->dbPath ) ) {
211  return dirname( $this->dbPath ) . '/locks';
212  } elseif ( $this->dbDir !== null && !self::isProcessMemoryPath( $this->dbDir ) ) {
213  return $this->dbDir . '/locks';
214  }
215 
216  return null;
217  }
218 
223  protected function closeConnection() {
224  $this->conn = null;
225 
226  return true;
227  }
228 
236  public static function generateFileName( $dir, $dbName ) {
237  if ( $dir == '' ) {
238  throw new DBUnexpectedError( null, __CLASS__ . ": no DB directory specified" );
239  } elseif ( self::isProcessMemoryPath( $dir ) ) {
240  throw new DBUnexpectedError(
241  null,
242  __CLASS__ . ": cannot use process memory directory '$dir'"
243  );
244  } elseif ( !strlen( $dbName ) ) {
245  throw new DBUnexpectedError( null, __CLASS__ . ": no DB name specified" );
246  }
247 
248  return "$dir/$dbName.sqlite";
249  }
250 
255  private static function generateDatabaseName( $path ) {
256  if ( preg_match( '/^(:memory:$|file::memory:)/', $path ) ) {
257  // E.g. "file::memory:?cache=shared" => ":memory":
258  return ':memory:';
259  } elseif ( preg_match( '/^file::([^?]+)\?mode=memory(&|$)/', $path, $m ) ) {
260  // E.g. "file:memdb1?mode=memory" => ":memdb1:"
261  return ":{$m[1]}:";
262  } else {
263  // E.g. "/home/.../some_db.sqlite3" => "some_db"
264  return preg_replace( '/\.sqlite\d?$/', '', basename( $path ) );
265  }
266  }
267 
272  private static function isProcessMemoryPath( $path ) {
273  return preg_match( '/^(:memory:$|file:(:memory:|[^?]+\?mode=memory(&|$)))/', $path );
274  }
275 
280  static function getFulltextSearchModule() {
281  static $cachedResult = null;
282  if ( $cachedResult !== null ) {
283  return $cachedResult;
284  }
285  $cachedResult = false;
286  $table = 'dummy_search_test';
287 
288  $db = self::newStandaloneInstance( ':memory:' );
289  if ( $db->query(
290  "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)",
291  __METHOD__,
292  IDatabase::QUERY_SILENCE_ERRORS
293  ) ) {
294  $cachedResult = 'FTS3';
295  }
296  $db->close();
297 
298  return $cachedResult;
299  }
300 
313  public function attachDatabase( $name, $file = false, $fname = __METHOD__ ) {
314  $file = is_string( $file ) ? $file : self::generateFileName( $this->dbDir, $name );
315  $encFile = $this->addQuotes( $file );
316 
317  return $this->query(
318  "ATTACH DATABASE $encFile AS $name",
319  $fname,
320  self::QUERY_IGNORE_DBO_TRX
321  );
322  }
323 
324  protected function isWriteQuery( $sql ) {
325  return parent::isWriteQuery( $sql ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql );
326  }
327 
328  protected function isTransactableQuery( $sql ) {
329  return parent::isTransactableQuery( $sql ) && !in_array(
330  $this->getQueryVerb( $sql ),
331  [ 'ATTACH', 'PRAGMA' ],
332  true
333  );
334  }
335 
342  protected function doQuery( $sql ) {
343  $res = $this->getBindingHandle()->query( $sql );
344  if ( $res === false ) {
345  return false;
346  }
347 
348  $resource = ResultWrapper::unwrap( $res );
349  $this->lastAffectedRowCount = $resource->rowCount();
350  $res = new ResultWrapper( $this, $resource->fetchAll() );
351 
352  return $res;
353  }
354 
358  function freeResult( $res ) {
359  if ( $res instanceof ResultWrapper ) {
360  $res->free();
361  }
362  }
363 
368  function fetchObject( $res ) {
369  $resource =& ResultWrapper::unwrap( $res );
370 
371  $cur = current( $resource );
372  if ( is_array( $cur ) ) {
373  next( $resource );
374  $obj = new stdClass;
375  foreach ( $cur as $k => $v ) {
376  if ( !is_numeric( $k ) ) {
377  $obj->$k = $v;
378  }
379  }
380 
381  return $obj;
382  }
383 
384  return false;
385  }
386 
391  function fetchRow( $res ) {
392  $resource =& ResultWrapper::unwrap( $res );
393  $cur = current( $resource );
394  if ( is_array( $cur ) ) {
395  next( $resource );
396 
397  return $cur;
398  }
399 
400  return false;
401  }
402 
409  function numRows( $res ) {
410  // false does not implement Countable
411  $resource = ResultWrapper::unwrap( $res );
412 
413  return is_array( $resource ) ? count( $resource ) : 0;
414  }
415 
420  function numFields( $res ) {
421  $resource = ResultWrapper::unwrap( $res );
422  if ( is_array( $resource ) && count( $resource ) > 0 ) {
423  // The size of the result array is twice the number of fields. (T67578)
424  return count( $resource[0] ) / 2;
425  } else {
426  // If the result is empty return 0
427  return 0;
428  }
429  }
430 
436  function fieldName( $res, $n ) {
437  $resource = ResultWrapper::unwrap( $res );
438  if ( is_array( $resource ) ) {
439  $keys = array_keys( $resource[0] );
440 
441  return $keys[$n];
442  }
443 
444  return false;
445  }
446 
447  protected function doSelectDomain( DatabaseDomain $domain ) {
448  if ( $domain->getSchema() !== null ) {
449  throw new DBExpectedError(
450  $this,
451  __CLASS__ . ": domain '{$domain->getId()}' has a schema component"
452  );
453  }
454 
455  $database = $domain->getDatabase();
456  // A null database means "don't care" so leave it as is and update the table prefix
457  if ( $database === null ) {
458  $this->currentDomain = new DatabaseDomain(
459  $this->currentDomain->getDatabase(),
460  null,
461  $domain->getTablePrefix()
462  );
463 
464  return true;
465  }
466 
467  if ( $database !== $this->getDBname() ) {
468  throw new DBExpectedError(
469  $this,
470  __CLASS__ . ": cannot change database (got '$database')"
471  );
472  }
473 
474  return true;
475  }
476 
484  function tableName( $name, $format = 'quoted' ) {
485  // table names starting with sqlite_ are reserved
486  if ( strpos( $name, 'sqlite_' ) === 0 ) {
487  return $name;
488  }
489 
490  return str_replace( '"', '', parent::tableName( $name, $format ) );
491  }
492 
498  function insertId() {
499  // PDO::lastInsertId yields a string :(
500  return intval( $this->getBindingHandle()->lastInsertId() );
501  }
502 
507  function dataSeek( $res, $row ) {
508  $resource =& ResultWrapper::unwrap( $res );
509  reset( $resource );
510  if ( $row > 0 ) {
511  for ( $i = 0; $i < $row; $i++ ) {
512  next( $resource );
513  }
514  }
515  }
516 
520  function lastError() {
521  if ( !is_object( $this->conn ) ) {
522  return "Cannot return last error, no db connection";
523  }
524  $e = $this->conn->errorInfo();
525 
526  return $e[2] ?? '';
527  }
528 
532  function lastErrno() {
533  if ( !is_object( $this->conn ) ) {
534  return "Cannot return last error, no db connection";
535  } else {
536  $info = $this->conn->errorInfo();
537 
538  return $info[1];
539  }
540  }
541 
545  protected function fetchAffectedRowCount() {
547  }
548 
549  function tableExists( $table, $fname = __METHOD__ ) {
550  $tableRaw = $this->tableName( $table, 'raw' );
551  if ( isset( $this->sessionTempTables[$tableRaw] ) ) {
552  return true; // already known to exist
553  }
554 
555  $encTable = $this->addQuotes( $tableRaw );
556  $res = $this->query(
557  "SELECT 1 FROM sqlite_master WHERE type='table' AND name=$encTable",
558  __METHOD__,
559  self::QUERY_IGNORE_DBO_TRX
560  );
561 
562  return $res->numRows() ? true : false;
563  }
564 
575  function indexInfo( $table, $index, $fname = __METHOD__ ) {
576  $sql = 'PRAGMA index_info(' . $this->addQuotes( $this->indexName( $index ) ) . ')';
577  $res = $this->query( $sql, $fname, self::QUERY_IGNORE_DBO_TRX );
578  if ( !$res || $res->numRows() == 0 ) {
579  return false;
580  }
581  $info = [];
582  foreach ( $res as $row ) {
583  $info[] = $row->name;
584  }
585 
586  return $info;
587  }
588 
595  function indexUnique( $table, $index, $fname = __METHOD__ ) {
596  $row = $this->selectRow( 'sqlite_master', '*',
597  [
598  'type' => 'index',
599  'name' => $this->indexName( $index ),
600  ], $fname );
601  if ( !$row || !isset( $row->sql ) ) {
602  return null;
603  }
604 
605  // $row->sql will be of the form CREATE [UNIQUE] INDEX ...
606  $indexPos = strpos( $row->sql, 'INDEX' );
607  if ( $indexPos === false ) {
608  return null;
609  }
610  $firstPart = substr( $row->sql, 0, $indexPos );
611  $options = explode( ' ', $firstPart );
612 
613  return in_array( 'UNIQUE', $options );
614  }
615 
616  protected function makeSelectOptions( array $options ) {
617  // Remove problematic options that the base implementation converts to SQL
618  foreach ( $options as $k => $v ) {
619  if ( is_numeric( $k ) && ( $v === 'FOR UPDATE' || $v === 'LOCK IN SHARE MODE' ) ) {
620  $options[$k] = '';
621  }
622  }
623 
624  return parent::makeSelectOptions( $options );
625  }
626 
631  protected function makeUpdateOptionsArray( $options ) {
632  $options = parent::makeUpdateOptionsArray( $options );
633  $options = $this->rewriteIgnoreKeyword( $options );
634 
635  return $options;
636  }
637 
642  private function rewriteIgnoreKeyword( $options ) {
643  # SQLite uses OR IGNORE not just IGNORE
644  foreach ( $options as $k => $v ) {
645  if ( $v == 'IGNORE' ) {
646  $options[$k] = 'OR IGNORE';
647  }
648  }
649 
650  return $options;
651  }
652 
657  protected function makeInsertOptions( $options ) {
658  $options = self::rewriteIgnoreKeyword( $options );
659 
660  return parent::makeInsertOptions( $options );
661  }
662 
663  public function insert( $table, $rows, $fname = __METHOD__, $options = [] ) {
664  if ( version_compare( $this->getServerVersion(), '3.7.11', '>=' ) ) {
665  // Batch INSERT support per http://www.sqlite.org/releaselog/3_7_11.html
666  return parent::insert( $table, $rows, $fname, $options );
667  }
668 
669  if ( !$rows ) {
670  return true;
671  }
672 
673  $multi = $this->isMultiRowArray( $rows );
674  if ( $multi ) {
675  $affectedRowCount = 0;
676  try {
677  $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
678  foreach ( $rows as $row ) {
679  parent::insert( $table, $row, "$fname/multi-row", $options );
680  $affectedRowCount += $this->affectedRows();
681  }
682  $this->endAtomic( $fname );
683  } catch ( Exception $e ) {
684  $this->cancelAtomic( $fname );
685  throw $e;
686  }
687  $this->affectedRowCount = $affectedRowCount;
688  } else {
689  parent::insert( $table, $rows, "$fname/single-row", $options );
690  }
691 
692  return true;
693  }
694 
701  function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
702  if ( !count( $rows ) ) {
703  return;
704  }
705 
706  # SQLite can't handle multi-row replaces, so divide up into multiple single-row queries
707  if ( isset( $rows[0] ) && is_array( $rows[0] ) ) {
708  $affectedRowCount = 0;
709  try {
710  $this->startAtomic( $fname, self::ATOMIC_CANCELABLE );
711  foreach ( $rows as $v ) {
712  $this->nativeReplace( $table, $v, "$fname/multi-row" );
713  $affectedRowCount += $this->affectedRows();
714  }
715  $this->endAtomic( $fname );
716  } catch ( Exception $e ) {
717  $this->cancelAtomic( $fname );
718  throw $e;
719  }
720  $this->affectedRowCount = $affectedRowCount;
721  } else {
722  $this->nativeReplace( $table, $rows, "$fname/single-row" );
723  }
724  }
725 
734  function textFieldSize( $table, $field ) {
735  return -1;
736  }
737 
742  return false;
743  }
744 
750  function unionQueries( $sqls, $all ) {
751  $glue = $all ? ' UNION ALL ' : ' UNION ';
752 
753  return implode( $glue, $sqls );
754  }
755 
759  function wasDeadlock() {
760  return $this->lastErrno() == 5; // SQLITE_BUSY
761  }
762 
766  function wasReadOnlyError() {
767  return $this->lastErrno() == 8; // SQLITE_READONLY;
768  }
769 
770  public function wasConnectionError( $errno ) {
771  return $errno == 17; // SQLITE_SCHEMA;
772  }
773 
774  protected function wasKnownStatementRollbackError() {
775  // ON CONFLICT ROLLBACK clauses make it so that SQLITE_CONSTRAINT error is
776  // ambiguous with regard to whether it implies a ROLLBACK or an ABORT happened.
777  // https://sqlite.org/lang_createtable.html#uniqueconst
778  // https://sqlite.org/lang_conflict.html
779  return false;
780  }
781 
782  public function serverIsReadOnly() {
783  $this->assertHasConnectionHandle();
784 
785  $path = $this->getDbFilePath();
786 
787  return ( !self::isProcessMemoryPath( $path ) && !is_writable( $path ) );
788  }
789 
793  public function getSoftwareLink() {
794  return "[{{int:version-db-sqlite-url}} SQLite]";
795  }
796 
800  public function getServerVersion() {
801  if ( $this->version === null ) {
802  $this->version = $this->getBindingHandle()->getAttribute( PDO::ATTR_SERVER_VERSION );
803  }
804 
805  return $this->version;
806  }
807 
816  function fieldInfo( $table, $field ) {
817  $tableName = $this->tableName( $table );
818  $sql = 'PRAGMA table_info(' . $this->addQuotes( $tableName ) . ')';
819  $res = $this->query( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
820  foreach ( $res as $row ) {
821  if ( $row->name == $field ) {
822  return new SQLiteField( $row, $tableName );
823  }
824  }
825 
826  return false;
827  }
828 
829  protected function doBegin( $fname = '' ) {
830  if ( $this->trxMode != '' ) {
831  $this->query( "BEGIN {$this->trxMode}", $fname );
832  } else {
833  $this->query( 'BEGIN', $fname );
834  }
835  }
836 
841  function strencode( $s ) {
842  return substr( $this->addQuotes( $s ), 1, -1 );
843  }
844 
849  function encodeBlob( $b ) {
850  return new Blob( $b );
851  }
852 
857  function decodeBlob( $b ) {
858  if ( $b instanceof Blob ) {
859  $b = $b->fetch();
860  }
861 
862  return $b;
863  }
864 
869  function addQuotes( $s ) {
870  if ( $s instanceof Blob ) {
871  return "x'" . bin2hex( $s->fetch() ) . "'";
872  } elseif ( is_bool( $s ) ) {
873  return (string)(int)$s;
874  } elseif ( is_int( $s ) ) {
875  return (string)$s;
876  } elseif ( strpos( (string)$s, "\0" ) !== false ) {
877  // SQLite doesn't support \0 in strings, so use the hex representation as a workaround.
878  // This is a known limitation of SQLite's mprintf function which PDO
879  // should work around, but doesn't. I have reported this to php.net as bug #63419:
880  // https://bugs.php.net/bug.php?id=63419
881  // There was already a similar report for SQLite3::escapeString, bug #62361:
882  // https://bugs.php.net/bug.php?id=62361
883  // There is an additional bug regarding sorting this data after insert
884  // on older versions of sqlite shipped with ubuntu 12.04
885  // https://phabricator.wikimedia.org/T74367
886  $this->queryLogger->debug(
887  __FUNCTION__ .
888  ': Quoting value containing null byte. ' .
889  'For consistency all binary data should have been ' .
890  'first processed with self::encodeBlob()'
891  );
892  return "x'" . bin2hex( (string)$s ) . "'";
893  } else {
894  return $this->getBindingHandle()->quote( (string)$s );
895  }
896  }
897 
898  public function buildSubstring( $input, $startPosition, $length = null ) {
899  $this->assertBuildSubstringParams( $startPosition, $length );
900  $params = [ $input, $startPosition ];
901  if ( $length !== null ) {
902  $params[] = $length;
903  }
904  return 'SUBSTR(' . implode( ',', $params ) . ')';
905  }
906 
912  public function buildStringCast( $field ) {
913  return 'CAST ( ' . $field . ' AS TEXT )';
914  }
915 
922  public function deadlockLoop( ...$args ) {
923  $function = array_shift( $args );
924 
925  return $function( ...$args );
926  }
927 
932  protected function replaceVars( $s ) {
933  $s = parent::replaceVars( $s );
934  if ( preg_match( '/^\s*(CREATE|ALTER) TABLE/i', $s ) ) {
935  // CREATE TABLE hacks to allow schema file sharing with MySQL
936 
937  // binary/varbinary column type -> blob
938  $s = preg_replace( '/\b(var)?binary(\(\d+\))/i', 'BLOB', $s );
939  // no such thing as unsigned
940  $s = preg_replace( '/\b(un)?signed\b/i', '', $s );
941  // INT -> INTEGER
942  $s = preg_replace( '/\b(tiny|small|medium|big|)int(\s*\(\s*\d+\s*\)|\b)/i', 'INTEGER', $s );
943  // floating point types -> REAL
944  $s = preg_replace(
945  '/\b(float|double(\s+precision)?)(\s*\(\s*\d+\s*(,\s*\d+\s*)?\)|\b)/i',
946  'REAL',
947  $s
948  );
949  // varchar -> TEXT
950  $s = preg_replace( '/\b(var)?char\s*\(.*?\)/i', 'TEXT', $s );
951  // TEXT normalization
952  $s = preg_replace( '/\b(tiny|medium|long)text\b/i', 'TEXT', $s );
953  // BLOB normalization
954  $s = preg_replace( '/\b(tiny|small|medium|long|)blob\b/i', 'BLOB', $s );
955  // BOOL -> INTEGER
956  $s = preg_replace( '/\bbool(ean)?\b/i', 'INTEGER', $s );
957  // DATETIME -> TEXT
958  $s = preg_replace( '/\b(datetime|timestamp)\b/i', 'TEXT', $s );
959  // No ENUM type
960  $s = preg_replace( '/\benum\s*\([^)]*\)/i', 'TEXT', $s );
961  // binary collation type -> nothing
962  $s = preg_replace( '/\bbinary\b/i', '', $s );
963  // auto_increment -> autoincrement
964  $s = preg_replace( '/\bauto_increment\b/i', 'AUTOINCREMENT', $s );
965  // No explicit options
966  $s = preg_replace( '/\)[^);]*(;?)\s*$/', ')\1', $s );
967  // AUTOINCREMENT should immedidately follow PRIMARY KEY
968  $s = preg_replace( '/primary key (.*?) autoincrement/i', 'PRIMARY KEY AUTOINCREMENT $1', $s );
969  } elseif ( preg_match( '/^\s*CREATE (\s*(?:UNIQUE|FULLTEXT)\s+)?INDEX/i', $s ) ) {
970  // No truncated indexes
971  $s = preg_replace( '/\(\d+\)/', '', $s );
972  // No FULLTEXT
973  $s = preg_replace( '/\bfulltext\b/i', '', $s );
974  } elseif ( preg_match( '/^\s*DROP INDEX/i', $s ) ) {
975  // DROP INDEX is database-wide, not table-specific, so no ON <table> clause.
976  $s = preg_replace( '/\sON\s+[^\s]*/i', '', $s );
977  } elseif ( preg_match( '/^\s*INSERT IGNORE\b/i', $s ) ) {
978  // INSERT IGNORE --> INSERT OR IGNORE
979  $s = preg_replace( '/^\s*INSERT IGNORE\b/i', 'INSERT OR IGNORE', $s );
980  }
981 
982  return $s;
983  }
984 
985  public function lock( $lockName, $method, $timeout = 5 ) {
986  $status = $this->lockMgr->lock( [ $lockName ], LockManager::LOCK_EX, $timeout );
987  if (
988  $this->lockMgr instanceof FSLockManager &&
989  $status->hasMessage( 'lockmanager-fail-openlock' )
990  ) {
991  throw new DBError( $this, "Cannot create directory \"{$this->getLockFileDirectory()}\"" );
992  }
993 
994  return $status->isOK();
995  }
996 
997  public function unlock( $lockName, $method ) {
998  return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isGood();
999  }
1000 
1007  function buildConcat( $stringList ) {
1008  return '(' . implode( ') || (', $stringList ) . ')';
1009  }
1010 
1011  public function buildGroupConcatField(
1012  $delim, $table, $field, $conds = '', $join_conds = []
1013  ) {
1014  $fld = "group_concat($field," . $this->addQuotes( $delim ) . ')';
1015 
1016  return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')';
1017  }
1018 
1027  function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = __METHOD__ ) {
1028  $res = $this->query(
1029  "SELECT sql FROM sqlite_master WHERE tbl_name=" .
1030  $this->addQuotes( $oldName ) . " AND type='table'",
1031  $fname
1032  );
1033  $obj = $this->fetchObject( $res );
1034  if ( !$obj ) {
1035  throw new RuntimeException( "Couldn't retrieve structure for table $oldName" );
1036  }
1037  $sql = $obj->sql;
1038  $sql = preg_replace(
1039  '/(?<=\W)"?' .
1040  preg_quote( trim( $this->addIdentifierQuotes( $oldName ), '"' ), '/' ) .
1041  '"?(?=\W)/',
1042  $this->addIdentifierQuotes( $newName ),
1043  $sql,
1044  1
1045  );
1046  if ( $temporary ) {
1047  if ( preg_match( '/^\\s*CREATE\\s+VIRTUAL\\s+TABLE\b/i', $sql ) ) {
1048  $this->queryLogger->debug(
1049  "Table $oldName is virtual, can't create a temporary duplicate.\n" );
1050  } else {
1051  $sql = str_replace( 'CREATE TABLE', 'CREATE TEMPORARY TABLE', $sql );
1052  }
1053  }
1054 
1055  $res = $this->query( $sql, $fname, self::QUERY_PSEUDO_PERMANENT );
1056 
1057  // Take over indexes
1058  $indexList = $this->query( 'PRAGMA INDEX_LIST(' . $this->addQuotes( $oldName ) . ')' );
1059  foreach ( $indexList as $index ) {
1060  if ( strpos( $index->name, 'sqlite_autoindex' ) === 0 ) {
1061  continue;
1062  }
1063 
1064  if ( $index->unique ) {
1065  $sql = 'CREATE UNIQUE INDEX';
1066  } else {
1067  $sql = 'CREATE INDEX';
1068  }
1069  // Try to come up with a new index name, given indexes have database scope in SQLite
1070  $indexName = $newName . '_' . $index->name;
1071  $sql .= ' ' . $indexName . ' ON ' . $newName;
1072 
1073  $indexInfo = $this->query( 'PRAGMA INDEX_INFO(' . $this->addQuotes( $index->name ) . ')' );
1074  $fields = [];
1075  foreach ( $indexInfo as $indexInfoRow ) {
1076  $fields[$indexInfoRow->seqno] = $indexInfoRow->name;
1077  }
1078 
1079  $sql .= '(' . implode( ',', $fields ) . ')';
1080 
1081  $this->query( $sql );
1082  }
1083 
1084  return $res;
1085  }
1086 
1095  function listTables( $prefix = null, $fname = __METHOD__ ) {
1096  $result = $this->select(
1097  'sqlite_master',
1098  'name',
1099  "type='table'"
1100  );
1101 
1102  $endArray = [];
1103 
1104  foreach ( $result as $table ) {
1105  $vars = get_object_vars( $table );
1106  $table = array_pop( $vars );
1107 
1108  if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
1109  if ( strpos( $table, 'sqlite_' ) !== 0 ) {
1110  $endArray[] = $table;
1111  }
1112  }
1113  }
1114 
1115  return $endArray;
1116  }
1117 
1126  public function dropTable( $tableName, $fName = __METHOD__ ) {
1127  if ( !$this->tableExists( $tableName, $fName ) ) {
1128  return false;
1129  }
1130  $sql = "DROP TABLE " . $this->tableName( $tableName );
1131 
1132  return $this->query( $sql, $fName, self::QUERY_IGNORE_DBO_TRX );
1133  }
1134 
1135  public function setTableAliases( array $aliases ) {
1136  parent::setTableAliases( $aliases );
1137  if ( $this->isOpen() ) {
1139  }
1140  }
1141 
1145  private function attachDatabasesFromTableAliases() {
1146  foreach ( $this->tableAliases as $params ) {
1147  if (
1148  $params['dbname'] !== $this->getDBname() &&
1149  !isset( $this->sessionAttachedDbs[$params['dbname']] )
1150  ) {
1151  $this->attachDatabase( $params['dbname'] );
1152  $this->sessionAttachedDbs[$params['dbname']] = true;
1153  }
1154  }
1155  }
1156 
1157  public function resetSequenceForTable( $table, $fname = __METHOD__ ) {
1158  $encTable = $this->addIdentifierQuotes( 'sqlite_sequence' );
1159  $encName = $this->addQuotes( $this->tableName( $table, 'raw' ) );
1160  $this->query(
1161  "DELETE FROM $encTable WHERE name = $encName",
1162  $fname,
1163  self::QUERY_IGNORE_DBO_TRX
1164  );
1165  }
1166 
1167  public function databasesAreIndependent() {
1168  return true;
1169  }
1170 
1171  protected function doHandleSessionLossPreconnect() {
1172  $this->sessionAttachedDbs = [];
1173  }
1174 
1178  protected function getBindingHandle() {
1179  return parent::getBindingHandle();
1180  }
1181 }
1182 
1186 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:816
Wikimedia\Rdbms\DatabaseSqlite\$lockMgr
FSLockManager $lockMgr
(hopefully on the same server as the DB)
Definition: DatabaseSqlite.php:53
LockManager
Class for handling resource locking.
Definition: LockManager.php:47
Wikimedia\Rdbms\DatabaseSqlite\getBindingHandle
getBindingHandle()
Definition: DatabaseSqlite.php:1178
Wikimedia\Rdbms\DatabaseSqlite\addQuotes
addQuotes( $s)
Definition: DatabaseSqlite.php:869
Wikimedia\Rdbms\DatabaseSqlite\fetchRow
fetchRow( $res)
Definition: DatabaseSqlite.php:391
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:1171
Wikimedia\Rdbms\DatabaseSqlite
Definition: DatabaseSqlite.php:38
Wikimedia\Rdbms\DatabaseSqlite\wasKnownStatementRollbackError
wasKnownStatementRollbackError()
Definition: DatabaseSqlite.php:774
Wikimedia\Rdbms\DatabaseSqlite\listTables
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
Definition: DatabaseSqlite.php:1095
FSLockManager
Simple version of LockManager based on using FS lock files.
Definition: FSLockManager.php:36
Wikimedia\Rdbms\Database\isMultiRowArray
isMultiRowArray(array $a)
Definition: Database.php:2126
Wikimedia\Rdbms\DatabaseSqlite\deadlockLoop
deadlockLoop(... $args)
No-op version of deadlockLoop.
Definition: DatabaseSqlite.php:922
Wikimedia\Rdbms\DatabaseSqlite\unlock
unlock( $lockName, $method)
Release a lock.
Definition: DatabaseSqlite.php:997
Wikimedia\Rdbms\Database\getDomainID
getDomainID()
Return the currently selected domain ID.
Definition: Database.php:806
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:129
Wikimedia\Rdbms\Database\assertHasConnectionHandle
assertHasConnectionHandle()
Make sure there is an open connection handle (alive or not) as a sanity check.
Definition: Database.php:970
Wikimedia\Rdbms\DatabaseSqlite\attachDatabasesFromTableAliases
attachDatabasesFromTableAliases()
Issue ATTATCH statements for all unattached foreign DBs in table aliases.
Definition: DatabaseSqlite.php:1145
Wikimedia\Rdbms\Database\nativeReplace
nativeReplace( $table, $rows, $fname)
REPLACE query wrapper for MySQL and SQLite, which have a native REPLACE statement.
Definition: Database.php:2926
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:389
true
return true
Definition: router.php:92
Wikimedia\Rdbms\DatabaseSqlite\unionSupportsOrderAndLimit
unionSupportsOrderAndLimit()
Definition: DatabaseSqlite.php:741
Wikimedia\Rdbms\DatabaseSqlite\$version
string null $version
Definition: DatabaseSqlite.php:56
Wikimedia\Rdbms\DatabaseSqlite\databasesAreIndependent
databasesAreIndependent()
Returns true if DBs are assumed to be on potentially different servers.
Definition: DatabaseSqlite.php:1167
Wikimedia\Rdbms\DatabaseSqlite\isProcessMemoryPath
static isProcessMemoryPath( $path)
Definition: DatabaseSqlite.php:272
Wikimedia\Rdbms\DatabaseSqlite\getLockFileDirectory
getLockFileDirectory()
Definition: DatabaseSqlite.php:209
Wikimedia\Rdbms\Database\endAtomic
endAtomic( $fname=__METHOD__)
Ends an atomic section of SQL statements.
Definition: Database.php:3863
Wikimedia\Rdbms\Database\indexName
indexName( $index)
Allows for index remapping in queries where this is not consistent across DBMS.
Definition: Database.php:2751
Wikimedia\Rdbms\DatabaseDomain\getTablePrefix
getTablePrefix()
Definition: DatabaseDomain.php:189
Wikimedia\Rdbms\DatabaseSqlite\fetchAffectedRowCount
fetchAffectedRowCount()
Definition: DatabaseSqlite.php:545
Wikimedia\Rdbms\DatabaseSqlite\replace
replace( $table, $uniqueIndexes, $rows, $fname=__METHOD__)
Definition: DatabaseSqlite.php:701
Wikimedia\Rdbms\DatabaseSqlite\encodeBlob
encodeBlob( $b)
Definition: DatabaseSqlite.php:849
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:1135
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:520
Wikimedia\Rdbms\DatabaseSqlite\getServerVersion
getServerVersion()
Definition: DatabaseSqlite.php:800
$s
$s
Definition: mergeMessageFileList.php:185
Wikimedia\Rdbms\DatabaseSqlite\dataSeek
dataSeek( $res, $row)
Definition: DatabaseSqlite.php:507
Wikimedia\Rdbms\DatabaseSqlite\strencode
strencode( $s)
Definition: DatabaseSqlite.php:841
Wikimedia\Rdbms\DatabaseDomain\getDatabase
getDatabase()
Definition: DatabaseDomain.php:175
Wikimedia\Rdbms\DatabaseSqlite\buildSubstring
buildSubstring( $input, $startPosition, $length=null)
Definition: DatabaseSqlite.php:898
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:223
$res
$res
Definition: testCompression.php:54
Wikimedia\Rdbms\Database\cancelAtomic
cancelAtomic( $fname=__METHOD__, AtomicSectionIdentifier $sectionId=null)
Cancel an atomic section of SQL statements.
Definition: Database.php:3897
Wikimedia\Rdbms\Database\getFlag
getFlag( $flag)
Returns a boolean whether the flag $flag is set for this connection.
Definition: Database.php:802
Wikimedia\Rdbms\DBError
Database error base class.
Definition: DBError.php:30
Wikimedia\Rdbms\DatabaseSqlite\buildStringCast
buildStringCast( $field)
Definition: DatabaseSqlite.php:912
Wikimedia\Rdbms\DatabaseSqlite\makeInsertOptions
makeInsertOptions( $options)
Definition: DatabaseSqlite.php:657
DBO_TRX
const DBO_TRX
Definition: defines.php:12
Wikimedia\Rdbms\DatabaseSqlite\unionQueries
unionQueries( $sqls, $all)
Definition: DatabaseSqlite.php:750
Wikimedia\Rdbms\Database\close
close( $fname=__METHOD__, $owner=null)
Close the database connection.
Definition: Database.php:892
Wikimedia\Rdbms\Database\$affectedRowCount
integer null $affectedRowCount
Rows affected by the last query to query() or its CRUD wrappers.
Definition: Database.php:171
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:2366
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:3833
Wikimedia\Rdbms\DatabaseSqlite\wasDeadlock
wasDeadlock()
Definition: DatabaseSqlite.php:759
Wikimedia\Rdbms\DatabaseSqlite\generateFileName
static generateFileName( $dir, $dbName)
Generates a database file name.
Definition: DatabaseSqlite.php:236
Wikimedia\Rdbms\DatabaseSqlite\doBegin
doBegin( $fname='')
Issues the BEGIN command to the database server.
Definition: DatabaseSqlite.php:829
Wikimedia\Rdbms\DatabaseSqlite\$conn
PDO $conn
Definition: DatabaseSqlite.php:50
Wikimedia\Rdbms\DatabaseSqlite\resetSequenceForTable
resetSequenceForTable( $table, $fname=__METHOD__)
Definition: DatabaseSqlite.php:1157
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:1831
Wikimedia\Rdbms\DatabaseSqlite\insert
insert( $table, $rows, $fname=__METHOD__, $options=[])
INSERT wrapper, inserts an array into a table.
Definition: DatabaseSqlite.php:663
$args
if( $line===false) $args
Definition: mcc.php:124
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:549
Wikimedia\Rdbms\DatabaseSqlite\$VALID_TRX_MODES
static string[] $VALID_TRX_MODES
See https://www.sqlite.org/lang_transaction.html.
Definition: DatabaseSqlite.php:62
Wikimedia\Rdbms\DatabaseSqlite\getDbFilePath
getDbFilePath()
Definition: DatabaseSqlite.php:202
Wikimedia\Rdbms\DatabaseSqlite\numRows
numRows( $res)
The PDO::Statement class implements the array interface so count() will work.
Definition: DatabaseSqlite.php:409
Wikimedia\Rdbms\DatabaseSqlite\replaceVars
replaceVars( $s)
Definition: DatabaseSqlite.php:932
Wikimedia\Rdbms\DatabaseSqlite\fieldName
fieldName( $res, $n)
Definition: DatabaseSqlite.php:436
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:1914
Wikimedia\Rdbms\DatabaseSqlite\lock
lock( $lockName, $method, $timeout=5)
Acquire a named lock.
Definition: DatabaseSqlite.php:985
Wikimedia\Rdbms\DatabaseSqlite\fetchObject
fetchObject( $res)
Definition: DatabaseSqlite.php:368
Wikimedia\Rdbms\Database\getLogContext
getLogContext(array $extras=[])
Create a log context to pass to PSR-3 logger functions.
Definition: Database.php:881
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:342
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:96
Wikimedia\Rdbms\DatabaseSqlite\getType
getType()
Definition: DatabaseSqlite.php:125
Wikimedia\Rdbms\DatabaseSqlite\buildGroupConcatField
buildGroupConcatField( $delim, $table, $field, $conds='', $join_conds=[])
Build a GROUP_CONCAT or equivalent statement for a query.
Definition: DatabaseSqlite.php:1011
Wikimedia\Rdbms\DatabaseSqlite\attachDatabase
attachDatabase( $name, $file=false, $fname=__METHOD__)
Attaches external database to the connection handle.
Definition: DatabaseSqlite.php:313
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:328
Wikimedia\Rdbms\DatabaseSqlite\generateDatabaseName
static generateDatabaseName( $path)
Definition: DatabaseSqlite.php:255
Wikimedia\Rdbms\DatabaseSqlite\newStandaloneInstance
static newStandaloneInstance( $filename, array $p=[])
Definition: DatabaseSqlite.php:112
Wikimedia\Rdbms\Database\addIdentifierQuotes
addIdentifierQuotes( $s)
Escape a SQL identifier (e.g.
Definition: Database.php:2770
Wikimedia\Rdbms\DatabaseSqlite\getFulltextSearchModule
static getFulltextSearchModule()
Returns version of currently supported SQLite fulltext search module or false if none present.
Definition: DatabaseSqlite.php:280
Wikimedia\Rdbms\Database\getQueryVerb
getQueryVerb( $sql)
Definition: Database.php:1071
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:631
Wikimedia\Rdbms\DatabaseSqlite\getSoftwareLink
getSoftwareLink()
Definition: DatabaseSqlite.php:793
Wikimedia\Rdbms\Database\newExceptionAfterConnectError
newExceptionAfterConnectError( $error)
Definition: Database.php:1634
Wikimedia\Rdbms\DatabaseSqlite\insertId
insertId()
This must be called after nextSequenceVal.
Definition: DatabaseSqlite.php:498
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:59
Wikimedia\Rdbms\DatabaseSqlite\freeResult
freeResult( $res)
Definition: DatabaseSqlite.php:358
Wikimedia\Rdbms\DatabaseSqlite\lastErrno
lastErrno()
Definition: DatabaseSqlite.php:532
$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:595
Wikimedia\Rdbms\DatabaseSqlite\wasReadOnlyError
wasReadOnlyError()
Definition: DatabaseSqlite.php:766
Wikimedia\Rdbms\Database\$server
string $server
Server that this instance is currently connected to.
Definition: Database.php:75
$keys
$keys
Definition: testCompression.php:69
Wikimedia\Rdbms\Database\isOpen
isOpen()
Definition: Database.php:755
Wikimedia\Rdbms\DatabaseSqlite\doSelectDomain
doSelectDomain(DatabaseDomain $domain)
Definition: DatabaseSqlite.php:447
Wikimedia\Rdbms\Database\$flags
int $flags
Current bit field of class DBO_* constants.
Definition: Database.php:96
Wikimedia\Rdbms\DatabaseSqlite\__construct
__construct(array $params)
Additional params include:
Definition: DatabaseSqlite.php:71
Wikimedia\Rdbms\DatabaseSqlite\buildConcat
buildConcat( $stringList)
Build a concatenation list to feed into a SQL query.
Definition: DatabaseSqlite.php:1007
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:1823
Wikimedia\Rdbms\DatabaseSqlite\isWriteQuery
isWriteQuery( $sql)
Determine whether a query writes to the DB.
Definition: DatabaseSqlite.php:324
Wikimedia\Rdbms\Database\affectedRows
affectedRows()
Get the number of rows affected by the last write query.
Definition: Database.php:4270
Wikimedia\Rdbms\DatabaseSqlite\wasConnectionError
wasConnectionError( $errno)
Do not use this method outside of Database/DBError classes.
Definition: DatabaseSqlite.php:770
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\decodeBlob
decodeBlob( $b)
Definition: DatabaseSqlite.php:857
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:1126
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:1155
Wikimedia\Rdbms\DatabaseSqlite\serverIsReadOnly
serverIsReadOnly()
Definition: DatabaseSqlite.php:782
Wikimedia\Rdbms\DatabaseSqlite\duplicateTableStructure
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Definition: DatabaseSqlite.php:1027
Wikimedia\Rdbms\DatabaseSqlite\numFields
numFields( $res)
Definition: DatabaseSqlite.php:420
Wikimedia\Rdbms\DatabaseSqlite\tableName
tableName( $name, $format='quoted')
Use MySQL's naming (accounts for prefix etc) but remove surrounding backticks.
Definition: DatabaseSqlite.php:484
Wikimedia\Rdbms\DatabaseSqlite\rewriteIgnoreKeyword
rewriteIgnoreKeyword( $options)
Definition: DatabaseSqlite.php:642
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:575
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:734
Wikimedia\Rdbms\Database\getDBname
getDBname()
Get the current DB name.
Definition: Database.php:2426
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:616