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 
36 class DatabaseSqlite extends Database {
38  protected $dbDir;
40  protected $dbPath;
42  protected $trxMode;
43 
46 
48  protected $conn;
49 
51  protected $lockMgr;
52 
54  private $version;
55 
57  private $sessionAttachedDbs = [];
58 
60  private static $VALID_TRX_MODES = [ '', 'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE' ];
61 
63  private static $VALID_PRAGMAS = [
64  // Optimizations or requirements regarding fsync() usage
65  'synchronous' => [ 'EXTRA', 'FULL', 'NORMAL', 'OFF' ],
66  // Optimizations for TEMPORARY tables
67  'temp_store' => [ 'FILE', 'MEMORY' ]
68  ];
69 
77  public function __construct( array $params ) {
78  if ( isset( $params['dbFilePath'] ) ) {
79  $this->dbPath = $params['dbFilePath'];
80  if ( !strlen( $params['dbname'] ) ) {
81  $params['dbname'] = self::generateDatabaseName( $this->dbPath );
82  }
83  } elseif ( isset( $params['dbDirectory'] ) ) {
84  $this->dbDir = $params['dbDirectory'];
85  }
86 
87  parent::__construct( $params );
88 
89  $this->trxMode = strtoupper( $params['trxMode'] ?? '' );
90 
91  $lockDirectory = $this->getLockFileDirectory();
92  if ( $lockDirectory !== null ) {
93  $this->lockMgr = new FSLockManager( [
94  'domain' => $this->getDomainID(),
95  'lockDirectory' => $lockDirectory
96  ] );
97  } else {
98  $this->lockMgr = new NullLockManager( [ 'domain' => $this->getDomainID() ] );
99  }
100  }
101 
102  protected static function getAttributes() {
103  return [
104  self::ATTR_DB_IS_FILE => true,
105  self::ATTR_DB_LEVEL_LOCKING => true
106  ];
107  }
108 
118  public static function newStandaloneInstance( $filename, array $p = [] ) {
119  $p['dbFilePath'] = $filename;
120  $p['schema'] = null;
121  $p['tablePrefix'] = '';
123  $db = Database::factory( 'sqlite', $p );
124 
125  return $db;
126  }
127 
131  public function getType() {
132  return 'sqlite';
133  }
134 
135  protected function open( $server, $user, $password, $db, $schema, $tablePrefix ) {
136  $this->close( __METHOD__ );
137 
138  // Note that for SQLite, $server, $user, and $pass are ignored
139 
140  if ( $schema !== null ) {
141  throw $this->newExceptionAfterConnectError( "Got schema '$schema'; not supported." );
142  }
143 
144  if ( $this->dbPath !== null ) {
146  } elseif ( $this->dbDir !== null ) {
147  $path = self::generateFileName( $this->dbDir, $db );
148  } else {
149  throw $this->newExceptionAfterConnectError( "DB path or directory required" );
150  }
151 
152  // Check if the database file already exists but is non-readable
153  if ( !self::isProcessMemoryPath( $path ) && is_file( $path ) && !is_readable( $path ) ) {
154  throw $this->newExceptionAfterConnectError( 'SQLite database file is not readable' );
155  } elseif ( !in_array( $this->trxMode, self::$VALID_TRX_MODES, true ) ) {
156  throw $this->newExceptionAfterConnectError( "Got mode '{$this->trxMode}' for BEGIN" );
157  }
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( $db, 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  // Set any connection-level custom PRAGMA options
187  $pragmas = array_intersect_key( $this->connectionVariables, self::$VALID_PRAGMAS );
188  $pragmas += $this->getDefaultPragmas();
189  foreach ( $pragmas as $name => $value ) {
190  $allowed = self::$VALID_PRAGMAS[$name];
191  if ( in_array( $value, $allowed, true ) ) {
192  $this->query( "PRAGMA $name = $value", __METHOD__, $flags );
193  }
194  }
196  } catch ( RuntimeException $e ) {
197  throw $this->newExceptionAfterConnectError( $e->getMessage() );
198  }
199  }
200 
204  private function getDefaultPragmas() {
205  $variables = [];
206 
207  if ( !$this->cliMode ) {
208  $variables['temp_store'] = 'MEMORY';
209  }
210 
211  return $variables;
212  }
213 
219  public function getDbFilePath() {
220  return $this->dbPath ?? self::generateFileName( $this->dbDir, $this->getDBname() );
221  }
222 
226  public function getLockFileDirectory() {
227  if ( $this->dbPath !== null && !self::isProcessMemoryPath( $this->dbPath ) ) {
228  return dirname( $this->dbPath ) . '/locks';
229  } elseif ( $this->dbDir !== null && !self::isProcessMemoryPath( $this->dbDir ) ) {
230  return $this->dbDir . '/locks';
231  }
232 
233  return null;
234  }
235 
240  protected function closeConnection() {
241  $this->conn = null;
242 
243  return true;
244  }
245 
253  public static function generateFileName( $dir, $dbName ) {
254  if ( $dir == '' ) {
255  throw new DBUnexpectedError( null, __CLASS__ . ": no DB directory specified" );
256  } elseif ( self::isProcessMemoryPath( $dir ) ) {
257  throw new DBUnexpectedError(
258  null,
259  __CLASS__ . ": cannot use process memory directory '$dir'"
260  );
261  } elseif ( !strlen( $dbName ) ) {
262  throw new DBUnexpectedError( null, __CLASS__ . ": no DB name specified" );
263  }
264 
265  return "$dir/$dbName.sqlite";
266  }
267 
272  private static function generateDatabaseName( $path ) {
273  if ( preg_match( '/^(:memory:$|file::memory:)/', $path ) ) {
274  // E.g. "file::memory:?cache=shared" => ":memory":
275  return ':memory:';
276  } elseif ( preg_match( '/^file::([^?]+)\?mode=memory(&|$)/', $path, $m ) ) {
277  // E.g. "file:memdb1?mode=memory" => ":memdb1:"
278  return ":{$m[1]}:";
279  } else {
280  // E.g. "/home/.../some_db.sqlite3" => "some_db"
281  return preg_replace( '/\.sqlite\d?$/', '', basename( $path ) );
282  }
283  }
284 
289  private static function isProcessMemoryPath( $path ) {
290  return preg_match( '/^(:memory:$|file:(:memory:|[^?]+\?mode=memory(&|$)))/', $path );
291  }
292 
297  public static function getFulltextSearchModule() {
298  static $cachedResult = null;
299  if ( $cachedResult !== null ) {
300  return $cachedResult;
301  }
302  $cachedResult = false;
303  $table = 'dummy_search_test';
304 
305  $db = self::newStandaloneInstance( ':memory:' );
306  if ( $db->query(
307  "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)",
308  __METHOD__,
309  IDatabase::QUERY_SILENCE_ERRORS
310  ) ) {
311  $cachedResult = 'FTS3';
312  }
313  $db->close( __METHOD__ );
314 
315  return $cachedResult;
316  }
317 
330  public function attachDatabase( $name, $file = false, $fname = __METHOD__ ) {
331  $file = is_string( $file ) ? $file : self::generateFileName( $this->dbDir, $name );
332  $encFile = $this->addQuotes( $file );
333 
334  return $this->query(
335  "ATTACH DATABASE $encFile AS $name",
336  $fname,
337  self::QUERY_IGNORE_DBO_TRX
338  );
339  }
340 
341  protected function isWriteQuery( $sql, $flags ) {
342  return parent::isWriteQuery( $sql, $flags ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql );
343  }
344 
345  protected function isTransactableQuery( $sql ) {
346  return parent::isTransactableQuery( $sql ) && !in_array(
347  $this->getQueryVerb( $sql ),
348  [ 'ATTACH', 'PRAGMA' ],
349  true
350  );
351  }
352 
357  protected function doQuery( $sql ) {
358  $res = $this->getBindingHandle()->query( $sql );
359  if ( $res === false ) {
360  return false;
361  }
362 
363  $this->lastAffectedRowCount = $res->rowCount();
364  return new SqliteResultWrapper( $res );
365  }
366 
367  protected function doSelectDomain( DatabaseDomain $domain ) {
368  if ( $domain->getSchema() !== null ) {
369  throw new DBExpectedError(
370  $this,
371  __CLASS__ . ": domain '{$domain->getId()}' has a schema component"
372  );
373  }
374 
375  $database = $domain->getDatabase();
376  // A null database means "don't care" so leave it as is and update the table prefix
377  if ( $database === null ) {
378  $this->currentDomain = new DatabaseDomain(
379  $this->currentDomain->getDatabase(),
380  null,
381  $domain->getTablePrefix()
382  );
383 
384  return true;
385  }
386 
387  if ( $database !== $this->getDBname() ) {
388  throw new DBExpectedError(
389  $this,
390  __CLASS__ . ": cannot change database (got '$database')"
391  );
392  }
393 
394  return true;
395  }
396 
404  public function tableName( $name, $format = 'quoted' ) {
405  // table names starting with sqlite_ are reserved
406  if ( strpos( $name, 'sqlite_' ) === 0 ) {
407  return $name;
408  }
409 
410  return str_replace( '"', '', parent::tableName( $name, $format ) );
411  }
412 
418  public function insertId() {
419  // PDO::lastInsertId yields a string :(
420  return intval( $this->getBindingHandle()->lastInsertId() );
421  }
422 
426  public function lastError() {
427  if ( !is_object( $this->conn ) ) {
428  return "Cannot return last error, no db connection";
429  }
430  $e = $this->conn->errorInfo();
431 
432  return $e[2] ?? '';
433  }
434 
438  public function lastErrno() {
439  if ( !is_object( $this->conn ) ) {
440  return "Cannot return last error, no db connection";
441  } else {
442  $info = $this->conn->errorInfo();
443 
444  return $info[1];
445  }
446  }
447 
451  protected function fetchAffectedRowCount() {
453  }
454 
455  public function tableExists( $table, $fname = __METHOD__ ) {
456  $tableRaw = $this->tableName( $table, 'raw' );
457  if ( isset( $this->sessionTempTables[$tableRaw] ) ) {
458  return true; // already known to exist
459  }
460 
461  $encTable = $this->addQuotes( $tableRaw );
462  $res = $this->query(
463  "SELECT 1 FROM sqlite_master WHERE type='table' AND name=$encTable",
464  __METHOD__,
465  self::QUERY_IGNORE_DBO_TRX
466  );
467 
468  return $res->numRows() ? true : false;
469  }
470 
481  public function indexInfo( $table, $index, $fname = __METHOD__ ) {
482  $sql = 'PRAGMA index_info(' . $this->addQuotes( $this->indexName( $index ) ) . ')';
483  $res = $this->query( $sql, $fname, self::QUERY_IGNORE_DBO_TRX );
484  if ( !$res || $res->numRows() == 0 ) {
485  return false;
486  }
487  $info = [];
488  foreach ( $res as $row ) {
489  $info[] = $row->name;
490  }
491 
492  return $info;
493  }
494 
501  public function indexUnique( $table, $index, $fname = __METHOD__ ) {
502  $row = $this->selectRow( 'sqlite_master', '*',
503  [
504  'type' => 'index',
505  'name' => $this->indexName( $index ),
506  ], $fname );
507  if ( !$row || !isset( $row->sql ) ) {
508  return null;
509  }
510 
511  // $row->sql will be of the form CREATE [UNIQUE] INDEX ...
512  $indexPos = strpos( $row->sql, 'INDEX' );
513  if ( $indexPos === false ) {
514  return null;
515  }
516  $firstPart = substr( $row->sql, 0, $indexPos );
517  $options = explode( ' ', $firstPart );
518 
519  return in_array( 'UNIQUE', $options );
520  }
521 
522  protected function makeSelectOptions( array $options ) {
523  // Remove problematic options that the base implementation converts to SQL
524  foreach ( $options as $k => $v ) {
525  if ( is_numeric( $k ) && ( $v === 'FOR UPDATE' || $v === 'LOCK IN SHARE MODE' ) ) {
526  $options[$k] = '';
527  }
528  }
529 
530  return parent::makeSelectOptions( $options );
531  }
532 
537  protected function makeUpdateOptionsArray( $options ) {
538  $options = parent::makeUpdateOptionsArray( $options );
539  $options = $this->rewriteIgnoreKeyword( $options );
540 
541  return $options;
542  }
543 
548  private function rewriteIgnoreKeyword( $options ) {
549  # SQLite uses OR IGNORE not just IGNORE
550  foreach ( $options as $k => $v ) {
551  if ( $v == 'IGNORE' ) {
552  $options[$k] = 'OR IGNORE';
553  }
554  }
555 
556  return $options;
557  }
558 
560  return [ 'INSERT OR IGNORE INTO', '' ];
561  }
562 
563  protected function doReplace( $table, array $identityKey, array $rows, $fname ) {
564  $encTable = $this->tableName( $table );
565  list( $sqlColumns, $sqlTuples ) = $this->makeInsertLists( $rows );
566  // https://sqlite.org/lang_insert.html
567  $this->query( "REPLACE INTO $encTable ($sqlColumns) VALUES $sqlTuples", $fname );
568  }
569 
578  public function textFieldSize( $table, $field ) {
579  return -1;
580  }
581 
585  public function unionSupportsOrderAndLimit() {
586  return false;
587  }
588 
594  public function unionQueries( $sqls, $all ) {
595  $glue = $all ? ' UNION ALL ' : ' UNION ';
596 
597  return implode( $glue, $sqls );
598  }
599 
603  public function wasDeadlock() {
604  return $this->lastErrno() == 5; // SQLITE_BUSY
605  }
606 
610  public function wasReadOnlyError() {
611  return $this->lastErrno() == 8; // SQLITE_READONLY;
612  }
613 
614  public function wasConnectionError( $errno ) {
615  return $errno == 17; // SQLITE_SCHEMA;
616  }
617 
618  protected function wasKnownStatementRollbackError() {
619  // ON CONFLICT ROLLBACK clauses make it so that SQLITE_CONSTRAINT error is
620  // ambiguous with regard to whether it implies a ROLLBACK or an ABORT happened.
621  // https://sqlite.org/lang_createtable.html#uniqueconst
622  // https://sqlite.org/lang_conflict.html
623  return false;
624  }
625 
626  public function getTopologyBasedServerId() {
627  // Sqlite topologies trivially consist of single primary server for the dataset
628  return '0';
629  }
630 
631  public function serverIsReadOnly() {
632  $this->assertHasConnectionHandle();
633 
634  $path = $this->getDbFilePath();
635 
636  return ( !self::isProcessMemoryPath( $path ) && !is_writable( $path ) );
637  }
638 
642  public function getSoftwareLink() {
643  return "[{{int:version-db-sqlite-url}} SQLite]";
644  }
645 
649  public function getServerVersion() {
650  if ( $this->version === null ) {
651  $this->version = $this->getBindingHandle()->getAttribute( PDO::ATTR_SERVER_VERSION );
652  }
653 
654  return $this->version;
655  }
656 
665  public function fieldInfo( $table, $field ) {
666  $tableName = $this->tableName( $table );
667  $sql = 'PRAGMA table_info(' . $this->addQuotes( $tableName ) . ')';
668  $res = $this->query( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
669  foreach ( $res as $row ) {
670  if ( $row->name == $field ) {
671  return new SQLiteField( $row, $tableName );
672  }
673  }
674 
675  return false;
676  }
677 
678  protected function doBegin( $fname = '' ) {
679  if ( $this->trxMode != '' ) {
680  $this->query( "BEGIN {$this->trxMode}", $fname );
681  } else {
682  $this->query( 'BEGIN', $fname );
683  }
684  }
685 
690  public function strencode( $s ) {
691  return substr( $this->addQuotes( $s ), 1, -1 );
692  }
693 
698  public function encodeBlob( $b ) {
699  return new Blob( $b );
700  }
701 
706  public function decodeBlob( $b ) {
707  if ( $b instanceof Blob ) {
708  $b = $b->fetch();
709  }
710 
711  return $b;
712  }
713 
718  public function addQuotes( $s ) {
719  if ( $s instanceof Blob ) {
720  return "x'" . bin2hex( $s->fetch() ) . "'";
721  } elseif ( is_bool( $s ) ) {
722  return (string)(int)$s;
723  } elseif ( is_int( $s ) ) {
724  return (string)$s;
725  } elseif ( strpos( (string)$s, "\0" ) !== false ) {
726  // SQLite doesn't support \0 in strings, so use the hex representation as a workaround.
727  // This is a known limitation of SQLite's mprintf function which PDO
728  // should work around, but doesn't. I have reported this to php.net as bug #63419:
729  // https://bugs.php.net/bug.php?id=63419
730  // There was already a similar report for SQLite3::escapeString, bug #62361:
731  // https://bugs.php.net/bug.php?id=62361
732  // There is an additional bug regarding sorting this data after insert
733  // on older versions of sqlite shipped with ubuntu 12.04
734  // https://phabricator.wikimedia.org/T74367
735  $this->queryLogger->debug(
736  __FUNCTION__ .
737  ': Quoting value containing null byte. ' .
738  'For consistency all binary data should have been ' .
739  'first processed with self::encodeBlob()'
740  );
741  return "x'" . bin2hex( (string)$s ) . "'";
742  } else {
743  return $this->getBindingHandle()->quote( (string)$s );
744  }
745  }
746 
747  public function buildSubstring( $input, $startPosition, $length = null ) {
748  $this->assertBuildSubstringParams( $startPosition, $length );
749  $params = [ $input, $startPosition ];
750  if ( $length !== null ) {
751  $params[] = $length;
752  }
753  return 'SUBSTR(' . implode( ',', $params ) . ')';
754  }
755 
761  public function buildStringCast( $field ) {
762  return 'CAST ( ' . $field . ' AS TEXT )';
763  }
764 
771  public function deadlockLoop( ...$args ) {
772  $function = array_shift( $args );
773 
774  return $function( ...$args );
775  }
776 
781  protected function replaceVars( $s ) {
782  $s = parent::replaceVars( $s );
783  if ( preg_match( '/^\s*(CREATE|ALTER) TABLE/i', $s ) ) {
784  // CREATE TABLE hacks to allow schema file sharing with MySQL
785 
786  // binary/varbinary column type -> blob
787  $s = preg_replace( '/\b(var)?binary(\‍(\d+\‍))/i', 'BLOB', $s );
788  // no such thing as unsigned
789  $s = preg_replace( '/\b(un)?signed\b/i', '', $s );
790  // INT -> INTEGER
791  $s = preg_replace( '/\b(tiny|small|medium|big|)int(\s*\‍(\s*\d+\s*\‍)|\b)/i', 'INTEGER', $s );
792  // floating point types -> REAL
793  $s = preg_replace(
794  '/\b(float|double(\s+precision)?)(\s*\‍(\s*\d+\s*(,\s*\d+\s*)?\‍)|\b)/i',
795  'REAL',
796  $s
797  );
798  // varchar -> TEXT
799  $s = preg_replace( '/\b(var)?char\s*\‍(.*?\‍)/i', 'TEXT', $s );
800  // TEXT normalization
801  $s = preg_replace( '/\b(tiny|medium|long)text\b/i', 'TEXT', $s );
802  // BLOB normalization
803  $s = preg_replace( '/\b(tiny|small|medium|long|)blob\b/i', 'BLOB', $s );
804  // BOOL -> INTEGER
805  $s = preg_replace( '/\bbool(ean)?\b/i', 'INTEGER', $s );
806  // DATETIME -> TEXT
807  $s = preg_replace( '/\b(datetime|timestamp)\b/i', 'TEXT', $s );
808  // No ENUM type
809  $s = preg_replace( '/\benum\s*\‍([^)]*\‍)/i', 'TEXT', $s );
810  // binary collation type -> nothing
811  $s = preg_replace( '/\bbinary\b/i', '', $s );
812  // auto_increment -> autoincrement
813  $s = preg_replace( '/\bauto_increment\b/i', 'AUTOINCREMENT', $s );
814  // No explicit options
815  $s = preg_replace( '/\‍)[^);]*(;?)\s*$/', ')\1', $s );
816  // AUTOINCREMENT should immedidately follow PRIMARY KEY
817  $s = preg_replace( '/primary key (.*?) autoincrement/i', 'PRIMARY KEY AUTOINCREMENT $1', $s );
818  } elseif ( preg_match( '/^\s*CREATE (\s*(?:UNIQUE|FULLTEXT)\s+)?INDEX/i', $s ) ) {
819  // No truncated indexes
820  $s = preg_replace( '/\‍(\d+\‍)/', '', $s );
821  // No FULLTEXT
822  $s = preg_replace( '/\bfulltext\b/i', '', $s );
823  } elseif ( preg_match( '/^\s*DROP INDEX/i', $s ) ) {
824  // DROP INDEX is database-wide, not table-specific, so no ON <table> clause.
825  $s = preg_replace( '/\sON\s+[^\s]*/i', '', $s );
826  } elseif ( preg_match( '/^\s*INSERT IGNORE\b/i', $s ) ) {
827  // INSERT IGNORE --> INSERT OR IGNORE
828  $s = preg_replace( '/^\s*INSERT IGNORE\b/i', 'INSERT OR IGNORE', $s );
829  }
830 
831  return $s;
832  }
833 
834  public function doLockIsFree( string $lockName, string $method ) {
835  // Only locks by this thread will be checked
836  return true;
837  }
838 
839  public function doLock( string $lockName, string $method, int $timeout ) {
840  $status = $this->lockMgr->lock( [ $lockName ], LockManager::LOCK_EX, $timeout );
841  if (
842  $this->lockMgr instanceof FSLockManager &&
843  $status->hasMessage( 'lockmanager-fail-openlock' )
844  ) {
845  throw new DBError( $this, "Cannot create directory \"{$this->getLockFileDirectory()}\"" );
846  }
847 
848  return $status->isOK() ? microtime( true ) : null;
849  }
850 
851  public function doUnlock( string $lockName, string $method ) {
852  return $this->lockMgr->unlock( [ $lockName ], LockManager::LOCK_EX )->isGood();
853  }
854 
861  public function buildConcat( $stringList ) {
862  return '(' . implode( ') || (', $stringList ) . ')';
863  }
864 
865  public function buildGroupConcatField(
866  $delim, $table, $field, $conds = '', $join_conds = []
867  ) {
868  $fld = "group_concat($field," . $this->addQuotes( $delim ) . ')';
869 
870  return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')';
871  }
872 
873  public function buildGreatest( $fields, $values ) {
874  return $this->buildSuperlative( 'MAX', $fields, $values );
875  }
876 
877  public function buildLeast( $fields, $values ) {
878  return $this->buildSuperlative( 'MIN', $fields, $values );
879  }
880 
889  public function duplicateTableStructure(
890  $oldName, $newName, $temporary = false, $fname = __METHOD__
891  ) {
892  $queryFlags = self::QUERY_PSEUDO_PERMANENT | self::QUERY_IGNORE_DBO_TRX;
893 
894  $res = $this->query(
895  "SELECT sql FROM sqlite_master WHERE tbl_name=" .
896  $this->addQuotes( $oldName ) . " AND type='table'",
897  $fname,
898  $queryFlags
899  );
900  $obj = $this->fetchObject( $res );
901  if ( !$obj ) {
902  throw new RuntimeException( "Couldn't retrieve structure for table $oldName" );
903  }
904  $sql = $obj->sql;
905  $sql = preg_replace(
906  '/(?<=\W)"?' .
907  preg_quote( trim( $this->addIdentifierQuotes( $oldName ), '"' ), '/' ) .
908  '"?(?=\W)/',
909  $this->addIdentifierQuotes( $newName ),
910  $sql,
911  1
912  );
913  if ( $temporary ) {
914  if ( preg_match( '/^\\s*CREATE\\s+VIRTUAL\\s+TABLE\b/i', $sql ) ) {
915  $this->queryLogger->debug(
916  "Table $oldName is virtual, can't create a temporary duplicate." );
917  } else {
918  $sql = str_replace( 'CREATE TABLE', 'CREATE TEMPORARY TABLE', $sql );
919  }
920  }
921 
922  // @phan-suppress-next-line SecurityCheck-SQLInjection SQL is taken from database
923  $res = $this->query( $sql, $fname, $queryFlags );
924 
925  // Take over indexes
926  $indexList = $this->query(
927  'PRAGMA INDEX_LIST(' . $this->addQuotes( $oldName ) . ')',
928  $fname,
929  $queryFlags
930  );
931  foreach ( $indexList as $index ) {
932  if ( strpos( $index->name, 'sqlite_autoindex' ) === 0 ) {
933  continue;
934  }
935 
936  if ( $index->unique ) {
937  $sqlIndex = 'CREATE UNIQUE INDEX';
938  } else {
939  $sqlIndex = 'CREATE INDEX';
940  }
941  // Try to come up with a new index name, given indexes have database scope in SQLite
942  $indexName = $newName . '_' . $index->name;
943  $sqlIndex .= ' ' . $this->addIdentifierQuotes( $indexName ) .
944  ' ON ' . $this->addIdentifierQuotes( $newName );
945 
946  $indexInfo = $this->query(
947  'PRAGMA INDEX_INFO(' . $this->addQuotes( $index->name ) . ')',
948  $fname,
949  $queryFlags
950  );
951  $fields = [];
952  foreach ( $indexInfo as $indexInfoRow ) {
953  $fields[$indexInfoRow->seqno] = $this->addQuotes( $indexInfoRow->name );
954  }
955 
956  $sqlIndex .= '(' . implode( ',', $fields ) . ')';
957 
958  $this->query( $sqlIndex, __METHOD__ );
959  }
960 
961  return $res;
962  }
963 
972  public function listTables( $prefix = null, $fname = __METHOD__ ) {
973  $result = $this->query(
974  "SELECT name FROM sqlite_master WHERE type = 'table'",
975  $fname,
976  self::QUERY_IGNORE_DBO_TRX
977  );
978 
979  $endArray = [];
980 
981  foreach ( $result as $table ) {
982  $vars = get_object_vars( $table );
983  $table = array_pop( $vars );
984 
985  if ( !$prefix || strpos( $table, $prefix ) === 0 ) {
986  if ( strpos( $table, 'sqlite_' ) !== 0 ) {
987  $endArray[] = $table;
988  }
989  }
990  }
991 
992  return $endArray;
993  }
994 
995  public function dropTable( $table, $fname = __METHOD__ ) {
996  if ( !$this->tableExists( $table, $fname ) ) {
997  return false;
998  }
999 
1000  // No CASCADE support; https://www.sqlite.org/lang_droptable.html
1001  $sql = "DROP TABLE " . $this->tableName( $table );
1002  $this->query( $sql, $fname, self::QUERY_IGNORE_DBO_TRX );
1003 
1004  return true;
1005  }
1006 
1007  protected function doTruncate( array $tables, $fname ) {
1008  $this->startAtomic( $fname );
1009 
1010  $encSeqNames = [];
1011  foreach ( $tables as $table ) {
1012  // Use "truncate" optimization; https://www.sqlite.org/lang_delete.html
1013  $sql = "DELETE FROM " . $this->tableName( $table );
1014  $this->query( $sql, $fname, self::QUERY_CHANGE_SCHEMA );
1015 
1016  $encSeqNames[] = $this->addQuotes( $this->tableName( $table, 'raw' ) );
1017  }
1018 
1019  $encMasterTable = $this->addIdentifierQuotes( 'sqlite_sequence' );
1020  $this->query(
1021  "DELETE FROM $encMasterTable WHERE name IN(" . implode( ',', $encSeqNames ) . ")",
1022  $fname,
1023  self::QUERY_CHANGE_SCHEMA
1024  );
1025 
1026  $this->endAtomic( $fname );
1027  }
1028 
1029  public function setTableAliases( array $aliases ) {
1030  parent::setTableAliases( $aliases );
1031  if ( $this->isOpen() ) {
1033  }
1034  }
1035 
1039  private function attachDatabasesFromTableAliases() {
1040  foreach ( $this->tableAliases as $params ) {
1041  if (
1042  $params['dbname'] !== $this->getDBname() &&
1043  !isset( $this->sessionAttachedDbs[$params['dbname']] )
1044  ) {
1045  $this->attachDatabase( $params['dbname'], false, __METHOD__ );
1046  $this->sessionAttachedDbs[$params['dbname']] = true;
1047  }
1048  }
1049  }
1050 
1051  public function databasesAreIndependent() {
1052  return true;
1053  }
1054 
1055  protected function doHandleSessionLossPreconnect() {
1056  $this->sessionAttachedDbs = [];
1057  }
1058 
1062  protected function getBindingHandle() {
1063  return parent::getBindingHandle();
1064  }
1065 }
1066 
1070 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:42
Wikimedia\Rdbms\DatabaseSqlite\fieldInfo
fieldInfo( $table, $field)
Get information about a given field Returns false if the field does not exist.
Definition: DatabaseSqlite.php:665
Wikimedia\Rdbms\DatabaseSqlite\$lockMgr
FSLockManager $lockMgr
(hopefully on the same server as the DB)
Definition: DatabaseSqlite.php:51
LockManager
Class for handling resource locking.
Definition: LockManager.php:48
Wikimedia\Rdbms\DatabaseSqlite\getBindingHandle
getBindingHandle()
Definition: DatabaseSqlite.php:1062
Wikimedia\Rdbms\DatabaseSqlite\addQuotes
addQuotes( $s)
Definition: DatabaseSqlite.php:718
Wikimedia\Rdbms\DatabaseSqlite\$VALID_PRAGMAS
static string[][] $VALID_PRAGMAS
Definition: DatabaseSqlite.php:63
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:1055
Wikimedia\Rdbms\DatabaseSqlite
Definition: DatabaseSqlite.php:36
Wikimedia\Rdbms\DatabaseSqlite\wasKnownStatementRollbackError
wasKnownStatementRollbackError()
Definition: DatabaseSqlite.php:618
Wikimedia\Rdbms\DatabaseSqlite\listTables
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
Definition: DatabaseSqlite.php:972
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:771
Wikimedia\Rdbms\Database\getDomainID
getDomainID()
Return the currently selected domain ID.
Definition: Database.php:868
Wikimedia\Rdbms\DatabaseSqlite\makeInsertNonConflictingVerbAndOptions
makeInsertNonConflictingVerbAndOptions()
Definition: DatabaseSqlite.php:559
Wikimedia\Rdbms\Database\assertHasConnectionHandle
assertHasConnectionHandle()
Make sure there is an open connection handle (alive or not) as a sanity check.
Definition: Database.php:1069
Wikimedia\Rdbms\DatabaseSqlite\attachDatabasesFromTableAliases
attachDatabasesFromTableAliases()
Issue ATTATCH statements for all unattached foreign DBs in table aliases.
Definition: DatabaseSqlite.php:1039
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:585
Wikimedia\Rdbms\DatabaseSqlite\doReplace
doReplace( $table, array $identityKey, array $rows, $fname)
Definition: DatabaseSqlite.php:563
Wikimedia\Rdbms\DatabaseSqlite\$version
string null $version
Definition: DatabaseSqlite.php:54
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:1051
Wikimedia\Rdbms\DatabaseSqlite\isProcessMemoryPath
static isProcessMemoryPath( $path)
Definition: DatabaseSqlite.php:289
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:877
Wikimedia\Rdbms\DatabaseSqlite\getLockFileDirectory
getLockFileDirectory()
Definition: DatabaseSqlite.php:226
Wikimedia\Rdbms\Database\endAtomic
endAtomic( $fname=__METHOD__)
Ends an atomic section of SQL statements.
Definition: Database.php:4621
Wikimedia\Rdbms\Database\indexName
indexName( $index)
Allows for index remapping in queries where this is not consistent across DBMS.
Definition: Database.php:3321
Wikimedia\Rdbms\DatabaseSqlite\getTopologyBasedServerId
getTopologyBasedServerId()
Get a non-recycled ID that uniquely identifies this server within the replication topology.
Definition: DatabaseSqlite.php:626
Wikimedia\Rdbms\SqliteResultWrapper
Definition: SqliteResultWrapper.php:9
Wikimedia\Rdbms\DatabaseDomain\getTablePrefix
getTablePrefix()
Definition: DatabaseDomain.php:193
Wikimedia\Rdbms\DatabaseSqlite\fetchAffectedRowCount
fetchAffectedRowCount()
Definition: DatabaseSqlite.php:451
Wikimedia\Rdbms\DatabaseSqlite\doTruncate
doTruncate(array $tables, $fname)
Definition: DatabaseSqlite.php:1007
Wikimedia\Rdbms\DatabaseSqlite\encodeBlob
encodeBlob( $b)
Definition: DatabaseSqlite.php:698
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:1029
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:426
Wikimedia\Rdbms\DatabaseSqlite\getServerVersion
getServerVersion()
Definition: DatabaseSqlite.php:649
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:135
Wikimedia\Rdbms\DatabaseSqlite\doUnlock
doUnlock(string $lockName, string $method)
Definition: DatabaseSqlite.php:851
Wikimedia\Rdbms\DatabaseSqlite\strencode
strencode( $s)
Definition: DatabaseSqlite.php:690
Wikimedia\Rdbms\DatabaseDomain\getDatabase
getDatabase()
Definition: DatabaseDomain.php:179
Wikimedia\Rdbms\DatabaseSqlite\buildSubstring
buildSubstring( $input, $startPosition, $length=null)
Stability: stableto override
Definition: DatabaseSqlite.php:747
Wikimedia\Rdbms\DatabaseSqlite\closeConnection
closeConnection()
Does not actually close the connection, just destroys the reference for GC to do its work.
Definition: DatabaseSqlite.php:240
Wikimedia\Rdbms\DatabaseSqlite\isWriteQuery
isWriteQuery( $sql, $flags)
Determine whether a query writes to the DB.
Definition: DatabaseSqlite.php:341
$res
$res
Definition: testCompression.php:57
Wikimedia\Rdbms\DatabaseSqlite\dropTable
dropTable( $table, $fname=__METHOD__)
Delete a table.
Definition: DatabaseSqlite.php:995
Wikimedia\Rdbms\Database\getFlag
getFlag( $flag)
Returns a boolean whether the flag $flag is set for this connection.
Definition: Database.php:864
Wikimedia\Rdbms\DBError
Database error base class @newable.
Definition: DBError.php:32
Wikimedia\Rdbms\DatabaseSqlite\buildStringCast
buildStringCast( $field)
Definition: DatabaseSqlite.php:761
DBO_TRX
const DBO_TRX
Definition: defines.php:12
Wikimedia\Rdbms\DatabaseSqlite\unionQueries
unionQueries( $sqls, $all)
Definition: DatabaseSqlite.php:594
Wikimedia\Rdbms\DatabaseSqlite\doLock
doLock(string $lockName, string $method, int $timeout)
Definition: DatabaseSqlite.php:839
Wikimedia\Rdbms\Database\fetchObject
fetchObject(IResultWrapper $res)
Fetch the next row from the given result object, in object form.
Definition: Database.php:872
Wikimedia\Rdbms\Database\close
close( $fname=__METHOD__, $owner=null)
Close the database connection.
Definition: Database.php:990
Wikimedia\Rdbms\DatabaseSqlite\$lastAffectedRowCount
int $lastAffectedRowCount
The number of rows affected as an integer.
Definition: DatabaseSqlite.php:45
Wikimedia\Rdbms\Database\assertBuildSubstringParams
assertBuildSubstringParams( $startPosition, $length)
Check type and bounds for parameters to self::buildSubstring()
Definition: Database.php:2891
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:873
Wikimedia\Rdbms\Database\startAtomic
startAtomic( $fname=__METHOD__, $cancelable=self::ATOMIC_NOT_CANCELABLE)
Begin an atomic section of SQL statements.
Definition: Database.php:4559
Wikimedia\Rdbms\DatabaseSqlite\wasDeadlock
wasDeadlock()
Definition: DatabaseSqlite.php:603
Wikimedia\Rdbms\DatabaseSqlite\generateFileName
static generateFileName( $dir, $dbName)
Generates a database file name.
Definition: DatabaseSqlite.php:253
Wikimedia\Rdbms\DatabaseSqlite\doBegin
doBegin( $fname='')
Issues the BEGIN command to the database server.
Definition: DatabaseSqlite.php:678
Wikimedia\Rdbms\DatabaseSqlite\$conn
PDO $conn
Definition: DatabaseSqlite.php:48
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:2019
Wikimedia\Rdbms\Database\makeInsertLists
makeInsertLists(array $rows)
Make SQL lists of columns, row tuples for INSERT/VALUES expressions.
Definition: Database.php:2580
$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:455
Wikimedia\Rdbms\DatabaseSqlite\$VALID_TRX_MODES
static string[] $VALID_TRX_MODES
See https://www.sqlite.org/lang_transaction.html.
Definition: DatabaseSqlite.php:60
Wikimedia\Rdbms\DatabaseSqlite\getDbFilePath
getDbFilePath()
Definition: DatabaseSqlite.php:219
Wikimedia\Rdbms\DatabaseSqlite\replaceVars
replaceVars( $s)
Definition: DatabaseSqlite.php:781
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:2106
Wikimedia\Rdbms\Database\buildSuperlative
buildSuperlative( $sqlfunc, $fields, $values)
Build a superlative function statement comparing columns/values.
Definition: Database.php:2839
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
Wikimedia\Rdbms\Database\getLogContext
getLogContext(array $extras=[])
Create a log context to pass to PSR-3 logger functions.
Definition: Database.php:979
Wikimedia\Rdbms\DatabaseSqlite\doQuery
doQuery( $sql)
Definition: DatabaseSqlite.php:357
Wikimedia\Rdbms\DatabaseSqlite\$dbDir
string null $dbDir
Directory for SQLite database files listed under their DB name.
Definition: DatabaseSqlite.php:38
Wikimedia\Rdbms\DatabaseSqlite\getAttributes
static getAttributes()
Definition: DatabaseSqlite.php:102
Wikimedia\Rdbms\Database\query
query( $sql, $fname=__METHOD__, $flags=self::QUERY_NORMAL)
Run an SQL query and return the result.
Definition: Database.php:1316
Wikimedia\Rdbms\DatabaseSqlite\getType
getType()
Definition: DatabaseSqlite.php:131
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:865
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:330
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:345
Wikimedia\Rdbms\DatabaseSqlite\generateDatabaseName
static generateDatabaseName( $path)
Definition: DatabaseSqlite.php:272
Wikimedia\Rdbms\DatabaseSqlite\newStandaloneInstance
static newStandaloneInstance( $filename, array $p=[])
Definition: DatabaseSqlite.php:118
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:3348
Wikimedia\Rdbms\DatabaseSqlite\getFulltextSearchModule
static getFulltextSearchModule()
Returns version of currently supported SQLite fulltext search module or false if none present.
Definition: DatabaseSqlite.php:297
Wikimedia\Rdbms\Database\getQueryVerb
getQueryVerb( $sql)
Definition: Database.php:1186
Wikimedia\Rdbms\DatabaseSqlite\$dbPath
string null $dbPath
Explicit path for the SQLite database file.
Definition: DatabaseSqlite.php:40
Wikimedia\Rdbms\DatabaseSqlite\makeUpdateOptionsArray
makeUpdateOptionsArray( $options)
Definition: DatabaseSqlite.php:537
Wikimedia\Rdbms\DatabaseSqlite\getSoftwareLink
getSoftwareLink()
Definition: DatabaseSqlite.php:642
Wikimedia\Rdbms\Database\newExceptionAfterConnectError
newExceptionAfterConnectError( $error)
Definition: Database.php:1817
Wikimedia\Rdbms\DatabaseSqlite\insertId
insertId()
This must be called after nextSequenceVal.
Definition: DatabaseSqlite.php:418
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:57
Wikimedia\Rdbms\DatabaseSqlite\lastErrno
lastErrno()
Definition: DatabaseSqlite.php:438
$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:501
Wikimedia\Rdbms\DatabaseSqlite\wasReadOnlyError
wasReadOnlyError()
Definition: DatabaseSqlite.php:610
Wikimedia\Rdbms\Database\isOpen
isOpen()
Definition: Database.php:817
Wikimedia\Rdbms\DatabaseSqlite\doSelectDomain
doSelectDomain(DatabaseDomain $domain)
Definition: DatabaseSqlite.php:367
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:77
Wikimedia\Rdbms\DatabaseSqlite\buildConcat
buildConcat( $stringList)
Build a concatenation list to feed into a SQL query.
Definition: DatabaseSqlite.php:861
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:614
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:706
DBO_DEFAULT
const DBO_DEFAULT
Definition: defines.php:13
Wikimedia\Rdbms\DatabaseSqlite\getDefaultPragmas
getDefaultPragmas()
Definition: DatabaseSqlite.php:204
Wikimedia\Rdbms\DatabaseSqlite\serverIsReadOnly
serverIsReadOnly()
bool Whether the DB is marked as read-only server-side If an error occurs, {query} 1....
Definition: DatabaseSqlite.php:631
Wikimedia\Rdbms\DatabaseSqlite\duplicateTableStructure
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Definition: DatabaseSqlite.php:889
Wikimedia\Rdbms\DatabaseSqlite\tableName
tableName( $name, $format='quoted')
Use MySQL's naming (accounts for prefix etc) but remove surrounding backticks.
Definition: DatabaseSqlite.php:404
Wikimedia\Rdbms\DatabaseSqlite\rewriteIgnoreKeyword
rewriteIgnoreKeyword( $options)
Definition: DatabaseSqlite.php:548
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:481
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:578
Wikimedia\Rdbms\Database\getDBname
getDBname()
Get the current database name; null if there isn't one.
Definition: Database.php:3001
Wikimedia\Rdbms\DatabaseSqlite\doLockIsFree
doLockIsFree(string $lockName, string $method)
Definition: DatabaseSqlite.php:834
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:522