Projekt

Obecné

Profil

Stáhnout (16.7 KB) Statistiky
| Větev: | Tag: | Revize:
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
?>
(5-5/10)