PostgreSQL v12 will remove the long-deprecated column pg_attrdef.adsrc. The supported way to introspect into column default values is pg_get_expr(adbin, adrelid), which works back through all versions of PostgreSQL supported by wikimedia. Changing to the supported method will allow the upcoming v12 of the database to be used while maintaining compatibility with older versions, without needing to write version-specific code. This patch has been tested with maintenance/update.php and with phpunit in PostgreSQL versions 9.2, 11, and 12dev. It does not harm the first two, and fixes errors that would otherwise arise in the dev version. All unit tests which pass under version 11 now pass under 12dev as well. Change-Id: I874d347fd286b26773113d4f0c6c30d9a4055ad3
114 lines
2.4 KiB
PHP
114 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace Wikimedia\Rdbms;
|
|
|
|
class PostgresField implements Field {
|
|
private $name, $tablename, $type, $nullable, $max_length, $deferred, $deferrable, $conname,
|
|
$has_default, $default;
|
|
|
|
/**
|
|
* @param DatabasePostgres $db
|
|
* @param string $table
|
|
* @param string $field
|
|
* @return null|PostgresField
|
|
*/
|
|
static function fromText( DatabasePostgres $db, $table, $field ) {
|
|
$q = <<<SQL
|
|
SELECT
|
|
attnotnull, attlen, conname AS conname,
|
|
atthasdef,
|
|
pg_get_expr(adbin, adrelid) AS adsrc,
|
|
COALESCE(condeferred, 'f') AS deferred,
|
|
COALESCE(condeferrable, 'f') AS deferrable,
|
|
CASE WHEN typname = 'int2' THEN 'smallint'
|
|
WHEN typname = 'int4' THEN 'integer'
|
|
WHEN typname = 'int8' THEN 'bigint'
|
|
WHEN typname = 'bpchar' THEN 'char'
|
|
ELSE typname END AS typname
|
|
FROM pg_class c
|
|
JOIN pg_namespace n ON (n.oid = c.relnamespace)
|
|
JOIN pg_attribute a ON (a.attrelid = c.oid)
|
|
JOIN pg_type t ON (t.oid = a.atttypid)
|
|
LEFT JOIN pg_constraint o ON (o.conrelid = c.oid AND a.attnum = ANY(o.conkey) AND o.contype = 'f')
|
|
LEFT JOIN pg_attrdef d on c.oid=d.adrelid and a.attnum=d.adnum
|
|
WHERE relkind = 'r'
|
|
AND nspname=%s
|
|
AND relname=%s
|
|
AND attname=%s;
|
|
SQL;
|
|
|
|
$table = $db->remappedTableName( $table );
|
|
foreach ( $db->getCoreSchemas() as $schema ) {
|
|
$res = $db->query(
|
|
sprintf( $q,
|
|
$db->addQuotes( $schema ),
|
|
$db->addQuotes( $table ),
|
|
$db->addQuotes( $field )
|
|
)
|
|
);
|
|
$row = $db->fetchObject( $res );
|
|
if ( !$row ) {
|
|
continue;
|
|
}
|
|
$n = new PostgresField;
|
|
$n->type = $row->typname;
|
|
$n->nullable = ( $row->attnotnull == 'f' );
|
|
$n->name = $field;
|
|
$n->tablename = $table;
|
|
$n->max_length = $row->attlen;
|
|
$n->deferrable = ( $row->deferrable == 't' );
|
|
$n->deferred = ( $row->deferred == 't' );
|
|
$n->conname = $row->conname;
|
|
$n->has_default = ( $row->atthasdef === 't' );
|
|
$n->default = $row->adsrc;
|
|
|
|
return $n;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function name() {
|
|
return $this->name;
|
|
}
|
|
|
|
function tableName() {
|
|
return $this->tablename;
|
|
}
|
|
|
|
function type() {
|
|
return $this->type;
|
|
}
|
|
|
|
function isNullable() {
|
|
return $this->nullable;
|
|
}
|
|
|
|
function maxLength() {
|
|
return $this->max_length;
|
|
}
|
|
|
|
function is_deferrable() {
|
|
return $this->deferrable;
|
|
}
|
|
|
|
function is_deferred() {
|
|
return $this->deferred;
|
|
}
|
|
|
|
function conname() {
|
|
return $this->conname;
|
|
}
|
|
|
|
/**
|
|
* @since 1.19
|
|
* @return bool|mixed
|
|
*/
|
|
function defaultValue() {
|
|
if ( $this->has_default ) {
|
|
return $this->default;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|