1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
<?php
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Common;
use Icinga\Application\Config as AppConfig;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use ipl\Sql\Adapter\Pgsql;
use ipl\Sql\Config as SqlConfig;
use ipl\Sql\Connection;
use ipl\Sql\Expression;
use ipl\Sql\QueryBuilder;
use ipl\Sql\Select;
use PDO;
trait Database
{
/** @var Connection Connection to the Icinga database */
private $db;
/**
* Get the connection to the Icinga database
*
* @return Connection
*
* @throws ConfigurationError If the related resource configuration does not exist
*/
public function getDb(): Connection
{
if ($this->db === null) {
$config = new SqlConfig(ResourceFactory::getResourceConfig(
AppConfig::module('icingadb')->get('icingadb', 'resource')
));
$config->options = [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ];
if ($config->db === 'mysql') {
$config->options[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET SESSION SQL_MODE='STRICT_TRANS_TABLES"
. ",NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
}
$this->db = new Connection($config);
$adapter = $this->db->getAdapter();
if ($adapter instanceof Pgsql) {
$quoted = $adapter->quoteIdentifier('user');
$this->db->getQueryBuilder()
->on(QueryBuilder::ON_SELECT_ASSEMBLED, function (&$sql) use ($quoted) {
// user is a reserved key word in PostgreSQL, so we need to quote it.
// TODO(lippserd): This is pretty hacky,
// reconsider how to properly implement identifier quoting.
$sql = str_replace(' user ', sprintf(' %s ', $quoted), $sql);
$sql = str_replace(' user.', sprintf(' %s.', $quoted), $sql);
$sql = str_replace('(user.', sprintf('(%s.', $quoted), $sql);
})
->on(QueryBuilder::ON_ASSEMBLE_SELECT, function (Select $select) {
// For SELECT DISTINCT, all ORDER BY columns must appear in SELECT list.
if (! $select->getDistinct() || ! $select->hasOrderBy()) {
return;
}
$candidates = [];
foreach ($select->getOrderBy() as list($columnOrAlias, $_)) {
if ($columnOrAlias instanceof Expression) {
// Expressions can be and include anything,
// also columns that aren't already part of the SELECT list,
// so we're not trying to guess anything here.
// Such expressions must be in the SELECT list if necessary and
// referenced manually with an alias in ORDER BY.
continue;
}
$candidates[$columnOrAlias] = true;
}
foreach ($select->getColumns() as $alias => $column) {
if (is_int($alias)) {
if ($column instanceof Expression) {
// This is the complement to the above consideration.
// If it is an unaliased expression, ignore it.
continue;
}
} else {
unset($candidates[$alias]);
}
if (! $column instanceof Expression) {
unset($candidates[$column]);
}
}
if (! empty($candidates)) {
$select->columns(array_keys($candidates));
}
});
}
}
return $this->db;
}
}
|