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

Postgres::getPrivileges()   C

Complexity

Conditions 14
Paths 28

Size

Total Lines 66
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 66
rs 5.8815
c 0
b 0
f 0
cc 14
eloc 41
nc 28
nop 3

How to fix   Long Method    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\Database;
8
9
/**
10
 * A Class that implements the DB Interface for Postgres
11
 * Note: This Class uses ADODB and returns RecordSets.
12
 *
13
 * Id: Postgres.php,v 1.320 2008/02/20 20:43:09 ioguix Exp $
14
 *
15
 * @package PHPPgAdmin
16
 */
17
class Postgres extends ADOdbBase
18
{
19
    use \PHPPgAdmin\Traits\HelperTrait;
20
    use \PHPPgAdmin\Traits\SequenceTrait;
21
    use \PHPPgAdmin\Traits\ViewTrait;
22
    use \PHPPgAdmin\Traits\IndexTrait;
23
    use \PHPPgAdmin\Traits\RoleTrait;
24
    use \PHPPgAdmin\Traits\AggregateTrait;
25
    use \PHPPgAdmin\Traits\TableTrait;
26
    use \PHPPgAdmin\Traits\DomainTrait;
27
    use \PHPPgAdmin\Traits\FtsTrait;
28
    use \PHPPgAdmin\Traits\FunctionTrait;
29
    use \PHPPgAdmin\Traits\DatabaseTrait;
30
    use \PHPPgAdmin\Traits\SchemaTrait;
31
    use \PHPPgAdmin\Traits\TypeTrait;
32
    use \PHPPgAdmin\Traits\TablespaceTrait;
33
    use \PHPPgAdmin\Traits\OperatorTrait;
34
35
    public $lang;
36
    public $conf;
37
    protected $container;
38
    protected $server_info;
39
40
    public function __construct(&$conn, $container, $server_info)
41
    {
42
        //$this->prtrace('major_version :' . $this->major_version);
43
        $this->conn      = $conn;
44
        $this->container = $container;
45
46
        $this->lang        = $container->get('lang');
47
        $this->conf        = $container->get('conf');
48
        $this->server_info = $server_info;
49
    }
50
51
    /**
52
     * Fetch a URL (or array of URLs) for a given help page.
53
     *
54
     * @param string $help
55
     *
56
     * @return null|array|string the help page or pages related to the $help topic, or null if none exists
57
     */
58
    public function getHelp($help)
59
    {
60
        $this->getHelpPages();
61
62
        if (isset($this->help_page[$help])) {
63
            if (is_array($this->help_page[$help])) {
64
                $urls = [];
65
                foreach ($this->help_page[$help] as $link) {
66
                    $urls[] = $this->help_base.$link;
67
                }
68
69
                return $urls;
70
            }
71
72
            return $this->help_base.$this->help_page[$help];
73
        }
74
75
        return null;
76
    }
77
78
    /**
79
     * Gets the help pages.
80
     * get help page by instancing the corresponding help class
81
     * if $this->help_page and $this->help_base are set, this function is a noop.
82
     */
83
    public function getHelpPages()
84
    {
85
        if ($this->help_page === null || $this->help_base === null) {
86
            $help_classname = '\PHPPgAdmin\Help\PostgresDoc'.str_replace('.', '', $this->major_version);
87
88
            $help_class = new $help_classname($this->conf, $this->major_version);
89
90
            $this->help_base = $help_class->getHelpBase();
91
        }
92
    }
93
94
    // Formatting functions
95
96
    /**
97
     * Outputs the HTML code for a particular field.
98
     *
99
     * @param string $name   The name to give the field
100
     * @param mixed  $value  The value of the field.  Note this could be 'numeric(7,2)' sort of thing...
101
     * @param string $type   The database type of the field
102
     * @param array  $extras An array of attributes name as key and attributes' values as value
103
     */
104
    public function printField($name, $value, $type, $extras = [])
105
    {
106
        $lang = $this->lang;
107
108
        // Determine actions string
109
        $extra_str = '';
110
        foreach ($extras as $k => $v) {
111
            $extra_str .= " {$k}=\"".htmlspecialchars($v).'"';
112
        }
113
114
        switch (substr($type, 0, 9)) {
115
            case 'bool':
116
            case 'boolean':
117
                if ($value !== null && $value == '') {
118
                    $value = null;
119
                } elseif ($value == 'true') {
120
                    $value = 't';
121
                } elseif ($value == 'false') {
122
                    $value = 'f';
123
                }
124
125
                // If value is null, 't' or 'f'...
126
                if ($value === null || $value == 't' || $value == 'f') {
127
                    echo '<select name="', htmlspecialchars($name), "\"{$extra_str}>\n";
128
                    echo '<option value=""', ($value === null) ? ' selected="selected"' : '', "></option>\n";
129
                    echo '<option value="t"', ($value == 't') ? ' selected="selected"' : '', ">{$lang['strtrue']}</option>\n";
130
                    echo '<option value="f"', ($value == 'f') ? ' selected="selected"' : '', ">{$lang['strfalse']}</option>\n";
131
                    echo "</select>\n";
132
                } else {
133
                    echo '<input name="', htmlspecialchars($name), '" value="', htmlspecialchars($value), "\" size=\"35\"{$extra_str} />\n";
134
                }
135
136
                break;
137
            case 'bytea':
138
            case 'bytea[]':
139
                if (!is_null($value)) {
140
                    $value = $this->escapeBytea($value);
141
                }
142
            // no break
143
            case 'text':
144
            case 'text[]':
145
            case 'json':
146
            case 'jsonb':
147
            case 'xml':
148
            case 'xml[]':
149
                $n = substr_count($value, "\n");
150
                $n = $n < 5 ? max(2, $n) : $n;
151
                $n = $n > 20 ? 20 : $n;
152
                echo '<textarea name="', htmlspecialchars($name), "\" rows=\"{$n}\" cols=\"85\"{$extra_str}>\n";
153
                echo htmlspecialchars($value);
154
                echo "</textarea>\n";
155
156
                break;
157
            case 'character':
158
            case 'character[]':
159
                $n = substr_count($value, "\n");
160
                $n = $n < 5 ? 5 : $n;
161
                $n = $n > 20 ? 20 : $n;
162
                echo '<textarea name="', htmlspecialchars($name), "\" rows=\"{$n}\" cols=\"35\"{$extra_str}>\n";
163
                echo htmlspecialchars($value);
164
                echo "</textarea>\n";
165
166
                break;
167
            default:
168
                echo '<input name="', htmlspecialchars($name), '" value="', htmlspecialchars($value), "\" size=\"35\"{$extra_str} />\n";
169
170
                break;
171
        }
172
    }
173
174
    /**
175
     * Determines whether or not a user is a super user.
176
     *
177
     * @param string $username The username of the user
178
     *
179
     * @return bool true if is a super user, false otherwise
180
     */
181
    public function isSuperUser($username = '')
182
    {
183
        $this->clean($username);
184
185
        if (empty($username)) {
186
            $val = pg_parameter_status($this->conn->_connectionID, 'is_superuser');
187
            if ($val !== false) {
188
                return $val == 'on';
189
            }
190
        }
191
192
        $sql = "SELECT usesuper FROM pg_user WHERE usename='{$username}'";
193
194
        $usesuper = $this->selectField($sql, 'usesuper');
195
        if ($usesuper == -1) {
196
            return false;
197
        }
198
199
        return $usesuper == 't';
200
    }
201
202
    /**
203
     * Returns the current default_with_oids setting.
204
     *
205
     * @return string default_with_oids setting
206
     */
207
    public function getDefaultWithOid()
208
    {
209
        $sql = 'SHOW default_with_oids';
210
211
        return $this->selectField($sql, 'default_with_oids');
212
    }
213
214
    /**
215
     * Cleans (escapes) an object name (eg. table, field).
216
     *
217
     * @param null|string $str The string to clean, by reference
218
     *
219
     * @return null|string The cleaned string
220
     */
221
    public function fieldClean(&$str)
222
    {
223
        if (!$str) {
224
            return null;
225
        }
226
227
        $str = str_replace('"', '""', $str);
228
229
        return $str;
230
    }
231
232
    /**
233
     * Searches all system catalogs to find objects that match a certain name.
234
     *
235
     * @param string $term   The search term
236
     * @param string $filter The object type to restrict to ('' means no restriction)
237
     *
238
     * @return \PHPPgAdmin\ADORecordSet A recordset
239
     */
240
    public function findObject($term, $filter)
241
    {
242
        $conf = $this->conf;
243
244
        /*about escaping:
245
         * SET standard_conforming_string is not available before 8.2
246
         * So we must use PostgreSQL specific notation :/
247
         * E'' notation is not available before 8.1
248
         * $$ is available since 8.0
249
         * Nothing specific from 7.4
250
         */
251
252
        // Escape search term for ILIKE match
253
        $this->clean($term);
254
        $this->clean($filter);
255
        $term = str_replace('_', '\_', $term);
256
        $term = str_replace('%', '\%', $term);
257
258
        // Exclude system relations if necessary
259
        if (!$conf['show_system']) {
260
            // XXX: The mention of information_schema here is in the wrong place, but
261
            // it's the quickest fix to exclude the info schema from 7.4
262
            $where     = " AND pn.nspname NOT LIKE \$_PATERN_\$pg\\_%\$_PATERN_\$ AND pn.nspname != 'information_schema'";
263
            $lan_where = 'AND pl.lanispl';
264
        } else {
265
            $where     = '';
266
            $lan_where = '';
267
        }
268
269
        // Apply outer filter
270
        $sql = '';
271
        if ($filter != '') {
272
            $sql = 'SELECT * FROM (';
273
        }
274
275
        $term = "\$_PATERN_\$%{$term}%\$_PATERN_\$";
276
277
        $sql .= "
278
			SELECT 'SCHEMA' AS type, oid, NULL AS schemaname, NULL AS relname, nspname AS name
279
				FROM pg_catalog.pg_namespace pn WHERE nspname ILIKE {$term} {$where}
280
			UNION ALL
281
			SELECT CASE WHEN relkind='r' THEN 'TABLE' WHEN relkind='v' THEN 'VIEW' WHEN relkind='S' THEN 'SEQUENCE' END, pc.oid,
282
				pn.nspname, NULL, pc.relname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn
283
				WHERE pc.relnamespace=pn.oid AND relkind IN ('r', 'v', 'S') AND relname ILIKE {$term} {$where}
284
			UNION ALL
285
			SELECT CASE WHEN pc.relkind='r' THEN 'COLUMNTABLE' ELSE 'COLUMNVIEW' END, NULL, pn.nspname, pc.relname, pa.attname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
286
				pg_catalog.pg_attribute pa WHERE pc.relnamespace=pn.oid AND pc.oid=pa.attrelid
287
				AND pa.attname ILIKE {$term} AND pa.attnum > 0 AND NOT pa.attisdropped AND pc.relkind IN ('r', 'v') {$where}
288
			UNION ALL
289
			SELECT 'FUNCTION', pp.oid, pn.nspname, NULL, pp.proname || '(' || pg_catalog.oidvectortypes(pp.proargtypes) || ')' FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pn
290
				WHERE pp.pronamespace=pn.oid AND NOT pp.proisagg AND pp.proname ILIKE {$term} {$where}
291
			UNION ALL
292
			SELECT 'INDEX', NULL, pn.nspname, pc.relname, pc2.relname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
293
				pg_catalog.pg_index pi, pg_catalog.pg_class pc2 WHERE pc.relnamespace=pn.oid AND pc.oid=pi.indrelid
294
				AND pi.indexrelid=pc2.oid
295
				AND NOT EXISTS (
296
					SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
297
					ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
298
					WHERE d.classid = pc2.tableoid AND d.objid = pc2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
299
				)
300
				AND pc2.relname ILIKE {$term} {$where}
301
			UNION ALL
302
			SELECT 'CONSTRAINTTABLE', NULL, pn.nspname, pc.relname, pc2.conname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
303
				pg_catalog.pg_constraint pc2 WHERE pc.relnamespace=pn.oid AND pc.oid=pc2.conrelid AND pc2.conrelid != 0
304
				AND CASE WHEN pc2.contype IN ('f', 'c') THEN TRUE ELSE NOT EXISTS (
305
					SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
306
					ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
307
					WHERE d.classid = pc2.tableoid AND d.objid = pc2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p')
308
				) END
309
				AND pc2.conname ILIKE {$term} {$where}
310
			UNION ALL
311
			SELECT 'CONSTRAINTDOMAIN', pt.oid, pn.nspname, pt.typname, pc.conname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn,
312
				pg_catalog.pg_constraint pc WHERE pt.typnamespace=pn.oid AND pt.oid=pc.contypid AND pc.contypid != 0
313
				AND pc.conname ILIKE {$term} {$where}
314
			UNION ALL
315
			SELECT 'TRIGGER', NULL, pn.nspname, pc.relname, pt.tgname FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pn,
316
				pg_catalog.pg_trigger pt WHERE pc.relnamespace=pn.oid AND pc.oid=pt.tgrelid
317
					AND ( pt.tgconstraint = 0 OR NOT EXISTS
318
					(SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c
319
					ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
320
					WHERE d.classid = pt.tableoid AND d.objid = pt.oid AND d.deptype = 'i' AND c.contype = 'f'))
321
				AND pt.tgname ILIKE {$term} {$where}
322
			UNION ALL
323
			SELECT 'RULETABLE', NULL, pn.nspname AS schemaname, c.relname AS tablename, r.rulename FROM pg_catalog.pg_rewrite r
324
				JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
325
				LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = c.relnamespace
326
				WHERE c.relkind='r' AND r.rulename != '_RETURN' AND r.rulename ILIKE {$term} {$where}
327
			UNION ALL
328
			SELECT 'RULEVIEW', NULL, pn.nspname AS schemaname, c.relname AS tablename, r.rulename FROM pg_catalog.pg_rewrite r
329
				JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
330
				LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = c.relnamespace
331
				WHERE c.relkind='v' AND r.rulename != '_RETURN' AND r.rulename ILIKE {$term} {$where}
332
		";
333
334
        //\Kint::dump($sql);
335
336
        // Add advanced objects if show_advanced is set
337
        if ($conf['show_advanced']) {
338
            $sql .= "
339
				UNION ALL
340
				SELECT CASE WHEN pt.typtype='d' THEN 'DOMAIN' ELSE 'TYPE' END, pt.oid, pn.nspname, NULL,
341
					pt.typname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn
342
					WHERE pt.typnamespace=pn.oid AND typname ILIKE {$term}
343
					AND (pt.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = pt.typrelid))
344
					{$where}
345
			 	UNION ALL
346
				SELECT 'OPERATOR', po.oid, pn.nspname, NULL, po.oprname FROM pg_catalog.pg_operator po, pg_catalog.pg_namespace pn
347
					WHERE po.oprnamespace=pn.oid AND oprname ILIKE {$term} {$where}
348
				UNION ALL
349
				SELECT 'CONVERSION', pc.oid, pn.nspname, NULL, pc.conname FROM pg_catalog.pg_conversion pc,
350
					pg_catalog.pg_namespace pn WHERE pc.connamespace=pn.oid AND conname ILIKE {$term} {$where}
351
				UNION ALL
352
				SELECT 'LANGUAGE', pl.oid, NULL, NULL, pl.lanname FROM pg_catalog.pg_language pl
353
					WHERE lanname ILIKE {$term} {$lan_where}
354
				UNION ALL
355
				SELECT DISTINCT ON (p.proname) 'AGGREGATE', p.oid, pn.nspname, NULL, p.proname FROM pg_catalog.pg_proc p
356
					LEFT JOIN pg_catalog.pg_namespace pn ON p.pronamespace=pn.oid
357
					WHERE p.proisagg AND p.proname ILIKE {$term} {$where}
358
				UNION ALL
359
				SELECT DISTINCT ON (po.opcname) 'OPCLASS', po.oid, pn.nspname, NULL, po.opcname FROM pg_catalog.pg_opclass po,
360
					pg_catalog.pg_namespace pn WHERE po.opcnamespace=pn.oid
361
					AND po.opcname ILIKE {$term} {$where}
362
			";
363
        } else {
364
            // Otherwise just add domains
365
            $sql .= "
366
				UNION ALL
367
				SELECT 'DOMAIN', pt.oid, pn.nspname, NULL,
368
					pt.typname FROM pg_catalog.pg_type pt, pg_catalog.pg_namespace pn
369
					WHERE pt.typnamespace=pn.oid AND pt.typtype='d' AND typname ILIKE {$term}
370
					AND (pt.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = pt.typrelid))
371
					{$where}
372
			";
373
        }
374
375
        if ($filter != '') {
376
            // We use like to make RULE, CONSTRAINT and COLUMN searches work
377
            $sql .= ") AS sub WHERE type LIKE '{$filter}%' ";
378
        }
379
380
        $sql .= 'ORDER BY type, schemaname, relname, name';
381
382
        return $this->selectSet($sql);
383
    }
384
385
    /**
386
     * Given an array of attnums and a relation, returns an array mapping
387
     * attribute number to attribute name.
388
     *
389
     * @param string $table The table to get attributes for
390
     * @param array  $atts  An array of attribute numbers
391
     *
392
     * @return array|int An array mapping attnum to attname or error code
393
     *                   - -1 $atts must be an array
394
     *                   - -2 wrong number of attributes found
395
     */
396
    public function getAttributeNames($table, $atts)
397
    {
398
        $c_schema = $this->_schema;
399
        $this->clean($c_schema);
400
        $this->clean($table);
401
        $this->arrayClean($atts);
402
403
        if (!is_array($atts)) {
404
            return -1;
405
        }
406
407
        if (sizeof($atts) == 0) {
408
            return [];
409
        }
410
411
        $sql = "SELECT attnum, attname FROM pg_catalog.pg_attribute WHERE
412
			attrelid=(SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}' AND
413
			relnamespace=(SELECT oid FROM pg_catalog.pg_namespace WHERE nspname='{$c_schema}'))
414
			AND attnum IN ('".join("','", $atts)."')";
415
416
        $rs = $this->selectSet($sql);
417
        if ($rs->RecordCount() != sizeof($atts)) {
418
            return -2;
419
        }
420
421
        $temp = [];
422
        while (!$rs->EOF) {
423
            $temp[$rs->fields['attnum']] = $rs->fields['attname'];
424
            $rs->moveNext();
425
        }
426
427
        return $temp;
428
    }
429
430
    /**
431
     * Cleans (escapes) an array.
432
     *
433
     * @param array $arr The array to clean, by reference
434
     *
435
     * @return array The cleaned array
436
     */
437
    public function arrayClean(&$arr)
438
    {
439
        foreach ($arr as $k => $v) {
440
            if ($v === null) {
441
                continue;
442
            }
443
444
            $arr[$k] = pg_escape_string($v);
445
        }
446
447
        return $arr;
448
    }
449
450
    /**
451
     * Grabs an array of users and their privileges for an object,
452
     * given its type.
453
     *
454
     * @param string      $object The name of the object whose privileges are to be retrieved
455
     * @param string      $type   The type of the object (eg. database, schema, relation, function or language)
456
     * @param null|string $table  Optional, column's table if type = column
457
     *
458
     * @return array|int Privileges array or error code
459
     *                   - -1         invalid type
460
     *                   - -2         object not found
461
     *                   - -3         unknown privilege type
462
     */
463
    public function getPrivileges($object, $type, $table = null)
464
    {
465
        $c_schema = $this->_schema;
466
        $this->clean($c_schema);
467
        $this->clean($object);
468
469
        switch ($type) {
470
            case 'column':
471
                $this->clean($table);
472
                $sql = "
473
					SELECT E'{' || pg_catalog.array_to_string(attacl, E',') || E'}' as acl
474
					FROM pg_catalog.pg_attribute a
475
						LEFT JOIN pg_catalog.pg_class c ON (a.attrelid = c.oid)
476
						LEFT JOIN pg_catalog.pg_namespace n ON (c.relnamespace=n.oid)
477
					WHERE n.nspname='{$c_schema}'
478
						AND c.relname='{$table}'
479
						AND a.attname='{$object}'";
480
481
                break;
482
            case 'table':
483
            case 'view':
484
            case 'sequence':
485
                $sql = "
486
					SELECT relacl AS acl FROM pg_catalog.pg_class
487
					WHERE relname='{$object}'
488
						AND relnamespace=(SELECT oid FROM pg_catalog.pg_namespace
489
							WHERE nspname='{$c_schema}')";
490
491
                break;
492
            case 'database':
493
                $sql = "SELECT datacl AS acl FROM pg_catalog.pg_database WHERE datname='{$object}'";
494
495
                break;
496
            case 'function':
497
                // Since we fetch functions by oid, they are already constrained to
498
                // the current schema.
499
                $sql = "SELECT proacl AS acl FROM pg_catalog.pg_proc WHERE oid='{$object}'";
500
501
                break;
502
            case 'language':
503
                $sql = "SELECT lanacl AS acl FROM pg_catalog.pg_language WHERE lanname='{$object}'";
504
505
                break;
506
            case 'schema':
507
                $sql = "SELECT nspacl AS acl FROM pg_catalog.pg_namespace WHERE nspname='{$object}'";
508
509
                break;
510
            case 'tablespace':
511
                $sql = "SELECT spcacl AS acl FROM pg_catalog.pg_tablespace WHERE spcname='{$object}'";
512
513
                break;
514
            default:
515
                return -1;
516
        }
517
518
        // Fetch the ACL for object
519
        $acl = $this->selectField($sql, 'acl');
520
        if ($acl == -1) {
521
            return -2;
522
        }
523
524
        if ($acl == '' || $acl === null || !(bool) $acl) {
525
            return [];
526
        }
527
528
        return $this->parseACL($acl);
529
    }
530
531
    /**
532
     * Internal function used for parsing ACLs.
533
     *
534
     * @param string $acl The ACL to parse (of type aclitem[])
535
     *
536
     * @return array|int Privileges array or integer with error code
537
     *
538
     * @internal bool $in_quotes toggles acl in_quotes attribute
539
     */
540
    protected function parseACL($acl)
541
    {
542
        // Take off the first and last characters (the braces)
543
        $acl = substr($acl, 1, strlen($acl) - 2);
544
545
        // Pick out individual ACE's by carefully parsing.  This is necessary in order
546
        // to cope with usernames and stuff that contain commas
547
        $aces      = [];
548
        $i         = $j         = 0;
549
        $in_quotes = false;
550
        while ($i < strlen($acl)) {
551
            // If current char is a double quote and it's not escaped, then
552
            // enter quoted bit
553
            $char = substr($acl, $i, 1);
554
            if ($char == '"' && ($i == 0 || substr($acl, $i - 1, 1) != '\\')) {
555
                $in_quotes = !$in_quotes;
556
            } elseif ($char == ',' && !$in_quotes) {
557
                // Add text so far to the array
558
                $aces[] = substr($acl, $j, $i - $j);
559
                $j      = $i + 1;
560
            }
561
            ++$i;
562
        }
563
        // Add final text to the array
564
        $aces[] = substr($acl, $j);
565
566
        // Create the array to be returned
567
        $temp = [];
568
569
        // For each ACE, generate an entry in $temp
570
        foreach ($aces as $v) {
571
            // If the ACE begins with a double quote, strip them off both ends
572
            // and unescape backslashes and double quotes
573
            // $unquote = false;
574
            if (strpos($v, '"') === 0) {
575
                $v = substr($v, 1, strlen($v) - 2);
576
                $v = str_replace('\\"', '"', $v);
577
                $v = str_replace('\\\\', '\\', $v);
578
            }
579
580
            // Figure out type of ACE (public, user or group)
581
            if (strpos($v, '=') === 0) {
582
                $atype = 'public';
583
            } else {
584
                if ($this->hasRoles()) {
585
                    $atype = 'role';
586
                } else {
587
                    if (strpos($v, 'group ') === 0) {
588
                        $atype = 'group';
589
                        // Tear off 'group' prefix
590
                        $v = substr($v, 6);
591
                    } else {
592
                        $atype = 'user';
593
                    }
594
                }
595
            }
596
597
            // Break on unquoted equals sign...
598
            $i         = 0;
599
            $in_quotes = false;
600
            $entity    = null;
601
            $chars     = null;
602
            while ($i < strlen($v)) {
603
                // If current char is a double quote and it's not escaped, then
604
                // enter quoted bit
605
                $char      = substr($v, $i, 1);
606
                $next_char = substr($v, $i + 1, 1);
607
                if ($char == '"' && ($i == 0 || $next_char != '"')) {
608
                    $in_quotes = !$in_quotes;
609
                } elseif ($char == '"' && $next_char == '"') {
610
                    // Skip over escaped double quotes
611
                    ++$i;
612
                } elseif ($char == '=' && !$in_quotes) {
613
                    // Split on current equals sign
614
                    $entity = substr($v, 0, $i);
615
                    $chars  = substr($v, $i + 1);
616
617
                    break;
618
                }
619
                ++$i;
620
            }
621
622
            // Check for quoting on entity name, and unescape if necessary
623
            if (strpos($entity, '"') === 0) {
624
                $entity = substr($entity, 1, strlen($entity) - 2);
625
                $entity = str_replace('""', '"', $entity);
626
            }
627
628
            // New row to be added to $temp
629
            // (type, grantee, privileges, grantor, grant option?
630
            $row = [$atype, $entity, [], '', []];
631
632
            // Loop over chars and add privs to $row
633
            for ($i = 0; $i < strlen($chars); ++$i) {
634
                // Append to row's privs list the string representing
635
                // the privilege
636
                $char = substr($chars, $i, 1);
637
                if ($char == '*') {
638
                    $row[4][] = $this->privmap[substr($chars, $i - 1, 1)];
639
                } elseif ($char == '/') {
640
                    $grantor = substr($chars, $i + 1);
641
                    // Check for quoting
642
                    if (strpos($grantor, '"') === 0) {
643
                        $grantor = substr($grantor, 1, strlen($grantor) - 2);
644
                        $grantor = str_replace('""', '"', $grantor);
645
                    }
646
                    $row[3] = $grantor;
647
648
                    break;
649
                } else {
650
                    if (!isset($this->privmap[$char])) {
651
                        return -3;
652
                    }
653
654
                    $row[2][] = $this->privmap[$char];
655
                }
656
            }
657
658
            // Append row to temp
659
            $temp[] = $row;
660
        }
661
662
        return $temp;
663
    }
664
665
    /**
666
     * Gets all languages.
667
     *
668
     * @param bool $all True to get all languages, regardless of show_system
669
     *
670
     * @return \PHPPgAdmin\ADORecordSet A recordset
671
     */
672
    public function getLanguages($all = false)
673
    {
674
        $conf = $this->conf;
675
676
        if ($conf['show_system'] || $all) {
677
            $where = '';
678
        } else {
679
            $where = 'WHERE lanispl';
680
        }
681
682
        $sql = "
683
			SELECT
684
				lanname, lanpltrusted,
685
				lanplcallfoid::pg_catalog.regproc AS lanplcallf
686
			FROM
687
				pg_catalog.pg_language
688
			{$where}
689
			ORDER BY lanname
690
		";
691
692
        return $this->selectSet($sql);
693
    }
694
695
    /**
696
     * Executes an SQL script as a series of SQL statements.  Returns
697
     * the result of the final step.  This is a very complicated lexer
698
     * based on the REL7_4_STABLE src/bin/psql/mainloop.c lexer in
699
     * the PostgreSQL source code.
700
     * XXX: It does not handle multibyte languages properly.
701
     *
702
     * @param string        $name     Entry in $_FILES to use
703
     * @param null|callable $callback (optional) Callback function to call with each query, its result and line number
704
     *
705
     * @return bool true for general success, false on any failure
706
     */
707
    public function executeScript($name, $callback = null)
708
    {
709
        // This whole function isn't very encapsulated, but hey...
710
        $conn = $this->conn->_connectionID;
711
        if (!is_uploaded_file($_FILES[$name]['tmp_name'])) {
712
            return false;
713
        }
714
715
        $fd = fopen($_FILES[$name]['tmp_name'], 'rb');
716
        if ($fd === false) {
717
            return false;
718
        }
719
720
        // Build up each SQL statement, they can be multiline
721
        $query_buf    = null;
722
        $query_start  = 0;
723
        $in_quote     = 0;
724
        $in_xcomment  = 0;
725
        $bslash_count = 0;
726
        $dol_quote    = '';
727
        $paren_level  = 0;
728
        $len          = 0;
729
        $i            = 0;
730
        $prevlen      = 0;
731
        $thislen      = 0;
732
        $lineno       = 0;
733
734
        // Loop over each line in the file
735
        while (!feof($fd)) {
736
            $line = fgets($fd);
737
            ++$lineno;
738
739
            // Nothing left on line? Then ignore...
740
            if (trim($line) == '') {
741
                continue;
742
            }
743
744
            $len         = strlen($line);
745
            $query_start = 0;
746
747
            /**
748
             * Parse line, looking for command separators.
749
             *
750
             * The current character is at line[i], the prior character at line[i
751
             * - prevlen], the next character at line[i + thislen].
752
             */
753
            $prevlen = 0;
754
            $thislen = ($len > 0) ? 1 : 0;
755
756
            for ($i = 0; $i < $len; $this->advance_1($i, $prevlen, $thislen)) {
757
                /* was the previous character a backslash? */
758
                if ($i > 0 && substr($line, $i - $prevlen, 1) == '\\') {
759
                    $this->prtrace('bslash_count', $bslash_count, $line);
760
                    ++$bslash_count;
761
                } else {
762
                    $bslash_count = 0;
763
                }
764
765
                /*
766
                 * It is important to place the in_* test routines before the
767
                 * in_* detection routines. i.e. we have to test if we are in
768
                 * a quote before testing for comments.
769
                 */
770
771
                /* in quote? */
772
                if ($in_quote !== 0) {
773
                    //$this->prtrace('in_quote', $in_quote, $line);
774
                    /*
775
                     * end of quote if matching non-backslashed character.
776
                     * backslashes don't count for double quotes, though.
777
                     */
778
                    if (substr($line, $i, 1) == $in_quote &&
779
                        ($bslash_count % 2 == 0 || $in_quote == '"')
780
                    ) {
781
                        $in_quote = 0;
782
                    }
783
                } elseif ($dol_quote) {
784
                    $this->prtrace('dol_quote', $dol_quote, $line);
785
                    if (strncmp(substr($line, $i), $dol_quote, strlen($dol_quote)) == 0) {
786
                        $this->advance_1($i, $prevlen, $thislen);
787
                        while (substr($line, $i, 1) != '$') {
788
                            $this->advance_1($i, $prevlen, $thislen);
789
                        }
790
791
                        $dol_quote = '';
792
                    }
793
                } elseif (substr($line, $i, 2) == '/*') {
794
                    $this->prtrace('open_xcomment', $in_xcomment, $line, $i, $prevlen, $thislen);
795
                    if ($in_xcomment == 0) {
796
                        ++$in_xcomment;
797
                        $finishpos = strpos(substr($line, $i, $len), '*/');
798
                        if ($finishpos === false) {
799
                            $line = substr($line, 0, $i); /* remove comment */
800
                            break;
801
                        }
802
                        $pre         = substr($line, 0, $i);
803
                        $post        = substr($line, $i + 2 + $finishpos, $len);
804
                        $line        = $pre.' '.$post;
805
                        $in_xcomment = 0;
806
                        $i           = 0;
807
                    }
808
                } elseif ($in_xcomment) {
809
                    $position = strpos(substr($line, $i, $len), '*/');
810
                    if ($position === false) {
811
                        $line = '';
812
813
                        break;
814
                    }
815
816
                    $substr = substr($line, $i, 2);
817
818
                    if ($substr == '*/' && !--$in_xcomment) {
819
                        $line = substr($line, $i + 2, $len);
820
                        $i += 2;
821
                        $this->advance_1($i, $prevlen, $thislen);
822
                    }
823
                    // old logic
824
                    //  } else if (substr($line, $i, 2) == '/*') {
825
                    //      if ($in_xcomment == 0) {
826
                    //          ++$in_xcomment;
827
                    //          $this->advance_1($i, $prevlen, $thislen);
828
                    //      }
829
                    //  } else if ($in_xcomment) {
830
                    //      $substr = substr($line, $i, 2);
831
                    //      if ($substr == '*/' && !--$in_xcomment) {
832
                    //          $this->advance_1($i, $prevlen, $thislen);
833
                    //      }
834
                } elseif (substr($line, $i, 1) == '\'' || substr($line, $i, 1) == '"') {
835
                    $in_quote = substr($line, $i, 1);
836
                } elseif (!$dol_quote && $this->valid_dolquote(substr($line, $i))) {
837
                    $dol_end   = strpos(substr($line, $i + 1), '$');
838
                    $dol_quote = substr($line, $i, $dol_end + 1);
839
                    $this->advance_1($i, $prevlen, $thislen);
840
                    while (substr($line, $i, 1) != '$') {
841
                        $this->advance_1($i, $prevlen, $thislen);
842
                    }
843
                } else {
844
                    if (substr($line, $i, 2) == '--') {
845
                        $line = substr($line, 0, $i); /* remove comment */
846
                        break;
847
                    } /* count nested parentheses */
848
849
                    if (substr($line, $i, 1) == '(') {
850
                        ++$paren_level;
851
                    } elseif (substr($line, $i, 1) == ')' && $paren_level > 0) {
852
                        --$paren_level;
853
                    } elseif (substr($line, $i, 1) == ';' && !$bslash_count && !$paren_level) {
854
                        $subline = substr(substr($line, 0, $i), $query_start);
855
                        /*
856
                         * insert a cosmetic newline, if this is not the first
857
                         * line in the buffer
858
                         */
859
                        if (strlen($query_buf) > 0) {
860
                            $query_buf .= "\n";
861
                        }
862
863
                        /* append the line to the query buffer */
864
                        $query_buf .= $subline;
865
                        /* is there anything in the query_buf? */
866
                        if (trim($query_buf)) {
867
                            $query_buf .= ';';
868
869
                            // Execute the query. PHP cannot execute
870
                            // empty queries, unlike libpq
871
                            $res = @pg_query($conn, $query_buf);
872
873
                            // Call the callback function for display
874
                            if ($callback !== null) {
875
                                $callback($query_buf, $res, $lineno);
876
                            }
877
878
                            // Check for COPY request
879
                            if (pg_result_status($res) == 4) {
880
                                // 4 == PGSQL_COPY_FROM
881
                                while (!feof($fd)) {
882
                                    $copy = fgets($fd, 32768);
883
                                    ++$lineno;
884
                                    pg_put_line($conn, $copy);
885
                                    if ($copy == "\\.\n" || $copy == "\\.\r\n") {
886
                                        pg_end_copy($conn);
887
888
                                        break;
889
                                    }
890
                                }
891
                            }
892
                        }
893
                        $query_buf   = null;
894
                        $query_start = $i + $thislen;
895
                    } elseif (preg_match('/^[_[:alpha:]]$/', substr($line, $i, 1))) {
896
                        $sub = substr($line, $i, $thislen);
897
                        while (preg_match('/^[\$_A-Za-z0-9]$/', $sub)) {
898
                            /* keep going while we still have identifier chars */
899
                            $this->advance_1($i, $prevlen, $thislen);
900
                            $sub = substr($line, $i, $thislen);
901
                        }
902
                        // Since we're now over the next character to be examined, it is necessary
903
                        // to move back one space.
904
                        $i -= $prevlen;
905
                    }
906
                }
907
            } // end for
908
909
            /* Put the rest of the line in the query buffer. */
910
            $subline = substr($line, $query_start);
911
912
            if ($in_quote || $dol_quote || strspn($subline, " \t\n\r") != strlen($subline)) {
913
                if (strlen($query_buf) > 0) {
914
                    $query_buf .= "\n";
915
                }
916
917
                $query_buf .= $subline;
918
            }
919
920
            $line = null;
921
        } // end while
922
923
        /*
924
         * Process query at the end of file without a semicolon, so long as
925
         * it's non-empty.
926
         */
927
        if (strlen($query_buf) > 0 && strspn($query_buf, " \t\n\r") != strlen($query_buf)) {
928
            // Execute the query
929
            $res = @pg_query($conn, $query_buf);
930
931
            // Call the callback function for display
932
            if ($callback !== null) {
933
                $callback($query_buf, $res, $lineno);
934
            }
935
936
            // Check for COPY request
937
            if (pg_result_status($res) == 4) {
938
                // 4 == PGSQL_COPY_FROM
939
                while (!feof($fd)) {
940
                    $copy = fgets($fd, 32768);
941
                    ++$lineno;
942
                    pg_put_line($conn, $copy);
943
                    if ($copy == "\\.\n" || $copy == "\\.\r\n") {
944
                        pg_end_copy($conn);
945
946
                        break;
947
                    }
948
                }
949
            }
950
        }
951
952
        fclose($fd);
953
954
        return true;
955
    }
956
957
    /**
958
     * A private helper method for executeScript that advances the
959
     * character by 1.  In psql this is careful to take into account
960
     * multibyte languages, but we don't at the moment, so this function
961
     * is someone redundant, since it will always advance by 1.
962
     *
963
     * @param int $i       The current character position in the line
964
     * @param int $prevlen Length of previous character (ie. 1)
965
     * @param int $thislen Length of current character (ie. 1)
966
     */
967
    protected function advance_1(&$i, &$prevlen, &$thislen)
968
    {
969
        $prevlen = $thislen;
970
        $i += $thislen;
971
        $thislen = 1;
972
    }
973
974
    /**
975
     * Private helper method to detect a valid $foo$ quote delimiter at
976
     * the start of the parameter dquote.
977
     *
978
     * @param string $dquote
979
     *
980
     * @return bool true if valid, false otherwise
981
     */
982
    protected function valid_dolquote($dquote)
983
    {
984
        // XXX: support multibyte
985
        return preg_match('/^[$][$]/', $dquote) || preg_match('/^[$][_[:alpha:]][_[:alnum:]]*[$]/', $dquote);
986
    }
987
988
    // Capabilities
989
990
    /**
991
     * Returns a recordset of all columns in a query.  Supports paging.
992
     *
993
     * @param string   $type      Either 'QUERY' if it is an SQL query, or 'TABLE' if it is a table identifier,
994
     *                            or 'SELECT" if it's a select query
995
     * @param string   $table     The base table of the query.  NULL for no table.
996
     * @param string   $query     The query that is being executed.  NULL for no query.
997
     * @param string   $sortkey   The column number to sort by, or '' or null for no sorting
998
     * @param string   $sortdir   The direction in which to sort the specified column ('asc' or 'desc')
999
     * @param null|int $page      The page of the relation to retrieve
1000
     * @param null|int $page_size The number of rows per page
1001
     * @param int      $max_pages (return-by-ref) The max number of pages in the relation
1002
     *
1003
     * @return int|\PHPPgAdmin\ADORecordSet A  recordset on success or an int with error code
1004
     *                                      - -1 transaction error
1005
     *                                      - -2 counting error
1006
     *                                      - -3 page or page_size invalid
1007
     *                                      - -4 unknown type
1008
     *                                      - -5 failed setting transaction read only
1009
     */
1010
    public function browseQuery($type, $table, $query, $sortkey, $sortdir, $page, $page_size, &$max_pages)
1011
    {
1012
        // Check that we're not going to divide by zero
1013
        if (!is_numeric($page_size) || $page_size != (int) $page_size || $page_size <= 0) {
1014
            return -3;
1015
        }
1016
1017
        // If $type is TABLE, then generate the query
1018
        switch ($type) {
1019
            case 'TABLE':
1020
                if (preg_match('/^[0-9]+$/', $sortkey) && $sortkey > 0) {
1021
                    $orderby = [$sortkey => $sortdir];
1022
                } else {
1023
                    $orderby = [];
1024
                }
1025
1026
                $query = $this->getSelectSQL($table, [], [], [], $orderby);
1027
1028
                break;
1029
            case 'QUERY':
1030
            case 'SELECT':
1031
                // Trim query
1032
                $query = trim($query);
1033
                // Trim off trailing semi-colon if there is one
1034
                if (substr($query, strlen($query) - 1, 1) == ';') {
1035
                    $query = substr($query, 0, strlen($query) - 1);
1036
                }
1037
1038
                break;
1039
            default:
1040
                return -4;
1041
        }
1042
1043
        // Generate count query
1044
        $count = "SELECT COUNT(*) AS total FROM (${query}) AS sub";
1045
1046
        // Open a transaction
1047
        $status = $this->beginTransaction();
1048
        if ($status != 0) {
1049
            return -1;
1050
        }
1051
1052
        // If backend supports read only queries, then specify read only mode
1053
        // to avoid side effects from repeating queries that do writes.
1054
        if ($this->hasReadOnlyQueries()) {
1055
            $status = $this->execute('SET TRANSACTION READ ONLY');
1056
            if ($status != 0) {
1057
                $this->rollbackTransaction();
1058
1059
                return -5;
1060
            }
1061
        }
1062
1063
        // Count the number of rows
1064
        $total = $this->browseQueryCount($count);
1065
        if ($total < 0) {
1066
            $this->rollbackTransaction();
1067
1068
            return -2;
1069
        }
1070
1071
        // Calculate max pages
1072
        $max_pages = ceil($total / $page_size);
1073
1074
        // Check that page is less than or equal to max pages
1075
        if (!is_numeric($page) || $page != (int) $page || $page > $max_pages || $page < 1) {
1076
            $this->rollbackTransaction();
1077
1078
            return -3;
1079
        }
1080
1081
        // Set fetch mode to NUM so that duplicate field names are properly returned
1082
        // for non-table queries.  Since the SELECT feature only allows selecting one
1083
        // table, duplicate fields shouldn't appear.
1084
        if ($type == 'QUERY') {
1085
            $this->conn->setFetchMode(ADODB_FETCH_NUM);
1086
        }
1087
1088
        // Figure out ORDER BY.  Sort key is always the column number (based from one)
1089
        // of the column to order by.  Only need to do this for non-TABLE queries
1090
        if ($type != 'TABLE' && preg_match('/^[0-9]+$/', $sortkey) && $sortkey > 0) {
1091
            $orderby = " ORDER BY {$sortkey}";
1092
            // Add sort order
1093
            if ($sortdir == 'desc') {
1094
                $orderby .= ' DESC';
1095
            } else {
1096
                $orderby .= ' ASC';
1097
            }
1098
        } else {
1099
            $orderby = '';
1100
        }
1101
1102
        // Actually retrieve the rows, with offset and limit
1103
        $rs     = $this->selectSet("SELECT * FROM ({$query}) AS sub {$orderby} LIMIT {$page_size} OFFSET ".($page - 1) * $page_size);
1104
        $status = $this->endTransaction();
1105
        if ($status != 0) {
1106
            $this->rollbackTransaction();
1107
1108
            return -1;
1109
        }
1110
1111
        return $rs;
1112
    }
1113
1114
    /**
1115
     * Generates the SQL for the 'select' function.
1116
     *
1117
     * @param string $table   The table from which to select
1118
     * @param array  $show    An array of columns to show.  Empty array means all columns.
1119
     * @param array  $values  An array mapping columns to values
1120
     * @param array  $ops     An array of the operators to use
1121
     * @param array  $orderby (optional) An array of column numbers or names (one based)
1122
     *                        mapped to sort direction (asc or desc or '' or null) to order by
1123
     *
1124
     * @return string The SQL query
1125
     */
1126
    public function getSelectSQL($table, $show, $values, $ops, $orderby = [])
1127
    {
1128
        $this->fieldArrayClean($show);
1129
1130
        // If an empty array is passed in, then show all columns
1131
        if (sizeof($show) == 0) {
1132
            if ($this->hasObjectID($table)) {
1133
                $sql = "SELECT \"{$this->id}\", * FROM ";
1134
            } else {
1135
                $sql = 'SELECT * FROM ';
1136
            }
1137
        } else {
1138
            // Add oid column automatically to results for editing purposes
1139
            if (!in_array($this->id, $show, true) && $this->hasObjectID($table)) {
1140
                $sql = "SELECT \"{$this->id}\", \"";
1141
            } else {
1142
                $sql = 'SELECT "';
1143
            }
1144
1145
            $sql .= join('","', $show).'" FROM ';
1146
        }
1147
1148
        $this->fieldClean($table);
1149
1150
        if (isset($_REQUEST['schema'])) {
1151
            $f_schema = $_REQUEST['schema'];
1152
            $this->fieldClean($f_schema);
1153
            $sql .= "\"{$f_schema}\".";
1154
        }
1155
        $sql .= "\"{$table}\"";
1156
1157
        // If we have values specified, add them to the WHERE clause
1158
        $first = true;
1159
        if (is_array($values) && sizeof($values) > 0) {
1160
            foreach ($values as $k => $v) {
1161
                if ($v != '' || $this->selectOps[$ops[$k]] == 'p') {
1162
                    $this->fieldClean($k);
1163
                    if ($first) {
1164
                        $sql .= ' WHERE ';
1165
                        $first = false;
1166
                    } else {
1167
                        $sql .= ' AND ';
1168
                    }
1169
                    // Different query format depending on operator type
1170
                    switch ($this->selectOps[$ops[$k]]) {
1171
                        case 'i':
1172
                            // Only clean the field for the inline case
1173
                            // this is because (x), subqueries need to
1174
                            // to allow 'a','b' as input.
1175
                            $this->clean($v);
1176
                            $sql .= "\"{$k}\" {$ops[$k]} '{$v}'";
1177
1178
                            break;
1179
                        case 'p':
1180
                            $sql .= "\"{$k}\" {$ops[$k]}";
1181
1182
                            break;
1183
                        case 'x':
1184
                            $sql .= "\"{$k}\" {$ops[$k]} ({$v})";
1185
1186
                            break;
1187
                        case 't':
1188
                            $sql .= "\"{$k}\" {$ops[$k]}('{$v}')";
1189
1190
                            break;
1191
                        default:
1192
                            // Shouldn't happen
1193
                    }
1194
                }
1195
            }
1196
        }
1197
1198
        // ORDER BY
1199
        if (is_array($orderby) && sizeof($orderby) > 0) {
1200
            $sql .= ' ORDER BY ';
1201
            $first = true;
1202
            foreach ($orderby as $k => $v) {
1203
                if ($first) {
1204
                    $first = false;
1205
                } else {
1206
                    $sql .= ', ';
1207
                }
1208
1209
                if (preg_match('/^[0-9]+$/', $k)) {
1210
                    $sql .= $k;
1211
                } else {
1212
                    $this->fieldClean($k);
1213
                    $sql .= '"'.$k.'"';
1214
                }
1215
                if (strtoupper($v) == 'DESC') {
1216
                    $sql .= ' DESC';
1217
                }
1218
            }
1219
        }
1220
1221
        return $sql;
1222
    }
1223
1224
    /**
1225
     * Finds the number of rows that would be returned by a
1226
     * query.
1227
     *
1228
     * @param string $count The count query
1229
     *
1230
     * @return int|string The count of rows or -1 of no rows are found
1231
     */
1232
    public function browseQueryCount($count)
1233
    {
1234
        return $this->selectField($count, 'total');
1235
    }
1236
1237
    /**
1238
     * Change the value of a parameter to 't' or 'f' depending on whether it evaluates to true or false.
1239
     *
1240
     * @param null|bool|int|string $parameter the parameter
1241
     *
1242
     * @return string the parameter transformed to 't' of 'f'
1243
     */
1244
    public function dbBool(&$parameter)
1245
    {
1246
        if ($parameter) {
1247
            $parameter = 't';
1248
        } else {
1249
            $parameter = 'f';
1250
        }
1251
1252
        return $parameter;
1253
    }
1254
1255
    /**
1256
     * Fetches statistics for a database.
1257
     *
1258
     * @param string $database The database to fetch stats for
1259
     *
1260
     * @return \PHPPgAdmin\ADORecordSet A recordset
1261
     */
1262
    public function getStatsDatabase($database)
1263
    {
1264
        $this->clean($database);
1265
1266
        $sql = "SELECT * FROM pg_stat_database WHERE datname='{$database}'";
1267
1268
        return $this->selectSet($sql);
1269
    }
1270
1271
    /**
1272
     * Fetches tuple statistics for a table.
1273
     *
1274
     * @param string $table The table to fetch stats for
1275
     *
1276
     * @return \PHPPgAdmin\ADORecordSet A recordset
1277
     */
1278
    public function getStatsTableTuples($table)
1279
    {
1280
        $c_schema = $this->_schema;
1281
        $this->clean($c_schema);
1282
        $this->clean($table);
1283
1284
        $sql = "SELECT * FROM pg_stat_all_tables
1285
			WHERE schemaname='{$c_schema}' AND relname='{$table}'";
1286
1287
        return $this->selectSet($sql);
1288
    }
1289
1290
    /**
1291
     * Fetches I/0 statistics for a table.
1292
     *
1293
     * @param string $table The table to fetch stats for
1294
     *
1295
     * @return \PHPPgAdmin\ADORecordSet A recordset
1296
     */
1297
    public function getStatsTableIO($table)
1298
    {
1299
        $c_schema = $this->_schema;
1300
        $this->clean($c_schema);
1301
        $this->clean($table);
1302
1303
        $sql = "SELECT * FROM pg_statio_all_tables
1304
			WHERE schemaname='{$c_schema}' AND relname='{$table}'";
1305
1306
        return $this->selectSet($sql);
1307
    }
1308
1309
    /**
1310
     * Fetches tuple statistics for all indexes on a table.
1311
     *
1312
     * @param string $table The table to fetch index stats for
1313
     *
1314
     * @return \PHPPgAdmin\ADORecordSet A recordset
1315
     */
1316
    public function getStatsIndexTuples($table)
1317
    {
1318
        $c_schema = $this->_schema;
1319
        $this->clean($c_schema);
1320
        $this->clean($table);
1321
1322
        $sql = "SELECT * FROM pg_stat_all_indexes
1323
			WHERE schemaname='{$c_schema}' AND relname='{$table}' ORDER BY indexrelname";
1324
1325
        return $this->selectSet($sql);
1326
    }
1327
1328
    /**
1329
     * Fetches I/0 statistics for all indexes on a table.
1330
     *
1331
     * @param string $table The table to fetch index stats for
1332
     *
1333
     * @return \PHPPgAdmin\ADORecordSet A recordset
1334
     */
1335
    public function getStatsIndexIO($table)
1336
    {
1337
        $c_schema = $this->_schema;
1338
        $this->clean($c_schema);
1339
        $this->clean($table);
1340
1341
        $sql = "SELECT * FROM pg_statio_all_indexes
1342
			WHERE schemaname='{$c_schema}' AND relname='{$table}'
1343
			ORDER BY indexrelname";
1344
1345
        return $this->selectSet($sql);
1346
    }
1347
}
1348