1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* A class that implements the Slony 1.0.x support plugin
|
5
|
*
|
6
|
* $Id: Slony.php,v 1.8.2.1 2005/11/16 08:02:28 chriskl Exp $
|
7
|
*/
|
8
|
|
9
|
include_once('./classes/plugins/Plugin.php');
|
10
|
|
11
|
class Slony extends Plugin {
|
12
|
|
13
|
var $slony_version;
|
14
|
var $slony_schema;
|
15
|
var $slony_cluster;
|
16
|
var $slony_owner;
|
17
|
var $slony_comment;
|
18
|
var $enabled = null;
|
19
|
|
20
|
/**
|
21
|
* Constructor
|
22
|
*/
|
23
|
function Slony() {
|
24
|
$this->Plugin('slony');
|
25
|
$this->isEnabled();
|
26
|
}
|
27
|
|
28
|
/**
|
29
|
* Determines whether or not Slony is installed in the current
|
30
|
* database.
|
31
|
* @post Will populate version and schema fields, etc.
|
32
|
* @return True if Slony is installed, false otherwise.
|
33
|
*/
|
34
|
function isEnabled() {
|
35
|
// Access cache
|
36
|
if ($this->enabled !== null) return $this->enabled;
|
37
|
else $this->enabled = false;
|
38
|
|
39
|
global $data;
|
40
|
|
41
|
// Slony needs schemas
|
42
|
if (!$data->hasSchemas()) return false;
|
43
|
|
44
|
// Check for the slonyversion() function and find the schema
|
45
|
// it's in. We put an order by and limit 1 in here to guarantee
|
46
|
// only finding the first one, even if there are somehow two
|
47
|
// Slony schemas.
|
48
|
$sql = "SELECT pn.nspname AS schema, pu.usename AS owner, SUBSTRING(pn.nspname FROM 2) AS cluster,
|
49
|
pg_catalog.obj_description(pn.oid, 'pg_namespace') AS nspcomment
|
50
|
FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pn, pg_catalog.pg_user pu
|
51
|
WHERE pp.pronamespace=pn.oid
|
52
|
AND pn.nspowner = pu.usesysid
|
53
|
AND pp.proname='slonyversion'
|
54
|
AND pn.nspname LIKE '\\\\_%'
|
55
|
ORDER BY pn.nspname LIMIT 1";
|
56
|
$rs = $data->selectSet($sql);
|
57
|
if ($rs->recordCount() == 1) {
|
58
|
$schema = $rs->f['schema'];
|
59
|
$this->slony_schema = $schema;
|
60
|
$this->slony_owner = $rs->f['owner'];
|
61
|
$this->slony_comment = $rs->f['nspcomment'];
|
62
|
// Cluster name is schema minus "_" prefix.
|
63
|
$this->slony_cluster = $rs->f['cluster'];
|
64
|
$data->fieldClean($schema);
|
65
|
$sql = "SELECT \"{$schema}\".slonyversion() AS version";
|
66
|
$version = $data->selectField($sql, 'version');
|
67
|
if ($version === -1) return false;
|
68
|
else {
|
69
|
$this->slony_version = $version;
|
70
|
$this->enabled = true;
|
71
|
return true;
|
72
|
}
|
73
|
}
|
74
|
else return false;
|
75
|
}
|
76
|
|
77
|
// CLUSTERS
|
78
|
|
79
|
/**
|
80
|
* Gets the clusters in this database
|
81
|
*/
|
82
|
function getClusters() {
|
83
|
include_once('./classes/ArrayRecordSet.php');
|
84
|
|
85
|
if ($this->isEnabled()) {
|
86
|
$clusters = array(array('cluster' => $this->slony_cluster, 'comment' => $this->slony_comment));
|
87
|
}
|
88
|
else
|
89
|
$clusters = array();
|
90
|
|
91
|
return new ArrayRecordSet($clusters);
|
92
|
}
|
93
|
|
94
|
/**
|
95
|
* Gets a single cluster
|
96
|
*/
|
97
|
function getCluster() {
|
98
|
global $data;
|
99
|
|
100
|
$schema = $this->slony_schema;
|
101
|
$data->fieldClean($schema);
|
102
|
$data->clean($no_id);
|
103
|
|
104
|
$sql = "SELECT no_id, no_comment, \"{$schema}\".slonyversion() AS version
|
105
|
FROM \"{$schema}\".sl_local_node_id, \"{$schema}\".sl_node
|
106
|
WHERE no_id=last_value";
|
107
|
|
108
|
|
109
|
return $data->selectSet($sql);
|
110
|
}
|
111
|
|
112
|
/**
|
113
|
* Drops an entire cluster.
|
114
|
*/
|
115
|
function dropCluster() {
|
116
|
global $data;
|
117
|
|
118
|
$schema = $this->slony_schema;
|
119
|
$data->fieldClean($schema);
|
120
|
|
121
|
$sql = "SELECT \"{$schema}\".uninstallnode(); DROP SCHEMA \"{$schema}\" CASCADE";
|
122
|
|
123
|
$status = $data->execute($sql);
|
124
|
if ($status == 0) {
|
125
|
$this->enabled = null;
|
126
|
$enabled = $this->isEnabled();
|
127
|
}
|
128
|
return $status;
|
129
|
}
|
130
|
|
131
|
/**
|
132
|
* Helper function to get a file into a string and replace
|
133
|
* variables.
|
134
|
* @return The file contents, or FALSE on error.
|
135
|
*/
|
136
|
function _getFile($file, $cluster) {
|
137
|
global $data,$misc;
|
138
|
$schema = '_' . $cluster;
|
139
|
$data->fieldClean($cluster);
|
140
|
|
141
|
$server_info = $misc->getServerInfo();
|
142
|
$path = $server_info['slony_sql'] . '/' . $file;
|
143
|
|
144
|
// Check that we can access the file
|
145
|
if (!file_exists($path) || !is_readable($path)) return false;
|
146
|
|
147
|
$buffer = null;
|
148
|
$handle = fopen($path, 'r');
|
149
|
if ($handle === false) return false;
|
150
|
while (!feof($handle)) {
|
151
|
$temp = fgets($handle, 4096);
|
152
|
$temp = str_replace('@CLUSTERNAME@', $cluster, $temp);
|
153
|
|
154
|
$temp = str_replace('@NAMESPACE@', $schema, $temp);
|
155
|
$buffer .= $temp;
|
156
|
}
|
157
|
fclose($handle);
|
158
|
|
159
|
return $buffer;
|
160
|
}
|
161
|
|
162
|
/**
|
163
|
* Initializes a new cluster
|
164
|
*/
|
165
|
function initCluster($name, $no_id, $no_comment) {
|
166
|
global $data, $misc;
|
167
|
|
168
|
// Prevent timeouts since cluster initialization can be slow
|
169
|
if (!ini_get('safe_mode')) set_time_limit(0);
|
170
|
|
171
|
$server_info = $misc->getServerInfo();
|
172
|
|
173
|
if (!$data->isSuperUser($server_info['username'])) {
|
174
|
return -10;
|
175
|
}
|
176
|
|
177
|
// Determine Slony compatibility version.
|
178
|
if ($data->major_version == 7.3)
|
179
|
$ver = '73';
|
180
|
elseif ($data->major_version >= 7.4)
|
181
|
$ver = '74';
|
182
|
else {
|
183
|
return -11;
|
184
|
}
|
185
|
|
186
|
$status = $data->beginTransaction();
|
187
|
if ($status != 0) return -1;
|
188
|
|
189
|
// Create the schema
|
190
|
$status = $data->createSchema('_' . $name);
|
191
|
if ($status != 0) {
|
192
|
$data->rollbackTransaction();
|
193
|
return -2;
|
194
|
}
|
195
|
|
196
|
$sql = $this->_getFile("xxid.v{$ver}.sql", $name);
|
197
|
if ($sql === false) {
|
198
|
$data->rollbackTransaction();
|
199
|
return -6;
|
200
|
}
|
201
|
$status = $data->execute($sql);
|
202
|
if ($status != 0) {
|
203
|
$data->rollbackTransaction();
|
204
|
return -3;
|
205
|
}
|
206
|
|
207
|
$sql = $this->_getFile('slony1_base.sql', $name);
|
208
|
if ($sql === false) {
|
209
|
$data->rollbackTransaction();
|
210
|
return -6;
|
211
|
}
|
212
|
$status = $data->execute($sql);
|
213
|
if ($status != 0) {
|
214
|
$data->rollbackTransaction();
|
215
|
return -3;
|
216
|
}
|
217
|
/* THIS FILE IS EMPTY AND JUST CAUSES ERRORS
|
218
|
$sql = $this->_getFile('slony1_base.v74.sql', $name);
|
219
|
$status = $data->execute($sql);
|
220
|
if ($status != 0) {
|
221
|
$data->rollbackTransaction();
|
222
|
return -3;
|
223
|
}
|
224
|
*/
|
225
|
$sql = $this->_getFile('slony1_funcs.sql', $name);
|
226
|
if ($sql === false) {
|
227
|
$data->rollbackTransaction();
|
228
|
return -6;
|
229
|
}
|
230
|
$status = $data->execute($sql);
|
231
|
if ($status != 0) {
|
232
|
$data->rollbackTransaction();
|
233
|
return -3;
|
234
|
}
|
235
|
|
236
|
$sql = $this->_getFile("slony1_funcs.v{$ver}.sql", $name);
|
237
|
if ($sql === false) {
|
238
|
$data->rollbackTransaction();
|
239
|
return -6;
|
240
|
}
|
241
|
$status = $data->execute($sql);
|
242
|
if ($status != 0) {
|
243
|
$data->rollbackTransaction();
|
244
|
return -3;
|
245
|
}
|
246
|
|
247
|
$this->enabled = null;
|
248
|
$enabled = $this->isEnabled();
|
249
|
if (!$enabled) {
|
250
|
$data->rollbackTransaction();
|
251
|
return -4;
|
252
|
}
|
253
|
|
254
|
$schema = $this->slony_schema;
|
255
|
$data->fieldClean($schema);
|
256
|
$data->clean($no_id);
|
257
|
$data->clean($no_comment);
|
258
|
|
259
|
$sql = "SELECT \"{$schema}\".initializelocalnode('{$no_id}', '{$no_comment}'); SELECT \"{$schema}\".enablenode('{$no_id}')";
|
260
|
$status = $data->execute($sql);
|
261
|
if ($status != 0) {
|
262
|
$data->rollbackTransaction();
|
263
|
return -5;
|
264
|
}
|
265
|
|
266
|
return $data->endTransaction();
|
267
|
}
|
268
|
|
269
|
// NODES
|
270
|
|
271
|
/**
|
272
|
* Gets the nodes in this database
|
273
|
*/
|
274
|
function getNodes() {
|
275
|
global $data;
|
276
|
|
277
|
$schema = $this->slony_schema;
|
278
|
$data->fieldClean($schema);
|
279
|
|
280
|
$sql = "SELECT * FROM \"{$schema}\".sl_node ORDER BY no_comment";
|
281
|
|
282
|
return $data->selectSet($sql);
|
283
|
}
|
284
|
|
285
|
/**
|
286
|
* Gets a single node
|
287
|
*/
|
288
|
function getNode($no_id) {
|
289
|
global $data;
|
290
|
|
291
|
$schema = $this->slony_schema;
|
292
|
$data->fieldClean($schema);
|
293
|
$data->clean($no_id);
|
294
|
|
295
|
$sql = "SELECT * FROM \"{$schema}\".sl_node WHERE no_id='{$no_id}'";
|
296
|
|
297
|
return $data->selectSet($sql);
|
298
|
}
|
299
|
|
300
|
/**
|
301
|
* Creates a node
|
302
|
*/
|
303
|
function createNode($no_id, $no_comment) {
|
304
|
global $data;
|
305
|
|
306
|
$schema = $this->slony_schema;
|
307
|
$data->fieldClean($schema);
|
308
|
$data->clean($no_comment);
|
309
|
$data->clean($no_id);
|
310
|
|
311
|
if ($no_id != '')
|
312
|
$sql = "SELECT \"{$schema}\".storenode('{$no_id}', '{$no_comment}')";
|
313
|
else
|
314
|
$sql = "SELECT \"{$schema}\".storenode((SELECT COALESCE(MAX(no_id), 0) + 1 FROM \"{$schema}\".sl_node), '{$no_comment}')";
|
315
|
|
316
|
return $data->execute($sql);
|
317
|
}
|
318
|
|
319
|
/**
|
320
|
* Drops a node
|
321
|
*/
|
322
|
function dropNode($no_id) {
|
323
|
global $data;
|
324
|
|
325
|
$schema = $this->slony_schema;
|
326
|
$data->fieldClean($schema);
|
327
|
$data->clean($no_id);
|
328
|
|
329
|
$sql = "SELECT \"{$schema}\".dropnode('{$no_id}')";
|
330
|
|
331
|
return $data->execute($sql);
|
332
|
}
|
333
|
|
334
|
// REPLICATION SETS
|
335
|
|
336
|
/**
|
337
|
* Gets the replication sets in this database
|
338
|
*/
|
339
|
function getReplicationSets() {
|
340
|
global $data;
|
341
|
|
342
|
$schema = $this->slony_schema;
|
343
|
$data->fieldClean($schema);
|
344
|
|
345
|
$sql = "SELECT *, set_locked IS NOT NULL AS is_locked FROM \"{$schema}\".sl_set ORDER BY set_id";
|
346
|
|
347
|
return $data->selectSet($sql);
|
348
|
}
|
349
|
|
350
|
/**
|
351
|
* Gets a particular replication set
|
352
|
*/
|
353
|
function getReplicationSet($set_id) {
|
354
|
global $data;
|
355
|
|
356
|
$schema = $this->slony_schema;
|
357
|
$data->fieldClean($schema);
|
358
|
$data->clean($set_id);
|
359
|
|
360
|
$sql = "SELECT *, (SELECT COUNT(*) FROM \"{$schema}\".sl_subscribe ssub WHERE ssub.sub_set=ss.set_id) AS subscriptions,
|
361
|
set_locked IS NOT NULL AS is_locked
|
362
|
FROM \"{$schema}\".sl_set ss, \"{$schema}\".sl_node sn
|
363
|
WHERE ss.set_origin=sn.no_id
|
364
|
AND set_id='{$set_id}'";
|
365
|
|
366
|
return $data->selectSet($sql);
|
367
|
}
|
368
|
|
369
|
/**
|
370
|
* Creates a set
|
371
|
*/
|
372
|
function createReplicationSet($set_id, $set_comment) {
|
373
|
global $data;
|
374
|
|
375
|
$schema = $this->slony_schema;
|
376
|
$data->fieldClean($schema);
|
377
|
$data->clean($set_comment);
|
378
|
$data->clean($set_id);
|
379
|
|
380
|
if ($set_id != '')
|
381
|
$sql = "SELECT \"{$schema}\".storeset('{$set_id}', '{$set_comment}')";
|
382
|
else
|
383
|
$sql = "SELECT \"{$schema}\".storeset((SELECT COALESCE(MAX(set_id), 0) + 1 FROM \"{$schema}\".sl_set), '{$set_comment}')";
|
384
|
|
385
|
return $data->execute($sql);
|
386
|
}
|
387
|
|
388
|
/**
|
389
|
* Drops a set
|
390
|
*/
|
391
|
function dropReplicationSet($set_id) {
|
392
|
global $data;
|
393
|
|
394
|
$schema = $this->slony_schema;
|
395
|
$data->fieldClean($schema);
|
396
|
$data->clean($set_id);
|
397
|
|
398
|
$sql = "SELECT \"{$schema}\".dropset('{$set_id}')";
|
399
|
|
400
|
return $data->execute($sql);
|
401
|
}
|
402
|
|
403
|
/**
|
404
|
* Locks or unlocks a set
|
405
|
* @param boolean $lock True to lock, false to unlock
|
406
|
*/
|
407
|
function lockReplicationSet($set_id, $lock) {
|
408
|
global $data;
|
409
|
|
410
|
$schema = $this->slony_schema;
|
411
|
$data->fieldClean($schema);
|
412
|
$data->clean($set_id);
|
413
|
|
414
|
if ($lock)
|
415
|
$sql = "SELECT \"{$schema}\".lockset('{$set_id}')";
|
416
|
else
|
417
|
$sql = "SELECT \"{$schema}\".unlockset('{$set_id}')";
|
418
|
|
419
|
return $data->execute($sql);
|
420
|
}
|
421
|
|
422
|
/**
|
423
|
* Merges two sets
|
424
|
*/
|
425
|
function mergeReplicationSet($set_id, $target) {
|
426
|
global $data;
|
427
|
|
428
|
$schema = $this->slony_schema;
|
429
|
$data->fieldClean($schema);
|
430
|
$data->clean($set_id);
|
431
|
$data->clean($target);
|
432
|
|
433
|
$sql = "SELECT \"{$schema}\".mergeset('{$target}', '{$set_id}')";
|
434
|
|
435
|
return $data->execute($sql);
|
436
|
}
|
437
|
|
438
|
/**
|
439
|
* Moves a set to a new origin
|
440
|
*/
|
441
|
function moveReplicationSet($set_id, $new_origin) {
|
442
|
global $data;
|
443
|
|
444
|
$schema = $this->slony_schema;
|
445
|
$data->fieldClean($schema);
|
446
|
$data->clean($set_id);
|
447
|
$data->clean($new_origin);
|
448
|
|
449
|
$sql = "SELECT \"{$schema}\".moveset('{$set_id}', '{$new_origin}')";
|
450
|
|
451
|
return $data->execute($sql);
|
452
|
}
|
453
|
|
454
|
/**
|
455
|
* Executes schema changing DDL set on nodes
|
456
|
*/
|
457
|
function executeReplicationSet($set_id, $script) {
|
458
|
global $data;
|
459
|
|
460
|
$schema = $this->slony_schema;
|
461
|
$data->fieldClean($schema);
|
462
|
$data->clean($set_id);
|
463
|
$data->clean($script);
|
464
|
|
465
|
$sql = "SELECT \"{$schema}\".ddlscript('{$set_id}', '{$script}')";
|
466
|
|
467
|
return $data->execute($sql);
|
468
|
}
|
469
|
|
470
|
// TABLES
|
471
|
|
472
|
/**
|
473
|
* Return all tables in a replication set
|
474
|
* @param $set_id The ID of the replication set
|
475
|
* @return Tables in the replication set, sorted alphabetically
|
476
|
*/
|
477
|
function getTables($set_id) {
|
478
|
global $data;
|
479
|
|
480
|
$schema = $this->slony_schema;
|
481
|
$data->fieldClean($schema);
|
482
|
$data->clean($set_id);
|
483
|
|
484
|
$sql = "SELECT st.tab_id, c.relname, n.nspname, n.nspname||'.'||c.relname AS qualname,
|
485
|
pg_catalog.pg_get_userbyid(c.relowner) AS relowner,
|
486
|
reltuples::integer";
|
487
|
// Tablespace
|
488
|
if ($data->hasTablespaces()) {
|
489
|
$sql .= ", (SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=c.reltablespace) AS tablespace";
|
490
|
}
|
491
|
$sql .= " FROM pg_catalog.pg_class c, \"{$schema}\".sl_table st, pg_catalog.pg_namespace n
|
492
|
WHERE c.oid=st.tab_reloid
|
493
|
AND c.relnamespace=n.oid
|
494
|
AND st.tab_set='{$set_id}'
|
495
|
ORDER BY n.nspname, c.relname";
|
496
|
|
497
|
return $data->selectSet($sql);
|
498
|
}
|
499
|
|
500
|
/**
|
501
|
* Adds a table to a replication set
|
502
|
*/
|
503
|
function addTable($set_id, $tab_id, $nspname, $relname, $idxname, $comment, $storedtriggers) {
|
504
|
global $data;
|
505
|
|
506
|
$schema = $this->slony_schema;
|
507
|
$data->fieldClean($schema);
|
508
|
$data->clean($set_id);
|
509
|
$data->clean($tab_id);
|
510
|
$fqname = $nspname . '.' . $relname;
|
511
|
$data->clean($fqname);
|
512
|
$data->clean($nspname);
|
513
|
$data->clean($relname);
|
514
|
$data->clean($idxname);
|
515
|
$data->clean($comment);
|
516
|
|
517
|
$hastriggers = (sizeof($storedtriggers) > 0);
|
518
|
if ($hastriggers) {
|
519
|
// Begin a transaction
|
520
|
$status = $data->beginTransaction();
|
521
|
if ($status != 0) return -1;
|
522
|
}
|
523
|
|
524
|
if ($tab_id != '')
|
525
|
$sql = "SELECT \"{$schema}\".setaddtable('{$set_id}', '{$tab_id}', '{$fqname}', '{$idxname}', '{$comment}')";
|
526
|
else {
|
527
|
$sql = "SELECT \"{$schema}\".setaddtable('{$set_id}', (SELECT COALESCE(MAX(tab_id), 0) + 1 FROM \"{$schema}\".sl_table), '{$fqname}', '{$idxname}', '{$comment}')";
|
528
|
}
|
529
|
|
530
|
$status = $data->execute($sql);
|
531
|
if ($status != 0) {
|
532
|
if ($hastriggers) $data->rollbackTransaction();
|
533
|
return -3;
|
534
|
}
|
535
|
|
536
|
// If we are storing triggers, we need to know the tab_id that was assigned to the table
|
537
|
if ($tab_id == '' && $hastriggers) {
|
538
|
$sql = "SELECT tab_id
|
539
|
FROM \"{$schema}\".sl_table
|
540
|
WHERE tab_set='{$set_id}'
|
541
|
AND tab_reloid=(SELECT pc.oid FROM pg_catalog.pg_class pc, pg_namespace pn
|
542
|
WHERE pc.relnamespace=pn.oid AND pc.relname='{$relname}'
|
543
|
AND pn.nspname='{$nspname}')";
|
544
|
$tab_id = $data->selectField($sql, 'tab_id');
|
545
|
if ($tab_id === -1) {
|
546
|
$data->rollbackTransaction();
|
547
|
return -4;
|
548
|
}
|
549
|
}
|
550
|
|
551
|
// Store requested triggers
|
552
|
if ($hastriggers) {
|
553
|
foreach ($storedtriggers as $tgname) {
|
554
|
$data->clean($tgname);
|
555
|
$sql = "SELECT \"{$schema}\".storetrigger('{$tab_id}', '{$tgname}')";
|
556
|
$status = $data->execute($sql);
|
557
|
if ($status != 0) {
|
558
|
$data->rollbackTransaction();
|
559
|
return -5;
|
560
|
}
|
561
|
}
|
562
|
}
|
563
|
|
564
|
if ($hastriggers)
|
565
|
return $data->endTransaction();
|
566
|
else
|
567
|
return $status;
|
568
|
}
|
569
|
|
570
|
/**
|
571
|
* Removes a table from a replication set
|
572
|
*/
|
573
|
function removeTable($tab_id) {
|
574
|
global $data;
|
575
|
|
576
|
$schema = $this->slony_schema;
|
577
|
$data->fieldClean($schema);
|
578
|
$data->clean($tab_id);
|
579
|
|
580
|
$sql = "SELECT \"{$schema}\".setdroptable('{$tab_id}')";
|
581
|
|
582
|
return $data->execute($sql);
|
583
|
}
|
584
|
|
585
|
/**
|
586
|
* Moves a table to another replication set
|
587
|
*/
|
588
|
function moveTable($tab_id, $new_set_id) {
|
589
|
global $data;
|
590
|
|
591
|
$schema = $this->slony_schema;
|
592
|
$data->fieldClean($schema);
|
593
|
$data->clean($tab_id);
|
594
|
$data->clean($new_set_id);
|
595
|
|
596
|
$sql = "SELECT \"{$schema}\".setmovetable('{$tab_id}', '{$new_set_id}')";
|
597
|
|
598
|
return $data->execute($sql);
|
599
|
}
|
600
|
|
601
|
// SEQUENCES
|
602
|
|
603
|
/**
|
604
|
* Return all sequences in a replication set
|
605
|
* @param $set_id The ID of the replication set
|
606
|
* @return Sequences in the replication set, sorted alphabetically
|
607
|
*/
|
608
|
function getSequences($set_id) {
|
609
|
global $data;
|
610
|
|
611
|
$schema = $this->slony_schema;
|
612
|
$data->fieldClean($schema);
|
613
|
$data->clean($set_id);
|
614
|
|
615
|
$sql = "SELECT ss.seq_id, c.relname AS seqname, n.nspname, n.nspname||'.'||c.relname AS qualname,
|
616
|
pg_catalog.obj_description(c.oid, 'pg_class') AS seqcomment,
|
617
|
pg_catalog.pg_get_userbyid(c.relowner) AS seqowner
|
618
|
FROM pg_catalog.pg_class c, \"{$schema}\".sl_sequence ss, pg_catalog.pg_namespace n
|
619
|
WHERE c.oid=ss.seq_reloid
|
620
|
AND c.relnamespace=n.oid
|
621
|
AND ss.seq_set='{$set_id}'
|
622
|
ORDER BY n.nspname, c.relname";
|
623
|
|
624
|
return $data->selectSet($sql);
|
625
|
}
|
626
|
|
627
|
/**
|
628
|
* Adds a sequence to a replication set
|
629
|
*/
|
630
|
function addSequence($set_id, $seq_id, $fqname, $comment) {
|
631
|
global $data;
|
632
|
|
633
|
$schema = $this->slony_schema;
|
634
|
$data->fieldClean($schema);
|
635
|
$data->clean($set_id);
|
636
|
$data->clean($seq_id);
|
637
|
$data->clean($fqname);
|
638
|
$data->clean($comment);
|
639
|
|
640
|
if ($seq_id != '')
|
641
|
$sql = "SELECT \"{$schema}\".setaddsequence('{$set_id}', '{$seq_id}', '{$fqname}', '{$comment}')";
|
642
|
else
|
643
|
$sql = "SELECT \"{$schema}\".setaddsequence('{$set_id}', (SELECT COALESCE(MAX(seq_id), 0) + 1 FROM \"{$schema}\".sl_sequence), '{$fqname}', '{$comment}')";
|
644
|
|
645
|
return $data->execute($sql); }
|
646
|
|
647
|
/**
|
648
|
* Removes a sequence from a replication set
|
649
|
*/
|
650
|
function removeSequence($seq_id) {
|
651
|
global $data;
|
652
|
|
653
|
$schema = $this->slony_schema;
|
654
|
$data->fieldClean($schema);
|
655
|
$data->clean($seq_id);
|
656
|
|
657
|
$sql = "SELECT \"{$schema}\".setdropsequence('{$seq_id}')";
|
658
|
|
659
|
return $data->execute($sql);
|
660
|
}
|
661
|
|
662
|
/**
|
663
|
* Moves a sequence to another replication set
|
664
|
*/
|
665
|
function moveSequence($seq_id, $new_set_id) {
|
666
|
global $data;
|
667
|
|
668
|
$schema = $this->slony_schema;
|
669
|
$data->fieldClean($schema);
|
670
|
$data->clean($seq_id);
|
671
|
$data->clean($new_set_id);
|
672
|
|
673
|
$sql = "SELECT \"{$schema}\".setmovesequence('{$seq_id}', '{$new_set_id}')";
|
674
|
|
675
|
return $data->execute($sql);
|
676
|
}
|
677
|
|
678
|
// SUBSCRIPTIONS
|
679
|
|
680
|
/**
|
681
|
* Gets all nodes subscribing to a set
|
682
|
* @param $set_id The ID of the replication set
|
683
|
* @return Nodes subscribing to this set
|
684
|
*/
|
685
|
function getSubscribedNodes($set_id) {
|
686
|
global $data;
|
687
|
|
688
|
$schema = $this->slony_schema;
|
689
|
$data->fieldClean($schema);
|
690
|
$data->clean($set_id);
|
691
|
|
692
|
$sql = "SELECT sn.*, ss.sub_set
|
693
|
FROM \"{$schema}\".sl_subscribe ss, \"{$schema}\".sl_node sn
|
694
|
WHERE ss.sub_set='{$set_id}'
|
695
|
AND ss.sub_receiver = sn.no_id
|
696
|
ORDER BY sn.no_comment";
|
697
|
|
698
|
return $data->selectSet($sql);
|
699
|
}
|
700
|
|
701
|
/**
|
702
|
* Gets all nodes subscribing to a set
|
703
|
* @param $set_id The ID of the replication set
|
704
|
* @return Nodes subscribing to this set
|
705
|
*/
|
706
|
function getSubscription($set_id, $no_id) {
|
707
|
global $data;
|
708
|
|
709
|
$schema = $this->slony_schema;
|
710
|
$data->fieldClean($schema);
|
711
|
$data->clean($set_id);
|
712
|
$data->clean($no_id);
|
713
|
|
714
|
$sql = "SELECT ss.*, sn.no_comment AS receiver, sn2.no_comment AS provider
|
715
|
FROM \"{$schema}\".sl_subscribe ss, \"{$schema}\".sl_node sn, \"{$schema}\".sl_node sn2
|
716
|
WHERE ss.sub_set='{$set_id}'
|
717
|
AND ss.sub_receiver = sn.no_id
|
718
|
AND ss.sub_provider = sn2.no_id
|
719
|
AND sn.no_id='{$no_id}'";
|
720
|
|
721
|
return $data->selectSet($sql);
|
722
|
}
|
723
|
|
724
|
// NODES
|
725
|
|
726
|
/**
|
727
|
* Gets node paths
|
728
|
*/
|
729
|
function getPaths($no_id) {
|
730
|
global $data;
|
731
|
|
732
|
$schema = $this->slony_schema;
|
733
|
$data->fieldClean($schema);
|
734
|
$data->clean($no_id);
|
735
|
|
736
|
$sql = "SELECT * FROM \"{$schema}\".sl_path sp, \"{$schema}\".sl_node sn
|
737
|
WHERE sp.pa_server=sn.no_id
|
738
|
AND sp.pa_client='{$no_id}'
|
739
|
ORDER BY sn.no_comment";
|
740
|
|
741
|
return $data->selectSet($sql);
|
742
|
}
|
743
|
|
744
|
/**
|
745
|
* Gets node path details
|
746
|
*/
|
747
|
function getPath($no_id, $path_id) {
|
748
|
global $data;
|
749
|
|
750
|
$schema = $this->slony_schema;
|
751
|
$data->fieldClean($schema);
|
752
|
$data->clean($no_id);
|
753
|
$data->clean($path_id);
|
754
|
|
755
|
$sql = "SELECT * FROM \"{$schema}\".sl_path sp, \"{$schema}\".sl_node sn
|
756
|
WHERE sp.pa_server=sn.no_id
|
757
|
AND sp.pa_client='{$no_id}'
|
758
|
AND sn.no_id='{$path_id}'";
|
759
|
|
760
|
return $data->selectSet($sql);
|
761
|
}
|
762
|
|
763
|
/**
|
764
|
* Creates a path
|
765
|
*/
|
766
|
function createPath($no_id, $server, $conn, $retry) {
|
767
|
global $data;
|
768
|
|
769
|
$schema = $this->slony_schema;
|
770
|
$data->fieldClean($schema);
|
771
|
$data->clean($no_id);
|
772
|
$data->clean($server);
|
773
|
$data->clean($conn);
|
774
|
$data->clean($retry);
|
775
|
|
776
|
$sql = "SELECT \"{$schema}\".storepath('{$server}', '{$no_id}', '{$conn}', '{$retry}')";
|
777
|
|
778
|
return $data->execute($sql);
|
779
|
}
|
780
|
|
781
|
/**
|
782
|
* Drops a path
|
783
|
*/
|
784
|
function dropPath($no_id, $path_id) {
|
785
|
global $data;
|
786
|
|
787
|
$schema = $this->slony_schema;
|
788
|
$data->fieldClean($schema);
|
789
|
$data->clean($no_id);
|
790
|
$data->clean($path_id);
|
791
|
|
792
|
$sql = "SELECT \"{$schema}\".droppath('{$path_id}', '{$no_id}')";
|
793
|
|
794
|
return $data->execute($sql);
|
795
|
}
|
796
|
|
797
|
// LISTENS
|
798
|
|
799
|
/**
|
800
|
* Gets node listens
|
801
|
*/
|
802
|
function getListens($no_id) {
|
803
|
global $data;
|
804
|
|
805
|
$schema = $this->slony_schema;
|
806
|
$data->fieldClean($schema);
|
807
|
$data->clean($no_id);
|
808
|
|
809
|
$sql = "SELECT * FROM \"{$schema}\".sl_listen sl, \"{$schema}\".sl_node sn
|
810
|
WHERE sl.li_provider=sn.no_id
|
811
|
AND sl.li_receiver='{$no_id}'
|
812
|
ORDER BY sn.no_comment";
|
813
|
|
814
|
return $data->selectSet($sql);
|
815
|
}
|
816
|
|
817
|
/**
|
818
|
* Gets node listen details
|
819
|
*/
|
820
|
function getListen($no_id, $listen_id) {
|
821
|
global $data;
|
822
|
|
823
|
$schema = $this->slony_schema;
|
824
|
$data->fieldClean($schema);
|
825
|
$data->clean($no_id);
|
826
|
$data->clean($listen_id);
|
827
|
|
828
|
$sql = "SELECT sl.*, sn.*, sn2.no_comment AS origin FROM \"{$schema}\".sl_listen sl, \"{$schema}\".sl_node sn, \"{$schema}\".sl_node sn2
|
829
|
WHERE sl.li_provider=sn.no_id
|
830
|
AND sl.li_receiver='{$no_id}'
|
831
|
AND sn.no_id='{$listen_id}'
|
832
|
AND sn2.no_id=sl.li_origin";
|
833
|
|
834
|
return $data->selectSet($sql);
|
835
|
}
|
836
|
|
837
|
/**
|
838
|
* Creates a listen
|
839
|
*/
|
840
|
function createListen($no_id, $origin, $provider) {
|
841
|
global $data;
|
842
|
|
843
|
$schema = $this->slony_schema;
|
844
|
$data->fieldClean($schema);
|
845
|
$data->clean($no_id);
|
846
|
$data->clean($origin);
|
847
|
$data->clean($provider);
|
848
|
|
849
|
$sql = "SELECT \"{$schema}\".storelisten('{$origin}', '{$provider}', '{$no_id}')";
|
850
|
|
851
|
return $data->execute($sql);
|
852
|
}
|
853
|
|
854
|
/**
|
855
|
* Drops a listen
|
856
|
*/
|
857
|
function dropListen($no_id, $origin, $provider) {
|
858
|
global $data;
|
859
|
|
860
|
$schema = $this->slony_schema;
|
861
|
$data->fieldClean($schema);
|
862
|
$data->clean($no_id);
|
863
|
$data->clean($origin);
|
864
|
$data->clean($provider);
|
865
|
|
866
|
$sql = "SELECT \"{$schema}\".droplisten('{$origin}', '{$provider}', '{$no_id}')";
|
867
|
|
868
|
return $data->execute($sql);
|
869
|
}
|
870
|
|
871
|
// ACTIONS
|
872
|
|
873
|
|
874
|
|
875
|
}
|
876
|
|
877
|
?>
|