Passed
Push — develop ( c2019a...2cab77 )
by Felipe
04:50
created

IndexTrait::getReferrers()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 33
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 1
1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.48
5
 */
6
7
namespace PHPPgAdmin\Database\Traits;
8
9
/**
10
 * Common trait for indexes and constraints manipulation.
11
 */
12
trait IndexTrait
13
{
14
    /**
15
     * Test if a table has been clustered on an index.
16
     *
17
     * @param string $table The table to test
18
     *
19
     * @return bool true if the table has been already clustered
20
     */
21
    public function alreadyClustered($table)
22
    {
23
        $c_schema = $this->_schema;
24
        $this->clean($c_schema);
25
        $this->clean($table);
26
27
        $sql = "SELECT i.indisclustered
28
			FROM pg_catalog.pg_class c, pg_catalog.pg_index i
29
			WHERE c.relname = '{$table}'
30
				AND c.oid = i.indrelid AND i.indisclustered
31
				AND c.relnamespace = (SELECT oid FROM pg_catalog.pg_namespace
32
					WHERE nspname='{$c_schema}')
33
				";
34
35
        $v = $this->selectSet($sql);
36
37
        return !($v->RecordCount() == 0);
38
    }
39
40
    /**
41
     * Creates an index.
42
     *
43
     * @param string       $name         The index name (can be blank)
44
     * @param string       $table        The table on which to add the index
45
     * @param array|string $columns      An array of columns that form the index  or a string expression for a functional index
46
     * @param string       $type         The index type
47
     * @param bool         $unique       True if unique, false otherwise
48
     * @param string       $where        Index predicate ('' for none)
49
     * @param string       $tablespace   The tablespaces ('' means none/default)
50
     * @param bool         $concurrently true to create index concurrently
51
     *
52
     * @return array status (0 if operation was successful) and sql sentence
53
     */
54
    public function createIndex($name, $table, $columns, $type, $unique, $where, $tablespace, $concurrently)
55
    {
56
        $f_schema = $this->_schema;
57
        $this->fieldClean($f_schema);
58
        $this->fieldClean($name);
59
        $this->fieldClean($table);
60
61
        $sql = 'CREATE ';
62
63
        $sql .= $unique ? ' UNIQUE ' : '';
64
65
        $sql .= ' INDEX ';
66
67
        $sql .= $concurrently ? ' CONCURRENTLY ' : '';
68
69
        $sql .= $name ? "  \"{$name}\" " : '';
70
71
        $sql .= " ON \"{$f_schema}\".\"{$table}\" USING {$type} ";
72
73
        if (is_array($columns)) {
74
            $this->arrayClean($columns);
75
            $sql .= '("'.implode('","', $columns).'")';
76
        } else {
77
            $sql .= '('.$columns.')';
78
        }
79
80
        // Tablespace
81
        if ($this->hasTablespaces() && $tablespace != '') {
82
            $this->fieldClean($tablespace);
83
            $sql .= " TABLESPACE \"{$tablespace}\"";
84
        }
85
86
        // Predicate
87
        if (trim($where) != '') {
88
            $sql .= " WHERE ({$where})";
89
        }
90
91
        $status = $this->execute($sql);
92
93
        return [$status, $sql];
94
    }
95
96
    /**
97
     * Removes an index from the database.
98
     *
99
     * @param string $index   The index to drop
100
     * @param bool   $cascade True to cascade drop, false to restrict
101
     *
102
     * @return array<integer,mixed|string> 0 if operation was successful
103
     */
104
    public function dropIndex($index, $cascade)
105
    {
106
        $f_schema = $this->_schema;
107
        $this->fieldClean($f_schema);
108
        $this->fieldClean($index);
109
110
        $sql = "DROP INDEX \"{$f_schema}\".\"{$index}\"";
111
        if ($cascade) {
112
            $sql .= ' CASCADE';
113
        }
114
115
        $status = $this->execute($sql);
116
117
        return [$status, $sql];
118
    }
119
120
    /**
121
     * Rebuild indexes.
122
     *
123
     * @param string $type  'DATABASE' or 'TABLE' or 'INDEX'
124
     * @param string $name  The name of the specific database, table, or index to be reindexed
125
     * @param bool   $force If true, recreates indexes forcedly in PostgreSQL 7.0-7.1, forces rebuild of system indexes in
126
     *                      7.2-7.3, ignored in >=7.4
127
     *
128
     * @return int 0 if operation was successful
129
     */
130
    public function reindex($type, $name, $force = false)
131
    {
132
        $f_schema = $this->_schema;
133
        $this->fieldClean($f_schema);
134
        $this->fieldClean($name);
135
        switch ($type) {
136
            case 'DATABASE':
137
                $sql = "REINDEX {$type} \"{$name}\"";
138
                if ($force) {
139
                    $sql .= ' FORCE';
140
                }
141
142
                break;
143
            case 'TABLE':
144
            case 'INDEX':
145
                $sql = "REINDEX {$type} \"{$f_schema}\".\"{$name}\"";
146
                if ($force) {
147
                    $sql .= ' FORCE';
148
                }
149
150
                break;
151
            default:
152
                return -1;
153
        }
154
155
        return $this->execute($sql);
156
    }
157
158
    /**
159
     * Clusters an index.
160
     *
161
     * @param string $table The table the index is on
162
     * @param string $index The name of the index
163
     *
164
     * @return array<integer,mixed|string> 0 if operation was successful
165
     */
166
    public function clusterIndex($table = '', $index = '')
167
    {
168
        $sql = 'CLUSTER';
169
170
        // We don't bother with a transaction here, as there's no point rolling
171
        // back an expensive cluster if a cheap analyze fails for whatever reason
172
173
        if (!empty($table)) {
174
            $f_schema = $this->_schema;
175
            $this->fieldClean($f_schema);
176
            $this->fieldClean($table);
177
            $sql .= " \"{$f_schema}\".\"{$table}\"";
178
179
            if (!empty($index)) {
180
                $this->fieldClean($index);
181
                $sql .= " USING \"{$index}\"";
182
            }
183
        }
184
185
        $status = $this->execute($sql);
186
187
        return [$status, $sql];
188
    }
189
190
    /**
191
     * Returns a list of all constraints on a table,
192
     * including constraint name, definition, related col and referenced namespace,
193
     * table and col if needed.
194
     *
195
     * @param string $table the table where we are looking for fk
196
     *
197
     * @return \PHPPgAdmin\ADORecordSet A recordset
198
     */
199
    public function getConstraintsWithFields($table)
200
    {
201
        $c_schema = $this->_schema;
202
        $this->clean($c_schema);
203
        $this->clean($table);
204
205
        // get the max number of col used in a constraint for the table
206
        $sql = "SELECT DISTINCT
207
			max(SUBSTRING(array_dims(c.conkey) FROM  \$patern\$^\\[.*:(.*)\\]$\$patern\$)) as nb
208
		FROM pg_catalog.pg_constraint AS c
209
			JOIN pg_catalog.pg_class AS r ON (c.conrelid=r.oid)
210
			JOIN pg_catalog.pg_namespace AS ns ON (r.relnamespace=ns.oid)
211
		WHERE
212
			r.relname = '{$table}' AND ns.nspname='{$c_schema}'";
213
214
        $rs = $this->selectSet($sql);
215
216
        if ($rs->EOF) {
217
            $max_col = 0;
218
        } else {
219
            $max_col = $rs->fields['nb'];
220
        }
221
222
        $sql = '
223
			SELECT
224
				c.oid AS conid, c.contype, c.conname, pg_catalog.pg_get_constraintdef(c.oid, true) AS consrc,
225
				ns1.nspname as p_schema, r1.relname as p_table, ns2.nspname as f_schema,
226
				r2.relname as f_table, f1.attname as p_field, f1.attnum AS p_attnum, f2.attname as f_field,
227
				f2.attnum AS f_attnum, pg_catalog.obj_description(c.oid, \'pg_constraint\') AS constcomment,
228
				c.conrelid, c.confrelid
229
			FROM
230
				pg_catalog.pg_constraint AS c
231
				JOIN pg_catalog.pg_class AS r1 ON (c.conrelid=r1.oid)
232
				JOIN pg_catalog.pg_attribute AS f1 ON (f1.attrelid=r1.oid AND (f1.attnum=c.conkey[1]';
233
        for ($i = 2; $i <= $rs->fields['nb']; ++$i) {
234
            $sql .= " OR f1.attnum=c.conkey[${i}]";
235
        }
236
        $sql .= '))
237
				JOIN pg_catalog.pg_namespace AS ns1 ON r1.relnamespace=ns1.oid
238
				LEFT JOIN (
239
					pg_catalog.pg_class AS r2 JOIN pg_catalog.pg_namespace AS ns2 ON (r2.relnamespace=ns2.oid)
240
				) ON (c.confrelid=r2.oid)
241
				LEFT JOIN pg_catalog.pg_attribute AS f2 ON
242
					(f2.attrelid=r2.oid AND ((c.confkey[1]=f2.attnum AND c.conkey[1]=f1.attnum)';
243
        for ($i = 2; $i <= $rs->fields['nb']; ++$i) {
244
            $sql .= " OR (c.confkey[${i}]=f2.attnum AND c.conkey[${i}]=f1.attnum)";
245
        }
246
247
        $sql .= sprintf("))
248
			WHERE
249
				r1.relname = '%s' AND ns1.nspname='%s'
250
			ORDER BY 1", $table, $c_schema);
251
252
        return $this->selectSet($sql);
253
    }
254
255
    /**
256
     * Adds a primary key constraint to a table.
257
     *
258
     * @param string $table      The table to which to add the primery key
259
     * @param array  $fields     (array) An array of fields over which to add the primary key
260
     * @param string $name       (optional) The name to give the key, otherwise default name is assigned
261
     * @param string $tablespace (optional) The tablespace for the schema, '' indicates default
262
     *
263
     * @return int 0 if operation was successful
264
     */
265
    public function addPrimaryKey($table, $fields, $name = '', $tablespace = '')
266
    {
267
        if (!is_array($fields) || sizeof($fields) == 0) {
268
            return -1;
269
        }
270
271
        $f_schema = $this->_schema;
272
        $this->fieldClean($f_schema);
273
        $this->fieldClean($table);
274
        $this->fieldArrayClean($fields);
275
        $this->fieldClean($name);
276
        $this->fieldClean($tablespace);
277
278
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD ";
279
        if ($name != '') {
280
            $sql .= "CONSTRAINT \"{$name}\" ";
281
        }
282
283
        $sql .= 'PRIMARY KEY ("'.join('","', $fields).'")';
284
285
        if ($tablespace != '' && $this->hasTablespaces()) {
286
            $sql .= " USING INDEX TABLESPACE \"{$tablespace}\"";
287
        }
288
289
        return $this->execute($sql);
290
    }
291
292
    /**
293
     * Adds a unique constraint to a table.
294
     *
295
     * @param string      $table      The table to which to add the unique key
296
     * @param array|mixed $fields     (array) An array of fields over which to add the unique key
297
     * @param string      $name       (optional) The name to give the key, otherwise default name is assigned
298
     * @param string      $tablespace (optional) The tablespace for the schema, '' indicates default
299
     *
300
     * @return int 0 if operation was successful
301
     */
302
    public function addUniqueKey($table, $fields, $name = '', $tablespace = '')
303
    {
304
        if (!is_array($fields) || sizeof($fields) == 0) {
305
            return -1;
306
        }
307
308
        $f_schema = $this->_schema;
309
        $this->fieldClean($f_schema);
310
        $this->fieldClean($table);
311
        $this->fieldArrayClean($fields);
312
        $this->fieldClean($name);
313
        $this->fieldClean($tablespace);
314
315
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD ";
316
        if ($name != '') {
317
            $sql .= "CONSTRAINT \"{$name}\" ";
318
        }
319
320
        $sql .= 'UNIQUE ("'.join('","', $fields).'")';
321
322
        if ($tablespace != '' && $this->hasTablespaces()) {
323
            $sql .= " USING INDEX TABLESPACE \"{$tablespace}\"";
324
        }
325
326
        return $this->execute($sql);
327
    }
328
329
    // Function functions
330
331
    /**
332
     * Adds a check constraint to a table.
333
     *
334
     * @param string $table      The table to which to add the check
335
     * @param string $definition The definition of the check
336
     * @param string $name       (optional) The name to give the check, otherwise default name is assigned
337
     *
338
     * @return int 0 if operation was successful
339
     */
340
    public function addCheckConstraint($table, $definition, $name = '')
341
    {
342
        $f_schema = $this->_schema;
343
        $this->fieldClean($f_schema);
344
        $this->fieldClean($table);
345
        $this->fieldClean($name);
346
        // @@ How the heck do you clean a definition???
347
348
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD ";
349
        if ($name != '') {
350
            $sql .= "CONSTRAINT \"{$name}\" ";
351
        }
352
353
        $sql .= "CHECK ({$definition})";
354
355
        return $this->execute($sql);
356
    }
357
358
    /**
359
     * Drops a check constraint from a table.
360
     *
361
     * @param string $table The table from which to drop the check
362
     * @param string $name  The name of the check to be dropped
363
     *
364
     * @return bool|int 0 success
365
     */
366
    public function dropCheckConstraint($table, $name)
367
    {
368
        $f_schema = $this->_schema;
369
        $this->fieldClean($f_schema);
370
        $c_schema = $this->_schema;
371
        $this->clean($c_schema);
372
        $c_table = $table;
373
        $this->fieldClean($table);
374
        $this->clean($c_table);
375
        $this->clean($name);
376
377
        // Begin transaction
378
        $status = $this->beginTransaction();
379
        if ($status != 0) {
380
            return -2;
381
        }
382
383
        // Properly lock the table
384
        $sql    = "LOCK TABLE \"{$f_schema}\".\"{$table}\" IN ACCESS EXCLUSIVE MODE";
385
        $status = $this->execute($sql);
386
        if ($status != 0) {
387
            $this->rollbackTransaction();
388
389
            return -3;
390
        }
391
392
        // Delete the check constraint
393
        $sql = "DELETE FROM pg_relcheck WHERE rcrelid=(SELECT oid FROM pg_catalog.pg_class WHERE relname='{$c_table}'
394
			AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
395
			nspname = '{$c_schema}')) AND rcname='{$name}'";
396
        $status = $this->execute($sql);
397
        if ($status != 0) {
398
            $this->rollbackTransaction();
399
400
            return -4;
401
        }
402
403
        // Update the pg_class catalog to reflect the new number of checks
404
        $sql = "UPDATE pg_class SET relchecks=(SELECT COUNT(*) FROM pg_relcheck WHERE
405
					rcrelid=(SELECT oid FROM pg_catalog.pg_class WHERE relname='{$c_table}'
406
						AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
407
						nspname = '{$c_schema}')))
408
					WHERE relname='{$c_table}'";
409
        $status = $this->execute($sql);
410
        if ($status != 0) {
411
            $this->rollbackTransaction();
412
413
            return -4;
414
        }
415
416
        // Otherwise, close the transaction
417
        return $this->endTransaction();
418
    }
419
420
    /**
421
     * Adds a foreign key constraint to a table.
422
     *
423
     * @param string $table      The table on which to add an FK
424
     * @param string $targschema The schema that houses the target table to which to add the foreign key
425
     * @param string $targtable  The table to which to add the foreign key
426
     * @param array  $sfields    (array) An array of source fields over which to add the foreign key
427
     * @param array  $tfields    (array) An array of target fields over which to add the foreign key
428
     * @param string $upd_action The action for updates (eg. RESTRICT)
429
     * @param string $del_action The action for deletes (eg. RESTRICT)
430
     * @param string $match      The match type (eg. MATCH FULL)
431
     * @param string $deferrable The deferrability (eg. NOT DEFERRABLE)
432
     * @param string $initially  The initially parameter for the FK (eg. INITIALLY IMMEDIATE)
433
     * @param string $name       [optional] The name to give the key, otherwise default name is assigned
434
     *
435
     * @return int 0 if operation was successful
436
     *
437
     * @internal param \PHPPgAdmin\Database\The $target table that contains the target columns
438
     * @internal param \PHPPgAdmin\Database\The $intially initial deferrability (eg. INITIALLY IMMEDIATE)
439
     */
440
    public function addForeignKey(
441
        $table,
442
        $targschema,
443
        $targtable,
444
        $sfields,
445
        $tfields,
446
        $upd_action,
447
        $del_action,
448
        $match,
449
        $deferrable,
450
        $initially,
451
        $name = ''
452
    ) {
453
        if (!is_array($sfields) || sizeof($sfields) == 0 ||
454
            !is_array($tfields) || sizeof($tfields) == 0) {
455
            return -1;
456
        }
457
458
        $f_schema = $this->_schema;
459
        $this->fieldClean($f_schema);
460
        $this->fieldClean($table);
461
        $this->fieldClean($targschema);
462
        $this->fieldClean($targtable);
463
        $this->fieldArrayClean($sfields);
464
        $this->fieldArrayClean($tfields);
465
        $this->fieldClean($name);
466
467
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD ";
468
        if ($name != '') {
469
            $sql .= "CONSTRAINT \"{$name}\" ";
470
        }
471
472
        $sql .= 'FOREIGN KEY ("'.join('","', $sfields).'") ';
473
        // Target table needs to be fully qualified
474
        $sql .= "REFERENCES \"{$targschema}\".\"{$targtable}\"(\"".join('","', $tfields).'") ';
475
        if ($match != $this->fkmatches[0]) {
476
            $sql .= " {$match}";
477
        }
478
479
        if ($upd_action != $this->fkactions[0]) {
480
            $sql .= " ON UPDATE {$upd_action}";
481
        }
482
483
        if ($del_action != $this->fkactions[0]) {
484
            $sql .= " ON DELETE {$del_action}";
485
        }
486
487
        if ($deferrable != $this->fkdeferrable[0]) {
488
            $sql .= " {$deferrable}";
489
        }
490
491
        if ($initially != $this->fkinitial[0]) {
492
            $sql .= " {$initially}";
493
        }
494
495
        return $this->execute($sql);
496
    }
497
498
    /**
499
     * Removes a constraint from a relation.
500
     *
501
     * @param string $constraint The constraint to drop
502
     * @param string $relation   The relation from which to drop
503
     * @param string $type       The type of constraint (c, f, u or p)
504
     * @param bool   $cascade    True to cascade drop, false to restrict
505
     *
506
     * @return int 0 if operation was successful
507
     */
508
    public function dropConstraint($constraint, $relation, $type, $cascade)
509
    {
510
        $f_schema = $this->_schema;
511
        $this->fieldClean($f_schema);
512
        $this->fieldClean($constraint);
513
        $this->fieldClean($relation);
514
515
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$relation}\" DROP CONSTRAINT \"{$constraint}\"";
516
        if ($cascade) {
517
            $sql .= ' CASCADE';
518
        }
519
520
        return $this->execute($sql);
521
    }
522
523
    /**
524
     * A function for getting all columns linked by foreign keys given a group of tables.
525
     *
526
     * @param array $tables multi dimensional assoc array that holds schema and table name
527
     *
528
     * @return int|\PHPPgAdmin\ADORecordSet recordset of linked tables and columns or -1 if $tables isn't an array
529
     */
530
    public function getLinkingKeys($tables)
531
    {
532
        if (!is_array($tables)) {
533
            return -1;
534
        }
535
536
        $this->clean($tables[0]['tablename']);
537
        $this->clean($tables[0]['schemaname']);
538
        $tables_list        = "'{$tables[0]['tablename']}'";
539
        $schema_list        = "'{$tables[0]['schemaname']}'";
540
        $schema_tables_list = "'{$tables[0]['schemaname']}.{$tables[0]['tablename']}'";
541
        $tablescount        = sizeof($tables);
542
543
        for ($i = 1; $i < $tablescount; ++$i) {
544
            $this->clean($tables[$i]['tablename']);
545
            $this->clean($tables[$i]['schemaname']);
546
            $tables_list .= ", '{$tables[$i]['tablename']}'";
547
            $schema_list .= ", '{$tables[$i]['schemaname']}'";
548
            $schema_tables_list .= ", '{$tables[$i]['schemaname']}.{$tables[$i]['tablename']}'";
549
        }
550
551
        $maxDimension = 1;
552
553
        $sql = "
554
			SELECT DISTINCT
555
				array_dims(pc.conkey) AS arr_dim,
556
				pgc1.relname AS p_table
557
			FROM
558
				pg_catalog.pg_constraint AS pc,
559
				pg_catalog.pg_class AS pgc1
560
			WHERE
561
				pc.contype = 'f'
562
				AND (pc.conrelid = pgc1.relfilenode OR pc.confrelid = pgc1.relfilenode)
563
				AND pgc1.relname IN (${tables_list})
564
			";
565
566
        //parse our output to find the highest dimension of foreign keys since pc.conkey is stored in an array
567
        $rs = $this->selectSet($sql);
568
        while (!$rs->EOF) {
569
            $arrData      = explode(':', $rs->fields['arr_dim']);
570
            $strdimension = trim(substr($arrData[1], 0, strlen($arrData[1]) - 1));
571
            $tmpDimension = (int) $strdimension;
572
            $maxDimension = $tmpDimension > $maxDimension ? $tmpDimension : $maxDimension;
573
            $rs->MoveNext();
574
        }
575
576
        //we know the highest index for foreign keys that conkey goes up to, expand for us in an IN query
577
        $cons_str = '( (pfield.attnum = conkey[1] AND cfield.attnum = confkey[1]) ';
578
        for ($i = 2; $i <= $maxDimension; ++$i) {
579
            $cons_str .= "OR (pfield.attnum = conkey[{$i}] AND cfield.attnum = confkey[{$i}]) ";
580
        }
581
        $cons_str .= ') ';
582
583
        $sql = "
584
			SELECT
585
				pgc1.relname AS p_table,
586
				pgc2.relname AS f_table,
587
				pfield.attname AS p_field,
588
				cfield.attname AS f_field,
589
				pgns1.nspname AS p_schema,
590
				pgns2.nspname AS f_schema
591
			FROM
592
				pg_catalog.pg_constraint AS pc,
593
				pg_catalog.pg_class AS pgc1,
594
				pg_catalog.pg_class AS pgc2,
595
				pg_catalog.pg_attribute AS pfield,
596
				pg_catalog.pg_attribute AS cfield,
597
				(SELECT oid AS ns_id, nspname FROM pg_catalog.pg_namespace WHERE nspname IN (${schema_list}) ) AS pgns1,
598
 				(SELECT oid AS ns_id, nspname FROM pg_catalog.pg_namespace WHERE nspname IN (${schema_list}) ) AS pgns2
599
			WHERE
600
				pc.contype = 'f'
601
				AND pgc1.relnamespace = pgns1.ns_id
602
 				AND pgc2.relnamespace = pgns2.ns_id
603
				AND pc.conrelid = pgc1.relfilenode
604
				AND pc.confrelid = pgc2.relfilenode
605
				AND pfield.attrelid = pc.conrelid
606
				AND cfield.attrelid = pc.confrelid
607
				AND ${cons_str}
608
				AND pgns1.nspname || '.' || pgc1.relname IN (${schema_tables_list})
609
				AND pgns2.nspname || '.' || pgc2.relname IN (${schema_tables_list})
610
		";
611
612
        return $this->selectSet($sql);
613
    }
614
615
    /**
616
     * Finds the foreign keys that refer to the specified table.
617
     *
618
     * @param string $table The table to find referrers for
619
     *
620
     * @return int|\PHPPgAdmin\ADORecordSet A recordset or -1 in case of error
621
     */
622
    public function getReferrers($table)
623
    {
624
        $this->clean($table);
625
626
        $status = $this->beginTransaction();
627
        if ($status != 0) {
628
            return -1;
629
        }
630
631
        $c_schema = $this->_schema;
632
        $this->clean($c_schema);
633
634
        $sql = "
635
			SELECT
636
				pn.nspname,
637
				pl.relname,
638
				pc.conname,
639
				pg_catalog.pg_get_constraintdef(pc.oid) AS consrc
640
			FROM
641
				pg_catalog.pg_constraint pc,
642
				pg_catalog.pg_namespace pn,
643
				pg_catalog.pg_class pl
644
			WHERE
645
				pc.connamespace = pn.oid
646
				AND pc.conrelid = pl.oid
647
				AND pc.contype = 'f'
648
				AND confrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
649
					AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace
650
					WHERE nspname='{$c_schema}'))
651
			ORDER BY 1,2,3
652
		";
653
654
        return $this->selectSet($sql);
655
    }
656
657
    abstract public function fieldClean(&$str);
658
659
    abstract public function beginTransaction();
660
661
    abstract public function rollbackTransaction();
662
663
    abstract public function endTransaction();
664
665
    abstract public function execute($sql);
666
667
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
668
669
    abstract public function selectSet($sql);
670
671
    abstract public function clean(&$str);
672
673
    abstract public function hasTablespaces();
674
675
    abstract public function arrayClean(&$arr);
676
677
    abstract public function fieldArrayClean(&$arr);
678
}
679