1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* A class that implements the DB interface for Postgres
|
5
|
* Note: This class uses ADODB and returns RecordSets.
|
6
|
*
|
7
|
* $Id: Postgres72.php,v 1.84 2005/09/07 08:09:21 chriskl Exp $
|
8
|
*/
|
9
|
|
10
|
|
11
|
include_once('./classes/database/Postgres71.php');
|
12
|
|
13
|
class Postgres72 extends Postgres71 {
|
14
|
|
15
|
var $major_version = 7.2;
|
16
|
|
17
|
// Set the maximum built-in ID.
|
18
|
var $_lastSystemOID = 16554;
|
19
|
|
20
|
// List of all legal privileges that can be applied to different types
|
21
|
// of objects.
|
22
|
var $privlist = array(
|
23
|
'table' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
24
|
'view' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'ALL PRIVILEGES'),
|
25
|
'sequence' => array('SELECT', 'UPDATE', 'ALL PRIVILEGES')
|
26
|
);
|
27
|
|
28
|
// Extra "magic" types. BIGSERIAL was added in PostgreSQL 7.2.
|
29
|
var $extraTypes = array('SERIAL', 'BIGSERIAL');
|
30
|
|
31
|
/**
|
32
|
* Constructor
|
33
|
* @param $conn The database connection
|
34
|
*/
|
35
|
function Postgres72($conn) {
|
36
|
$this->Postgres71($conn);
|
37
|
|
38
|
// Correct the error in the encoding tables, that was
|
39
|
// fixed in PostgreSQL 7.2
|
40
|
$this->codemap['LATIN5'] = 'ISO-8859-9';
|
41
|
}
|
42
|
|
43
|
// Help functions
|
44
|
|
45
|
function getHelpPages() {
|
46
|
include_once('./help/PostgresDoc72.php');
|
47
|
return $this->help_page;
|
48
|
}
|
49
|
|
50
|
/**
|
51
|
* Returns all available process information.
|
52
|
* @param $database (optional) Find only connections to specified database
|
53
|
* @return A recordset
|
54
|
*/
|
55
|
function getProcesses($database = null) {
|
56
|
if ($database === null)
|
57
|
$sql = "SELECT * FROM pg_stat_activity ORDER BY datname, usename, procpid";
|
58
|
else {
|
59
|
$this->clean($database);
|
60
|
$sql = "SELECT * FROM pg_stat_activity WHERE datname='{$database}' ORDER BY usename, procpid";
|
61
|
}
|
62
|
|
63
|
return $this->selectSet($sql);
|
64
|
}
|
65
|
|
66
|
// Table functions
|
67
|
|
68
|
/**
|
69
|
* Returns the SQL for changing the current user
|
70
|
* @param $user The user to change to
|
71
|
* @return The SQL
|
72
|
*/
|
73
|
function getChangeUserSQL($user) {
|
74
|
$this->clean($user);
|
75
|
return "SET SESSION AUTHORIZATION '{$user}';";
|
76
|
}
|
77
|
|
78
|
/**
|
79
|
* Checks to see whether or not a table has a unique id column
|
80
|
* @param $table The table name
|
81
|
* @return True if it has a unique id, false otherwise
|
82
|
* @return -99 error
|
83
|
*/
|
84
|
function hasObjectID($table) {
|
85
|
$this->clean($table);
|
86
|
|
87
|
$sql = "SELECT relhasoids FROM pg_class WHERE relname='{$table}'";
|
88
|
|
89
|
$rs = $this->selectSet($sql);
|
90
|
if ($rs->recordCount() != 1) return -99;
|
91
|
else {
|
92
|
$rs->f['relhasoids'] = $this->phpBool($rs->f['relhasoids']);
|
93
|
return $rs->f['relhasoids'];
|
94
|
}
|
95
|
}
|
96
|
|
97
|
/**
|
98
|
* Returns table information
|
99
|
* @param $table The name of the table
|
100
|
* @return A recordset
|
101
|
*/
|
102
|
function getTable($table) {
|
103
|
$this->clean($table);
|
104
|
|
105
|
$sql = "SELECT pc.relname,
|
106
|
pg_get_userbyid(pc.relowner) AS relowner,
|
107
|
(SELECT description FROM pg_description pd
|
108
|
WHERE pc.oid=pd.objoid AND objsubid = 0) AS relcomment
|
109
|
FROM pg_class pc
|
110
|
WHERE pc.relname='{$table}'";
|
111
|
|
112
|
return $this->selectSet($sql);
|
113
|
}
|
114
|
|
115
|
/**
|
116
|
* Return all tables in current database
|
117
|
* @param $all True to fetch all tables, false for just in current schema
|
118
|
* @return All tables, sorted alphabetically
|
119
|
*/
|
120
|
function getTables($all = false) {
|
121
|
global $conf;
|
122
|
if (!$conf['show_system'] || $all) $where = "AND c.relname NOT LIKE 'pg\\\\_%' ";
|
123
|
else $where = '';
|
124
|
|
125
|
$sql = "SELECT NULL AS nspname, c.relname,
|
126
|
(SELECT usename FROM pg_user u WHERE u.usesysid=c.relowner) AS relowner,
|
127
|
(SELECT description FROM pg_description pd WHERE c.oid=pd.objoid AND objsubid = 0) AS relcomment,
|
128
|
reltuples::integer
|
129
|
FROM pg_class c WHERE c.relkind='r' {$where}ORDER BY relname";
|
130
|
return $this->selectSet($sql);
|
131
|
}
|
132
|
|
133
|
/**
|
134
|
* Retrieve the attribute definition of a table
|
135
|
* @param $table The name of the table
|
136
|
* @param $field (optional) The name of a field to return
|
137
|
* @return All attributes in order
|
138
|
*/
|
139
|
function getTableAttributes($table, $field = '') {
|
140
|
$this->clean($table);
|
141
|
$this->clean($field);
|
142
|
|
143
|
if ($field == '') {
|
144
|
$sql = "
|
145
|
SELECT
|
146
|
a.attname,
|
147
|
format_type(a.atttypid, a.atttypmod) as type, a.atttypmod,
|
148
|
a.attnotnull, a.atthasdef, adef.adsrc,
|
149
|
-1 AS attstattarget, a.attstorage, t.typstorage, false AS attisserial,
|
150
|
description as comment
|
151
|
FROM
|
152
|
pg_attribute a LEFT JOIN pg_attrdef adef
|
153
|
ON a.attrelid=adef.adrelid AND a.attnum=adef.adnum
|
154
|
LEFT JOIN pg_type t ON a.atttypid=t.oid
|
155
|
LEFT JOIN pg_description d ON (a.attrelid = d.objoid AND a.attnum = d.objsubid)
|
156
|
WHERE
|
157
|
a.attrelid = (SELECT oid FROM pg_class WHERE relname='{$table}')
|
158
|
AND a.attnum > 0
|
159
|
ORDER BY a.attnum";
|
160
|
}
|
161
|
else {
|
162
|
$sql = "
|
163
|
SELECT
|
164
|
a.attname,
|
165
|
format_type(a.atttypid, a.atttypmod) as type,
|
166
|
format_type(a.atttypid, NULL) as base_type,
|
167
|
a.atttypmod,
|
168
|
a.attnotnull, a.atthasdef, adef.adsrc,
|
169
|
-1 AS attstattarget, a.attstorage, t.typstorage,
|
170
|
description as comment
|
171
|
FROM
|
172
|
pg_attribute a LEFT JOIN pg_attrdef adef
|
173
|
ON a.attrelid=adef.adrelid AND a.attnum=adef.adnum
|
174
|
LEFT JOIN pg_type t ON a.atttypid=t.oid
|
175
|
LEFT JOIN pg_description d ON (a.attrelid = d.objoid AND a.attnum = d.objsubid)
|
176
|
WHERE
|
177
|
a.attrelid = (SELECT oid FROM pg_class WHERE relname='{$table}')
|
178
|
AND a.attname = '{$field}'";
|
179
|
}
|
180
|
|
181
|
return $this->selectSet($sql);
|
182
|
}
|
183
|
|
184
|
// View functions
|
185
|
|
186
|
/**
|
187
|
* Returns a list of all views in the database
|
188
|
* @return All views
|
189
|
*/
|
190
|
function getViews() {
|
191
|
global $conf;
|
192
|
|
193
|
if (!$conf['show_system'])
|
194
|
$where = " WHERE viewname NOT LIKE 'pg\\\\_%'";
|
195
|
else
|
196
|
$where = '';
|
197
|
|
198
|
$sql = "SELECT viewname AS relname, viewowner AS relowner, definition AS vwdefinition,
|
199
|
(SELECT description FROM pg_description pd, pg_class pc
|
200
|
WHERE pc.oid=pd.objoid AND pc.relname=v.viewname AND pd.objsubid = 0) AS relcomment
|
201
|
FROM pg_views v
|
202
|
{$where}
|
203
|
ORDER BY relname";
|
204
|
|
205
|
return $this->selectSet($sql);
|
206
|
}
|
207
|
|
208
|
/**
|
209
|
* Returns all details for a particular view
|
210
|
* @param $view The name of the view to retrieve
|
211
|
* @return View info
|
212
|
*/
|
213
|
function getView($view) {
|
214
|
$this->clean($view);
|
215
|
|
216
|
$sql = "SELECT viewname AS relname, viewowner AS relowner, definition AS vwdefinition,
|
217
|
(SELECT description FROM pg_description pd, pg_class pc
|
218
|
WHERE pc.oid=pd.objoid AND pc.relname=v.viewname AND pd.objsubid = 0) AS relcomment
|
219
|
FROM pg_views v
|
220
|
WHERE viewname='{$view}'";
|
221
|
|
222
|
return $this->selectSet($sql);
|
223
|
}
|
224
|
|
225
|
// Constraint functions
|
226
|
|
227
|
/**
|
228
|
* Removes a constraint from a relation
|
229
|
* @param $constraint The constraint to drop
|
230
|
* @param $relation The relation from which to drop
|
231
|
* @param $type The type of constraint (c, f, u or p)
|
232
|
* @param $cascade True to cascade drop, false to restrict
|
233
|
* @return 0 success
|
234
|
* @return -99 dropping foreign keys not supported
|
235
|
*/
|
236
|
function dropConstraint($constraint, $relation, $type, $cascade) {
|
237
|
$this->fieldClean($constraint);
|
238
|
$this->fieldClean($relation);
|
239
|
|
240
|
switch ($type) {
|
241
|
case 'c':
|
242
|
// CHECK constraint
|
243
|
$sql = "ALTER TABLE \"{$relation}\" DROP CONSTRAINT \"{$constraint}\" RESTRICT";
|
244
|
|
245
|
return $this->execute($sql);
|
246
|
break;
|
247
|
case 'p':
|
248
|
case 'u':
|
249
|
// PRIMARY KEY or UNIQUE constraint
|
250
|
return $this->dropIndex($constraint, $cascade);
|
251
|
break;
|
252
|
case 'f':
|
253
|
// FOREIGN KEY constraint
|
254
|
return -99;
|
255
|
}
|
256
|
}
|
257
|
|
258
|
/**
|
259
|
* Adds a unique constraint to a table
|
260
|
* @param $table The table to which to add the unique key
|
261
|
* @param $fields (array) An array of fields over which to add the unique key
|
262
|
* @param $name (optional) The name to give the key, otherwise default name is assigned
|
263
|
* @param $tablespace (optional) The tablespace for the schema, '' indicates default.
|
264
|
* @return 0 success
|
265
|
* @return -1 no fields given
|
266
|
*/
|
267
|
function addUniqueKey($table, $fields, $name = '', $tablespace = '') {
|
268
|
if (!is_array($fields) || sizeof($fields) == 0) return -1;
|
269
|
$this->fieldClean($table);
|
270
|
$this->fieldArrayClean($fields);
|
271
|
$this->fieldClean($name);
|
272
|
$this->fieldClean($tablespace);
|
273
|
|
274
|
$sql = "ALTER TABLE \"{$table}\" ADD ";
|
275
|
if ($name != '') $sql .= "CONSTRAINT \"{$name}\" ";
|
276
|
$sql .= "UNIQUE (\"" . join('","', $fields) . "\")";
|
277
|
|
278
|
if ($tablespace != '' && $this->hasTablespaces())
|
279
|
$sql .= " USING INDEX TABLESPACE \"{$tablespace}\"";
|
280
|
|
281
|
return $this->execute($sql);
|
282
|
}
|
283
|
|
284
|
/**
|
285
|
* Adds a primary key constraint to a table
|
286
|
* @param $table The table to which to add the primery key
|
287
|
* @param $fields (array) An array of fields over which to add the primary key
|
288
|
* @param $name (optional) The name to give the key, otherwise default name is assigned
|
289
|
* @param $tablespace (optional) The tablespace for the schema, '' indicates default.
|
290
|
* @return 0 success
|
291
|
* @return -1 no fields given
|
292
|
*/
|
293
|
function addPrimaryKey($table, $fields, $name = '', $tablespace = '') {
|
294
|
if (!is_array($fields) || sizeof($fields) == 0) return -1;
|
295
|
$this->fieldClean($table);
|
296
|
$this->fieldArrayClean($fields);
|
297
|
$this->fieldClean($name);
|
298
|
$this->fieldClean($tablespace);
|
299
|
|
300
|
$sql = "ALTER TABLE \"{$table}\" ADD ";
|
301
|
if ($name != '') $sql .= "CONSTRAINT \"{$name}\" ";
|
302
|
$sql .= "PRIMARY KEY (\"" . join('","', $fields) . "\")";
|
303
|
|
304
|
if ($tablespace != '' && $this->hasTablespaces())
|
305
|
$sql .= " USING INDEX TABLESPACE \"{$tablespace}\"";
|
306
|
|
307
|
return $this->execute($sql);
|
308
|
}
|
309
|
|
310
|
// Function functions
|
311
|
|
312
|
/**
|
313
|
* Returns a list of all functions in the database
|
314
|
* @param $all If true, will find all available functions, if false just userland ones
|
315
|
* @return All functions
|
316
|
*/
|
317
|
function getFunctions($all = false) {
|
318
|
if ($all)
|
319
|
$where = '';
|
320
|
else
|
321
|
$where = "AND p.oid > '{$this->_lastSystemOID}'";
|
322
|
|
323
|
$sql = "SELECT
|
324
|
p.oid AS prooid,
|
325
|
p.proname,
|
326
|
false AS proretset,
|
327
|
format_type(p.prorettype, NULL) AS proresult,
|
328
|
oidvectortypes(p.proargtypes) AS proarguments,
|
329
|
pl.lanname AS prolanguage,
|
330
|
(SELECT description FROM pg_description pd WHERE p.oid=pd.objoid) AS procomment,
|
331
|
p.proname || ' (' || oidvectortypes(p.proargtypes) || ')' AS proproto,
|
332
|
format_type(p.prorettype, NULL) AS proreturns
|
333
|
FROM
|
334
|
pg_proc p, pg_language pl
|
335
|
WHERE
|
336
|
p.prolang = pl.oid AND
|
337
|
(pronargs = 0 OR oidvectortypes(p.proargtypes) <> '')
|
338
|
{$where}
|
339
|
ORDER BY
|
340
|
p.proname, proresult
|
341
|
";
|
342
|
|
343
|
return $this->selectSet($sql);
|
344
|
}
|
345
|
|
346
|
/**
|
347
|
* Updates (replaces) a function.
|
348
|
* @param $function_oid The OID of the function
|
349
|
* @param $funcname The name of the function to create
|
350
|
* @param $newname The new name for the function
|
351
|
* @param $args The array of argument types
|
352
|
* @param $returns The return type
|
353
|
* @param $definition The definition for the new function
|
354
|
* @param $language The language the function is written for
|
355
|
* @param $flags An array of optional flags
|
356
|
* @param $setof True if returns a set, false otherwise
|
357
|
* @param $comment The comment on the function
|
358
|
* @return 0 success
|
359
|
* @return -1 transaction error
|
360
|
* @return -2 drop function error
|
361
|
* @return -3 create function error
|
362
|
* @return -4 comment error
|
363
|
*/
|
364
|
function setFunction($function_oid, $funcname, $newname, $args, $returns, $definition, $language, $flags, $setof, $comment) {
|
365
|
// Begin a transaction
|
366
|
$status = $this->beginTransaction();
|
367
|
if ($status != 0) {
|
368
|
$this->rollbackTransaction();
|
369
|
return -1;
|
370
|
}
|
371
|
|
372
|
// Replace the existing function
|
373
|
if ($funcname != $newname) {
|
374
|
$status = $this->dropFunction($function_oid, false);
|
375
|
if ($status != 0) {
|
376
|
$this->rollbackTransaction();
|
377
|
return -2;
|
378
|
}
|
379
|
|
380
|
$status = $this->createFunction($newname, $args, $returns, $definition, $language, $flags, $setof, false);
|
381
|
if ($status != 0) {
|
382
|
$this->rollbackTransaction();
|
383
|
return -3;
|
384
|
}
|
385
|
} else {
|
386
|
$status = $this->createFunction($funcname, $args, $returns, $definition, $language, $flags, $setof, true);
|
387
|
if ($status != 0) {
|
388
|
$this->rollbackTransaction();
|
389
|
return -3;
|
390
|
}
|
391
|
}
|
392
|
|
393
|
// Comment on the function
|
394
|
$this->fieldClean($newname);
|
395
|
$this->clean($comment);
|
396
|
$status = $this->setComment('FUNCTION', "\"{$newname}\"({$args})", null, $comment);
|
397
|
if ($status != 0) {
|
398
|
$this->rollbackTransaction();
|
399
|
return -4;
|
400
|
}
|
401
|
|
402
|
return $this->endTransaction();
|
403
|
}
|
404
|
|
405
|
// Type functions
|
406
|
|
407
|
/**
|
408
|
* Returns a list of all types in the database
|
409
|
* @param $all If true, will find all available functions, if false just those in search path
|
410
|
* @param $tabletypes If true, will include table types
|
411
|
* @param $domains Ignored
|
412
|
* @return A recordet
|
413
|
*/
|
414
|
function getTypes($all = false, $tabletypes = false, $domains = false) {
|
415
|
global $conf;
|
416
|
|
417
|
if ($all || $conf['show_system']) {
|
418
|
$where = '';
|
419
|
} else {
|
420
|
$where = "AND pt.oid > '{$this->_lastSystemOID}'::oid";
|
421
|
}
|
422
|
// Never show system table types
|
423
|
$where2 = "AND c.oid > '{$this->_lastSystemOID}'::oid";
|
424
|
|
425
|
// Create type filter
|
426
|
$tqry = "'c'";
|
427
|
if ($tabletypes)
|
428
|
$tqry .= ", 'r', 'v'";
|
429
|
|
430
|
$sql = "SELECT
|
431
|
pt.typname AS basename,
|
432
|
format_type(pt.oid, NULL) AS typname,
|
433
|
pu.usename AS typowner,
|
434
|
(SELECT description FROM pg_description pd WHERE pt.oid=pd.objoid) AS typcomment
|
435
|
FROM
|
436
|
pg_type pt,
|
437
|
pg_user pu
|
438
|
WHERE
|
439
|
pt.typowner = pu.usesysid
|
440
|
AND (pt.typrelid = 0 OR (SELECT c.relkind IN ({$tqry}) FROM pg_class c WHERE c.oid = pt.typrelid {$where2}))
|
441
|
AND typname !~ '^_'
|
442
|
{$where}
|
443
|
ORDER BY typname
|
444
|
";
|
445
|
|
446
|
return $this->selectSet($sql);
|
447
|
}
|
448
|
|
449
|
// Opclass functions
|
450
|
|
451
|
/**
|
452
|
* Gets all opclasses
|
453
|
* @return A recordset
|
454
|
*/
|
455
|
function getOpClasses() {
|
456
|
global $conf;
|
457
|
|
458
|
if ($conf['show_system'])
|
459
|
$where = '';
|
460
|
else
|
461
|
$where = "AND po.oid > '{$this->_lastSystemOID}'::oid";
|
462
|
|
463
|
$sql = "
|
464
|
SELECT DISTINCT
|
465
|
pa.amname,
|
466
|
po.opcname,
|
467
|
format_type(po.opcintype, NULL) AS opcintype,
|
468
|
TRUE AS opcdefault,
|
469
|
NULL::text AS opccomment
|
470
|
FROM
|
471
|
pg_opclass po, pg_am pa
|
472
|
WHERE
|
473
|
po.opcamid=pa.oid
|
474
|
{$where}
|
475
|
ORDER BY 1,2
|
476
|
";
|
477
|
|
478
|
return $this->selectSet($sql);
|
479
|
}
|
480
|
|
481
|
// Administration functions
|
482
|
|
483
|
/**
|
484
|
* Vacuums a database
|
485
|
* @param $table The table to vacuum
|
486
|
* @param $analyze If true, also does analyze
|
487
|
* @param $full If true, selects "full" vacuum (PostgreSQL >= 7.2)
|
488
|
* @param $freeze If true, selects aggressive "freezing" of tuples (PostgreSQL >= 7.2)
|
489
|
*/
|
490
|
function vacuumDB($table = '', $analyze = false, $full = false, $freeze = false) {
|
491
|
$sql = "VACUUM";
|
492
|
if ($full) $sql .= " FULL";
|
493
|
if ($freeze) $sql .= " FREEZE";
|
494
|
if ($analyze) $sql .= " ANALYZE";
|
495
|
if ($table != '') {
|
496
|
$this->fieldClean($table);
|
497
|
$sql .= " \"{$table}\"";
|
498
|
}
|
499
|
|
500
|
return $this->execute($sql);
|
501
|
}
|
502
|
|
503
|
/**
|
504
|
* Analyze a database
|
505
|
* @note PostgreSQL 7.2 finally had an independent ANALYZE command
|
506
|
* @param $table (optional) The table to analyze
|
507
|
*/
|
508
|
function analyzeDB($table = '') {
|
509
|
if ($table != '') {
|
510
|
$this->fieldClean($table);
|
511
|
$sql = "ANALYZE \"{$table}\"";
|
512
|
}
|
513
|
else
|
514
|
$sql = "ANALYZE";
|
515
|
|
516
|
return $this->execute($sql);
|
517
|
}
|
518
|
|
519
|
// Statistics collector functions
|
520
|
|
521
|
/**
|
522
|
* Fetches statistics for a database
|
523
|
* @param $database The database to fetch stats for
|
524
|
* @return A recordset
|
525
|
*/
|
526
|
function getStatsDatabase($database) {
|
527
|
$this->clean($database);
|
528
|
|
529
|
$sql = "SELECT * FROM pg_stat_database WHERE datname='{$database}'";
|
530
|
|
531
|
return $this->selectSet($sql);
|
532
|
}
|
533
|
|
534
|
/**
|
535
|
* Fetches tuple statistics for a table
|
536
|
* @param $table The table to fetch stats for
|
537
|
* @return A recordset
|
538
|
*/
|
539
|
function getStatsTableTuples($table) {
|
540
|
$this->clean($table);
|
541
|
|
542
|
$sql = 'SELECT * FROM pg_stat_all_tables WHERE';
|
543
|
if ($this->hasSchemas()) $sql .= " schemaname='{$this->_schema}' AND";
|
544
|
$sql .= " relname='{$table}'";
|
545
|
|
546
|
return $this->selectSet($sql);
|
547
|
}
|
548
|
|
549
|
/**
|
550
|
* Fetches I/0 statistics for a table
|
551
|
* @param $table The table to fetch stats for
|
552
|
* @return A recordset
|
553
|
*/
|
554
|
function getStatsTableIO($table) {
|
555
|
$this->clean($table);
|
556
|
|
557
|
$sql = 'SELECT * FROM pg_statio_all_tables WHERE';
|
558
|
if ($this->hasSchemas()) $sql .= " schemaname='{$this->_schema}' AND";
|
559
|
$sql .= " relname='{$table}'";
|
560
|
|
561
|
return $this->selectSet($sql);
|
562
|
}
|
563
|
|
564
|
/**
|
565
|
* Fetches tuple statistics for all indexes on a table
|
566
|
* @param $table The table to fetch index stats for
|
567
|
* @return A recordset
|
568
|
*/
|
569
|
function getStatsIndexTuples($table) {
|
570
|
$this->clean($table);
|
571
|
|
572
|
$sql = 'SELECT * FROM pg_stat_all_indexes WHERE';
|
573
|
if ($this->hasSchemas()) $sql .= " schemaname='{$this->_schema}' AND";
|
574
|
$sql .= " relname='{$table}' ORDER BY indexrelname";
|
575
|
|
576
|
return $this->selectSet($sql);
|
577
|
}
|
578
|
|
579
|
/**
|
580
|
* Fetches I/0 statistics for all indexes on a table
|
581
|
* @param $table The table to fetch index stats for
|
582
|
* @return A recordset
|
583
|
*/
|
584
|
function getStatsIndexIO($table) {
|
585
|
$this->clean($table);
|
586
|
|
587
|
$sql = 'SELECT * FROM pg_statio_all_indexes WHERE';
|
588
|
if ($this->hasSchemas()) $sql .= " schemaname='{$this->_schema}' AND";
|
589
|
$sql .= " relname='{$table}' ORDER BY indexrelname";
|
590
|
|
591
|
return $this->selectSet($sql);
|
592
|
}
|
593
|
|
594
|
// Capabilities
|
595
|
function hasWithoutOIDs() { return true; }
|
596
|
function hasPartialIndexes() { return true; }
|
597
|
function hasProcesses() { return true; }
|
598
|
function hasStatsCollector() { return true; }
|
599
|
function hasFullVacuum() { return true; }
|
600
|
|
601
|
}
|
602
|
|
603
|
?>
|