Passed
Push — develop ( 2d5edd...a33225 )
by Felipe
05:40
created

DatabaseTrait::createDatabase()   C

Complexity

Conditions 10
Paths 64

Size

Total Lines 47
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 47
rs 5.1578
c 0
b 0
f 0
cc 10
eloc 23
nc 64
nop 7

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.47
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
/**
10
 * Common trait for tables manipulation.
11
 */
12
trait DatabaseTrait
13
{
14
    /**
15
     * Analyze a database.
16
     *
17
     * @param string $table (optional) The table to analyze
18
     *
19
     * @return bool 0 if successful
20
     */
21
    public function analyzeDB($table = '')
22
    {
23
        if ($table != '') {
24
            $f_schema = $this->_schema;
25
            $this->fieldClean($f_schema);
26
            $this->fieldClean($table);
27
28
            $sql = "ANALYZE \"{$f_schema}\".\"{$table}\"";
29
        } else {
30
            $sql = 'ANALYZE';
31
        }
32
33
        return $this->execute($sql);
34
    }
35
36
    /**
37
     * Return all information about a particular database.
38
     *
39
     * @param string $database The name of the database to retrieve
40
     *
41
     * @return \PHPPgAdmin\ADORecordSet The database info
42
     */
43
    public function getDatabase($database)
44
    {
45
        $this->clean($database);
46
        $sql = "SELECT * FROM pg_database WHERE datname='{$database}'";
47
48
        return $this->selectSet($sql);
49
    }
50
51
    /**
52
     * Return all database available on the server.
53
     *
54
     * @param null|string $currentdatabase database name that should be on top of the resultset
55
     *
56
     * @return \PHPPgAdmin\ADORecordSet A list of databases, sorted alphabetically
57
     */
58
    public function getDatabases($currentdatabase = null)
59
    {
60
        $conf        = $this->conf;
61
        $server_info = $this->server_info;
62
63
        //$this->prtrace('server_info', $server_info);
64
65
        if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser()) {
0 ignored issues
show
Bug introduced by
It seems like isSuperUser() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

65
        if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->/** @scrutinizer ignore-call */ isSuperUser()) {
Loading history...
66
            $username = $server_info['username'];
67
            $this->clean($username);
68
            $clause = " AND pr.rolname='{$username}'";
69
        } else {
70
            $clause = '';
71
        }
72
        if (isset($server_info['useonlydefaultdb']) && $server_info['useonlydefaultdb']) {
73
            $currentdatabase = $server_info['defaultdb'];
74
            $clause .= " AND pdb.datname = '{$currentdatabase}' ";
75
        }
76
77
        if (isset($server_info['hiddendbs']) && $server_info['hiddendbs']) {
78
            $hiddendbs = $server_info['hiddendbs'];
79
80
            $not_in = "('".implode("','", $hiddendbs)."')";
81
            $clause .= " AND pdb.datname NOT IN {$not_in} ";
82
        }
83
84
        if ($currentdatabase != null) {
85
            $this->clean($currentdatabase);
86
            $orderby = "ORDER BY pdb.datname = '{$currentdatabase}' DESC, pdb.datname";
87
        } else {
88
            $orderby = 'ORDER BY pdb.datname';
89
        }
90
91
        if (!$conf['show_system']) {
92
            $where = ' AND NOT pdb.datistemplate';
93
        } else {
94
            $where = ' AND pdb.datallowconn';
95
        }
96
97
        $sql = "
98
            SELECT pdb.datname AS datname,
99
                    pr.rolname AS datowner,
100
                    pg_encoding_to_char(encoding) AS datencoding,
101
                    (SELECT description FROM pg_catalog.pg_shdescription pd WHERE pdb.oid=pd.objoid AND pd.classoid='pg_database'::regclass) AS datcomment,
102
                    (SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=pdb.dattablespace) AS tablespace,
103
                CASE WHEN pg_catalog.has_database_privilege(current_user, pdb.oid, 'CONNECT')
104
                    THEN pg_catalog.pg_database_size(pdb.oid)
105
                    ELSE -1 -- set this magic value, which we will convert to no access later
106
                END as dbsize,
107
                pdb.datcollate,
108
                pdb.datctype
109
            FROM pg_catalog.pg_database pdb
110
            LEFT JOIN pg_catalog.pg_roles pr ON (pdb.datdba = pr.oid)
111
            WHERE true
112
                {$where}
113
                {$clause}
114
            {$orderby}";
115
116
        return $this->selectSet($sql);
117
    }
118
119
    /**
120
     * Return the database comment of a db from the shared description table.
121
     *
122
     * @param string $database the name of the database to get the comment for
123
     *
124
     * @return \PHPPgAdmin\ADORecordSet recordset of the db comment info
125
     */
126
    public function getDatabaseComment($database)
127
    {
128
        $this->clean($database);
129
        $sql = "SELECT description
130
                FROM pg_catalog.pg_database
131
                JOIN pg_catalog.pg_shdescription
132
                ON (oid=objoid AND classoid='pg_database'::regclass)
133
                WHERE pg_database.datname = '{$database}' ";
134
135
        return $this->selectSet($sql);
136
    }
137
138
    /**
139
     * Return the database owner of a db.
140
     *
141
     * @param string $database the name of the database to get the owner for
142
     *
143
     * @return \PHPPgAdmin\ADORecordSet recordset of the db owner info
144
     */
145
    public function getDatabaseOwner($database)
146
    {
147
        $this->clean($database);
148
        $sql = "SELECT usename FROM pg_user, pg_database WHERE pg_user.usesysid = pg_database.datdba AND pg_database.datname = '{$database}' ";
149
150
        return $this->selectSet($sql);
151
    }
152
153
    // Help functions
154
155
    // Database functions
156
157
    /**
158
     * Returns the current database encoding.
159
     *
160
     * @return string The encoding.  eg. SQL_ASCII, UTF-8, etc.
161
     */
162
    public function getDatabaseEncoding()
163
    {
164
        return pg_parameter_status($this->conn->_connectionID, 'server_encoding');
165
    }
166
167
    /**
168
     * Creates a database.
169
     *
170
     * @param string $database   The name of the database to create
171
     * @param string $encoding   Encoding of the database
172
     * @param string $tablespace (optional) The tablespace name
173
     * @param string $comment
174
     * @param string $template
175
     * @param string $lc_collate
176
     * @param string $lc_ctype
177
     *
178
     * @return int 0 success
179
     */
180
    public function createDatabase(
181
        $database,
182
        $encoding,
183
        $tablespace = '',
184
        $comment = '',
185
        $template = 'template1',
186
        $lc_collate = '',
187
        $lc_ctype = ''
188
    ) {
189
        $this->fieldClean($database);
190
        $this->clean($encoding);
191
        $this->fieldClean($tablespace);
192
        $this->fieldClean($template);
193
        $this->clean($lc_collate);
194
        $this->clean($lc_ctype);
195
196
        $sql = "CREATE DATABASE \"{$database}\" WITH TEMPLATE=\"{$template}\"";
197
198
        if ($encoding != '') {
199
            $sql .= " ENCODING='{$encoding}'";
200
        }
201
202
        if ($lc_collate != '') {
203
            $sql .= " LC_COLLATE='{$lc_collate}'";
204
        }
205
206
        if ($lc_ctype != '') {
207
            $sql .= " LC_CTYPE='{$lc_ctype}'";
208
        }
209
210
        if ($tablespace != '' && $this->hasTablespaces()) {
211
            $sql .= " TABLESPACE \"{$tablespace}\"";
212
        }
213
214
        $status = $this->execute($sql);
215
        if ($status != 0) {
216
            return -1;
217
        }
218
219
        if ($comment != '' && $this->hasSharedComments()) {
0 ignored issues
show
Bug introduced by
It seems like hasSharedComments() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

219
        if ($comment != '' && $this->/** @scrutinizer ignore-call */ hasSharedComments()) {
Loading history...
220
            $status = $this->setComment('DATABASE', $database, '', $comment);
221
            if ($status != 0) {
222
                return -2;
223
            }
224
        }
225
226
        return 0;
227
    }
228
229
    /**
230
     * Drops a database.
231
     *
232
     * @param string $database The name of the database to drop
233
     *
234
     * @return int 0 if operation was successful
235
     */
236
    public function dropDatabase($database)
237
    {
238
        $this->fieldClean($database);
239
        $sql = "DROP DATABASE \"{$database}\"";
240
241
        return $this->execute($sql);
242
    }
243
244
    /**
245
     * Alters a database
246
     * the multiple return vals are for postgres 8+ which support more functionality in alter database.
247
     *
248
     * @param string $dbName   The name of the database
249
     * @param string $newName  new name for the database
250
     * @param string $newOwner The new owner for the database
251
     * @param string $comment
252
     *
253
     * @return bool|int 0 success
254
     */
255
    public function alterDatabase($dbName, $newName, $newOwner = '', $comment = '')
256
    {
257
        $status = $this->beginTransaction();
258
        if ($status != 0) {
259
            $this->rollbackTransaction();
260
261
            return -1;
262
        }
263
264
        if ($dbName != $newName) {
265
            $status = $this->alterDatabaseRename($dbName, $newName);
266
            if ($status != 0) {
267
                $this->rollbackTransaction();
268
269
                return -3;
270
            }
271
            $dbName = $newName;
272
        }
273
274
        if ($newOwner != '') {
275
            $status = $this->alterDatabaseOwner($newName, $newOwner);
276
            if ($status != 0) {
277
                $this->rollbackTransaction();
278
279
                return -2;
280
            }
281
        }
282
283
        $this->fieldClean($dbName);
284
        $status = $this->setComment('DATABASE', $dbName, '', $comment);
285
        if ($status != 0) {
286
            $this->rollbackTransaction();
287
288
            return -4;
289
        }
290
291
        return $this->endTransaction();
292
    }
293
294
    /**
295
     * Renames a database, note that this operation cannot be
296
     * performed on a database that is currently being connected to.
297
     *
298
     * @param string $oldName name of database to rename
299
     * @param string $newName new name of database
300
     *
301
     * @return int 0 on success
302
     */
303
    public function alterDatabaseRename($oldName, $newName)
304
    {
305
        $this->fieldClean($oldName);
306
        $this->fieldClean($newName);
307
308
        if ($oldName != $newName) {
309
            $sql = "ALTER DATABASE \"{$oldName}\" RENAME TO \"{$newName}\"";
310
311
            return $this->execute($sql);
312
        }
313
314
        return 0;
315
    }
316
317
    /**
318
     * Changes ownership of a database
319
     * This can only be done by a superuser or the owner of the database.
320
     *
321
     * @param string $dbName   database to change ownership of
322
     * @param string $newOwner user that will own the database
323
     *
324
     * @return int 0 on success
325
     */
326
    public function alterDatabaseOwner($dbName, $newOwner)
327
    {
328
        $this->fieldClean($dbName);
329
        $this->fieldClean($newOwner);
330
331
        $sql = "ALTER DATABASE \"{$dbName}\" OWNER TO \"{$newOwner}\"";
332
333
        return $this->execute($sql);
334
    }
335
336
    /**
337
     * Returns prepared transactions information.
338
     *
339
     * @param null|string $database (optional) Find only prepared transactions executed in a specific database
340
     *
341
     * @return \PHPPgAdmin\ADORecordSet A recordset
342
     */
343
    public function getPreparedXacts($database = null)
344
    {
345
        if ($database === null) {
346
            $sql = 'SELECT * FROM pg_prepared_xacts';
347
        } else {
348
            $this->clean($database);
349
            $sql = "SELECT transaction, gid, prepared, owner FROM pg_prepared_xacts
350
                WHERE database='{$database}' ORDER BY owner";
351
        }
352
353
        return $this->selectSet($sql);
354
    }
355
356
    /**
357
     * Returns all available process information.
358
     *
359
     * @param null|string $database (optional) Find only connections to specified database
360
     *
361
     * @return \PHPPgAdmin\ADORecordSet A recordset
362
     */
363
    public function getProcesses($database = null)
364
    {
365
        if ($database === null) {
366
            $sql = "SELECT datname, usename, pid, waiting, state_change as query_start,
367
                  case when state='idle in transaction' then '<IDLE> in transaction' when state = 'idle' then '<IDLE>' else query end as query
368
                FROM pg_catalog.pg_stat_activity
369
                ORDER BY datname, usename, pid";
370
        } else {
371
            $this->clean($database);
372
            $sql = "SELECT datname, usename, pid, waiting, state_change as query_start,
373
                  case when state='idle in transaction' then '<IDLE> in transaction' when state = 'idle' then '<IDLE>' else query end as query
374
                FROM pg_catalog.pg_stat_activity
375
                WHERE datname='{$database}'
376
                ORDER BY usename, pid";
377
        }
378
379
        return $this->selectSet($sql);
380
    }
381
382
    // interfaces Statistics collector functions
383
384
    /**
385
     * Returns table locks information in the current database.
386
     *
387
     * @return \PHPPgAdmin\ADORecordSet A recordset
388
     */
389
    public function getLocks()
390
    {
391
        $conf = $this->conf;
392
393
        if (!$conf['show_system']) {
394
            $where = 'AND pn.nspname NOT LIKE $$pg\_%$$';
395
        } else {
396
            $where = "AND nspname !~ '^pg_t(emp_[0-9]+|oast)$'";
397
        }
398
399
        $sql = "
400
            SELECT
401
                pn.nspname, pc.relname AS tablename, pl.pid, pl.mode, pl.granted, pl.virtualtransaction,
402
                (select transactionid from pg_catalog.pg_locks l2 where l2.locktype='transactionid'
403
                    and l2.mode='ExclusiveLock' and l2.virtualtransaction=pl.virtualtransaction) as transaction
404
            FROM
405
                pg_catalog.pg_locks pl,
406
                pg_catalog.pg_class pc,
407
                pg_catalog.pg_namespace pn
408
            WHERE
409
                pl.relation = pc.oid AND pc.relnamespace=pn.oid
410
            {$where}
411
            ORDER BY pid,nspname,tablename";
412
413
        return $this->selectSet($sql);
414
    }
415
416
    /**
417
     * Sends a cancel or kill command to a process.
418
     *
419
     * @param int    $pid    The ID of the backend process
420
     * @param string $signal 'CANCEL' or 'KILL'
421
     *
422
     * @return int 0 success
423
     */
424
    public function sendSignal($pid, $signal)
425
    {
426
        // Clean
427
        $pid = (int) $pid;
428
429
        if ($signal == 'CANCEL') {
430
            $sql = "SELECT pg_catalog.pg_cancel_backend({$pid}) AS val";
431
        } elseif ($signal == 'KILL') {
432
            $sql = "SELECT pg_catalog.pg_terminate_backend({$pid}) AS val";
433
        } else {
434
            return -1;
435
        }
436
437
        // Execute the query
438
        $val = $this->selectField($sql, 'val');
0 ignored issues
show
Bug introduced by
The method selectField() does not exist on PHPPgAdmin\Traits\DatabaseTrait. Did you maybe mean selectSet()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

438
        /** @scrutinizer ignore-call */ 
439
        $val = $this->selectField($sql, 'val');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
439
440
        if ($val === 'f') {
441
            return -1;
442
        }
443
444
        if ($val === 't') {
445
            return 0;
446
        }
447
448
        return -1;
449
    }
450
451
    /**
452
     * Vacuums a database.
453
     *
454
     * @param string $table   The table to vacuum
455
     * @param bool   $analyze If true, also does analyze
456
     * @param bool   $full    If true, selects "full" vacuum
457
     * @param bool   $freeze  If true, selects aggressive "freezing" of tuples
458
     *
459
     * @return bool 0 if successful
460
     */
461
    public function vacuumDB($table = '', $analyze = false, $full = false, $freeze = false)
462
    {
463
        $sql = 'VACUUM';
464
        if ($full) {
465
            $sql .= ' FULL';
466
        }
467
468
        if ($freeze) {
469
            $sql .= ' FREEZE';
470
        }
471
472
        if ($analyze) {
473
            $sql .= ' ANALYZE';
474
        }
475
476
        if ($table != '') {
477
            $f_schema = $this->_schema;
478
            $this->fieldClean($f_schema);
479
            $this->fieldClean($table);
480
            $sql .= " \"{$f_schema}\".\"{$table}\"";
481
        }
482
483
        return $this->execute($sql);
484
    }
485
486
    /**
487
     * Returns all autovacuum global configuration.
488
     *
489
     * @return array associative array array( param => value, ...)
490
     */
491
    public function getAutovacuum()
492
    {
493
        $_defaults = $this->selectSet(
494
            "SELECT name, setting
495
            FROM pg_catalog.pg_settings
496
            WHERE
497
                name = 'autovacuum'
498
                OR name = 'autovacuum_vacuum_threshold'
499
                OR name = 'autovacuum_vacuum_scale_factor'
500
                OR name = 'autovacuum_analyze_threshold'
501
                OR name = 'autovacuum_analyze_scale_factor'
502
                OR name = 'autovacuum_vacuum_cost_delay'
503
                OR name = 'autovacuum_vacuum_cost_limit'
504
                OR name = 'vacuum_freeze_min_age'
505
                OR name = 'autovacuum_freeze_max_age'
506
            "
507
        );
508
509
        $ret = [];
510
        while (!$_defaults->EOF) {
511
            $ret[$_defaults->fields['name']] = $_defaults->fields['setting'];
512
            $_defaults->moveNext();
513
        }
514
515
        return $ret;
516
    }
517
518
    /**
519
     * Returns all available variable information.
520
     *
521
     * @return \PHPPgAdmin\ADORecordSet A recordset
522
     */
523
    public function getVariables()
524
    {
525
        $sql = 'SHOW ALL';
526
527
        return $this->selectSet($sql);
528
    }
529
530
    abstract public function fieldClean(&$str);
531
532
    abstract public function beginTransaction();
533
534
    abstract public function rollbackTransaction();
535
536
    abstract public function endTransaction();
537
538
    abstract public function execute($sql);
539
540
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
541
542
    abstract public function selectSet($sql);
543
544
    abstract public function clean(&$str);
545
546
    abstract public function phpBool($parameter);
547
548
    abstract public function hasCreateTableLikeWithConstraints();
549
550
    abstract public function hasCreateTableLikeWithIndexes();
551
552
    abstract public function hasTablespaces();
553
554
    abstract public function delete($table, $conditions, $schema = '');
555
556
    abstract public function fieldArrayClean(&$arr);
557
558
    abstract public function hasCreateFieldWithConstraints();
559
560
    abstract public function getAttributeNames($table, $atts);
561
}
562