rdbms: Map PostgreSQL boolean values to MySQL-compatible forms
Also fix callers that were checking for t/f. In CASE and COALESCE expressions, using 't' and 'f' did actually work, because those literals have an unknown type and the other argument is boolean, so PG coerces them to boolean. But it seems safer and clearer to use the strongly typed literals TRUE and FALSE. Bug: T352229 Change-Id: Ia01b76d3d6d2e048feac8e3118d9faff63a9ac56
This commit is contained in:
parent
b23e47c20a
commit
c5d182eb01
6 changed files with 76 additions and 13 deletions
|
|
@ -318,12 +318,12 @@ class PostgresInstaller extends DatabaseInstaller {
|
|||
|
||||
protected function canCreateAccounts() {
|
||||
$perms = $this->getInstallUserPermissions();
|
||||
return $perms && ( $perms->rolsuper === 't' || $perms->rolcreaterole === 't' );
|
||||
return $perms && $perms->rolsuper || $perms->rolcreaterole;
|
||||
}
|
||||
|
||||
protected function isSuperUser() {
|
||||
$perms = $this->getInstallUserPermissions();
|
||||
return $perms && $perms->rolsuper === 't';
|
||||
return $perms && $perms->rolsuper;
|
||||
}
|
||||
|
||||
public function getSettingsForm() {
|
||||
|
|
|
|||
|
|
@ -1054,7 +1054,7 @@ __INDEXATTR__;
|
|||
$res = $this->query( $query, $method );
|
||||
$row = $res->fetchObject();
|
||||
|
||||
return ( $row->unlocked === 't' );
|
||||
return (bool)$row->unlocked;
|
||||
}
|
||||
|
||||
public function doLock( string $lockName, string $method, int $timeout ) {
|
||||
|
|
@ -1094,7 +1094,7 @@ __INDEXATTR__;
|
|||
$result = $this->query( $query, $method );
|
||||
$row = $result->fetchObject();
|
||||
|
||||
return ( $row->released === 't' );
|
||||
return (bool)$row->released;
|
||||
}
|
||||
|
||||
protected function doFlushSession( $fname ) {
|
||||
|
|
|
|||
|
|
@ -27,13 +27,55 @@ class PostgresResultWrapper extends ResultWrapper {
|
|||
}
|
||||
|
||||
protected function doFetchObject() {
|
||||
// pg_fetch_object may raise a warning after a seek to an invalid offset
|
||||
// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
|
||||
return @pg_fetch_object( $this->result );
|
||||
$row = @pg_fetch_object( $this->result );
|
||||
// Map boolean values (T352229)
|
||||
if ( is_object( $row ) ) {
|
||||
$numFields = pg_num_fields( $this->result );
|
||||
for ( $i = 0; $i < $numFields; $i++ ) {
|
||||
if ( pg_field_type( $this->result, $i ) === 'bool' ) {
|
||||
$name = pg_field_name( $this->result, $i );
|
||||
$row->$name = $this->convertBoolean( $row->$name );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
protected function doFetchRow() {
|
||||
// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
|
||||
return @pg_fetch_array( $this->result );
|
||||
$row = @pg_fetch_array( $this->result );
|
||||
// Map boolean values (T352229)
|
||||
if ( is_array( $row ) ) {
|
||||
$numFields = pg_num_fields( $this->result );
|
||||
for ( $i = 0; $i < $numFields; $i++ ) {
|
||||
if ( pg_field_type( $this->result, $i ) === 'bool' ) {
|
||||
$name = pg_field_name( $this->result, $i );
|
||||
$row[$i] = $this->convertBoolean( $row[$i] );
|
||||
$row[$name] = $this->convertBoolean( $row[$name] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a boolean value from the database to the string '0' or '1' for
|
||||
* compatibility with MySQL.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
private function convertBoolean( $value ) {
|
||||
if ( $value === 't' ) {
|
||||
return '1';
|
||||
} elseif ( $value === 'f' ) {
|
||||
return '0';
|
||||
} else {
|
||||
// Just pass through values that are not 't' or 'f'
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
protected function doSeek( $pos ) {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ SELECT
|
|||
attnotnull, attlen, conname AS conname,
|
||||
atthasdef,
|
||||
pg_get_expr(adbin, adrelid) AS adsrc,
|
||||
COALESCE(condeferred, 'f') AS deferred,
|
||||
COALESCE(condeferrable, 'f') AS deferrable,
|
||||
COALESCE(condeferred, FALSE) AS deferred,
|
||||
COALESCE(condeferrable, FALSE) AS deferrable,
|
||||
CASE WHEN typname = 'int2' THEN 'smallint'
|
||||
WHEN typname = 'int4' THEN 'integer'
|
||||
WHEN typname = 'int8' THEN 'bigint'
|
||||
|
|
@ -52,14 +52,14 @@ SQL;
|
|||
}
|
||||
$n = new PostgresField;
|
||||
$n->type = $row->typname;
|
||||
$n->nullable = ( $row->attnotnull == 'f' );
|
||||
$n->nullable = !$row->attnotnull;
|
||||
$n->name = $field;
|
||||
$n->tablename = $table;
|
||||
$n->max_length = $row->attlen;
|
||||
$n->deferrable = ( $row->deferrable == 't' );
|
||||
$n->deferred = ( $row->deferred == 't' );
|
||||
$n->deferrable = (bool)$row->deferrable;
|
||||
$n->deferred = (bool)$row->deferred;
|
||||
$n->conname = $row->conname;
|
||||
$n->has_default = ( $row->atthasdef === 't' );
|
||||
$n->has_default = (bool)$row->atthasdef;
|
||||
$n->default = $row->adsrc;
|
||||
|
||||
return $n;
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ class PostgresPlatform extends SQLPlatform {
|
|||
// http://www.postgresql.org/docs/9.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
|
||||
$key = $this->quoter->addQuotes( $this->bigintFromLockName( $lockName ) );
|
||||
return "SELECT (CASE(pg_try_advisory_lock($key))
|
||||
WHEN 'f' THEN 'f' ELSE pg_advisory_unlock($key) END) AS unlocked";
|
||||
WHEN FALSE THEN FALSE ELSE pg_advisory_unlock($key) END) AS unlocked";
|
||||
}
|
||||
|
||||
public function unlockSQLText( $lockName ) {
|
||||
|
|
|
|||
|
|
@ -101,4 +101,25 @@ class DatabaseIntegrationTest extends MediaWikiIntegrationTestCase {
|
|||
"The generated schema in '$type' type has to be the same"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* T352229
|
||||
*/
|
||||
public function testBooleanValues() {
|
||||
$res = $this->db->newSelectQueryBuilder()
|
||||
->select( [ 'false' => '1=0', 'true' => '1=1' ] )
|
||||
->fetchResultSet();
|
||||
$obj = $res->fetchObject();
|
||||
$this->assertCount( 2, (array)$obj );
|
||||
$this->assertSame( '0', $obj->false );
|
||||
$this->assertSame( '1', $obj->true );
|
||||
|
||||
$res->seek( 0 );
|
||||
$row = $res->fetchRow();
|
||||
$this->assertCount( 4, $row );
|
||||
$this->assertSame( '0', $row[0] );
|
||||
$this->assertSame( '1', $row[1] );
|
||||
$this->assertSame( '0', $row['false'] );
|
||||
$this->assertSame( '1', $row['true'] );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue