IdoQuery: Add prototype for dynamic GROUP BY clauses

This commit is contained in:
Johannes Meyer 2015-06-18 09:36:04 +02:00
parent 386447b847
commit 1169793213
2 changed files with 379 additions and 23 deletions

View File

@ -3,13 +3,14 @@
namespace Icinga\Data\Db; namespace Icinga\Data\Db;
use Icinga\Data\SimpleQuery;
use Icinga\Data\Filter\FilterChain;
use Icinga\Data\Filter\FilterOr;
use Icinga\Data\Filter\FilterAnd;
use Icinga\Data\Filter\FilterNot;
use Icinga\Exception\QueryException;
use Zend_Db_Select; use Zend_Db_Select;
use Icinga\Data\Filter\FilterAnd;
use Icinga\Data\Filter\FilterChain;
use Icinga\Data\Filter\FilterNot;
use Icinga\Data\Filter\FilterOr;
use Icinga\Data\SimpleQuery;
use Icinga\Exception\ProgrammingError;
use Icinga\Exception\QueryException;
/** /**
* Database query class * Database query class
@ -428,6 +429,35 @@ class DbQuery extends SimpleQuery
return false; return false;
} }
/**
* Return the alias used for joining the given table
*
* @param string $table
*
* @return string|null null in case no alias is being used
*
* @throws ProgrammingError In case the given table has not been joined
*/
public function getJoinedTableAlias($table)
{
$fromPart = $this->select->getPart(Zend_Db_Select::FROM);
if (isset($fromPart[$table])) {
if ($fromPart[$table]['joinType'] === Zend_Db_Select::FROM) {
throw new ProgrammingError('Table "%s" has not been joined', $table);
}
return; // No alias in use
}
foreach ($fromPart as $alias => $options) {
if ($options['tableName'] === $table && $options['joinType'] !== Zend_Db_Select::FROM) {
return $alias;
}
}
throw new ProgrammingError('Table "%s" has not been joined', $table);
}
/** /**
* Add an INNER JOIN table and colums to the query * Add an INNER JOIN table and colums to the query
* *

View File

@ -10,6 +10,7 @@ use Icinga\Data\Db\DbQuery;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression; use Icinga\Data\Filter\FilterExpression;
use Icinga\Exception\IcingaException; use Icinga\Exception\IcingaException;
use Icinga\Exception\NotImplementedError;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use Icinga\Web\Session; use Icinga\Web\Session;
@ -46,24 +47,31 @@ abstract class IdoQuery extends DbQuery
/** /**
* The prefix to use * The prefix to use
* *
* @var String * @var string
*/ */
protected $prefix; protected $prefix;
/** /**
* The alias name for the index column * An array to map aliases to table names
* *
* @var String * @var array
*/ */
protected $idxAliasColumn; protected $idxAliasColumn;
/** /**
* The table containing the index column alias * An array to map aliases to column names
* *
* @var String * @var array
*/ */
protected $idxAliasTable; protected $idxAliasTable;
/**
* An array to map custom aliases to aliases
*
* @var array
*/
protected $idxCustomAliases;
/** /**
* The column map containing all filterable columns * The column map containing all filterable columns
* *
@ -111,53 +119,235 @@ abstract class IdoQuery extends DbQuery
protected $joinedVirtualTables = array(); protected $joinedVirtualTables = array();
/** /**
* The primary field name for the object table * The primary key column for the instances table
*
* @var string
*/
protected $instance_id = 'instance_id';
/**
* The primary key column for the objects table
* *
* @var string * @var string
*/ */
protected $object_id = 'object_id'; protected $object_id = 'object_id';
/** /**
* The primary field name for the IDO host table * The primary key column for the acknowledgements table
* *
* @var string * @var string
*/ */
protected $host_id = 'host_id'; protected $acknowledgement_id = 'acknowledgement_id';
/** /**
* The primary field name for the IDO hostgroup table * The primary key column for the commenthistory table
* *
* @var string * @var string
*/ */
protected $hostgroup_id = 'hostgroup_id'; protected $commenthistory_id = 'commenthistory_id';
/** /**
* The primary field name for the IDO service table * The primary key column for the contactnotifications table
* *
* @var string * @var string
*/ */
protected $service_id = 'service_id'; protected $contactnotification_id = 'contactnotification_id';
/** /**
* The primary field name for the IDO serviegroup table * The primary key column for the downtimehistory table
*
* @var string
*/
protected $downtimehistory_id = 'downtimehistory_id';
/**
* The primary key column for the flappinghistory table
*
* @var string
*/
protected $flappinghistory_id = 'flappinghistory_id';
/**
* The primary key column for the notifications table
*
* @var string
*/
protected $notification_id = 'notification_id';
/**
* The primary key column for the statehistory table
*
* @var string
*/
protected $statehistory_id = 'statehistory_id';
/**
* The primary key column for the comments table
*
* @var string
*/
protected $comment_id = 'comment_id';
/**
* The primary key column for the customvariablestatus table
*
* @var string
*/
protected $customvariablestatus_id = 'customvariablestatus_id';
/**
* The primary key column for the hoststatus table
*
* @var string
*/
protected $hoststatus_id = 'hoststatus_id';
/**
* The primary key column for the programstatus table
*
* @var string
*/
protected $programstatus_id = 'programstatus_id';
/**
* The primary key column for the runtimevariables table
*
* @var string
*/
protected $runtimevariable_id = 'runtimevariable_id';
/**
* The primary key column for the scheduleddowntime table
*
* @var string
*/
protected $scheduleddowntime_id = 'scheduleddowntime_id';
/**
* The primary key column for the servicestatus table
*
* @var string
*/
protected $servicestatus_id = 'servicestatus_id';
/**
* The primary key column for the contactstatus table
*
* @var string
*/
protected $contactstatus_id = 'contactstatus_id';
/**
* The primary key column for the commands table
*
* @var string
*/
protected $command_id = 'command_id';
/**
* The primary key column for the contactgroup_members table
*
* @var string
*/
protected $contactgroup_member_id = 'contactgroup_member_id';
/**
* The primary key column for the contactgroups table
*
* @var string
*/
protected $contactgroup_id = 'contactgroup_id';
/**
* The primary key column for the contacts table
*
* @var string
*/
protected $contact_id = 'contact_id';
/**
* The primary key column for the customvariables table
*
* @var string
*/
protected $customvariable_id = 'customvariable_id';
/**
* The primary key column for the host_contactgroups table
*
* @var string
*/
protected $host_contactgroup_id = 'host_contactgroup_id';
/**
* The primary key column for the host_contacts table
*
* @var string
*/
protected $host_contact_id = 'host_contact_id';
/**
* The primary key column for the hostgroup_members table
*
* @var string
*/
protected $hostgroup_member_id = 'hostgroup_member_id';
/**
* The primary key column for the hostgroups table
*
* @var string
*/
protected $hostgroup_id = 'hostgroup_id';
/**
* The primary key column for the hosts table
*
* @var string
*/
protected $host_id = 'host_id';
/**
* The primary key column for the service_contactgroup table
*
* @var string
*/
protected $service_contactgroup_id = 'service_contactgroup_id';
/**
* The primary key column for the service_contact table
*
* @var string
*/
protected $service_contact_id = 'service_contact_id';
/**
* The primary key column for the servicegroup_members table
*
* @var string
*/
protected $servicegroup_member_id = 'servicegroup_member_id';
/**
* The primary key column for the servicegroups table
* *
* @var string * @var string
*/ */
protected $servicegroup_id = 'servicegroup_id'; protected $servicegroup_id = 'servicegroup_id';
/** /**
* The primary field name for the IDO contact table * The primary key column for the services table
* *
* @var string * @var string
*/ */
protected $contact_id = 'contact_id'; protected $service_id = 'service_id';
/** /**
* The primary field name for the IDO contactgroup table * The primary key column for the timeperiods table
* *
* @var string * @var string
*/ */
protected $contactgroup_id = 'contactgroup_id'; protected $timeperiod_id = 'timeperiod_id';
/** /**
* An array containing Column names that cause an aggregation of the query * An array containing Column names that cause an aggregation of the query
@ -483,6 +673,8 @@ abstract class IdoQuery extends DbQuery
} }
if (is_int($alias)) { if (is_int($alias)) {
$alias = $col; $alias = $col;
} else {
$this->idxCustomAliases[$alias] = $col;
} }
$resolvedColumns[$alias] = preg_replace('|\n|', ' ', $name); $resolvedColumns[$alias] = preg_replace('|\n|', ' ', $name);
@ -688,6 +880,11 @@ abstract class IdoQuery extends DbQuery
return $this->idxAliasColumn[$alias]; return $this->idxAliasColumn[$alias];
} }
public function customAliasToAlias($alias)
{
return $this->idxCustomAliases[$alias];
}
/** /**
* Create a sub query * Create a sub query
* *
@ -714,12 +911,55 @@ abstract class IdoQuery extends DbQuery
*/ */
public function columns(array $columns) public function columns(array $columns)
{ {
$this->idxCustomAliases = array();
$this->columns = $this->resolveColumns($columns); $this->columns = $this->resolveColumns($columns);
// TODO: we need to refresh our select! // TODO: we need to refresh our select!
// $this->select->columns($columns); // $this->select->columns($columns);
return $this; return $this;
} }
/**
* {@inheritdoc}
*/
public function _getGroup()
{
throw new NotImplementedError('Does not work in its current state but will, probably, in the future');
// TODO: order by??
$group = parent::getGroup();
if (! empty($group) && $this->ds->getDbType() === 'pgsql') {
$group = is_array($group) ? $group : array($group);
foreach ($this->columns as $alias => $column) {
if ($column instanceof Zend_Db_Expr) {
continue;
}
// TODO: What if $alias is neither a native nor a custom alias???
$table = $this->aliasToTableName(
$this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias)
);
// TODO: We cannot rely on the underlying select here, tables may be joined multiple times with
// different aliases so the only way to get the correct alias here is to register such by ourself
// for each virtual column (We may also inspect $column for the alias but this will probably lead
// to false positives.. AND prevents custom implementations from providing their own "mapping")
if (($tableAlias = $this->getJoinedTableAlias($this->prefix . $table)) === null) {
$tableAlias = $table;
}
// TODO: Same issue as with identifying table aliases; Our virtual tables are not named exactly how
// they are in the IDO. We definitely need to register aliases explicitly (hint: DbRepository
// is already providing such..)
$aliasedPk = $tableAlias . '.' . $this->getPrimaryKeyColumn($table);
if (! in_array($aliasedPk, $group)) {
$group[] = $aliasedPk;
}
}
}
return $group;
}
// TODO: Move this away, see note related to $idoVersion var // TODO: Move this away, see note related to $idoVersion var
protected function getIdoVersion() protected function getIdoVersion()
{ {
@ -745,4 +985,90 @@ abstract class IdoQuery extends DbQuery
} }
return self::$idoVersion; return self::$idoVersion;
} }
/**
* Return the name of the primary key column for the given table name
*
* @param string $table
*
* @return string
*
* @throws ProgrammingError In case $table is unknown
*/
protected function getPrimaryKeyColumn($table)
{
// TODO: For god's sake, make this being a mapping
// (instead of matching a ton of properties using a ridiculous long switch case)
switch ($table)
{
case 'instances':
return $this->instance_id;
case 'objects':
return $this->object_id;
case 'acknowledgements':
return $this->acknowledgement_id;
case 'commenthistory':
return $this->commenthistory_id;
case 'contactnotifiations':
return $this->contactnotification_id;
case 'downtimehistory':
return $this->downtimehistory_id;
case 'flappinghistory':
return $this->flappinghistory_id;
case 'notifications':
return $this->notification_id;
case 'statehistory':
return $this->statehistory_id;
case 'comments':
return $this->comment_id;
case 'customvariablestatus':
return $this->customvariablestatus_id;
case 'hoststatus':
return $this->hoststatus_id;
case 'programstatus':
return $this->programstatus_id;
case 'runtimevariables':
return $this->runtimevariable_id;
case 'scheduleddowntime':
return $this->scheduleddowntime_id;
case 'servicestatus':
return $this->servicestatus_id;
case 'contactstatus':
return $this->contactstatus_id;
case 'commands':
return $this->command_id;
case 'contactgroup_members':
return $this->contactgroup_member_id;
case 'contactgroups':
return $this->contactgroup_id;
case 'contacts':
return $this->contact_id;
case 'customvariables':
return $this->customvariable_id;
case 'host_contactgroups':
return $this->host_contactgroup_id;
case 'host_contacts':
return $this->host_contact_id;
case 'hostgroup_members':
return $this->hostgroup_member_id;
case 'hostgroups':
return $this->hostgroup_id;
case 'hosts':
return $this->host_id;
case 'service_contactgroups':
return $this->service_contactgroup_id;
case 'service_contacts':
return $this->service_contact_id;
case 'servicegroup_members':
return $this->servicegroup_member_id;
case 'servicegroups':
return $this->servicegroup_id;
case 'services':
return $this->service_id;
case 'timeperiods':
return $this->timeperiod_id;
default:
throw new ProgrammingError('Cannot provide a primary key column. Table "%s" is unknown', $table);
}
}
} }