Passed
Branch main (a6702e)
by Thierry
04:09 queued 02:04
created

Query   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 51
c 1
b 0
f 0
dl 0
loc 140
rs 10
wmc 25

11 Methods

Rating   Name   Duplication   Size   Complexity  
A slowQuery() 0 5 1
B insertOrUpdate() 0 22 8
A error() 0 12 2
A limitToOne() 0 5 3
A explain() 0 3 1
A user() 0 3 1
A view() 0 12 1
A countRows() 0 9 3
A convertSearch() 0 5 3
A schema() 0 3 1
A lastAutoIncrementId() 0 3 1
1
<?php
2
3
namespace Lagdo\DbAdmin\Driver\PgSql\Db;
4
5
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
6
use Lagdo\DbAdmin\Driver\Entity\TableEntity;
7
8
use Lagdo\DbAdmin\Driver\Db\ConnectionInterface;
9
10
use Lagdo\DbAdmin\Driver\Db\Query as AbstractQuery;
11
12
use function strtoupper;
13
14
class Query extends AbstractQuery
15
{
16
    /**
17
     * @inheritDoc
18
     */
19
    protected function limitToOne(string $table, string $query, string $where, string $separator = "\n")
20
    {
21
        return (preg_match('~^INTO~', $query) ? $this->driver->limit($query, $where, 1, 0, $separator) :
22
            " $query" . ($this->driver->isView($this->driver->tableStatusOrName($table)) ? $where :
23
            " WHERE ctid = (SELECT ctid FROM " . $this->driver->table($table) . $where . $separator . "LIMIT 1)")
24
        );
25
    }
26
27
    /**
28
     * @inheritDoc
29
     */
30
    public function insertOrUpdate(string $table, array $rows, array $primary)
31
    {
32
        foreach ($rows as $set) {
33
            $update = [];
34
            $where = [];
35
            foreach ($set as $key => $val) {
36
                $update[] = "$key = $val";
37
                if (isset($primary[$this->driver->unescapeId($key)])) {
38
                    $where[] = "$key = $val";
39
                }
40
            }
41
            if (!(
42
                ($where && $this->driver->execute("UPDATE " . $this->driver->table($table) .
43
                " SET " . implode(", ", $update) . " WHERE " . implode(" AND ", $where)) &&
44
                $this->driver->affectedRows()) ||
45
                $this->driver->execute("INSERT INTO " . $this->driver->table($table) .
46
                " (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")")
47
            )) {
48
                return false;
49
            }
50
        }
51
        return true;
52
    }
53
54
    /**
55
     * @inheritDoc
56
     */
57
    public function lastAutoIncrementId()
58
    {
59
        return '0'; // there can be several sequences
60
    }
61
62
    /**
63
     * @inheritDoc
64
     */
65
    public function convertSearch(string $idf, array $val, TableFieldEntity $field)
66
    {
67
        return (preg_match('~char|text' . (!preg_match('~LIKE~', $val["op"]) ?
68
            '|date|time(stamp)?|boolean|uuid|' . $this->driver->numberRegex() : '') .
69
            '~', $field->type) ? $idf : "CAST($idf AS text)"
70
        );
71
    }
72
73
    /**
74
     * @inheritDoc
75
     */
76
    public function countRows(TableEntity $tableStatus, array $where)
77
    {
78
        $query = "EXPLAIN SELECT * FROM " . $this->driver->escapeId($tableStatus->name) .
79
            ($where ? " WHERE " . implode(" AND ", $where) : "");
80
        if (preg_match("~ rows=([0-9]+)~", $this->connection->result($query), $regs))
81
        {
82
            return $regs[1];
83
        }
84
        return 0;
85
    }
86
87
    /**
88
     * @inheritDoc
89
     */
90
    public function view(string $name)
91
    {
92
        $status = $this->driver->tableStatus($name);
93
        $type = strtoupper($status->engine);
94
        return [
95
            'name' => $name,
96
            'type' => $type,
97
            'materialized' => ($type != 'VIEW'),
98
            'select' => trim($this->connection->result("SELECT pg_get_viewdef(" .
99
                $this->connection->result("SELECT oid FROM pg_class WHERE relnamespace = " .
100
                "(SELECT oid FROM pg_namespace WHERE nspname = current_schema()) AND relname = " .
101
                $this->driver->quote($name)) . ")"))
102
        ];
103
    }
104
105
    /**
106
     * @inheritDoc
107
     */
108
    public function slowQuery(string $query, int $timeout)
109
    {
110
        // $this->connection->timeout = 1000 * $timeout;
111
        $this->connection->query("SET statement_timeout = " . (1000 * $timeout));
112
        return $query;
113
    }
114
115
    /**
116
     * @inheritDoc
117
     */
118
    public function explain(ConnectionInterface $connection, string $query)
119
    {
120
        return $connection->query("EXPLAIN $query");
121
    }
122
123
    /**
124
     * @inheritDoc
125
     */
126
    public function user()
127
    {
128
        return $this->connection->result("SELECT user");
129
    }
130
131
    /**
132
     * @inheritDoc
133
     */
134
    public function schema()
135
    {
136
        return $this->connection->result("SELECT current_schema()");
137
    }
138
139
    /**
140
     * @inheritDoc
141
     */
142
    public function error()
143
    {
144
        $message = parent::error();
145
        if (preg_match('~^(.*\n)?([^\n]*)\n( *)\^(\n.*)?$~s', $message, $match)) {
146
            $match1 = $match[1] ?? '';
147
            $match2 = $match[2] ?? '';
148
            $match3 = $match[3] ?? '';
149
            $match4 = $match[4] ?? '';
150
            $message = $match1 . preg_replace('~((?:[^&]|&[^;]*;){' .
151
                strlen($match3) . '})(.*)~', '\1<b>\2</b>', $match2) . $match4;
152
        }
153
        return $this->util->convertEolToHtml($message);
154
    }
155
}
156