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;
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 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
@ -428,6 +429,35 @@ class DbQuery extends SimpleQuery
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
*

View File

@ -10,6 +10,7 @@ use Icinga\Data\Db\DbQuery;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Exception\IcingaException;
use Icinga\Exception\NotImplementedError;
use Icinga\Exception\ProgrammingError;
use Icinga\Web\Session;
@ -46,24 +47,31 @@ abstract class IdoQuery extends DbQuery
/**
* The prefix to use
*
* @var String
* @var string
*/
protected $prefix;
/**
* The alias name for the index column
* An array to map aliases to table names
*
* @var String
* @var array
*/
protected $idxAliasColumn;
/**
* The table containing the index column alias
* An array to map aliases to column names
*
* @var String
* @var array
*/
protected $idxAliasTable;
/**
* An array to map custom aliases to aliases
*
* @var array
*/
protected $idxCustomAliases;
/**
* The column map containing all filterable columns
*
@ -111,53 +119,235 @@ abstract class IdoQuery extends DbQuery
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
*/
protected $object_id = 'object_id';
/**
* The primary field name for the IDO host table
* The primary key column for the acknowledgements table
*
* @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
*/
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
*/
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
*/
protected $servicegroup_id = 'servicegroup_id';
/**
* The primary field name for the IDO contact table
* The primary key column for the services table
*
* @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
*/
protected $contactgroup_id = 'contactgroup_id';
protected $timeperiod_id = 'timeperiod_id';
/**
* 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)) {
$alias = $col;
} else {
$this->idxCustomAliases[$alias] = $col;
}
$resolvedColumns[$alias] = preg_replace('|\n|', ' ', $name);
@ -688,6 +880,11 @@ abstract class IdoQuery extends DbQuery
return $this->idxAliasColumn[$alias];
}
public function customAliasToAlias($alias)
{
return $this->idxCustomAliases[$alias];
}
/**
* Create a sub query
*
@ -714,12 +911,55 @@ abstract class IdoQuery extends DbQuery
*/
public function columns(array $columns)
{
$this->idxCustomAliases = array();
$this->columns = $this->resolveColumns($columns);
// TODO: we need to refresh our select!
// $this->select->columns($columns);
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
protected function getIdoVersion()
{
@ -745,4 +985,90 @@ abstract class IdoQuery extends DbQuery
}
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);
}
}
}