Passed
Pull Request — develop (#200)
by Felipe
06:52 queued 01:49
created

ADOdbBase::hasAlterColumnType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.46
5
 */
6
7
namespace PHPPgAdmin\Database;
8
9
/**
10
 * @file
11
 * Parent class of all ADODB objects.
12
 *
13
 * Id: ADOdbBase.php,v 1.24 2008/02/20 20:43:10 ioguix Exp $
14
 *
15
 * @package PHPPgAdmin
16
 */
17
class ADOdbBase
18
{
19
    use \PHPPgAdmin\Traits\HelperTrait;
20
    use \PHPPgAdmin\Traits\HasTrait;
21
22
    public $lang;
23
    public $conf;
24
    protected $container;
25
    protected $server_info;
26
27
    /**
28
     * Base constructor.
29
     *
30
     * @param \PHPPgAdmin\ADONewConnection $conn        The connection object
31
     * @param mixed                        $container
32
     * @param mixed                        $server_info
33
     */
34
    public function __construct(&$conn, $container, $server_info)
35
    {
36
        $this->container   = $container;
37
        $this->server_info = $server_info;
38
39
        $this->lang = $container->get('lang');
40
        $this->conf = $container->get('conf');
41
42
        $this->prtrace('instanced connection class');
43
        $this->conn = $conn;
44
    }
45
46
    /**
47
     * Sets the comment for an object in the database.
48
     *
49
     * @pre All parameters must already be cleaned
50
     *
51
     * @param string      $obj_type One of 'TABLE' | 'COLUMN' | 'VIEW' | 'SCHEMA' | 'SEQUENCE' | 'TYPE' | 'FUNCTION' | 'AGGREGATE'
52
     * @param string      $obj_name the name of the object for which to attach a comment
53
     * @param string      $table    Name of table that $obj_name belongs to.  Ignored unless $obj_type is 'TABLE' or 'COLUMN'.
54
     * @param string      $comment  the comment to add
55
     * @param null|string $basetype
56
     *
57
     * @return int|\PHPPgAdmin\ADORecordSet recordset of results or error code
58
     */
59
    public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null)
60
    {
61
        $sql = "COMMENT ON {$obj_type} ";
62
63
        $f_schema = $this->_schema;
64
        $this->fieldClean($f_schema);
65
        $this->clean($comment); // Passing in an already cleaned comment will lead to double escaped data
66
        // So, while counter-intuitive, it is important to not clean comments before
67
        // calling setComment. We will clean it here instead.
68
        /*
69
         * $this->fieldClean($table);
70
         * $this->fieldClean($obj_name);
71
         */
72
73
        switch ($obj_type) {
74
            case 'TABLE':
75
                $sql .= "\"{$f_schema}\".\"{$table}\" IS ";
76
77
                break;
78
            case 'COLUMN':
79
                $sql .= "\"{$f_schema}\".\"{$table}\".\"{$obj_name}\" IS ";
80
81
                break;
82
            case 'SEQUENCE':
83
            case 'VIEW':
84
            case 'MATERIALIZED VIEW':
85
            case 'TEXT SEARCH CONFIGURATION':
86
            case 'TEXT SEARCH DICTIONARY':
87
            case 'TEXT SEARCH TEMPLATE':
88
            case 'TEXT SEARCH PARSER':
89
            case 'TYPE':
90
                $sql .= "\"{$f_schema}\".";
91
            // no break
92
            case 'DATABASE':
93
            case 'ROLE':
94
            case 'SCHEMA':
95
            case 'TABLESPACE':
96
                $sql .= "\"{$obj_name}\" IS ";
97
98
                break;
99
            case 'FUNCTION':
100
                $sql .= "\"{$f_schema}\".{$obj_name} IS ";
101
102
                break;
103
            case 'AGGREGATE':
104
                $sql .= "\"{$f_schema}\".\"{$obj_name}\" (\"{$basetype}\") IS ";
105
106
                break;
107
            default:
108
                // Unknown object type
109
                return -1;
110
        }
111
112
        if ($comment != '') {
113
            $sql .= "'{$comment}';";
114
        } else {
115
            $sql .= 'NULL;';
116
        }
117
118
        return $this->execute($sql);
119
    }
120
121
    /**
122
     * Turns on or off query debugging.
123
     *
124
     * @param bool $debug True to turn on debugging, false otherwise
125
     */
126
    public function setDebug($debug)
127
    {
128
        $this->conn->debug = $debug;
129
    }
130
131
    /**
132
     * Cleans (escapes) an array of field names.
133
     *
134
     * @param array $arr The array to clean, by reference
135
     *
136
     * @return array The cleaned array
137
     */
138
    public function fieldArrayClean(&$arr)
139
    {
140
        foreach ($arr as $k => $v) {
141
            if ($v === null) {
142
                continue;
143
            }
144
145
            $arr[$k] = str_replace('"', '""', $v);
146
        }
147
148
        return $arr;
149
    }
150
151
    /**
152
     * Cleans (escapes) an array.
153
     *
154
     * @param array $arr The array to clean, by reference
155
     *
156
     * @return array The cleaned array
157
     */
158
    public function arrayClean(&$arr)
159
    {
160
        foreach ($arr as $k => $v) {
161
            if ($v === null) {
162
                continue;
163
            }
164
            $arr[$k] = pg_escape_string($v);
165
        }
166
167
        return $arr;
168
    }
169
170
    /**
171
     * Executes a query on the underlying connection.
172
     *
173
     * @param string $sql The SQL query to execute
174
     *
175
     * @return \PHPPgAdmin\ADORecordSet A recordset
176
     */
177
    public function execute($sql)
178
    {
179
        // Execute the statement
180
        $rs = $this->conn->Execute($sql);
1 ignored issue
show
Unused Code introduced by
The assignment to $rs is dead and can be removed.
Loading history...
181
182
        // If failure, return error value
183
        return $this->conn->ErrorNo();
184
    }
185
186
    /**
187
     * Closes the connection the database class
188
     * relies on.
189
     */
190
    public function close()
191
    {
192
        $this->conn->close();
193
    }
194
195
    /**
196
     * Retrieves a ResultSet from a query.
197
     *
198
     * @param string $sql The SQL statement to be executed
199
     *
200
     * @return int|\PHPPgAdmin\ADORecordSet A recordset or an error number
201
     */
202
    public function selectSet($sql)
203
    {
204
        // Execute the statement
205
        $rs = $this->conn->Execute($sql);
206
207
        if (!$rs) {
208
            return $this->conn->ErrorNo();
209
        }
210
211
        return $rs;
212
    }
213
214
    /**
215
     * Retrieves a single value from a query.
216
     *
217
     * @@ assumes that the query will return only one row - returns field value in the first row
218
     *
219
     * @param string $sql   The SQL statement to be executed
220
     * @param string $field The field name to be returned
221
     *
222
     * @return int|string single field value, error number on error or -1 if no rows where found
223
     */
224
    public function selectField($sql, $field)
225
    {
226
        // Execute the statement
227
        $rs = $this->conn->Execute($sql);
228
229
        // If failure, or no rows returned, return error value
230
        if (!$rs) {
231
            return $this->conn->ErrorNo();
232
        }
233
234
        if ($rs->RecordCount() == 0) {
235
            return -1;
236
        }
237
238
        return $rs->fields[$field];
239
    }
240
241
    /**
242
     * Delete from the database.
243
     *
244
     * @param string $table      The name of the table
245
     * @param array  $conditions (array) A map of field names to conditions
246
     * @param string $schema     (optional) The table's schema
247
     *
248
     * @return int 0 success
249
     */
250
    public function delete($table, $conditions, $schema = '')
251
    {
252
        $this->fieldClean($table);
253
254
        reset($conditions);
255
256
        if (!empty($schema)) {
257
            $this->fieldClean($schema);
258
            $schema = "\"{$schema}\".";
259
        }
260
261
        // Build clause
262
        $sql = '';
263
        //while (list($key, $value) = each($conditions)) {
264
        foreach ($conditions as $key => $value) {
265
            $this->clean($key);
266
            $this->clean($value);
267
            if ($sql) {
268
                $sql .= " AND \"{$key}\"='{$value}'";
269
            } else {
270
                $sql = "DELETE FROM {$schema}\"{$table}\" WHERE \"{$key}\"='{$value}'";
271
            }
272
        }
273
274
        // Check for failures
275
        if (!$this->conn->Execute($sql)) {
276
            // Check for referential integrity failure
277
            if (stristr($this->conn->ErrorMsg(), 'referential')) {
278
                return -1;
279
            }
280
        }
281
282
        // Check for no rows modified
283
        if ($this->conn->Affected_Rows() == 0) {
284
            return -2;
285
        }
286
287
        return $this->conn->ErrorNo();
288
    }
289
290
    /**
291
     * Cleans (escapes) an object name (eg. table, field).
292
     *
293
     * @param null|string $str The string to clean, by reference
294
     *
295
     * @return null|string The cleaned string
296
     */
297
    public function fieldClean(&$str)
298
    {
299
        if ($str === null) {
300
            return null;
301
        }
302
        $str = str_replace('"', '""', $str);
303
304
        return $str;
305
    }
306
307
    /**
308
     * Cleans (escapes) a string.
309
     *
310
     * @param null|string $str The string to clean, by reference
311
     *
312
     * @return null|string The cleaned string
313
     */
314
    public function clean(&$str)
315
    {
316
        if ($str === null) {
317
            return null;
318
        }
319
        $str = str_replace("\r\n", "\n", $str);
320
        $str = pg_escape_string($str);
321
322
        return $str;
323
    }
324
325
    /**
326
     * Escapes bytea data for display on the screen.
327
     *
328
     * @param string $data The bytea data
329
     *
330
     * @return string Data formatted for on-screen display
331
     */
332
    public function escapeBytea($data)
333
    {
334
        return htmlentities($data, ENT_QUOTES, 'UTF-8');
335
    }
336
337
    /**
338
     * Insert a set of values into the database.
339
     *
340
     * @param string $table The table to insert into
341
     * @param array  $vars  (array) A mapping of the field names to the values to be inserted
342
     *
343
     * @return int 0 success
344
     */
345
    public function insert($table, $vars)
346
    {
347
        $this->fieldClean($table);
348
349
        // Build clause
350
        if (sizeof($vars) > 0) {
351
            $fields = '';
352
            $values = '';
353
            foreach ($vars as $key => $value) {
354
                $this->clean($key);
355
                $this->clean($value);
356
357
                if ($fields) {
358
                    $fields .= ", \"{$key}\"";
359
                } else {
360
                    $fields = "INSERT INTO \"{$table}\" (\"{$key}\"";
361
                }
362
363
                if ($values) {
364
                    $values .= ", '{$value}'";
365
                } else {
366
                    $values = ") VALUES ('{$value}'";
367
                }
368
            }
369
            $sql = $fields . $values . ')';
370
        }
371
372
        // Check for failures
373
        if (!$this->conn->Execute($sql)) {
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...
374
            // Check for unique constraint failure
375
            if (stristr($this->conn->ErrorMsg(), 'unique')) {
376
                return -1;
377
            }
378
379
            if (stristr($this->conn->ErrorMsg(), 'referential')) {
380
                return -2;
381
            } // Check for referential integrity failure
382
        }
383
384
        return $this->conn->ErrorNo();
385
    }
386
387
    /**
388
     * Update a row in the database.
389
     *
390
     * @param string $table The table that is to be updated
391
     * @param array  $vars  (array) A mapping of the field names to the values to be updated
392
     * @param array  $where (array) A mapping of field names to values for the where clause
393
     * @param array  $nulls (array, optional) An array of fields to be set null
394
     *
395
     * @return int 0 success
396
     */
397
    public function update($table, $vars, $where, $nulls = [])
398
    {
399
        $this->fieldClean($table);
400
401
        $setClause   = '';
402
        $whereClause = '';
403
404
        // Populate the syntax arrays
405
        reset($vars);
406
        //while (list($key, $value) = each($vars)) {
407
        foreach ($vars as $key => $value) {
408
            $this->fieldClean($key);
409
            $this->clean($value);
410
            if ($setClause) {
411
                $setClause .= ", \"{$key}\"='{$value}'";
412
            } else {
413
                $setClause = "UPDATE \"{$table}\" SET \"{$key}\"='{$value}'";
414
            }
415
        }
416
417
        reset($nulls);
418
        //while (list(, $value) = each($nulls)) {
419
        foreach ($nulls as $key => $value) {
420
            $this->fieldClean($value);
421
            if ($setClause) {
422
                $setClause .= ", \"{$value}\"=NULL";
423
            } else {
424
                $setClause = "UPDATE \"{$table}\" SET \"{$value}\"=NULL";
425
            }
426
        }
427
428
        reset($where);
429
        //while (list($key, $value) = each($where)) {
430
        foreach ($where as $key => $value) {
431
            $this->fieldClean($key);
432
            $this->clean($value);
433
            if ($whereClause) {
434
                $whereClause .= " AND \"{$key}\"='{$value}'";
435
            } else {
436
                $whereClause = " WHERE \"{$key}\"='{$value}'";
437
            }
438
        }
439
440
        // Check for failures
441
        if (!$this->conn->Execute($setClause . $whereClause)) {
442
            // Check for unique constraint failure
443
            if (stristr($this->conn->ErrorMsg(), 'unique')) {
444
                return -1;
445
            }
446
447
            if (stristr($this->conn->ErrorMsg(), 'referential')) {
448
                return -2;
449
            } // Check for referential integrity failure
450
        }
451
452
        // Check for no rows modified
453
        if ($this->conn->Affected_Rows() == 0) {
454
            return -3;
455
        }
456
457
        return $this->conn->ErrorNo();
458
    }
459
460
    /**
461
     * Begin a transaction.
462
     *
463
     * @return bool 0 success
464
     */
465
    public function beginTransaction()
466
    {
467
        return !$this->conn->BeginTrans();
468
    }
469
470
    /**
471
     * End a transaction.
472
     *
473
     * @return bool 0 success
474
     */
475
    public function endTransaction()
476
    {
477
        return !$this->conn->CommitTrans();
478
    }
479
480
    /**
481
     * Roll back a transaction.
482
     *
483
     * @return bool 0 success
484
     */
485
    public function rollbackTransaction()
486
    {
487
        return !$this->conn->RollbackTrans();
488
    }
489
490
    /**
491
     * Get the backend platform.
492
     *
493
     * @return string The backend platform
494
     */
495
    public function getPlatform()
496
    {
497
        try {
498
            return $this->conn->platform;
499
        } catch (\Exception $e) {
500
            $this->prtrace($e->getMessage());
501
502
            return 'UNKNOWN';
503
        }
504
    }
505
506
    // Type conversion routines
507
508
    /**
509
     * Change the value of a parameter to database representation depending on whether it evaluates to true or false.
510
     *
511
     * @param mixed $parameter the parameter
512
     *
513
     * @return string boolean  database representation
514
     */
515
    public function dbBool(&$parameter)
516
    {
517
        if ($parameter) {
518
            $parameter = 't';
519
        } else {
520
            $parameter = 'f';
521
        }
522
523
        return $parameter;
524
    }
525
526
    /**
527
     * Change a parameter from database representation to a boolean, (others evaluate to false).
528
     *
529
     * @param string $parameter the parameter
530
     *
531
     * @return bool
532
     */
533
    public function phpBool($parameter)
534
    {
535
        return $parameter === 't';
536
    }
537
538
    /**
539
     * Change a db array into a PHP array.
540
     *
541
     * @param string $dbarr
542
     *
543
     * @return array A PHP array
544
     *
545
     * @internal param String $arr representing the DB array
546
     */
547
    public function phpArray($dbarr)
548
    {
549
        // Take off the first and last characters (the braces)
550
        $arr = substr($dbarr, 1, strlen($dbarr) - 2);
551
552
        // Pick out array entries by carefully parsing.  This is necessary in order
553
        // to cope with double quotes and commas, etc.
554
        $elements  = [];
555
        $i         = $j         = 0;
556
        $in_quotes = false;
557
        while ($i < strlen($arr)) {
558
            // If current char is a double quote and it's not escaped, then
559
            // enter quoted bit
560
            $char = substr($arr, $i, 1);
561
            if ($char == '"' && ($i == 0 || substr($arr, $i - 1, 1) != '\\')) {
562
                $in_quotes = !$in_quotes;
1 ignored issue
show
introduced by
$in_quotes is of type mixed, thus it always evaluated to false.
Loading history...
563
            } elseif ($char == ',' && !$in_quotes) {
564
                // Add text so far to the array
565
                $elements[] = substr($arr, $j, $i - $j);
566
                $j          = $i + 1;
567
            }
568
            ++$i;
569
        }
570
        // Add final text to the array
571
        $elements[] = substr($arr, $j);
572
573
        // Do one further loop over the elements array to remote double quoting
574
        // and escaping of double quotes and backslashes
575
        for ($i = 0; $i < sizeof($elements); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
576
            $v = $elements[$i];
577
            if (strpos($v, '"') === 0) {
578
                $v            = substr($v, 1, strlen($v) - 2);
579
                $v            = str_replace('\\"', '"', $v);
580
                $v            = str_replace('\\\\', '\\', $v);
581
                $elements[$i] = $v;
582
            }
583
        }
584
585
        return $elements;
586
    }
587
}
588