23 use InvalidArgumentException;
24 use Psr\Log\NullLogger;
26 use Wikimedia\RequestTimeout\CriticalSectionProvider;
38 private $deprecationLogger;
52 $this->agent = $params[
'agent'] ??
'';
53 $this->deprecationLogger = $params[
'deprecationLogger'] ??
static function ( $msg ) {
54 trigger_error( $msg, E_USER_DEPRECATED );
56 $this->csProvider = $params[
'criticalSectionProvider'] ??
null;
57 $this->profiler = $params[
'profiler'] ??
null;
58 $this->cliMode = $params[
'cliMode'] ?? ( PHP_SAPI ===
'cli' || PHP_SAPI ===
'phpdbg' );
59 $this->debugSql = $params[
'debugSql'] ??
false;
113 public function create( $type, $params = [], $connect = Database::NEW_CONNECTED ) {
114 $class = $this->
getClass( $type, $params[
'driver'] ??
null );
116 if ( class_exists( $class ) && is_subclass_of( $class, IDatabase::class ) ) {
127 'serverName' =>
null,
128 'topologyRole' =>
null,
132 'logger' => $params[
'logger'] ??
new NullLogger(),
133 'errorLogger' => $params[
'errorLogger'] ??
static function ( Throwable $e ) {
134 trigger_error( get_class( $e ) .
': ' . $e->getMessage(), E_USER_WARNING );
138 $params[
'flags'] ??= 0;
139 if ( $this->debugSql ) {
145 'flags' => $this->initConnFlags( $params[
'flags'] ),
146 'cliMode' => $this->cliMode,
147 'agent' => $this->agent,
148 'profiler' => $this->profiler,
149 'deprecationLogger' => $this->deprecationLogger,
150 'criticalSectionProvider' => $this->csProvider,
154 $conn =
new $class( array_merge( $params, $overrides ) );
155 if ( $connect === Database::NEW_CONNECTED ) {
156 $conn->initConnection();
173 Database::ATTR_DB_IS_FILE =>
false,
174 Database::ATTR_DB_LEVEL_LOCKING =>
false,
175 Database::ATTR_SCHEMAS_AS_TABLE_GROUPS => false
178 $class = $this->
getClass( $dbType, $driver );
179 if ( class_exists( $class ) ) {
180 return call_user_func( [ $class,
'getAttributes' ] ) + $defaults;
182 throw new DBUnexpectedError(
null,
"$dbType is not a supported database type." );
192 protected function getClass( $dbType, $driver =
null ) {
199 static $builtinTypes = [
200 'mysql' => [
'mysqli' => DatabaseMySQL::class ],
201 'sqlite' => DatabaseSqlite::class,
202 'postgres' => DatabasePostgres::class,
205 $dbType = strtolower( $dbType );
207 if ( !isset( $builtinTypes[$dbType] ) ) {
209 return 'Database' . ucfirst( $dbType );
213 $possibleDrivers = $builtinTypes[$dbType];
214 if ( is_string( $possibleDrivers ) ) {
215 $class = $possibleDrivers;
216 } elseif ( (
string)$driver !==
'' ) {
217 if ( !isset( $possibleDrivers[$driver] ) ) {
218 throw new InvalidArgumentException( __METHOD__ .
219 " type '$dbType' does not support driver '{$driver}'" );
222 $class = $possibleDrivers[$driver];
224 foreach ( $possibleDrivers as $posDriver => $possibleClass ) {
225 if ( extension_loaded( $posDriver ) ) {
226 $class = $possibleClass;
232 if ( $class ===
false ) {
233 throw new InvalidArgumentException( __METHOD__ .
234 " no viable database extension found for type '$dbType'" );
245 private function initConnFlags( $flags ) {
247 if ( $this->cliMode ) {
261 private function fieldHasBit(
int $flags,
int $bit ) {
262 return ( ( $flags & $bit ) === $bit );
Simple store for keeping values in an associative array for the current process.