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

Database::routine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 11
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 13
rs 9.9
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
use Lagdo\DbAdmin\Driver\Entity\IndexEntity;
8
use Lagdo\DbAdmin\Driver\Entity\ForeignKeyEntity;
9
use Lagdo\DbAdmin\Driver\Entity\TriggerEntity;
10
11
use Lagdo\DbAdmin\Driver\Db\ConnectionInterface;
12
13
use Lagdo\DbAdmin\Driver\Db\Database as AbstractDatabase;
14
15
class Database extends AbstractDatabase
16
{
17
    /**
18
     * @inheritDoc
19
     */
20
    public function alterTable(string $table, string $name, array $fields, array $foreign,
21
        string $comment, string $engine, string $collation, int $autoIncrement, string $partitioning)
22
    {
23
        $alter = [];
24
        $queries = [];
25
        if ($table != "" && $table != $name) {
26
            $queries[] = "ALTER TABLE " . $this->driver->table($table) . " RENAME TO " . $this->driver->table($name);
27
        }
28
        foreach ($fields as $field) {
29
            $column = $this->driver->escapeId($field[0]);
30
            $val = $field[1];
31
            if (!$val) {
32
                $alter[] = "DROP $column";
33
            } else {
34
                $val5 = $val[5];
35
                unset($val[5]);
36
                if ($field[0] == "") {
37
                    if (isset($val[6])) { // auto increment
38
                        $val[1] = ($val[1] == " bigint" ? " big" : ($val[1] == " smallint" ? " small" : " ")) . "serial";
39
                    }
40
                    $alter[] = ($table != "" ? "ADD " : "  ") . implode($val);
41
                    if (isset($val[6])) {
42
                        $alter[] = ($table != "" ? "ADD" : " ") . " PRIMARY KEY ($val[0])";
43
                    }
44
                } else {
45
                    if ($column != $val[0]) {
46
                        $queries[] = "ALTER TABLE " . $this->driver->table($name) . " RENAME $column TO $val[0]";
47
                    }
48
                    $alter[] = "ALTER $column TYPE$val[1]";
49
                    if (!$val[6]) {
50
                        $alter[] = "ALTER $column " . ($val[3] ? "SET$val[3]" : "DROP DEFAULT");
51
                        $alter[] = "ALTER $column " . ($val[2] == " NULL" ? "DROP NOT" : "SET") . $val[2];
52
                    }
53
                }
54
                if ($field[0] != "" || $val5 != "") {
55
                    $queries[] = "COMMENT ON COLUMN " . $this->driver->table($name) . ".$val[0] IS " . ($val5 != "" ? substr($val5, 9) : "''");
56
                }
57
            }
58
        }
59
        $alter = array_merge($alter, $foreign);
60
        if ($table == "") {
61
            array_unshift($queries, "CREATE TABLE " . $this->driver->table($name) . " (\n" . implode(",\n", $alter) . "\n)");
62
        } elseif (!empty($alter)) {
63
            array_unshift($queries, "ALTER TABLE " . $this->driver->table($table) . "\n" . implode(",\n", $alter));
64
        }
65
        if ($table != "" || $comment != "") {
66
            $queries[] = "COMMENT ON TABLE " . $this->driver->table($name) . " IS " . $this->driver->quote($comment);
67
        }
68
        if ($autoIncrement != "") {
69
            //! $queries[] = "SELECT setval(pg_get_serial_sequence(" . $this->driver->quote($name) . ", ), $autoIncrement)";
70
        }
71
        foreach ($queries as $query) {
72
            if (!$this->driver->execute($query)) {
73
                return false;
74
            }
75
        }
76
        return true;
77
    }
78
79
    /**
80
     * @inheritDoc
81
     */
82
    public function alterIndexes(string $table, array $alter)
83
    {
84
        $create = [];
85
        $drop = [];
86
        $queries = [];
87
        foreach ($alter as $val) {
88
            if ($val[0] != "INDEX") {
89
                //! descending UNIQUE indexes results in syntax error
90
                $create[] = (
91
                    $val[2] == "DROP" ? "\nDROP CONSTRAINT " . $this->driver->escapeId($val[1]) :
92
                    "\nADD" . ($val[1] != "" ? " CONSTRAINT " . $this->driver->escapeId($val[1]) : "") .
93
                    " $val[0] " . ($val[0] == "PRIMARY" ? "KEY " : "") . "(" . implode(", ", $val[2]) . ")"
94
                );
95
            } elseif ($val[2] == "DROP") {
96
                $drop[] = $this->driver->escapeId($val[1]);
97
            } else {
98
                $queries[] = "CREATE INDEX " . $this->driver->escapeId($val[1] != "" ? $val[1] : uniqid($table . "_")) .
99
                    " ON " . $this->driver->table($table) . " (" . implode(", ", $val[2]) . ")";
100
            }
101
        }
102
        if ($create) {
103
            array_unshift($queries, "ALTER TABLE " . $this->driver->table($table) . implode(",", $create));
104
        }
105
        if ($drop) {
106
            array_unshift($queries, "DROP INDEX " . implode(", ", $drop));
107
        }
108
        foreach ($queries as $query) {
109
            if (!$this->driver->execute($query)) {
110
                return false;
111
            }
112
        }
113
        return true;
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    public function tables()
120
    {
121
        $query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = current_schema()";
122
        if ($this->driver->support('materializedview')) {
123
            $query .= " UNION ALL SELECT matviewname, 'MATERIALIZED VIEW' FROM pg_matviews WHERE schemaname = current_schema()";
124
        }
125
        $query .= " ORDER BY 1";
126
        return $this->driver->keyValues($query);
127
    }
128
129
    /**
130
     * @inheritDoc
131
     */
132
    public function sequences()
133
    {
134
        // From db.inc.php
135
        $query = 'SELECT sequence_name FROM information_schema.sequences ' .
136
            'WHERE sequence_schema = selectedSchema() ORDER BY sequence_name';
137
        return $this->driver->values($query);
138
    }
139
140
    /**
141
     * @inheritDoc
142
     */
143
    public function countTables(array $databases)
144
    {
145
        $connection = $this->driver->createConnection(); // New connection
146
        $counts = [];
147
        $systemSchemas = ['information_schema', 'pg_catalog', 'pg_temp_1', 'pg_toast', 'pg_toast_temp_1'];
148
        $query = "SELECT count(*) FROM information_schema.tables WHERE table_schema NOT IN ('" .
149
            implode("','", $systemSchemas) . "')";
150
        foreach ($databases as $database) {
151
            $counts[$database] = 0;
152
            if (!$connection->open($database)) {
153
                continue;
154
            }
155
            $statement = $connection->query($query);
156
            if (is_object($statement) && ($row = $statement->fetchRow())) {
157
                $counts[$database] = intval($row[0]);
158
            }
159
        }
160
        return $counts;
161
    }
162
163
    /**
164
     * @inheritDoc
165
     */
166
    public function dropViews(array $views)
167
    {
168
        return $this->dropTables($views);
169
    }
170
171
    /**
172
     * @inheritDoc
173
     */
174
    public function dropTables(array $tables)
175
    {
176
        foreach ($tables as $table) {
177
            $status = $this->driver->tableStatus($table);
178
            if (!$this->driver->execute("DROP " . strtoupper($status->engine) . " " . $this->driver->table($table))) {
179
                return false;
180
            }
181
        }
182
        return true;
183
    }
184
185
    /**
186
     * @inheritDoc
187
     */
188
    public function moveTables(array $tables, array $views, string $target)
189
    {
190
        foreach (array_merge($tables, $views) as $table) {
191
            $status = $this->driver->tableStatus($table);
192
            if (!$this->driver->execute("ALTER " . strtoupper($status->engine) . " " .
193
                $this->driver->table($table) . " SET SCHEMA " . $this->driver->escapeId($target))) {
194
                return false;
195
            }
196
        }
197
        return true;
198
    }
199
200
    /**
201
     * @inheritDoc
202
     */
203
    public function truncateTables(array $tables)
204
    {
205
        $this->driver->execute("TRUNCATE " . implode(", ", array_map(function ($table) {
206
            return $this->driver->table($table);
207
        }, $tables)));
208
        return true;
209
    }
210
211
    /**
212
     * @inheritDoc
213
     */
214
    public function userTypes()
215
    {
216
        $query = "SELECT typname FROM pg_type WHERE typnamespace = " .
217
            "(SELECT oid FROM pg_namespace WHERE nspname = current_schema()) " .
218
            "AND typtype IN ('b','d','e') AND typelem = 0";
219
        return $this->driver->values($query);
220
    }
221
222
    /**
223
     * @inheritDoc
224
     */
225
    public function schemas()
226
    {
227
        return $this->driver->values("SELECT nspname FROM pg_namespace ORDER BY nspname");
228
    }
229
230
    /**
231
     * @inheritDoc
232
     */
233
    public function routine(string $name, string $type)
234
    {
235
        $query = 'SELECT routine_definition AS definition, LOWER(external_language) AS language, * ' .
236
            'FROM information_schema.routines WHERE routine_schema = current_schema() ' .
237
            'AND specific_name = ' . $this->driver->quote($name);
238
        $rows = $this->driver->rows($query);
239
        $routines = $rows[0];
240
        $routines["returns"] = ["type" => $routines["type_udt_name"]];
241
        $query = 'SELECT parameter_name AS field, data_type AS type, character_maximum_length AS length, ' .
242
            'parameter_mode AS inout FROM information_schema.parameters WHERE specific_schema = current_schema() ' .
243
            'AND specific_name = ' . $this->driver->quote($name) . ' ORDER BY ordinal_position';
244
        $routines["fields"] = $this->driver->rows($query);
245
        return $routines;
246
    }
247
248
    /**
249
     * @inheritDoc
250
     */
251
    public function routines()
252
    {
253
        $query = 'SELECT specific_name AS "SPECIFIC_NAME", routine_type AS "ROUTINE_TYPE", ' .
254
            'routine_name AS "ROUTINE_NAME", type_udt_name AS "DTD_IDENTIFIER" ' .
255
            'FROM information_schema.routines WHERE routine_schema = current_schema() ORDER BY SPECIFIC_NAME';
256
        $rows = $this->driver->rows($query);
257
        return array_map(function($row) {
258
            return new RoutineEntity($row['ROUTINE_NAME'], $row['SPECIFIC_NAME'], $row['ROUTINE_TYPE'], $row['DTD_IDENTIFIER']);
0 ignored issues
show
Bug introduced by
The type Lagdo\DbAdmin\Driver\PgSql\Db\RoutineEntity was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
259
        }, $rows);
260
    }
261
262
    /**
263
     * @inheritDoc
264
     */
265
    public function routineId(string $name, array $row)
266
    {
267
        $routine = [];
268
        foreach ($row["fields"] as $field) {
269
            $routine[] = $field->type;
270
        }
271
        return $this->driver->escapeId($name) . "(" . implode(", ", $routine) . ")";
272
    }
273
}
274