DbObject: remove binary column magic

Binary columns must be configured explicitly, binary keys are now also
possible

fixes #1702
This commit is contained in:
Thomas Gelf 2018-10-30 16:40:17 +01:00
parent 117699c957
commit 6377ed61cc
14 changed files with 103 additions and 44 deletions

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Data\Db; namespace Icinga\Module\Director\Data\Db;
use Icinga\Data\Db\DbConnection as IcingaDbConnection; use Icinga\Data\Db\DbConnection as IcingaDbConnection;
use Zend_Db_Expr;
class DbConnection extends IcingaDbConnection class DbConnection extends IcingaDbConnection
{ {
@ -16,6 +17,15 @@ class DbConnection extends IcingaDbConnection
return $this->getDbType() === 'pgsql'; return $this->getDbType() === 'pgsql';
} }
public function quoteBinary($binary)
{
if ($this->isPgsql()) {
return new Zend_Db_Expr("'\\x" . bin2hex($binary) . "'");
}
return $binary;
}
public function hasPgExtension($name) public function hasPgExtension($name)
{ {
$db = $this->db(); $db = $this->db();

View File

@ -72,6 +72,8 @@ abstract class DbObject
/** @var bool forbid updates to autoinc values */ /** @var bool forbid updates to autoinc values */
protected $protectAutoinc = true; protected $protectAutoinc = true;
protected $binaryProperties = [];
/** /**
* Filled with object instances when prefetchAll is used * Filled with object instances when prefetchAll is used
*/ */
@ -742,7 +744,7 @@ abstract class DbObject
// TODO: Remove this! // TODO: Remove this!
if ($this->connection->isPgsql()) { if ($this->connection->isPgsql()) {
foreach ($properties as $key => $value) { foreach ($properties as $key => $value) {
if (preg_match('/checksum$/', $key)) { if ($this->isBinaryColumn($key)) {
$properties[$key] = Util::pgBinEscape($value); $properties[$key] = Util::pgBinEscape($value);
} }
} }
@ -751,6 +753,11 @@ abstract class DbObject
return $this->db->insert($this->table, $properties); return $this->db->insert($this->table, $properties);
} }
protected function isBinaryColumn($column)
{
return in_array($column, $this->binaryProperties);
}
/** /**
* Store object to database * Store object to database
* *
@ -920,19 +927,13 @@ abstract class DbObject
if ($this->loadedProperties[$k] === null) { if ($this->loadedProperties[$k] === null) {
$where[] = sprintf('%s IS NULL', $k); $where[] = sprintf('%s IS NULL', $k);
} else { } else {
$where[] = $this->db->quoteInto( $where[] = $this->createQuotedWhere($k, $this->loadedProperties[$k]);
sprintf('%s = ?', $k),
$this->loadedProperties[$k]
);
} }
} else { } else {
if ($this->properties[$k] === null) { if ($this->properties[$k] === null) {
$where[] = sprintf('%s IS NULL', $k); $where[] = sprintf('%s IS NULL', $k);
} else { } else {
$where[] = $this->db->quoteInto( $where[] = $this->createQuotedWhere($k, $this->properties[$k]);
sprintf('%s = ?', $k),
$this->properties[$k]
);
} }
} }
} }
@ -940,16 +941,27 @@ abstract class DbObject
return implode(' AND ', $where); return implode(' AND ', $where);
} else { } else {
if ($this->hasBeenLoadedFromDb()) { if ($this->hasBeenLoadedFromDb()) {
return $this->db->quoteInto( return $this->createQuotedWhere($key, $this->loadedProperties[$key]);
sprintf('%s = ?', $key),
$this->loadedProperties[$key]
);
} else { } else {
return $this->createQuotedWhere($key, $this->properties[$key]);
}
}
}
protected function createQuotedWhere($column, $value)
{
return $this->db->quoteInto( return $this->db->quoteInto(
sprintf('%s = ?', $key), sprintf('%s = ?', $column),
$this->properties[$key] $this->eventuallyQuoteBinary($value, $column)
); );
} }
protected function eventuallyQuoteBinary($value, $column)
{
if ($this->isBinaryColumn($column)) {
return $this->connection->quoteBinary($value);
} else {
return $value;
} }
} }

View File

@ -11,7 +11,6 @@ use Icinga\Module\Director\Data\Db\DbConnection;
use Icinga\Module\Director\Objects\IcingaEndpoint; use Icinga\Module\Director\Objects\IcingaEndpoint;
use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\IcingaObject;
use RuntimeException; use RuntimeException;
use Zend_Db_Expr;
use Zend_Db_Select; use Zend_Db_Select;
class Db extends DbConnection class Db extends DbConnection
@ -711,15 +710,6 @@ class Db extends DbConnection
} }
} }
public function quoteBinary($binary)
{
if ($this->isPgsql()) {
return new Zend_Db_Expr("'\\x" . bin2hex($binary) . "'");
}
return $binary;
}
public function enumDeployedConfigs() public function enumDeployedConfigs()
{ {
$db = $this->db(); $db = $this->db();

View File

@ -31,6 +31,10 @@ class Basket extends DbObject implements ExportInterface
'owner_value' => null, 'owner_value' => null,
]; ];
protected $binaryProperties = [
'uuid'
];
public function getHexUuid() public function getHexUuid()
{ {
return bin2hex($this->get('uuid')); return bin2hex($this->get('uuid'));

View File

@ -17,4 +17,8 @@ class BasketContent extends DbObject
'summary' => null, 'summary' => null,
'content' => null, 'content' => null,
]; ];
protected $binaryProperties = [
'checksum'
];
} }

View File

@ -65,6 +65,11 @@ class BasketSnapshot extends DbObject
'ts_create' => null, 'ts_create' => null,
]; ];
protected $binaryProperties = [
'basket_uuid',
'content_checksum',
];
public static function supports($type) public static function supports($type)
{ {
return isset(self::$typeClasses[$type]); return isset(self::$typeClasses[$type]);

View File

@ -17,7 +17,7 @@ class DirectorActivityLog extends DbObject
protected $autoincKeyName = 'id'; protected $autoincKeyName = 'id';
protected $defaultProperties = array( protected $defaultProperties = [
'id' => null, 'id' => null,
'object_name' => null, 'object_name' => null,
'action_name' => null, 'action_name' => null,
@ -28,7 +28,12 @@ class DirectorActivityLog extends DbObject
'change_time' => null, 'change_time' => null,
'checksum' => null, 'checksum' => null,
'parent_checksum' => null, 'parent_checksum' => null,
); ];
protected $binaryProperties = [
'checksum',
'parent_checksum'
];
/** /**
* @param $name * @param $name
@ -82,7 +87,7 @@ class DirectorActivityLog extends DbObject
public static function loadLatest(Db $connection) public static function loadLatest(Db $connection)
{ {
$db = $connection->getDbAdapter(); $db = $connection->getDbAdapter();
$query = $db->select()->from('director_activity_log', array('id' => 'MAX(id)')); $query = $db->select()->from('director_activity_log', ['id' => 'MAX(id)']);
return static::load($db->fetchOne($query), $connection); return static::load($db->fetchOne($query), $connection);
} }

View File

@ -9,7 +9,6 @@ use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db; use Icinga\Module\Director\Db;
use Icinga\Module\Director\IcingaConfig\IcingaConfig; use Icinga\Module\Director\IcingaConfig\IcingaConfig;
use Icinga\Module\Director\Util; use Icinga\Module\Director\Util;
use RuntimeException;
class DirectorDeploymentLog extends DbObject class DirectorDeploymentLog extends DbObject
{ {
@ -21,7 +20,7 @@ class DirectorDeploymentLog extends DbObject
protected $config; protected $config;
protected $defaultProperties = array( protected $defaultProperties = [
'id' => null, 'id' => null,
'config_checksum' => null, 'config_checksum' => null,
'last_activity_checksum' => null, 'last_activity_checksum' => null,
@ -38,7 +37,12 @@ class DirectorDeploymentLog extends DbObject
'startup_succeeded' => null, 'startup_succeeded' => null,
'username' => null, 'username' => null,
'startup_log' => null, 'startup_log' => null,
); ];
protected $binaryProperties = [
'config_checksum',
'last_activity_checksum'
];
public function getConfigHexChecksum() public function getConfigHexChecksum()
{ {
@ -97,6 +101,11 @@ class DirectorDeploymentLog extends DbObject
return $db->fetchOne($query, $stage); return $db->fetchOne($query, $stage);
} }
/**
* @param Db $connection
* @return DirectorDeploymentLog
* @throws NotFoundError
*/
public static function loadLatest(Db $connection) public static function loadLatest(Db $connection)
{ {
$db = $connection->getDbAdapter(); $db = $connection->getDbAdapter();

View File

@ -15,12 +15,17 @@ class IcingaFlatVar extends DbObject
'flatname_checksum' 'flatname_checksum'
); );
protected $defaultProperties = array( protected $defaultProperties = [
'var_checksum' => null, 'var_checksum' => null,
'flatname_checksum' => null, 'flatname_checksum' => null,
'flatname' => null, 'flatname' => null,
'flatvalue' => null, 'flatvalue' => null,
); ];
protected $binaryProperties = [
'var_checksum',
'flatname_checksum',
];
public static function generateForCustomVar(CustomVariable $var, Db $db) public static function generateForCustomVar(CustomVariable $var, Db $db)
{ {

View File

@ -4,7 +4,6 @@ namespace Icinga\Module\Director\Objects;
use Icinga\Module\Director\CustomVariable\CustomVariable; use Icinga\Module\Director\CustomVariable\CustomVariable;
use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
use Icinga\Module\Director\Db; use Icinga\Module\Director\Db;
class IcingaVar extends DbObject class IcingaVar extends DbObject
@ -16,13 +15,18 @@ class IcingaVar extends DbObject
/** @var CustomVariable */ /** @var CustomVariable */
protected $var; protected $var;
protected $defaultProperties = array( protected $defaultProperties = [
'checksum' => null, 'checksum' => null,
'rendered_checksum' => null, 'rendered_checksum' => null,
'varname' => null, 'varname' => null,
'varvalue' => null, 'varvalue' => null,
'rendered' => null 'rendered' => null
); ];
protected $binaryProperties = [
'checksum',
'rendered_checksum',
];
/** /**
* @param CustomVariable $var * @param CustomVariable $var
@ -48,10 +52,11 @@ class IcingaVar extends DbObject
} }
/** /**
* @param CustomVariable $var * @param CustomVariable $customVar
* @param Db $db * @param Db $db
* *
* @return static * @return static
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException
*/ */
public static function generateForCustomVar(CustomVariable $customVar, Db $db) public static function generateForCustomVar(CustomVariable $customVar, Db $db)
{ {

View File

@ -16,7 +16,7 @@ class ImportRun extends DbObject
/** @var ImportSource */ /** @var ImportSource */
protected $importSource = null; protected $importSource = null;
protected $defaultProperties = array( protected $defaultProperties = [
'id' => null, 'id' => null,
'source_id' => null, 'source_id' => null,
'rowset_checksum' => null, 'rowset_checksum' => null,
@ -24,7 +24,11 @@ class ImportRun extends DbObject
'end_time' => null, 'end_time' => null,
// TODO: Check whether succeeded could be dropped // TODO: Check whether succeeded could be dropped
'succeeded' => null, 'succeeded' => null,
); ];
protected $binaryProperties = [
'rowset_checksum',
];
public function prepareImportedObjectQuery($columns = array('object_name')) public function prepareImportedObjectQuery($columns = array('object_name'))
{ {

View File

@ -9,6 +9,7 @@ use Icinga\Exception\NotImplementedError;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use dipl\Html\Html; use dipl\Html\Html;
use dipl\Html\Link; use dipl\Html\Link;
use RuntimeException;
use Zend_Db_Expr; use Zend_Db_Expr;
class Util class Util
@ -19,6 +20,10 @@ class Util
public static function pgBinEscape($binary) public static function pgBinEscape($binary)
{ {
if ($binary instanceof Zend_Db_Expr) {
throw new RuntimeException('Trying to escape binary twice');
}
return new Zend_Db_Expr("'\\x" . bin2hex($binary) . "'"); return new Zend_Db_Expr("'\\x" . bin2hex($binary) . "'");
} }

View File

@ -12,6 +12,8 @@ use RuntimeException;
class BasketSnapshotTable extends ZfQueryBasedTable class BasketSnapshotTable extends ZfQueryBasedTable
{ {
use DbHelper;
protected $searchColumns = [ protected $searchColumns = [
'basket_name', 'basket_name',
'summary' 'summary'
@ -87,7 +89,7 @@ class BasketSnapshotTable extends ZfQueryBasedTable
protected function linkToSnapshot($caption, $row) protected function linkToSnapshot($caption, $row)
{ {
return new Link($caption, 'director/basket/snapshot', [ return new Link($caption, 'director/basket/snapshot', [
'checksum' => bin2hex($row->content_checksum), 'checksum' => bin2hex($this->wantBinaryValue($row->content_checksum)),
'ts' => $row->ts_create, 'ts' => $row->ts_create,
'name' => $row->basket_name, 'name' => $row->basket_name,
]); ]);
@ -115,7 +117,7 @@ class BasketSnapshotTable extends ZfQueryBasedTable
)->order('bs.ts_create DESC'); )->order('bs.ts_create DESC');
if ($this->basket !== null) { if ($this->basket !== null) {
$query->where('b.uuid = ?', $this->basket->get('uuid')); $query->where('b.uuid = ?', $this->quoteBinary($this->basket->get('uuid')));
} }
return $query; return $query;

View File

@ -13,7 +13,6 @@ class BasketTable extends ZfQueryBasedTable
public function renderRow($row) public function renderRow($row)
{ {
$hexUuid = bin2hex($row->uuid);
$tr = $this::row([ $tr = $this::row([
new Link( new Link(
$row->basket_name, $row->basket_name,