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: Postgres71.php,v 1.74 2005/10/18 03:45:16 chriskl Exp $
|
8
|
*/
|
9
|
|
10
|
// @@@ THOUGHT: What about inherits? ie. use of ONLY???
|
11
|
|
12
|
include_once('./classes/database/Postgres.php');
|
13
|
|
14
|
class Postgres71 extends Postgres {
|
15
|
|
16
|
var $major_version = 7.1;
|
17
|
var $_lastSystemOID = 18539;
|
18
|
var $_maxNameLen = 31;
|
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', 'ALL'),
|
24
|
'view' => array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'ALL'),
|
25
|
'sequence' => array('SELECT', 'UPDATE', 'ALL')
|
26
|
);
|
27
|
|
28
|
// List of characters in acl lists and the privileges they
|
29
|
// refer to.
|
30
|
var $privmap = array(
|
31
|
'r' => 'SELECT',
|
32
|
'w' => 'UPDATE',
|
33
|
'a' => 'INSERT',
|
34
|
'd' => 'DELETE',
|
35
|
'R' => 'RULE',
|
36
|
'x' => 'REFERENCES',
|
37
|
't' => 'TRIGGER',
|
38
|
'X' => 'EXECUTE',
|
39
|
'U' => 'USAGE',
|
40
|
'C' => 'CREATE',
|
41
|
'T' => 'TEMPORARY'
|
42
|
);
|
43
|
|
44
|
// Function properties
|
45
|
var $funcprops = array(array('', 'ISSTRICT'), array('', 'ISCACHABLE'));
|
46
|
var $defaultprops = array('', '');
|
47
|
|
48
|
// Select operators
|
49
|
var $selectOps = array('=' => 'i', '!=' => 'i', '<' => 'i', '>' => 'i', '<=' => 'i', '>=' => 'i', 'LIKE' => 'i', 'NOT LIKE' => 'i',
|
50
|
'ILIKE' => 'i', 'NOT ILIKE' => 'i', '~' => 'i', '!~' => 'i', '~*' => 'i', '!~*' => 'i',
|
51
|
'IS NULL' => 'p', 'IS NOT NULL' => 'p', 'IN' => 'x', 'NOT IN' => 'x');
|
52
|
// Supported join operations for use with view wizard
|
53
|
var $joinOps = array('INNER JOIN' => 'INNER JOIN', 'LEFT JOIN' => 'LEFT JOIN', 'RIGHT JOIN' => 'RIGHT JOIN', 'FULL JOIN' => 'FULL JOIN');
|
54
|
|
55
|
/**
|
56
|
* Constructor
|
57
|
* @param $conn The database connection
|
58
|
*/
|
59
|
function Postgres71($conn) {
|
60
|
$this->Postgres($conn);
|
61
|
}
|
62
|
|
63
|
// Help functions
|
64
|
|
65
|
function getHelpPages() {
|
66
|
include_once('./help/PostgresDoc71.php');
|
67
|
return $this->help_page;
|
68
|
}
|
69
|
|
70
|
/**
|
71
|
* Sets the client encoding
|
72
|
* @param $encoding The encoding to for the client
|
73
|
* @return 0 success
|
74
|
*/
|
75
|
function setClientEncoding($encoding) {
|
76
|
$this->clean($encoding);
|
77
|
|
78
|
$sql = "SET CLIENT_ENCODING TO '{$encoding}'";
|
79
|
|
80
|
return $this->execute($sql);
|
81
|
}
|
82
|
|
83
|
// Database functions
|
84
|
|
85
|
/**
|
86
|
* Return all database available on the server
|
87
|
* @return A list of databases, sorted alphabetically
|
88
|
*/
|
89
|
function getDatabases($currentdatabase = NULL) {
|
90
|
global $conf, $misc;
|
91
|
|
92
|
$server_info = $misc->getServerInfo();
|
93
|
|
94
|
if (isset($conf['owned_only']) && $conf['owned_only'] && !$this->isSuperUser($server_info['username'])) {
|
95
|
$username = $server_info['username'];
|
96
|
$this->clean($username);
|
97
|
$clause = " AND pu.usename='{$username}'";
|
98
|
}
|
99
|
else $clause = '';
|
100
|
|
101
|
if ($currentdatabase != NULL)
|
102
|
$orderby = "ORDER BY pdb.datname = '{$currentdatabase}' DESC, pdb.datname";
|
103
|
else
|
104
|
$orderby = "ORDER BY pdb.datname";
|
105
|
|
106
|
if (!$conf['show_system'])
|
107
|
$where = ' AND NOT pdb.datistemplate';
|
108
|
else
|
109
|
$where = ' AND pdb.datallowconn';
|
110
|
|
111
|
$sql = "SELECT pdb.datname AS datname, pu.usename AS datowner, pg_encoding_to_char(encoding) AS datencoding,
|
112
|
(SELECT description FROM pg_description pd WHERE pdb.oid=pd.objoid) AS datcomment
|
113
|
FROM pg_database pdb, pg_user pu
|
114
|
WHERE pdb.datdba = pu.usesysid
|
115
|
{$where}
|
116
|
{$clause}
|
117
|
{$orderby}";
|
118
|
|
119
|
return $this->selectSet($sql);
|
120
|
}
|
121
|
|
122
|
// Table functions
|
123
|
|
124
|
/**
|
125
|
* Finds the number of rows that would be returned by a
|
126
|
* query.
|
127
|
* @param $query The SQL query
|
128
|
* @param $count The count query
|
129
|
* @return The count of rows
|
130
|
* @return -1 error
|
131
|
*/
|
132
|
function browseQueryCount($query, $count) {
|
133
|
return $this->selectField($count, 'total');
|
134
|
}
|
135
|
|
136
|
/**
|
137
|
* Retrieve the attribute definition of a table
|
138
|
* @param $table The name of the table
|
139
|
* @param $field (optional) The name of a field to return
|
140
|
* @return All attributes in order
|
141
|
*/
|
142
|
function getTableAttributes($table, $field = '') {
|
143
|
$this->clean($table);
|
144
|
$this->clean($field);
|
145
|
|
146
|
if ($field == '') {
|
147
|
$sql = "SELECT
|
148
|
a.attname, t.typname as type, a.attlen, a.atttypmod, a.attnotnull,
|
149
|
a.atthasdef, adef.adsrc, -1 AS attstattarget, a.attstorage, t.typstorage,
|
150
|
false AS attisserial,
|
151
|
(SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
|
152
|
FROM
|
153
|
pg_attribute a LEFT JOIN pg_attrdef adef
|
154
|
ON a.attrelid=adef.adrelid AND a.attnum=adef.adnum,
|
155
|
pg_class c,
|
156
|
pg_type t
|
157
|
WHERE
|
158
|
c.relname = '{$table}' AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
|
159
|
ORDER BY a.attnum";
|
160
|
}
|
161
|
else {
|
162
|
$sql = "SELECT
|
163
|
a.attname, t.typname as type, t.typname as base_type,
|
164
|
a.attlen, a.atttypmod, a.attnotnull,
|
165
|
a.atthasdef, adef.adsrc, -1 AS attstattarget, a.attstorage, t.typstorage,
|
166
|
(SELECT description FROM pg_description d WHERE d.objoid = a.oid) as comment
|
167
|
FROM
|
168
|
pg_attribute a LEFT JOIN pg_attrdef adef
|
169
|
ON a.attrelid=adef.adrelid AND a.attnum=adef.adnum,
|
170
|
pg_class c,
|
171
|
pg_type t
|
172
|
WHERE
|
173
|
c.relname = '{$table}' AND a.attname='{$field}' AND a.attrelid = c.oid AND a.atttypid = t.oid";
|
174
|
}
|
175
|
|
176
|
return $this->selectSet($sql);
|
177
|
}
|
178
|
|
179
|
/**
|
180
|
* Formats a type correctly for display. This is a no-op in PostgreSQL 7.1+
|
181
|
* @param $typname The name of the type
|
182
|
* @param $typmod The contents of the typmod field
|
183
|
*/
|
184
|
function formatType($typname, $typmod) {
|
185
|
return $typname;
|
186
|
}
|
187
|
|
188
|
// Sequence functions
|
189
|
|
190
|
/**
|
191
|
* Resets a given sequence to min value of sequence
|
192
|
* @param $sequence Sequence name
|
193
|
* @return 0 success
|
194
|
* @return -1 sequence not found
|
195
|
*/
|
196
|
function resetSequence($sequence) {
|
197
|
// Get the minimum value of the sequence
|
198
|
$seq = $this->getSequence($sequence);
|
199
|
if ($seq->recordCount() != 1) return -1;
|
200
|
$minvalue = $seq->f['min_value'];
|
201
|
|
202
|
/* This double-cleaning is deliberate */
|
203
|
$this->fieldClean($sequence);
|
204
|
$this->clean($sequence);
|
205
|
|
206
|
$sql = "SELECT SETVAL('\"{$sequence}\"', {$minvalue}, FALSE)";
|
207
|
|
208
|
return $this->execute($sql);
|
209
|
}
|
210
|
|
211
|
// Function functions
|
212
|
|
213
|
/**
|
214
|
* Returns all details for a particular function
|
215
|
* @param $func The name of the function to retrieve
|
216
|
* @return Function info
|
217
|
*/
|
218
|
function getFunction($function_oid) {
|
219
|
$this->clean($function_oid);
|
220
|
|
221
|
$sql = "SELECT
|
222
|
pc.oid AS prooid,
|
223
|
proname,
|
224
|
lanname as prolanguage,
|
225
|
format_type(prorettype, NULL) as proresult,
|
226
|
prosrc,
|
227
|
probin,
|
228
|
proretset,
|
229
|
proisstrict,
|
230
|
proiscachable,
|
231
|
oidvectortypes(pc.proargtypes) AS proarguments,
|
232
|
(SELECT description FROM pg_description pd WHERE pc.oid=pd.objoid) AS procomment
|
233
|
FROM
|
234
|
pg_proc pc, pg_language pl
|
235
|
WHERE
|
236
|
pc.oid = '$function_oid'::oid
|
237
|
AND pc.prolang = pl.oid
|
238
|
";
|
239
|
|
240
|
return $this->selectSet($sql);
|
241
|
}
|
242
|
|
243
|
/**
|
244
|
* Returns an array containing a function's properties
|
245
|
* @param $f The array of data for the function
|
246
|
* @return An array containing the properties
|
247
|
*/
|
248
|
function getFunctionProperties($f) {
|
249
|
$temp = array();
|
250
|
|
251
|
// Strict
|
252
|
$f['proisstrict'] = $this->phpBool($f['proisstrict']);
|
253
|
if ($f['proisstrict'])
|
254
|
$temp[] = 'ISSTRICT';
|
255
|
else
|
256
|
$temp[] = '';
|
257
|
|
258
|
// Cachable
|
259
|
$f['proiscachable'] = $this->phpBool($f['proiscachable']);
|
260
|
if ($f['proiscachable'])
|
261
|
$temp[] = 'ISCACHABLE';
|
262
|
else
|
263
|
$temp[] = '';
|
264
|
|
265
|
return $temp;
|
266
|
}
|
267
|
|
268
|
// Constraint functions
|
269
|
|
270
|
/**
|
271
|
* Returns a list of all constraints on a table
|
272
|
* @param $table The table to find rules for
|
273
|
* @return A recordset
|
274
|
*/
|
275
|
function getConstraints($table) {
|
276
|
$this->clean($table);
|
277
|
|
278
|
$status = $this->beginTransaction();
|
279
|
if ($status != 0) return -1;
|
280
|
|
281
|
$sql = "
|
282
|
SELECT conname, consrc, contype, indkey FROM (
|
283
|
SELECT
|
284
|
rcname AS conname,
|
285
|
'CHECK (' || rcsrc || ')' AS consrc,
|
286
|
'c' AS contype,
|
287
|
rcrelid AS relid,
|
288
|
NULL AS indkey
|
289
|
FROM
|
290
|
pg_relcheck
|
291
|
UNION ALL
|
292
|
SELECT
|
293
|
pc.relname,
|
294
|
NULL,
|
295
|
CASE WHEN indisprimary THEN
|
296
|
'p'
|
297
|
ELSE
|
298
|
'u'
|
299
|
END,
|
300
|
pi.indrelid,
|
301
|
indkey
|
302
|
FROM
|
303
|
pg_class pc,
|
304
|
pg_index pi
|
305
|
WHERE
|
306
|
pc.oid=pi.indexrelid
|
307
|
AND (pi.indisunique OR pi.indisprimary)
|
308
|
) AS sub
|
309
|
WHERE relid = (SELECT oid FROM pg_class WHERE relname='{$table}')
|
310
|
ORDER BY
|
311
|
1
|
312
|
";
|
313
|
|
314
|
return $this->selectSet($sql);
|
315
|
}
|
316
|
|
317
|
// Trigger functions
|
318
|
|
319
|
/**
|
320
|
* Grabs a list of triggers on a table
|
321
|
* @param $table The name of a table whose triggers to retrieve
|
322
|
* @return A recordset
|
323
|
*/
|
324
|
function getTriggers($table = '') {
|
325
|
$this->clean($table);
|
326
|
|
327
|
// We include constraint triggers
|
328
|
$sql = "SELECT t.tgname, t.tgisconstraint, t.tgdeferrable, t.tginitdeferred, t.tgtype,
|
329
|
t.tgargs, t.tgnargs, t.tgconstrrelid,
|
330
|
(SELECT relname FROM pg_class c2 WHERE c2.oid=t.tgconstrrelid) AS tgconstrrelname,
|
331
|
p.proname AS tgfname, c.relname, NULL AS tgdef
|
332
|
FROM pg_trigger t LEFT JOIN pg_proc p
|
333
|
ON t.tgfoid=p.oid, pg_class c
|
334
|
WHERE t.tgrelid=c.oid
|
335
|
AND c.relname='{$table}'";
|
336
|
|
337
|
return $this->selectSet($sql);
|
338
|
}
|
339
|
|
340
|
// Aggregate functions
|
341
|
|
342
|
/**
|
343
|
* Gets all aggregates
|
344
|
* @return A recordset
|
345
|
*/
|
346
|
function getAggregates() {
|
347
|
global $conf;
|
348
|
|
349
|
if ($conf['show_system'])
|
350
|
$where = '';
|
351
|
else
|
352
|
$where = "WHERE a.oid > '{$this->_lastSystemOID}'::oid";
|
353
|
|
354
|
$sql = "
|
355
|
SELECT
|
356
|
a.aggname AS proname,
|
357
|
CASE a.aggbasetype
|
358
|
WHEN 0 THEN NULL
|
359
|
ELSE format_type(a.aggbasetype, NULL)
|
360
|
END AS proargtypes,
|
361
|
(SELECT description FROM pg_description pd WHERE a.oid=pd.objoid) AS aggcomment
|
362
|
FROM
|
363
|
pg_aggregate a
|
364
|
{$where}
|
365
|
ORDER BY
|
366
|
1, 2;
|
367
|
";
|
368
|
|
369
|
return $this->selectSet($sql);
|
370
|
}
|
371
|
|
372
|
// Capabilities
|
373
|
function hasAlterTableOwner() { return true; }
|
374
|
function hasFullSubqueries() { return true; }
|
375
|
|
376
|
}
|
377
|
|
378
|
?>
|