wiki.techinc.nl/includes/libs/rdbms/field/PostgresField.php
Jeff Janes 27d342ef4b rdbms: Remove references to pg_attrdef.adsrc in Postgres code
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
2019-01-22 19:23:06 +00:00

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;
}
}
}