Test Failed
Push — master ( 34dd7c...325a03 )
by Felipe
11:17 queued 06:14
created

TableTrait::alterColumn()   F

Complexity

Conditions 18
Paths 2162

Size

Total Lines 110
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 110
rs 2
c 0
b 0
f 0
cc 18
eloc 55
nc 2162
nop 12

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.43
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
/**
10
 * Common trait for tables manipulation.
11
 */
12
trait TableTrait
13
{
14
    /**
15
     * Return all tables in current database (and schema).
16
     *
17
     * @param bool|true $all True to fetch all tables, false for just in current schema
18
     *
19
     * @return \PHPPgAdmin\ADORecordSet All tables, sorted alphabetically
20
     */
21
    public function getTables($all = false)
22
    {
23
        $c_schema = $this->_schema;
24
        $this->clean($c_schema);
25
        if ($all) {
26
            // Exclude pg_catalog and information_schema tables
27
            $sql = "SELECT
28
                        schemaname AS nspname,
29
                        tablename AS relname,
30
                        tableowner AS relowner
31
                    FROM pg_catalog.pg_tables
32
                    WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
33
                    ORDER BY schemaname, tablename";
34
        } else {
35
            $sql = "
36
                SELECT c.relname,
37
                    pg_catalog.pg_get_userbyid(c.relowner) AS relowner,
38
                    pg_catalog.obj_description(c.oid, 'pg_class') AS relcomment,
39
                    reltuples::bigint,
40
                    pt.spcname as tablespace,
41
                    pg_size_pretty(pg_total_relation_size(c.oid)) as table_size
42
                FROM pg_catalog.pg_class c
43
                LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
44
                LEFT JOIN  pg_catalog.pg_tablespace pt ON  pt.oid=c.reltablespace
45
                WHERE c.relkind = 'r'
46
                AND nspname='{$c_schema}'
47
                ORDER BY c.relname";
48
        }
49
50
        return $this->selectSet($sql);
51
    }
52
53
    /**
54
     * Finds the names and schemas of parent tables (in order).
55
     *
56
     * @param string $table The table to find the parents for
57
     *
58
     * @return \PHPPgAdmin\ADORecordSet A recordset
59
     */
60
    public function getTableParents($table)
61
    {
62
        $c_schema = $this->_schema;
63
        $this->clean($c_schema);
64
        $this->clean($table);
65
66
        $sql = "
67
            SELECT
68
                pn.nspname, relname
69
            FROM
70
                pg_catalog.pg_class pc, pg_catalog.pg_inherits pi, pg_catalog.pg_namespace pn
71
            WHERE
72
                pc.oid=pi.inhparent
73
                AND pc.relnamespace=pn.oid
74
                AND pi.inhrelid = (SELECT oid from pg_catalog.pg_class WHERE relname='{$table}'
75
                    AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = '{$c_schema}'))
76
            ORDER BY
77
                pi.inhseqno
78
        ";
79
80
        return $this->selectSet($sql);
81
    }
82
83
    /**
84
     * Finds the names and schemas of child tables.
85
     *
86
     * @param string $table The table to find the children for
87
     *
88
     * @return \PHPPgAdmin\ADORecordSet A recordset
89
     */
90
    public function getTableChildren($table)
91
    {
92
        $c_schema = $this->_schema;
93
        $this->clean($c_schema);
94
        $this->clean($table);
95
96
        $sql = "
97
            SELECT
98
                pn.nspname, relname
99
            FROM
100
                pg_catalog.pg_class pc, pg_catalog.pg_inherits pi, pg_catalog.pg_namespace pn
101
            WHERE
102
                pc.oid=pi.inhrelid
103
                AND pc.relnamespace=pn.oid
104
                AND pi.inhparent = (SELECT oid from pg_catalog.pg_class WHERE relname='{$table}'
105
                    AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = '{$c_schema}'))
106
        ";
107
108
        return $this->selectSet($sql);
109
    }
110
111
    /**
112
     * Returns the SQL definition for the table.
113
     * MUST be run within a transaction.
114
     *
115
     * @param string    $table The table to define
116
     * @param bool|true $clean True to issue drop command, false otherwise
117
     *
118
     * @return string A string containing the formatted SQL code
119
     */
120
    public function getTableDefPrefix($table, $clean = false)
121
    {
122
        // Fetch table
123
        $t = $this->getTable($table);
124
        if (!is_object($t) || $t->recordCount() != 1) {
0 ignored issues
show
introduced by
The condition $t->recordCount() != 1 is always true.
Loading history...
125
            $this->rollbackTransaction();
126
127
            return null;
128
        }
129
        $this->fieldClean($t->fields['relname']);
130
        $this->fieldClean($t->fields['nspname']);
131
132
        // Fetch attributes
133
        $atts = $this->getTableAttributes($table);
134
        if (!is_object($atts)) {
135
            $this->rollbackTransaction();
136
137
            return null;
138
        }
139
140
        // Fetch constraints
141
        $cons = $this->getConstraints($table);
142
        if (!is_object($cons)) {
143
            $this->rollbackTransaction();
144
145
            return null;
146
        }
147
148
        // Output a reconnect command to create the table as the correct user
149
        $sql = $this->getChangeUserSQL($t->fields['relowner']) . "\n\n";
150
151
        // Set schema search path
152
        $sql .= "SET search_path = \"{$t->fields['nspname']}\", pg_catalog;\n\n";
153
154
        // Begin CREATE TABLE definition
155
        $sql .= "-- Definition\n\n";
156
        // DROP TABLE must be fully qualified in case a table with the same name exists
157
        // in pg_catalog.
158
        if (!$clean) {
159
            $sql .= '-- ';
160
        }
161
162
        $sql .= 'DROP TABLE ';
163
        $sql .= "\"{$t->fields['nspname']}\".\"{$t->fields['relname']}\";\n";
164
        $sql .= "CREATE TABLE \"{$t->fields['nspname']}\".\"{$t->fields['relname']}\" (\n";
165
166
        // Output all table columns
167
        $col_comments_sql = ''; // Accumulate comments on columns
168
        $num              = $atts->recordCount() + $cons->recordCount();
169
        $i                = 1;
170
        while (!$atts->EOF) {
171
            $this->fieldClean($atts->fields['attname']);
172
            $sql .= "    \"{$atts->fields['attname']}\"";
173
            // Dump SERIAL and BIGSERIAL columns correctly
174
            if ($this->phpBool($atts->fields['attisserial']) &&
175
                ($atts->fields['type'] == 'integer' || $atts->fields['type'] == 'bigint')) {
1 ignored issue
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
176
                if ($atts->fields['type'] == 'integer') {
177
                    $sql .= ' SERIAL';
178
                } else {
179
                    $sql .= ' BIGSERIAL';
180
                }
181
            } else {
182
                $sql .= ' ' . $this->formatType($atts->fields['type'], $atts->fields['atttypmod']);
183
184
                // Add NOT NULL if necessary
185
                if ($this->phpBool($atts->fields['attnotnull'])) {
186
                    $sql .= ' NOT NULL';
187
                }
188
189
                // Add default if necessary
190
                if ($atts->fields['adsrc'] !== null) {
191
                    $sql .= " DEFAULT {$atts->fields['adsrc']}";
192
                }
193
            }
194
195
            // Output comma or not
196
            if ($i < $num) {
197
                $sql .= ",\n";
198
            } else {
199
                $sql .= "\n";
200
            }
201
202
            // Does this column have a comment?
203
            if ($atts->fields['comment'] !== null) {
204
                $this->clean($atts->fields['comment']);
205
                $col_comments_sql .= "COMMENT ON COLUMN \"{$t->fields['relname']}\".\"{$atts->fields['attname']}\"  IS '{$atts->fields['comment']}';\n";
206
            }
207
208
            $atts->moveNext();
209
            ++$i;
210
        }
211
        // Output all table constraints
212
        while (!$cons->EOF) {
213
            $this->fieldClean($cons->fields['conname']);
214
            $sql .= "    CONSTRAINT \"{$cons->fields['conname']}\" ";
215
            // Nasty hack to support pre-7.4 PostgreSQL
216
            if ($cons->fields['consrc'] !== null) {
217
                $sql .= $cons->fields['consrc'];
218
            } else {
219
                switch ($cons->fields['contype']) {
220
                    case 'p':
221
                        $keys = $this->getAttributeNames($table, explode(' ', $cons->fields['indkey']));
222
                        $sql .= 'PRIMARY KEY (' . join(',', $keys) . ')';
223
224
                        break;
225
                    case 'u':
226
                        $keys = $this->getAttributeNames($table, explode(' ', $cons->fields['indkey']));
227
                        $sql .= 'UNIQUE (' . join(',', $keys) . ')';
228
229
                        break;
230
                    default:
231
                        // Unrecognised constraint
232
                        $this->rollbackTransaction();
233
234
                        return null;
235
                }
236
            }
237
238
            // Output comma or not
239
            if ($i < $num) {
240
                $sql .= ",\n";
241
            } else {
242
                $sql .= "\n";
243
            }
244
245
            $cons->moveNext();
246
            ++$i;
247
        }
248
249
        $sql .= ')';
250
251
        // @@@@ DUMP CLUSTERING INFORMATION
252
253
        // Inherits
254
        /**
255
         * XXX: This is currently commented out as handling inheritance isn't this simple.
256
         * You also need to make sure you don't dump inherited columns and defaults, as well
257
         * as inherited NOT NULL and CHECK constraints.  So for the time being, we just do
258
         * not claim to support inheritance.
259
         * $parents = $this->getTableParents($table);
260
         * if ($parents->recordCount() > 0) {
261
         * $sql .= " INHERITS (";
262
         * while (!$parents->EOF) {
263
         * $this->fieldClean($parents->fields['relname']);
264
         * // Qualify the parent table if it's in another schema
265
         * if ($parents->fields['schemaname'] != $this->_schema) {
266
         * $this->fieldClean($parents->fields['schemaname']);
267
         * $sql .= "\"{$parents->fields['schemaname']}\".";
268
         * }
269
         * $sql .= "\"{$parents->fields['relname']}\"";.
270
         *
271
         * $parents->moveNext();
272
         * if (!$parents->EOF) $sql .= ', ';
273
         * }
274
         * $sql .= ")";
275
         * }
276
         */
277
278
        // Handle WITHOUT OIDS
279
        if ($this->hasObjectID($table)) {
280
            $sql .= ' WITH OIDS';
281
        } else {
282
            $sql .= ' WITHOUT OIDS';
283
        }
284
285
        $sql .= ";\n";
286
287
        // Column storage and statistics
288
        $atts->moveFirst();
289
        $first = true;
290
        while (!$atts->EOF) {
291
            $this->fieldClean($atts->fields['attname']);
292
            // Statistics first
293
            if ($atts->fields['attstattarget'] >= 0) {
294
                if ($first) {
295
                    $sql .= "\n";
296
                    $first = false;
297
                }
298
                $sql .= "ALTER TABLE ONLY \"{$t->fields['nspname']}\".\"{$t->fields['relname']}\" ALTER COLUMN \"{$atts->fields['attname']}\" SET STATISTICS {$atts->fields['attstattarget']};\n";
299
            }
300
            // Then storage
301
            if ($atts->fields['attstorage'] != $atts->fields['typstorage']) {
302
                switch ($atts->fields['attstorage']) {
303
                    case 'p':
304
                        $storage = 'PLAIN';
305
306
                        break;
307
                    case 'e':
308
                        $storage = 'EXTERNAL';
309
310
                        break;
311
                    case 'm':
312
                        $storage = 'MAIN';
313
314
                        break;
315
                    case 'x':
316
                        $storage = 'EXTENDED';
317
318
                        break;
319
                    default:
320
                        // Unknown storage type
321
                        $this->rollbackTransaction();
322
323
                        return null;
324
                }
325
                $sql .= "ALTER TABLE ONLY \"{$t->fields['nspname']}\".\"{$t->fields['relname']}\" ALTER COLUMN \"{$atts->fields['attname']}\" SET STORAGE {$storage};\n";
326
            }
327
328
            $atts->moveNext();
329
        }
330
331
        // Comment
332
        if ($t->fields['relcomment'] !== null) {
333
            $this->clean($t->fields['relcomment']);
334
            $sql .= "\n-- Comment\n\n";
335
            $sql .= "COMMENT ON TABLE \"{$t->fields['nspname']}\".\"{$t->fields['relname']}\" IS '{$t->fields['relcomment']}';\n";
336
        }
337
338
        // Add comments on columns, if any
339
        if ($col_comments_sql != '') {
340
            $sql .= $col_comments_sql;
341
        }
342
343
        // Privileges
344
        $privs = $this->getPrivileges($table, 'table');
345
        if (!is_array($privs)) {
346
            $this->rollbackTransaction();
347
348
            return null;
349
        }
350
351
        if (sizeof($privs) > 0) {
352
            $sql .= "\n-- Privileges\n\n";
353
            /*
354
             * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
355
             * wire-in knowledge about the default public privileges for different
356
             * kinds of objects.
357
             */
358
            $sql .= "REVOKE ALL ON TABLE \"{$t->fields['nspname']}\".\"{$t->fields['relname']}\" FROM PUBLIC;\n";
359
            foreach ($privs as $v) {
360
                // Get non-GRANT OPTION privs
361
                $nongrant = array_diff($v[2], $v[4]);
362
363
                // Skip empty or owner ACEs
364
                if (sizeof($v[2]) == 0 || ($v[0] == 'user' && $v[1] == $t->fields['relowner'])) {
365
                    continue;
366
                }
367
368
                // Change user if necessary
369
                if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
370
                    $grantor = $v[3];
371
                    $this->clean($grantor);
372
                    $sql .= "SET SESSION AUTHORIZATION '{$grantor}';\n";
373
                }
374
375
                // Output privileges with no GRANT OPTION
376
                $sql .= 'GRANT ' . join(', ', $nongrant) . " ON TABLE \"{$t->fields['relname']}\" TO ";
377
                switch ($v[0]) {
378
                    case 'public':
379
                        $sql .= "PUBLIC;\n";
380
381
                        break;
382
                    case 'user':
383
                        $this->fieldClean($v[1]);
384
                        $sql .= "\"{$v[1]}\";\n";
385
386
                        break;
387
                    case 'group':
388
                        $this->fieldClean($v[1]);
389
                        $sql .= "GROUP \"{$v[1]}\";\n";
390
391
                        break;
392
                    default:
393
                        // Unknown privilege type - fail
394
                        $this->rollbackTransaction();
395
396
                        return null;
397
                }
398
399
                // Reset user if necessary
400
                if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
401
                    $sql .= "RESET SESSION AUTHORIZATION;\n";
402
                }
403
404
                // Output privileges with GRANT OPTION
405
406
                // Skip empty or owner ACEs
407
                if (!$this->hasGrantOption() || sizeof($v[4]) == 0) {
408
                    continue;
409
                }
410
411
                // Change user if necessary
412
                if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
413
                    $grantor = $v[3];
414
                    $this->clean($grantor);
415
                    $sql .= "SET SESSION AUTHORIZATION '{$grantor}';\n";
416
                }
417
418
                $sql .= 'GRANT ' . join(', ', $v[4]) . " ON \"{$t->fields['relname']}\" TO ";
419
                switch ($v[0]) {
420
                    case 'public':
421
                        $sql .= 'PUBLIC';
422
423
                        break;
424
                    case 'user':
425
                        $this->fieldClean($v[1]);
426
                        $sql .= "\"{$v[1]}\"";
427
428
                        break;
429
                    case 'group':
430
                        $this->fieldClean($v[1]);
431
                        $sql .= "GROUP \"{$v[1]}\"";
432
433
                        break;
434
                    default:
435
                        // Unknown privilege type - fail
436
                        return null;
437
                }
438
                $sql .= " WITH GRANT OPTION;\n";
439
440
                // Reset user if necessary
441
                if ($this->hasGrantOption() && $v[3] != $t->fields['relowner']) {
442
                    $sql .= "RESET SESSION AUTHORIZATION;\n";
443
                }
444
            }
445
        }
446
447
        // Add a newline to separate data that follows (if any)
448
        $sql .= "\n";
449
450
        return $sql;
451
    }
452
453
    /**
454
     * Returns table information.
455
     *
456
     * @param string $table The name of the table
457
     *
458
     * @return \PHPPgAdmin\ADORecordSet A recordset
459
     */
460
    public function getTable($table)
461
    {
462
        $c_schema = $this->_schema;
463
        $this->clean($c_schema);
464
        $this->clean($table);
465
466
        $sql = "
467
            SELECT
468
              c.relname, n.nspname, u.usename AS relowner,
469
              pg_catalog.obj_description(c.oid, 'pg_class') AS relcomment,
470
              (SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=c.reltablespace) AS tablespace
471
            FROM pg_catalog.pg_class c
472
                 LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
473
                 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
474
            WHERE c.relkind = 'r'
475
                  AND n.nspname = '{$c_schema}'
476
                  AND n.oid = c.relnamespace
477
                  AND c.relname = '{$table}'";
478
479
        return $this->selectSet($sql);
480
    }
481
482
    /**
483
     * Retrieve the attribute definition of a table.
484
     *
485
     * @param string $table The name of the table
486
     * @param string $field (optional) The name of a field to return
487
     *
488
     * @return \PHPPgAdmin\ADORecordSet All attributes in order
489
     */
490
    public function getTableAttributes($table, $field = '')
491
    {
492
        $c_schema = $this->_schema;
493
        $this->clean($c_schema);
494
        $this->clean($table);
495
        $this->clean($field);
496
497
        if ($field == '') {
498
            // This query is made much more complex by the addition of the 'attisserial' field.
499
            // The subquery to get that field checks to see if there is an internally dependent
500
            // sequence on the field.
501
            $sql = "
502
                SELECT
503
                    a.attname, a.attnum,
504
                    pg_catalog.format_type(a.atttypid, a.atttypmod) as type,
505
                    a.atttypmod,
506
                    a.attnotnull, a.atthasdef, pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true) as adsrc,
507
                    a.attstattarget, a.attstorage, t.typstorage,
508
                    (
509
                        SELECT 1 FROM pg_catalog.pg_depend pd, pg_catalog.pg_class pc
510
                        WHERE pd.objid=pc.oid
511
                        AND pd.classid=pc.tableoid
512
                        AND pd.refclassid=pc.tableoid
513
                        AND pd.refobjid=a.attrelid
514
                        AND pd.refobjsubid=a.attnum
515
                        AND pd.deptype='i'
516
                        AND pc.relkind='S'
517
                    ) IS NOT NULL AS attisserial,
518
                    pg_catalog.col_description(a.attrelid, a.attnum) AS comment
519
                FROM
520
                    pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef adef
521
                    ON a.attrelid=adef.adrelid
522
                    AND a.attnum=adef.adnum
523
                    LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid
524
                WHERE
525
                    a.attrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
526
                        AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
527
                        nspname = '{$c_schema}'))
528
                    AND a.attnum > 0 AND NOT a.attisdropped
529
                ORDER BY a.attnum";
530
        } else {
531
            $sql = "
532
                SELECT
533
                    a.attname, a.attnum,
534
                    pg_catalog.format_type(a.atttypid, a.atttypmod) as type,
535
                    pg_catalog.format_type(a.atttypid, NULL) as base_type,
536
                    a.atttypmod,
537
                    a.attnotnull, a.atthasdef, pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true) as adsrc,
538
                    a.attstattarget, a.attstorage, t.typstorage,
539
                    pg_catalog.col_description(a.attrelid, a.attnum) AS comment
540
                FROM
541
                    pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef adef
542
                    ON a.attrelid=adef.adrelid
543
                    AND a.attnum=adef.adnum
544
                    LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid
545
                WHERE
546
                    a.attrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
547
                        AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
548
                        nspname = '{$c_schema}'))
549
                    AND a.attname = '{$field}'";
550
        }
551
552
        return $this->selectSet($sql);
553
    }
554
555
    /**
556
     * Returns a list of all constraints on a table.
557
     *
558
     * @param string $table The table to find rules for
559
     *
560
     * @return \PHPPgAdmin\ADORecordSet A recordset
561
     */
562
    public function getConstraints($table)
563
    {
564
        $c_schema = $this->_schema;
565
        $this->clean($c_schema);
566
        $this->clean($table);
567
568
        // This SQL is greatly complicated by the need to retrieve
569
        // index clustering information for primary and unique constraints
570
        $sql = "SELECT
571
                pc.conname,
572
                pg_catalog.pg_get_constraintdef(pc.oid, true) AS consrc,
573
                pc.contype,
574
                CASE WHEN pc.contype='u' OR pc.contype='p' THEN (
575
                    SELECT
576
                        indisclustered
577
                    FROM
578
                        pg_catalog.pg_depend pd,
579
                        pg_catalog.pg_class pl,
580
                        pg_catalog.pg_index pi
581
                    WHERE
582
                        pd.refclassid=pc.tableoid
583
                        AND pd.refobjid=pc.oid
584
                        AND pd.objid=pl.oid
585
                        AND pl.oid=pi.indexrelid
586
                ) ELSE
587
                    NULL
588
                END AS indisclustered
589
            FROM
590
                pg_catalog.pg_constraint pc
591
            WHERE
592
                pc.conrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
593
                    AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace
594
                    WHERE nspname='{$c_schema}'))
595
            ORDER BY
596
                1
597
        ";
598
599
        return $this->selectSet($sql);
600
    }
601
602
    /**
603
     * Checks to see whether or not a table has a unique id column.
604
     *
605
     * @param string $table The table name
606
     *
607
     * @return true if it has a unique id, false otherwise
608
     */
609
    public function hasObjectID($table)
610
    {
611
        $c_schema = $this->_schema;
612
        $this->clean($c_schema);
613
        $this->clean($table);
614
615
        $sql = "SELECT relhasoids FROM pg_catalog.pg_class WHERE relname='{$table}'
616
            AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname='{$c_schema}')";
617
618
        $rs = $this->selectSet($sql);
619
        if ($rs->recordCount() != 1) {
620
            return null;
621
        }
622
623
        $rs->fields['relhasoids'] = $this->phpBool($rs->fields['relhasoids']);
624
625
        return $rs->fields['relhasoids'];
626
    }
627
628
    /**
629
     * Returns extra table definition information that is most usefully
630
     * dumped after the table contents for speed and efficiency reasons.
631
     *
632
     * @param string $table The table to define
633
     *
634
     * @return string A string containing the formatted SQL code
635
     */
636
    public function getTableDefSuffix($table)
637
    {
638
        $sql = '';
639
640
        // Indexes
641
        $indexes = $this->getIndexes($table);
642
        if (!is_object($indexes)) {
643
            $this->rollbackTransaction();
644
645
            return null;
646
        }
647
648
        if ($indexes->recordCount() > 0) {
649
            $sql .= "\n-- Indexes\n\n";
650
            while (!$indexes->EOF) {
651
                $sql .= $indexes->fields['inddef'] . ";\n";
652
653
                $indexes->moveNext();
654
            }
655
        }
656
657
        // Triggers
658
        $triggers = $this->getTriggers($table);
659
        if (!is_object($triggers)) {
660
            $this->rollbackTransaction();
661
662
            return null;
663
        }
664
665
        if ($triggers->recordCount() > 0) {
666
            $sql .= "\n-- Triggers\n\n";
667
            while (!$triggers->EOF) {
668
                $sql .= $triggers->fields['tgdef'];
669
                $sql .= ";\n";
670
671
                $triggers->moveNext();
672
            }
673
        }
674
675
        // Rules
676
        $rules = $this->getRules($table);
677
        if (!is_object($rules)) {
678
            $this->rollbackTransaction();
679
680
            return null;
681
        }
682
683
        if ($rules->recordCount() > 0) {
684
            $sql .= "\n-- Rules\n\n";
685
            while (!$rules->EOF) {
686
                $sql .= $rules->fields['definition'] . "\n";
687
688
                $rules->moveNext();
689
            }
690
        }
691
692
        return $sql;
693
    }
694
695
    /**
696
     * Grabs a list of indexes for a table.
697
     *
698
     * @param string $table  The name of a table whose indexes to retrieve
699
     * @param bool   $unique Only get unique/pk indexes
700
     *
701
     * @return \PHPPgAdmin\ADORecordSet A recordset
702
     */
703
    public function getIndexes($table = '', $unique = false)
704
    {
705
        $this->clean($table);
706
707
        $sql = "
708
            SELECT c2.relname AS indname, i.indisprimary, i.indisunique, i.indisclustered,
709
                pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS inddef
710
            FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
711
            WHERE c.relname = '{$table}' AND pg_catalog.pg_table_is_visible(c.oid)
712
                AND c.oid = i.indrelid AND i.indexrelid = c2.oid
713
        ";
714
        if ($unique) {
715
            $sql .= ' AND i.indisunique ';
716
        }
717
718
        $sql .= ' ORDER BY c2.relname';
719
720
        return $this->selectSet($sql);
721
    }
722
723
    /**
724
     * Grabs a list of triggers on a table.
725
     *
726
     * @param string $table The name of a table whose triggers to retrieve
727
     *
728
     * @return \PHPPgAdmin\ADORecordSet A recordset
729
     */
730
    public function getTriggers($table = '')
731
    {
732
        $c_schema = $this->_schema;
733
        $this->clean($c_schema);
734
        $this->clean($table);
735
736
        $sql = "SELECT
737
                t.tgname, pg_catalog.pg_get_triggerdef(t.oid) AS tgdef,
738
                CASE WHEN t.tgenabled = 'D' THEN FALSE ELSE TRUE END AS tgenabled, p.oid AS prooid,
739
                p.proname || ' (' || pg_catalog.oidvectortypes(p.proargtypes) || ')' AS proproto,
740
                ns.nspname AS pronamespace
741
            FROM pg_catalog.pg_trigger t, pg_catalog.pg_proc p, pg_catalog.pg_namespace ns
742
            WHERE t.tgrelid = (SELECT oid FROM pg_catalog.pg_class WHERE relname='{$table}'
743
                AND relnamespace=(SELECT oid FROM pg_catalog.pg_namespace WHERE nspname='{$c_schema}'))
744
                AND ( tgconstraint = 0 OR NOT EXISTS
745
                        (SELECT 1 FROM pg_catalog.pg_depend d    JOIN pg_catalog.pg_constraint c
746
                            ON (d.refclassid = c.tableoid AND d.refobjid = c.oid)
747
                        WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))
748
                AND p.oid=t.tgfoid
749
                AND p.pronamespace = ns.oid";
750
751
        return $this->selectSet($sql);
752
    }
753
754
    /**
755
     * Returns a list of all rules on a table OR view.
756
     *
757
     * @param string $table The table to find rules for
758
     *
759
     * @return \PHPPgAdmin\ADORecordSet A recordset
760
     */
761
    public function getRules($table)
762
    {
763
        $c_schema = $this->_schema;
764
        $this->clean($c_schema);
765
        $this->clean($table);
766
767
        $sql = "
768
            SELECT *
769
            FROM pg_catalog.pg_rules
770
            WHERE
771
                schemaname='{$c_schema}' AND tablename='{$table}'
772
            ORDER BY rulename
773
        ";
774
775
        return $this->selectSet($sql);
776
    }
777
778
    /**
779
     * Creates a new table in the database.
780
     *
781
     * @param string $name        The name of the table
782
     * @param int    $fields      The number of fields
783
     * @param array  $field       An array of field names
784
     * @param array  $type        An array of field types
785
     * @param array  $array       An array of '' or '[]' for each type if it's an array or not
786
     * @param array  $length      An array of field lengths
787
     * @param array  $notnull     An array of not null
788
     * @param array  $default     An array of default values
789
     * @param bool   $withoutoids True if WITHOUT OIDS, false otherwise
790
     * @param array  $colcomment  An array of comments
791
     * @param string $tblcomment  the comment for the table
792
     * @param string $tablespace  The tablespace name ('' means none/default)
793
     * @param array  $uniquekey   An Array indicating the fields that are unique (those indexes that are set)
794
     * @param array  $primarykey  An Array indicating the field used for the primarykey (those indexes that are set)
795
     *
796
     * @return bool|int 0 success
797
     */
798
    public function createTable(
799
        $name,
800
        $fields,
801
        $field,
802
        $type,
803
        $array,
804
        $length,
805
        $notnull,
806
        $default,
807
        $withoutoids,
808
        $colcomment,
809
        $tblcomment,
810
        $tablespace,
811
        $uniquekey,
812
        $primarykey
813
    ) {
814
        $f_schema = $this->_schema;
815
        $this->fieldClean($f_schema);
816
        $this->fieldClean($name);
817
818
        $status = $this->beginTransaction();
819
        if ($status != 0) {
820
            return -1;
821
        }
822
823
        $found       = false;
824
        $first       = true;
825
        $comment_sql = ''; //Accumulate comments for the columns
826
        $sql         = "CREATE TABLE \"{$f_schema}\".\"{$name}\" (";
827
        for ($i = 0; $i < $fields; ++$i) {
828
            $this->fieldClean($field[$i]);
829
            $this->clean($type[$i]);
830
            $this->clean($length[$i]);
831
            $this->clean($colcomment[$i]);
832
833
            // Skip blank columns - for user convenience
834
            if ($field[$i] == '' || $type[$i] == '') {
835
                continue;
836
            }
837
838
            // If not the first column, add a comma
839
            if (!$first) {
840
                $sql .= ', ';
841
            } else {
842
                $first = false;
843
            }
844
845
            switch ($type[$i]) {
846
                // Have to account for weird placing of length for with/without
847
                // time zone types
848
                case 'timestamp with time zone':
849
                case 'timestamp without time zone':
850
                    $qual = substr($type[$i], 9);
851
                    $sql .= "\"{$field[$i]}\" timestamp";
852
                    if ($length[$i] != '') {
853
                        $sql .= "({$length[$i]})";
854
                    }
855
856
                    $sql .= $qual;
857
858
                    break;
859
                case 'time with time zone':
860
                case 'time without time zone':
861
                    $qual = substr($type[$i], 4);
862
                    $sql .= "\"{$field[$i]}\" time";
863
                    if ($length[$i] != '') {
864
                        $sql .= "({$length[$i]})";
865
                    }
866
867
                    $sql .= $qual;
868
869
                    break;
870
                default:
871
                    $sql .= "\"{$field[$i]}\" {$type[$i]}";
872
                    if ($length[$i] != '') {
873
                        $sql .= "({$length[$i]})";
874
                    }
875
            }
876
            // Add array qualifier if necessary
877
            if ($array[$i] == '[]') {
878
                $sql .= '[]';
879
            }
880
881
            // Add other qualifiers
882
            if (!isset($primarykey[$i])) {
883
                if (isset($uniquekey[$i])) {
884
                    $sql .= ' UNIQUE';
885
                }
886
887
                if (isset($notnull[$i])) {
888
                    $sql .= ' NOT NULL';
889
                }
890
            }
891
            if ($default[$i] != '') {
892
                $sql .= " DEFAULT {$default[$i]}";
893
            }
894
895
            if ($colcomment[$i] != '') {
896
                $comment_sql .= "COMMENT ON COLUMN \"{$name}\".\"{$field[$i]}\" IS '{$colcomment[$i]}';\n";
897
            }
898
899
            $found = true;
900
        }
901
902
        if (!$found) {
0 ignored issues
show
introduced by
The condition $found is always false.
Loading history...
903
            return -1;
904
        }
905
906
        // PRIMARY KEY
907
        $primarykeycolumns = [];
908
        for ($i = 0; $i < $fields; ++$i) {
909
            if (isset($primarykey[$i])) {
910
                $primarykeycolumns[] = "\"{$field[$i]}\"";
911
            }
912
        }
913
        if (count($primarykeycolumns) > 0) {
914
            $sql .= ', PRIMARY KEY (' . implode(', ', $primarykeycolumns) . ')';
915
        }
916
917
        $sql .= ')';
918
919
        // WITHOUT OIDS
920
        if ($withoutoids) {
921
            $sql .= ' WITHOUT OIDS';
922
        } else {
923
            $sql .= ' WITH OIDS';
924
        }
925
926
        // Tablespace
927
        if ($this->hasTablespaces() && $tablespace != '') {
928
            $this->fieldClean($tablespace);
929
            $sql .= " TABLESPACE \"{$tablespace}\"";
930
        }
931
932
        $status = $this->execute($sql);
933
        if ($status) {
934
            $this->rollbackTransaction();
935
936
            return -1;
937
        }
938
939
        if ($tblcomment != '') {
940
            $status = $this->setComment('TABLE', '', $name, $tblcomment, true);
941
            if ($status) {
942
                $this->rollbackTransaction();
943
944
                return -1;
945
            }
946
        }
947
948
        if ($comment_sql != '') {
949
            $status = $this->execute($comment_sql);
950
            if ($status) {
951
                $this->rollbackTransaction();
952
953
                return -1;
954
            }
955
        }
956
957
        return $this->endTransaction();
958
    }
959
960
    /**
961
     * Creates a new table in the database copying attribs and other properties from another table.
962
     *
963
     * @param string $name        The name of the table
964
     * @param array  $like        an array giving the schema ans the name of the table from which attribs are copying
965
     *                            from: array(
966
     *                            'table' => table name,
967
     *                            'schema' => the schema name,
968
     *                            )
969
     * @param bool   $defaults    if true, copy the defaults values as well
970
     * @param bool   $constraints if true, copy the constraints as well (CHECK on table & attr)
971
     * @param bool   $idx
972
     * @param string $tablespace  The tablespace name ('' means none/default)
973
     *
974
     * @return bool|int
975
     */
976
    public function createTableLike($name, $like, $defaults = false, $constraints = false, $idx = false, $tablespace = '')
977
    {
978
        $f_schema = $this->_schema;
979
        $this->fieldClean($f_schema);
980
        $this->fieldClean($name);
981
        $this->fieldClean($like['schema']);
982
        $this->fieldClean($like['table']);
983
        $like = "\"{$like['schema']}\".\"{$like['table']}\"";
984
985
        $status = $this->beginTransaction();
986
        if ($status != 0) {
987
            return -1;
988
        }
989
990
        $sql = "CREATE TABLE \"{$f_schema}\".\"{$name}\" (LIKE {$like}";
991
992
        if ($defaults) {
993
            $sql .= ' INCLUDING DEFAULTS';
994
        }
995
996
        if ($this->hasCreateTableLikeWithConstraints() && $constraints) {
997
            $sql .= ' INCLUDING CONSTRAINTS';
998
        }
999
1000
        if ($this->hasCreateTableLikeWithIndexes() && $idx) {
1001
            $sql .= ' INCLUDING INDEXES';
1002
        }
1003
1004
        $sql .= ')';
1005
1006
        if ($this->hasTablespaces() && $tablespace != '') {
1007
            $this->fieldClean($tablespace);
1008
            $sql .= " TABLESPACE \"{$tablespace}\"";
1009
        }
1010
1011
        $status = $this->execute($sql);
1012
        if ($status) {
1013
            $this->rollbackTransaction();
1014
1015
            return -1;
1016
        }
1017
1018
        return $this->endTransaction();
1019
    }
1020
1021
    /**
1022
     * Alter table properties.
1023
     *
1024
     * @param string $table      The name of the table
1025
     * @param string $name       The new name for the table
1026
     * @param string $owner      The new owner for the table
1027
     * @param string $schema     The new schema for the table
1028
     * @param string $comment    The comment on the table
1029
     * @param string $tablespace The new tablespace for the table ('' means leave as is)
1030
     *
1031
     * @return bool|int 0 success
1032
     */
1033
    public function alterTable($table, $name, $owner, $schema, $comment, $tablespace)
1034
    {
1035
        $data = $this->getTable($table);
1036
1037
        if ($data->recordCount() != 1) {
0 ignored issues
show
introduced by
The condition $data->recordCount() != 1 is always true.
Loading history...
1038
            return -2;
1039
        }
1040
1041
        $status = $this->beginTransaction();
1042
        if ($status != 0) {
1043
            $this->rollbackTransaction();
1044
1045
            return -1;
1046
        }
1047
1048
        $status = $this->_alterTable($data, $name, $owner, $schema, $comment, $tablespace);
1049
1050
        if ($status != 0) {
1051
            $this->rollbackTransaction();
1052
1053
            return $status;
1054
        }
1055
1056
        return $this->endTransaction();
1057
    }
1058
1059
    /**
1060
     * Protected method which alter a table
1061
     * SHOULDN'T BE CALLED OUTSIDE OF A TRANSACTION.
1062
     *
1063
     * @param \PHPPgAdmin\ADORecordSet $tblrs      The table recordSet returned by getTable()
1064
     * @param string                   $name       The new name for the table
1065
     * @param string                   $owner      The new owner for the table
1066
     * @param string                   $schema     The new schema for the table
1067
     * @param string                   $comment    The comment on the table
1068
     * @param string                   $tablespace The new tablespace for the table ('' means leave as is)
1069
     *
1070
     * @return int 0 success
1071
     */
1072
    protected function _alterTable($tblrs, $name, $owner, $schema, $comment, $tablespace)
1 ignored issue
show
Coding Style introduced by
Protected method name "TableTrait::_alterTable" must not be prefixed with an underscore
Loading history...
1073
    {
1074
        $this->fieldArrayClean($tblrs->fields);
1075
1076
        // Comment
1077
        $status = $this->setComment('TABLE', '', $tblrs->fields['relname'], $comment);
1078
        if ($status != 0) {
1079
            return -4;
1080
        }
1081
1082
        // Owner
1083
        $this->fieldClean($owner);
1084
        $status = $this->alterTableOwner($tblrs, $owner);
1085
        if ($status != 0) {
1086
            return -5;
1087
        }
1088
1089
        // Tablespace
1090
        $this->fieldClean($tablespace);
1091
        $status = $this->alterTableTablespace($tblrs, $tablespace);
1092
        if ($status != 0) {
1093
            return -6;
1094
        }
1095
1096
        // Rename
1097
        $this->fieldClean($name);
1098
        $status = $this->alterTableName($tblrs, $name);
1099
        if ($status != 0) {
1100
            return -3;
1101
        }
1102
1103
        // Schema
1104
        $this->fieldClean($schema);
1105
        $status = $this->alterTableSchema($tblrs, $schema);
1106
        if ($status != 0) {
1107
            return -7;
1108
        }
1109
1110
        return 0;
1111
    }
1112
1113
    /**
1114
     * Alter a table's owner
1115
     * /!\ this function is called from _alterTable which take care of escaping fields.
1116
     *
1117
     * @param \PHPPgAdmin\ADORecordSet $tblrs The table RecordSet returned by getTable()
1118
     * @param null|string              $owner
1119
     *
1120
     * @return int 0 if operation was successful
1121
     */
1122
    public function alterTableOwner($tblrs, $owner = null)
1123
    {
1124
        /* vars cleaned in _alterTable */
1125
        if (!empty($owner) && ($tblrs->fields['relowner'] != $owner)) {
1126
            $f_schema = $this->_schema;
1127
            $this->fieldClean($f_schema);
1128
            // If owner has been changed, then do the alteration.  We are
1129
            // careful to avoid this generally as changing owner is a
1130
            // superuser only function.
1131
            $sql = "ALTER TABLE \"{$f_schema}\".\"{$tblrs->fields['relname']}\" OWNER TO \"{$owner}\"";
1132
1133
            return $this->execute($sql);
1134
        }
1135
1136
        return 0;
1137
    }
1138
1139
    /**
1140
     * Alter a table's tablespace
1141
     * /!\ this function is called from _alterTable which take care of escaping fields.
1142
     *
1143
     * @param \PHPPgAdmin\ADORecordSet $tblrs      The table RecordSet returned by getTable()
1144
     * @param null|string              $tablespace
1145
     *
1146
     * @return int 0 if operation was successful
1147
     */
1148
    public function alterTableTablespace($tblrs, $tablespace = null)
1149
    {
1150
        /* vars cleaned in _alterTable */
1151
        if (!empty($tablespace) && ($tblrs->fields['tablespace'] != $tablespace)) {
1152
            $f_schema = $this->_schema;
1153
            $this->fieldClean($f_schema);
1154
1155
            // If tablespace has been changed, then do the alteration.  We
1156
            // don't want to do this unnecessarily.
1157
            $sql = "ALTER TABLE \"{$f_schema}\".\"{$tblrs->fields['relname']}\" SET TABLESPACE \"{$tablespace}\"";
1158
1159
            return $this->execute($sql);
1160
        }
1161
1162
        return 0;
1163
    }
1164
1165
    /**
1166
     * Alter a table's name
1167
     * /!\ this function is called from _alterTable which take care of escaping fields.
1168
     *
1169
     * @param \PHPPgAdmin\ADORecordSet $tblrs The table RecordSet returned by getTable()
1170
     * @param string                   $name  The new table's name
1171
     *
1172
     * @return int 0 if operation was successful
1173
     */
1174
    public function alterTableName($tblrs, $name = null)
1175
    {
1176
        /* vars cleaned in _alterTable */
1177
        // Rename (only if name has changed)
1178
        if (!empty($name) && ($name != $tblrs->fields['relname'])) {
1179
            $f_schema = $this->_schema;
1180
            $this->fieldClean($f_schema);
1181
1182
            $sql    = "ALTER TABLE \"{$f_schema}\".\"{$tblrs->fields['relname']}\" RENAME TO \"{$name}\"";
1183
            $status = $this->execute($sql);
1184
            if ($status == 0) {
1185
                $tblrs->fields['relname'] = $name;
1186
            } else {
1187
                return $status;
1188
            }
1189
        }
1190
1191
        return 0;
1192
    }
1193
1194
    // Row functions
1195
1196
    /**
1197
     * Alter a table's schema
1198
     * /!\ this function is called from _alterTable which take care of escaping fields.
1199
     *
1200
     * @param \PHPPgAdmin\ADORecordSet $tblrs  The table RecordSet returned by getTable()
1201
     * @param null|string              $schema
1202
     *
1203
     * @return int 0 if operation was successful
1204
     */
1205
    public function alterTableSchema($tblrs, $schema = null)
1206
    {
1207
        /* vars cleaned in _alterTable */
1208
        if (!empty($schema) && ($tblrs->fields['nspname'] != $schema)) {
1209
            $f_schema = $this->_schema;
1210
            $this->fieldClean($f_schema);
1211
            // If tablespace has been changed, then do the alteration.  We
1212
            // don't want to do this unnecessarily.
1213
            $sql = "ALTER TABLE \"{$f_schema}\".\"{$tblrs->fields['relname']}\" SET SCHEMA \"{$schema}\"";
1214
1215
            return $this->execute($sql);
1216
        }
1217
1218
        return 0;
1219
    }
1220
1221
    /**
1222
     * Empties a table in the database.
1223
     *
1224
     * @param string $table   The table to be emptied
1225
     * @param bool   $cascade True to cascade truncate, false to restrict
1226
     *
1227
     * @return array<integer,mixed|string> 0 if operation was successful
1228
     */
1229
    public function emptyTable($table, $cascade)
1230
    {
1231
        $f_schema = $this->_schema;
1232
        $this->fieldClean($f_schema);
1233
        $this->fieldClean($table);
1234
1235
        $sql = "TRUNCATE TABLE \"{$f_schema}\".\"{$table}\" ";
1236
        if ($cascade) {
1237
            $sql = $sql . ' CASCADE';
1238
        }
1239
1240
        $status = $this->execute($sql);
1241
1242
        return [$status, $sql];
1243
    }
1244
1245
    /**
1246
     * Removes a table from the database.
1247
     *
1248
     * @param string $table   The table to drop
1249
     * @param bool   $cascade True to cascade drop, false to restrict
1250
     *
1251
     * @return int 0 if operation was successful
1252
     */
1253
    public function dropTable($table, $cascade)
1254
    {
1255
        $f_schema = $this->_schema;
1256
        $this->fieldClean($f_schema);
1257
        $this->fieldClean($table);
1258
1259
        $sql = "DROP TABLE \"{$f_schema}\".\"{$table}\"";
1260
        if ($cascade) {
1261
            $sql .= ' CASCADE';
1262
        }
1263
1264
        return $this->execute($sql);
1265
    }
1266
1267
    /**
1268
     * Add a new column to a table.
1269
     *
1270
     * @param string $table   The table to add to
1271
     * @param string $column  The name of the new column
1272
     * @param string $type    The type of the column
1273
     * @param bool   $array   True if array type, false otherwise
1274
     * @param int    $length  The optional size of the column (ie. 30 for varchar(30))
1275
     * @param bool   $notnull True if NOT NULL, false otherwise
1276
     * @param mixed  $default The default for the column.  '' for none.
1277
     * @param string $comment comment for the column
1278
     *
1279
     * @return bool|int 0 success
1280
     */
1281
    public function addColumn($table, $column, $type, $array, $length, $notnull, $default, $comment)
1282
    {
1283
        $f_schema = $this->_schema;
1284
        $this->fieldClean($f_schema);
1285
        $this->fieldClean($table);
1286
        $this->fieldClean($column);
1287
        $this->clean($type);
1288
        $this->clean($length);
1289
1290
        if ($length == '') {
1291
            $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD COLUMN \"{$column}\" {$type}";
1292
        } else {
1293
            switch ($type) {
1294
                // Have to account for weird placing of length for with/without
1295
                // time zone types
1296
                case 'timestamp with time zone':
1297
                case 'timestamp without time zone':
1298
                    $qual = substr($type, 9);
1299
                    $sql  = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD COLUMN \"{$column}\" timestamp({$length}){$qual}";
1300
1301
                    break;
1302
                case 'time with time zone':
1303
                case 'time without time zone':
1304
                    $qual = substr($type, 4);
1305
                    $sql  = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD COLUMN \"{$column}\" time({$length}){$qual}";
1306
1307
                    break;
1308
                default:
1309
                    $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ADD COLUMN \"{$column}\" {$type}({$length})";
1310
            }
1311
        }
1312
1313
        // Add array qualifier, if requested
1314
        if ($array) {
1315
            $sql .= '[]';
1316
        }
1317
1318
        // If we have advanced column adding, add the extra qualifiers
1319
        if ($this->hasCreateFieldWithConstraints()) {
1320
            // NOT NULL clause
1321
            if ($notnull) {
1322
                $sql .= ' NOT NULL';
1323
            }
1324
1325
            // DEFAULT clause
1326
            if ($default != '') {
1327
                $sql .= ' DEFAULT ' . $default;
1328
            }
1329
        }
1330
1331
        $status = $this->beginTransaction();
1332
        if ($status != 0) {
1333
            return -1;
1334
        }
1335
1336
        $status = $this->execute($sql);
1337
        if ($status != 0) {
1338
            $this->rollbackTransaction();
1339
1340
            return -1;
1341
        }
1342
1343
        $status = $this->setComment('COLUMN', $column, $table, $comment);
1344
        if ($status != 0) {
1345
            $this->rollbackTransaction();
1346
1347
            return -1;
1348
        }
1349
1350
        return $this->endTransaction();
1351
    }
1352
1353
    /**
1354
     * Alters a column in a table.
1355
     *
1356
     * @param string $table      The table in which the column resides
1357
     * @param string $column     The column to alter
1358
     * @param string $name       The new name for the column
1359
     * @param bool   $notnull    (boolean) True if not null, false otherwise
1360
     * @param bool   $oldnotnull (boolean) True if column is already not null, false otherwise
1361
     * @param mixed  $default    The new default for the column
1362
     * @param mixed  $olddefault The old default for the column
1363
     * @param string $type       The new type for the column
1364
     * @param int    $length     The optional size of the column (ie. 30 for varchar(30))
1365
     * @param bool   $array      True if array type, false otherwise
1366
     * @param string $oldtype    The old type for the column
1367
     * @param string $comment    Comment for the column
1368
     *
1369
     * @return array 0 success
1370
     */
1371
    public function alterColumn(
1372
        $table,
1373
        $column,
1374
        $name,
1375
        $notnull,
1376
        $oldnotnull,
1377
        $default,
1378
        $olddefault,
1379
        $type,
1380
        $length,
1381
        $array,
1382
        $oldtype,
1383
        $comment
1384
    ) {
1385
        // Begin transaction
1386
        $status = $this->beginTransaction();
1387
        $sql    = '';
1388
        if ($status != 0) {
1389
            $this->rollbackTransaction();
1390
1391
            return [-6, $sql];
1392
        }
1393
1394
        // Rename the column, if it has been changed
1395
        if ($column != $name) {
1396
            $status = $this->renameColumn($table, $column, $name);
1397
            if ($status != 0) {
1398
                $this->rollbackTransaction();
1399
1400
                return [-4, $sql];
1401
            }
1402
        }
1403
1404
        $f_schema = $this->_schema;
1405
        $this->fieldClean($f_schema);
1406
        $this->fieldClean($name);
1407
        $this->fieldClean($table);
1408
        $this->fieldClean($column);
1409
1410
        $toAlter = [];
1411
        // Create the command for changing nullability
1412
        if ($notnull != $oldnotnull) {
1413
            $toAlter[] = "ALTER COLUMN \"{$name}\" " . ($notnull ? 'SET' : 'DROP') . ' NOT NULL';
1414
        }
1415
1416
        // Add default, if it has changed
1417
        if ($default != $olddefault) {
1418
            if ($default == '') {
1419
                $toAlter[] = "ALTER COLUMN \"{$name}\" DROP DEFAULT";
1420
            } else {
1421
                $toAlter[] = "ALTER COLUMN \"{$name}\" SET DEFAULT {$default}";
1422
            }
1423
        }
1424
1425
        // Add type, if it has changed
1426
        if ($length == '') {
1427
            $ftype = $type;
1428
        } else {
1429
            switch ($type) {
1430
                // Have to account for weird placing of length for with/without
1431
                // time zone types
1432
                case 'timestamp with time zone':
1433
                case 'timestamp without time zone':
1434
                    $qual  = substr($type, 9);
1435
                    $ftype = "timestamp({$length}){$qual}";
1436
1437
                    break;
1438
                case 'time with time zone':
1439
                case 'time without time zone':
1440
                    $qual  = substr($type, 4);
1441
                    $ftype = "time({$length}){$qual}";
1442
1443
                    break;
1444
                default:
1445
                    $ftype = "{$type}({$length})";
1446
            }
1447
        }
1448
1449
        // Add array qualifier, if requested
1450
        if ($array) {
1451
            $ftype .= '[]';
1452
        }
1453
1454
        if ($ftype != $oldtype) {
1455
            $toAlter[] = "ALTER COLUMN \"{$name}\" TYPE {$ftype}";
1456
        }
1457
1458
        // Attempt to process the batch alteration, if anything has been changed
1459
        if (!empty($toAlter)) {
1460
            // Initialise an empty SQL string
1461
            $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" "
1462
            . implode(',', $toAlter);
1463
1464
            $status = $this->execute($sql);
1465
            if ($status != 0) {
1466
                $this->rollbackTransaction();
1467
1468
                return [-1, $sql];
1469
            }
1470
        }
1471
1472
        // Update the comment on the column
1473
        $status = $this->setComment('COLUMN', $name, $table, $comment);
1474
        if ($status != 0) {
1475
            $this->rollbackTransaction();
1476
1477
            return [-5, $sql];
1478
        }
1479
1480
        return [$this->endTransaction(), $sql];
1481
    }
1482
1483
    /**
1484
     * Renames a column in a table.
1485
     *
1486
     * @param string $table   The table containing the column to be renamed
1487
     * @param string $column  The column to be renamed
1488
     * @param string $newName The new name for the column
1489
     *
1490
     * @return int 0 if operation was successful
1491
     */
1492
    public function renameColumn($table, $column, $newName)
1493
    {
1494
        $f_schema = $this->_schema;
1495
        $this->fieldClean($f_schema);
1496
        $this->fieldClean($table);
1497
        $this->fieldClean($column);
1498
        $this->fieldClean($newName);
1499
1500
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" RENAME COLUMN \"{$column}\" TO \"{$newName}\"";
1501
1502
        return $this->execute($sql);
1503
    }
1504
1505
    /**
1506
     * Sets default value of a column.
1507
     *
1508
     * @param string $table   The table from which to drop
1509
     * @param string $column  The column name to set
1510
     * @param mixed  $default The new default value
1511
     *
1512
     * @return int 0 if operation was successful
1513
     */
1514
    public function setColumnDefault($table, $column, $default)
1515
    {
1516
        $f_schema = $this->_schema;
1517
        $this->fieldClean($f_schema);
1518
        $this->fieldClean($table);
1519
        $this->fieldClean($column);
1520
1521
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ALTER COLUMN \"{$column}\" SET DEFAULT {$default}";
1522
1523
        return $this->execute($sql);
1524
    }
1525
1526
    /**
1527
     * Sets whether or not a column can contain NULLs.
1528
     *
1529
     * @param string $table  The table that contains the column
1530
     * @param string $column The column to alter
1531
     * @param bool   $state  True to set null, false to set not null
1532
     *
1533
     * @return int 0 if operation was successful
1534
     */
1535
    public function setColumnNull($table, $column, $state)
1536
    {
1537
        $f_schema = $this->_schema;
1538
        $this->fieldClean($f_schema);
1539
        $this->fieldClean($table);
1540
        $this->fieldClean($column);
1541
1542
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ALTER COLUMN \"{$column}\" " . ($state ? 'DROP' : 'SET') . ' NOT NULL';
1543
1544
        return $this->execute($sql);
1545
    }
1546
1547
    /**
1548
     * Drops a column from a table.
1549
     *
1550
     * @param string $table   The table from which to drop a column
1551
     * @param string $column  The column to be dropped
1552
     * @param bool   $cascade True to cascade drop, false to restrict
1553
     *
1554
     * @return int 0 if operation was successful
1555
     */
1556
    public function dropColumn($table, $column, $cascade)
1557
    {
1558
        $f_schema = $this->_schema;
1559
        $this->fieldClean($f_schema);
1560
        $this->fieldClean($table);
1561
        $this->fieldClean($column);
1562
1563
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" DROP COLUMN \"{$column}\"";
1564
        if ($cascade) {
1565
            $sql .= ' CASCADE';
1566
        }
1567
1568
        return $this->execute($sql);
1569
    }
1570
1571
    /**
1572
     * Drops default value of a column.
1573
     *
1574
     * @param string $table  The table from which to drop
1575
     * @param string $column The column name to drop default
1576
     *
1577
     * @return int 0 if operation was successful
1578
     */
1579
    public function dropColumnDefault($table, $column)
1580
    {
1581
        $f_schema = $this->_schema;
1582
        $this->fieldClean($f_schema);
1583
        $this->fieldClean($table);
1584
        $this->fieldClean($column);
1585
1586
        $sql = "ALTER TABLE \"{$f_schema}\".\"{$table}\" ALTER COLUMN \"{$column}\" DROP DEFAULT";
1587
1588
        return $this->execute($sql);
1589
    }
1590
1591
    /**
1592
     * Sets up the data object for a dump.  eg. Starts the appropriate
1593
     * transaction, sets variables, etc.
1594
     *
1595
     * @return int 0 success
1596
     */
1597
    public function beginDump()
1598
    {
1599
        // Begin serializable transaction (to dump consistent data)
1600
        $status = $this->beginTransaction();
1601
        if ($status != 0) {
1602
            return -1;
1603
        }
1604
1605
        // Set serializable
1606
        $sql    = 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE';
1607
        $status = $this->execute($sql);
1608
        if ($status != 0) {
1609
            $this->rollbackTransaction();
1610
1611
            return -1;
1612
        }
1613
1614
        // Set datestyle to ISO
1615
        $sql    = 'SET DATESTYLE = ISO';
1616
        $status = $this->execute($sql);
1617
        if ($status != 0) {
1618
            $this->rollbackTransaction();
1619
1620
            return -1;
1621
        }
1622
1623
        // Set extra_float_digits to 2
1624
        $sql    = 'SET extra_float_digits TO 2';
1625
        $status = $this->execute($sql);
1626
        if ($status != 0) {
1627
            $this->rollbackTransaction();
1628
1629
            return -1;
1630
        }
1631
1632
        return 0;
1633
    }
1634
1635
    /**
1636
     * Ends the data object for a dump.
1637
     *
1638
     * @return bool 0 success
1639
     */
1640
    public function endDump()
1641
    {
1642
        return $this->endTransaction();
1643
    }
1644
1645
    /**
1646
     * Returns a recordset of all columns in a relation.  Used for data export.
1647
     *
1648
     * @@ Note: Really needs to use a cursor
1649
     *
1650
     * @param string $relation The name of a relation
1 ignored issue
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
1651
     * @param bool   $oids     true to dump also the oids
1652
     *
1653
     * @return \PHPPgAdmin\ADORecordSet A recordset on success
1654
     */
1655
    public function dumpRelation($relation, $oids)
1656
    {
1657
        $this->fieldClean($relation);
1658
1659
        // Actually retrieve the rows
1660
        if ($oids) {
1661
            $oid_str = $this->id . ', ';
1662
        } else {
1663
            $oid_str = '';
1664
        }
1665
1666
        return $this->selectSet("SELECT {$oid_str}* FROM \"{$relation}\"");
1667
    }
1668
1669
    /**
1670
     * Returns all available autovacuum per table information.
1671
     *
1672
     * @param string $table if given, return autovacuum info for the given table or return all informations for all table
1673
     *
1674
     * @return \PHPPgAdmin\ArrayRecordSet A recordset
1675
     */
1676
    public function getTableAutovacuum($table = '')
1677
    {
1678
        $sql = '';
1679
1680
        if ($table !== '') {
1681
            $this->clean($table);
1682
            $c_schema = $this->_schema;
1683
            $this->clean($c_schema);
1684
1685
            $sql = "SELECT c.oid, nspname, relname, pg_catalog.array_to_string(reloptions, E',') AS reloptions
1686
                FROM pg_class c
1687
                    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
1688
                WHERE c.relkind = 'r'::\"char\"
1689
                    AND n.nspname NOT IN ('pg_catalog','information_schema')
1690
                    AND c.reloptions IS NOT NULL
1691
                    AND c.relname = '{$table}' AND n.nspname = '{$c_schema}'
1692
                ORDER BY nspname, relname";
1693
        } else {
1694
            $sql = "SELECT c.oid, nspname, relname, pg_catalog.array_to_string(reloptions, E',') AS reloptions
1695
                FROM pg_class c
1696
                    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
1697
                WHERE c.relkind = 'r'::\"char\"
1698
                    AND n.nspname NOT IN ('pg_catalog','information_schema')
1699
                    AND c.reloptions IS NOT NULL
1700
                ORDER BY nspname, relname";
1701
        }
1702
1703
        /* tmp var to parse the results */
1704
        $_autovacs = $this->selectSet($sql);
1705
1706
        /* result aray to return as RS */
1707
        $autovacs = [];
1708
        while (!$_autovacs->EOF) {
1709
            $_ = [
1710
                'nspname' => $_autovacs->fields['nspname'],
1711
                'relname' => $_autovacs->fields['relname'],
1712
            ];
1713
1714
            foreach (explode(',', $_autovacs->fields['reloptions']) as $var) {
1715
                list($o, $v) = explode('=', $var);
1716
                $_[$o]       = $v;
1717
            }
1718
1719
            $autovacs[] = $_;
1720
1721
            $_autovacs->moveNext();
1722
        }
1723
1724
        return new \PHPPgAdmin\ArrayRecordSet($autovacs);
1725
    }
1726
1727
    /**
1728
     * Get the fields for uniquely identifying a row in a table.
1729
     *
1730
     * @param string $table The table for which to retrieve the identifier
1731
     *
1732
     * @return array|array<integer,string>|int An array mapping attribute number to attribute name, empty for no identifiers
1733
     */
1734
    public function getRowIdentifier($table)
1735
    {
1736
        $oldtable = $table;
1737
        $c_schema = $this->_schema;
1738
        $this->clean($c_schema);
1739
        $this->clean($table);
1740
1741
        $status = $this->beginTransaction();
1742
        if ($status != 0) {
1743
            return -1;
1744
        }
1745
1746
        // Get the first primary or unique index (sorting primary keys first) that
1747
        // is NOT a partial index.
1748
        $sql = "
1749
            SELECT indrelid, indkey
1750
            FROM pg_catalog.pg_index
1751
            WHERE indisunique AND indrelid=(
1752
                SELECT oid FROM pg_catalog.pg_class
1753
                WHERE relname='{$table}' AND relnamespace=(
1754
                    SELECT oid FROM pg_catalog.pg_namespace
1755
                    WHERE nspname='{$c_schema}'
1756
                )
1757
            ) AND indpred IS NULL AND indexprs IS NULL
1758
            ORDER BY indisprimary DESC LIMIT 1";
1759
        $rs = $this->selectSet($sql);
1760
1761
        // If none, check for an OID column.  Even though OIDs can be duplicated, the edit and delete row
1762
        // functions check that they're only modiying a single row.  Otherwise, return empty array.
1763
        if ($rs->recordCount() == 0) {
1764
            // Check for OID column
1765
            $temp = [];
1766
            if ($this->hasObjectID($table)) {
1767
                $temp = ['oid'];
1768
            }
1769
            $this->endTransaction();
1770
1771
            return $temp;
1772
        } // Otherwise find the names of the keys
1773
1774
        $attnames = $this->getAttributeNames($oldtable, explode(' ', $rs->fields['indkey']));
1775
        if (!is_array($attnames)) {
1776
            $this->rollbackTransaction();
1777
1778
            return -1;
1779
        }
1780
1781
        $this->endTransaction();
1782
1783
        return $attnames;
1784
    }
1785
1786
    /**
1787
     * Adds a new row to a table.
1788
     *
1789
     * @param string $table  The table in which to insert
1790
     * @param array  $fields Array of given field in values
1791
     * @param array  $values Array of new values for the row
1792
     * @param array  $nulls  An array mapping column => something if it is to be null
1793
     * @param array  $format An array of the data type (VALUE or EXPRESSION)
1794
     * @param array  $types  An array of field types
1795
     *
1796
     * @return int 0 if operation was successful
1797
     */
1798
    public function insertRow($table, $fields, $values, $nulls, $format, $types)
1799
    {
1800
        if (!is_array($fields) || !is_array($values) || !is_array($nulls)
3 ignored issues
show
introduced by
The condition is_array($nulls) is always true.
Loading history...
introduced by
The condition is_array($values) is always true.
Loading history...
introduced by
The condition is_array($fields) is always true.
Loading history...
1801
            || !is_array($format) || !is_array($types)
2 ignored issues
show
introduced by
The condition is_array($format) is always true.
Loading history...
introduced by
The condition is_array($types) is always true.
Loading history...
1802
            || (count($fields) != count($values))
1803
        ) {
1804
            return -1;
1805
        }
1806
1807
        // Build clause
1808
        if (count($values) > 0) {
1809
            // Escape all field names
1810
            $fields   = array_map(['\PHPPgAdmin\Database\Postgres', 'fieldClean'], $fields);
1811
            $f_schema = $this->_schema;
1812
            $this->fieldClean($table);
1813
            $this->fieldClean($f_schema);
1814
1815
            $sql = '';
1816
            foreach ($values as $i => $value) {
1817
                // Handle NULL values
1818
                if (isset($nulls[$i])) {
1819
                    $sql .= ',NULL';
1820
                } else {
1821
                    $sql .= ',' . $this->formatValue($types[$i], $format[$i], $value);
1822
                }
1823
            }
1824
1825
            $sql = "INSERT INTO \"{$f_schema}\".\"{$table}\" (\"" . implode('","', $fields) . '")
1826
                VALUES (' . substr($sql, 1) . ')';
1827
1828
            return $this->execute($sql);
1829
        }
1830
1831
        return -1;
1832
    }
1833
1834
    /**
1835
     * Formats a value or expression for sql purposes.
1836
     *
1837
     * @param string $type   The type of the field
1838
     * @param mixed  $format VALUE or EXPRESSION
1839
     * @param mixed  $value  The actual value entered in the field.  Can be NULL
1840
     *
1841
     * @return mixed The suitably quoted and escaped value
1842
     */
1843
    public function formatValue($type, $format, $value)
1844
    {
1845
        switch ($type) {
1846
            case 'bool':
1847
            case 'boolean':
1848
                if ($value == 't') {
1849
                    return 'TRUE';
1850
                }
1851
1852
                if ($value == 'f') {
1853
                    return 'FALSE';
1854
                }
1855
                if ($value == '') {
1856
                    return 'NULL';
1857
                }
1858
1859
                return $value;
1860
                break;
1 ignored issue
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1861
            default:
1862
                // Checking variable fields is difficult as there might be a size
1863
                // attribute...
1864
                if (strpos($type, 'time') === 0) {
1865
                    // Assume it's one of the time types...
1866
                    if ($value == '') {
1867
                        return "''";
1868
                    }
1869
1870
                    if (strcasecmp($value, 'CURRENT_TIMESTAMP') == 0
1871
                        || strcasecmp($value, 'CURRENT_TIME') == 0
1872
                        || strcasecmp($value, 'CURRENT_DATE') == 0
1873
                        || strcasecmp($value, 'LOCALTIME') == 0
1874
                        || strcasecmp($value, 'LOCALTIMESTAMP') == 0) {
1 ignored issue
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
1875
                        return $value;
1876
                    }
1877
                    if ($format == 'EXPRESSION') {
1878
                        return $value;
1879
                    }
1880
                    $this->clean($value);
1881
1882
                    return "'{$value}'";
1883
                }
1884
                if ($format == 'VALUE') {
1885
                    $this->clean($value);
1886
1887
                    return "'{$value}'";
1888
                }
1889
1890
                return $value;
1891
        }
1892
    }
1893
1894
    // View functions
1895
1896
    /**
1897
     * Updates a row in a table.
1898
     *
1899
     * @param string $table  The table in which to update
1900
     * @param array  $vars   An array mapping new values for the row
1901
     * @param array  $nulls  An array mapping column => something if it is to be null
1902
     * @param array  $format An array of the data type (VALUE or EXPRESSION)
1903
     * @param array  $types  An array of field types
1904
     * @param array  $keyarr An array mapping column => value to update
1905
     *
1906
     * @return bool|int 0 success
1907
     */
1908
    public function editRow($table, $vars, $nulls, $format, $types, $keyarr)
1909
    {
1910
        if (!is_array($vars) || !is_array($nulls) || !is_array($format) || !is_array($types)) {
4 ignored issues
show
introduced by
The condition is_array($format) is always true.
Loading history...
introduced by
The condition is_array($nulls) is always true.
Loading history...
introduced by
The condition is_array($vars) is always true.
Loading history...
introduced by
The condition is_array($types) is always true.
Loading history...
1911
            return -1;
1912
        }
1913
1914
        $f_schema = $this->_schema;
1915
        $this->fieldClean($f_schema);
1916
        $this->fieldClean($table);
1917
1918
        // Build clause
1919
        if (sizeof($vars) > 0) {
1920
            foreach ($vars as $key => $value) {
1921
                $this->fieldClean($key);
1922
1923
                // Handle NULL values
1924
                if (isset($nulls[$key])) {
1925
                    $tmp = 'NULL';
1926
                } else {
1927
                    $tmp = $this->formatValue($types[$key], $format[$key], $value);
1928
                }
1929
1930
                if (isset($sql)) {
1931
                    $sql .= ", \"{$key}\"={$tmp}";
1932
                } else {
1933
                    $sql = "UPDATE \"{$f_schema}\".\"{$table}\" SET \"{$key}\"={$tmp}";
1934
                }
1935
            }
1936
            $first = true;
1937
            foreach ($keyarr as $k => $v) {
1938
                $this->fieldClean($k);
1939
                $this->clean($v);
1940
                if ($first) {
1941
                    $sql .= " WHERE \"{$k}\"='{$v}'";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sql does not seem to be defined for all execution paths leading up to this point.
Loading history...
1942
                    $first = false;
1943
                } else {
1944
                    $sql .= " AND \"{$k}\"='{$v}'";
1945
                }
1946
            }
1947
        }
1948
1949
        // Begin transaction.  We do this so that we can ensure only one row is
1950
        // edited
1951
        $status = $this->beginTransaction();
1952
        if ($status != 0) {
1953
            $this->rollbackTransaction();
1954
1955
            return -1;
1956
        }
1957
1958
        $status = $this->execute($sql);
1959
        if ($status != 0) {
1960
            // update failed
1961
            $this->rollbackTransaction();
1962
1963
            return -1;
1964
        }
1965
1966
        if ($this->conn->Affected_Rows() != 1) {
1967
            // more than one row could be updated
1968
            $this->rollbackTransaction();
1969
1970
            return -2;
1971
        }
1972
1973
        // End transaction
1974
        return $this->endTransaction();
1975
    }
1976
1977
    /**
1978
     * Delete a row from a table.
1979
     *
1980
     * @param string $table  The table from which to delete
1981
     * @param array  $key    An array mapping column => value to delete
1982
     * @param string $schema the schema of the table
1983
     *
1984
     * @return bool|int 0 success
1985
     */
1986
    public function deleteRow($table, $key, $schema = '')
1987
    {
1988
        if (!is_array($key)) {
1 ignored issue
show
introduced by
The condition is_array($key) is always true.
Loading history...
1989
            return -1;
1990
        }
1991
1992
        // Begin transaction.  We do this so that we can ensure only one row is
1993
        // deleted
1994
        $status = $this->beginTransaction();
1995
        if ($status != 0) {
1996
            $this->rollbackTransaction();
1997
1998
            return -1;
1999
        }
2000
2001
        if ($schema === '') {
2002
            $schema = $this->_schema;
2003
        }
2004
2005
        $status = $this->delete($table, $key, $schema);
2006
        if ($status != 0 || $this->conn->Affected_Rows() != 1) {
2007
            $this->rollbackTransaction();
2008
2009
            return -2;
2010
        }
2011
2012
        // End transaction
2013
        return $this->endTransaction();
2014
    }
2015
2016
    /**
2017
     * Returns the SQL for changing the current user.
2018
     *
2019
     * @param string $user The user to change to
2020
     *
2021
     * @return string The SQL
2022
     */
2023
    public function getChangeUserSQL($user)
2024
    {
2025
        $this->clean($user);
2026
2027
        return "SET SESSION AUTHORIZATION '{$user}';";
2028
    }
2029
2030
    abstract public function fieldClean(&$str);
2031
2032
    abstract public function beginTransaction();
2033
2034
    abstract public function rollbackTransaction();
2035
2036
    abstract public function endTransaction();
2037
2038
    abstract public function execute($sql);
2039
2040
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
2041
2042
    abstract public function selectSet($sql);
2043
2044
    abstract public function clean(&$str);
2045
2046
    abstract public function phpBool($parameter);
2047
2048
    abstract public function hasCreateTableLikeWithConstraints();
2049
2050
    abstract public function hasCreateTableLikeWithIndexes();
2051
2052
    abstract public function hasTablespaces();
2053
2054
    abstract public function delete($table, $conditions, $schema = '');
2055
2056
    abstract public function fieldArrayClean(&$arr);
2057
2058
    abstract public function hasCreateFieldWithConstraints();
2059
2060
    abstract public function getAttributeNames($table, $atts);
2061
}
2062