Completed
Pull Request — develop (#209)
by Felipe
26:08 queued 36s
created

IndexTrait::dropIndex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 15
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 2
dl 15
loc 15
rs 9.4285
c 0
b 0
f 0
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 View Code Duplication
    public function alreadyClustered($table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
22
    {
23
        $c_schema = $this->_schema;
0 ignored issues
show
Bug introduced by
The property _schema does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
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 View Code Duplication
    public function dropIndex($index, $cascade)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function clusterIndex($table = '', $index = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function getConstraintsWithFields($table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
$max_col is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
218
        } else {
219
            $max_col = $rs->fields['nb'];
0 ignored issues
show
Unused Code introduced by
$max_col is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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 View Code Duplication
    public function addPrimaryKey($table, $fields, $name = '', $tablespace = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function addUniqueKey($table, $fields, $name = '', $tablespace = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public function addCheckConstraint($table, $definition, $name = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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(
0 ignored issues
show
Coding Style Naming introduced by
The parameter $upd_action is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Naming introduced by
The parameter $del_action is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
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]) {
0 ignored issues
show
Bug introduced by
The property fkmatches does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
476
            $sql .= " {$match}";
477
        }
478
479
        if ($upd_action != $this->fkactions[0]) {
0 ignored issues
show
Bug introduced by
The property fkactions does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
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]) {
0 ignored issues
show
Bug introduced by
The property fkdeferrable does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
488
            $sql .= " {$deferrable}";
489
        }
490
491
        if ($initially != $this->fkinitial[0]) {
0 ignored issues
show
Bug introduced by
The property fkinitial does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
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)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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 View Code Duplication
    public function getReferrers($table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
658
659
    abstract public function beginTransaction();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
660
661
    abstract public function rollbackTransaction();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
662
663
    abstract public function endTransaction();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
664
665
    abstract public function execute($sql);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
666
667
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
Coding Style Naming introduced by
The parameter $obj_type is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Naming introduced by
The parameter $obj_name is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
668
669
    abstract public function selectSet($sql);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
670
671
    abstract public function clean(&$str);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
672
673
    abstract public function hasTablespaces();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
674
675
    abstract public function arrayClean(&$arr);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
676
677
    abstract public function fieldArrayClean(&$arr);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
678
}
679