FunctionTrait::setFunction()   B
last analyzed

Complexity

Conditions 11
Paths 29

Size

Total Lines 87
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 35
c 0
b 0
f 0
nc 29
nop 15
dl 0
loc 87
rs 7.3166

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 6.1.3
5
 */
6
7
namespace PHPPgAdmin\Database\Traits;
8
9
/**
10
 * Common trait for full text search manipulation.
11
 */
12
trait FunctionTrait
13
{
14
    /**
15
     * Returns a list of all functions in the database.
16
     *
17
     * @param bool  $all  If true, will find all available functions, if false just those in search path
18
     * @param mixed $type If truthy, will return functions of type trigger
19
     *
20
     * @return int|\PHPPgAdmin\ADORecordSet
21
     */
22
    public function getFunctions($all = false, $type = null)
23
    {
24
        if ($all) {
25
            $where = 'pg_catalog.pg_function_is_visible(p.oid)';
26
            $distinct = 'DISTINCT ON (p.proname)';
27
28
            if ($type) {
29
                $where .= " AND p.prorettype = (select oid from pg_catalog.pg_type p where p.typname = 'trigger') ";
30
            }
31
        } else {
32
            $c_schema = $this->_schema;
33
            $this->clean($c_schema);
34
            $where = "n.nspname = '{$c_schema}'";
35
            $distinct = '';
36
        }
37
38
        $sql = "
39
            SELECT
40
                {$distinct}
41
                p.oid AS prooid,
42
                p.proname,
43
                p.proretset,
44
                pg_catalog.format_type(p.prorettype, NULL) AS proresult,
45
                pg_catalog.oidvectortypes(p.proargtypes) AS proarguments,
46
                pl.lanname AS prolanguage,
47
                pg_catalog.obj_description(p.oid, 'pg_proc') AS procomment,
48
                p.proname || ' (' || pg_catalog.oidvectortypes(p.proargtypes) || ')' AS proproto,
49
                CASE WHEN p.proretset THEN 'setof ' ELSE '' END || pg_catalog.format_type(p.prorettype, NULL) AS proreturns,
50
                coalesce(u.usename::text,p.proowner::text) AS proowner
51
52
            FROM pg_catalog.pg_proc p
53
                INNER JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
54
                INNER JOIN pg_catalog.pg_language pl ON pl.oid = p.prolang
55
                LEFT JOIN pg_catalog.pg_user u ON u.usesysid = p.proowner
56
            WHERE NOT p.proisagg
57
                AND {$where}
58
            ORDER BY p.proname, proresult
59
            ";
60
61
        return $this->selectSet($sql);
62
    }
63
64
    /**
65
     * Returns a list of all functions that can be used in triggers.
66
     *
67
     * @return \PHPPgAdmin\ADORecordSet Functions that can be used in a trigger
68
     */
69
    public function getTriggerFunctions()
70
    {
71
        return $this->getFunctions(true, 'trigger');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getFunctions(true, 'trigger') also could return the type integer which is incompatible with the documented return type PHPPgAdmin\ADORecordSet.
Loading history...
72
    }
73
74
    /**
75
     * Returns an array containing a function's properties.
76
     *
77
     * @param array $f The array of data for the function
78
     *
79
     * @return array|int An array containing the properties, or -1 in case of error
80
     */
81
    public function getFunctionProperties($f)
82
    {
83
        $temp = [];
84
85
        // Volatility
86
        if ('v' === $f['provolatile']) {
87
            $temp[] = 'VOLATILE';
88
        } elseif ('i' === $f['provolatile']) {
89
            $temp[] = 'IMMUTABLE';
90
        } elseif ('s' === $f['provolatile']) {
91
            $temp[] = 'STABLE';
92
        } else {
93
            return -1;
94
        }
95
96
        // Null handling
97
        $f['proisstrict'] = $this->phpBool($f['proisstrict']);
98
99
        if ($f['proisstrict']) {
100
            $temp[] = 'RETURNS NULL ON NULL INPUT';
101
        } else {
102
            $temp[] = 'CALLED ON NULL INPUT';
103
        }
104
105
        // Security
106
        $f['prosecdef'] = $this->phpBool($f['prosecdef']);
107
108
        if ($f['prosecdef']) {
109
            $temp[] = 'SECURITY DEFINER';
110
        } else {
111
            $temp[] = 'SECURITY INVOKER';
112
        }
113
114
        return $temp;
115
    }
116
117
    /**
118
     * Updates (replaces) a function.
119
     *
120
     * @param string $funcname   The name of the function to create
121
     * @param string $newname    The new name for the function
122
     * @param string $args       imploded array of argument types
123
     * @param string $returns    The return type
124
     * @param string $definition The definition for the new function
125
     * @param string $language   The language the function is written for
126
     * @param array  $flags      An array of optional flags
127
     * @param bool   $setof      True if returns a set, false otherwise
128
     * @param string $funcown
129
     * @param string $newown
130
     * @param string $funcschema
131
     * @param string $newschema
132
     * @param float  $cost
133
     * @param int    $rows
134
     * @param string $comment    The comment on the function
135
     *
136
     * @return bool|int 0 success
137
     */
138
    public function setFunction(
139
        $funcname,
140
        $newname,
141
        $args,
142
        $returns,
143
        $definition,
144
        $language,
145
        $flags,
146
        $setof,
147
        $funcown,
148
        $newown,
149
        $funcschema,
150
        $newschema,
151
        $cost,
152
        $rows,
153
        $comment
154
    ) {
155
        // Begin a transaction
156
        $status = $this->beginTransaction();
157
158
        if (0 !== $status) {
159
            $this->rollbackTransaction();
160
161
            return -1;
162
        }
163
164
        // Replace the existing function
165
        $status = $this->createFunction($funcname, $args, $returns, $definition, $language, $flags, $setof, $cost, $rows, $comment, true);
166
167
        if (0 !== $status) {
168
            $this->rollbackTransaction();
169
170
            return $status;
171
        }
172
173
        $f_schema = $this->_schema;
174
        $this->fieldClean($f_schema);
175
176
        // Rename the function, if necessary
177
        $this->fieldClean($newname);
178
        /* $funcname is escaped in createFunction */
179
        if ($funcname !== $newname) {
180
            $sql = "ALTER FUNCTION \"{$f_schema}\".\"{$funcname}\"({$args}) RENAME TO \"{$newname}\"";
181
            $status = $this->execute($sql);
182
183
            if (0 !== $status) {
184
                $this->rollbackTransaction();
185
186
                return -5;
187
            }
188
189
            $funcname = $newname;
190
        }
191
192
        // Alter the owner, if necessary
193
        if ($this->hasFunctionAlterOwner()) {
194
            $this->fieldClean($newown);
195
196
            if ($funcown !== $newown) {
197
                $sql = "ALTER FUNCTION \"{$f_schema}\".\"{$funcname}\"({$args}) OWNER TO \"{$newown}\"";
198
                $status = $this->execute($sql);
199
200
                if (0 !== $status) {
201
                    $this->rollbackTransaction();
202
203
                    return -6;
204
                }
205
            }
206
        }
207
208
        // Alter the schema, if necessary
209
        if ($this->hasFunctionAlterSchema()) {
210
            $this->fieldClean($newschema);
211
            /* $funcschema is escaped in createFunction */
212
            if ($funcschema !== $newschema) {
213
                $sql = "ALTER FUNCTION \"{$f_schema}\".\"{$funcname}\"({$args}) SET SCHEMA \"{$newschema}\"";
214
                $status = $this->execute($sql);
215
216
                if (0 !== $status) {
217
                    $this->rollbackTransaction();
218
219
                    return -7;
220
                }
221
            }
222
        }
223
224
        return $this->endTransaction();
225
    }
226
227
    /**
228
     * Creates a new function.
229
     *
230
     * @param string $funcname   The name of the function to create
231
     * @param string $args       A comma separated string of types
232
     * @param string $returns    The return type
233
     * @param string $definition The definition for the new function
234
     * @param string $language   The language the function is written for
235
     * @param array  $flags      An array of optional flags
236
     * @param bool   $setof      True if it returns a set, false otherwise
237
     * @param string $cost       cost the planner should use in the function  execution step
238
     * @param int    $rows       number of rows planner should estimate will be returned
239
     * @param string $comment    Comment for the function
240
     * @param bool   $replace    (optional) True if OR REPLACE, false for
241
     *                           normal
242
     *
243
     * @return bool|int 0 success
244
     */
245
    public function createFunction($funcname, $args, $returns, $definition, $language, $flags, $setof, $cost, $rows, $comment, $replace = false)
246
    {
247
        // Begin a transaction
248
        $status = $this->beginTransaction();
249
250
        if (0 !== $status) {
251
            $this->rollbackTransaction();
252
253
            return -1;
254
        }
255
256
        $this->fieldClean($funcname);
257
        $this->clean($args);
258
        $this->fieldClean($language);
259
        $this->arrayClean($flags);
260
        $this->clean($cost);
261
        $this->clean($rows);
262
        $f_schema = $this->_schema;
263
        $this->fieldClean($f_schema);
264
265
        $sql = 'CREATE';
266
267
        if ($replace) {
268
            $sql .= ' OR REPLACE';
269
        }
270
271
        $sql .= " FUNCTION \"{$f_schema}\".\"{$funcname}\" (";
272
273
        if ('' !== $args) {
274
            $sql .= $args;
275
        }
276
277
        // For some reason, the returns field cannot have quotes...
278
        $sql .= ') RETURNS ';
279
280
        if ($setof) {
281
            $sql .= 'SETOF ';
282
        }
283
284
        $sql .= "{$returns} AS ";
285
286
        if (\is_array($definition)) {
0 ignored issues
show
introduced by
The condition is_array($definition) is always false.
Loading history...
287
            $this->arrayClean($definition);
288
            $sql .= "'" . $definition[0] . "'";
289
290
            if ($definition[1]) {
291
                $sql .= ",'" . $definition[1] . "'";
292
            }
293
        } else {
294
            $this->clean($definition);
295
            $sql .= "'" . $definition . "'";
296
        }
297
298
        $sql .= " LANGUAGE \"{$language}\"";
299
300
        // Add costs
301
        if (!empty($cost)) {
302
            $sql .= " COST {$cost}";
303
        }
304
305
        if (0 !== $rows) {
306
            $sql .= " ROWS {$rows}";
307
        }
308
309
        // Add flags
310
        foreach ($flags as $v) {
311
            // Skip default flags
312
            if ('' === $v) {
313
                continue;
314
            }
315
316
            $sql .= "\n{$v}";
317
        }
318
319
        $status = $this->execute($sql);
320
321
        if (0 !== $status) {
322
            $this->rollbackTransaction();
323
324
            return -3;
325
        }
326
327
        /* set the comment */
328
        $status = $this->setComment('FUNCTION', "\"{$funcname}\"({$args})", null, $comment);
329
330
        if (0 !== $status) {
331
            $this->rollbackTransaction();
332
333
            return -4;
334
        }
335
336
        return $this->endTransaction();
337
    }
338
339
    /**
340
     * Drops a function.
341
     *
342
     * @param int  $function_oid The OID of the function to drop
343
     * @param bool $cascade      True to cascade drop, false to restrict
344
     *
345
     * @return int|\PHPPgAdmin\ADORecordSet
346
     */
347
    public function dropFunction($function_oid, $cascade)
348
    {
349
        // Function comes in with $object as function OID
350
        $fn = $this->getFunction($function_oid);
351
        $f_schema = $this->_schema;
352
        $this->fieldClean($f_schema);
353
        $this->fieldClean($fn->fields['proname']);
354
355
        $sql = "DROP FUNCTION \"{$f_schema}\".\"{$fn->fields['proname']}\"({$fn->fields['proarguments']})";
356
357
        if ($cascade) {
358
            $sql .= ' CASCADE';
359
        }
360
361
        return $this->execute($sql);
362
    }
363
364
    /**
365
     * Returns all details for a particular function.
366
     *
367
     * @param int $function_oid
368
     *
369
     * @return int|\PHPPgAdmin\ADORecordSet
370
     *
371
     * @internal param string The $func name of the function to retrieve
372
     */
373
    public function getFunction($function_oid)
374
    {
375
        $this->clean($function_oid);
376
377
        $sql = "
378
            SELECT
379
                pc.oid AS prooid, proname,
380
                pg_catalog.pg_get_userbyid(proowner) AS proowner,
381
                nspname as proschema, lanname as prolanguage, procost, prorows,
382
                pg_catalog.format_type(prorettype, NULL) as proresult, prosrc,
383
                probin, proretset, proisstrict, provolatile, prosecdef,
384
                pg_catalog.oidvectortypes(pc.proargtypes) AS proarguments,
385
                proargnames AS proargnames,
386
                pg_catalog.obj_description(pc.oid, 'pg_proc') AS procomment,
387
                proconfig,
388
                (select array_agg( (select typname from pg_type pt
389
                    where pt.oid = p.oid) ) from unnest(proallargtypes) p)
390
                AS proallarguments,
391
                proargmodes
392
            FROM
393
                pg_catalog.pg_proc pc, pg_catalog.pg_language pl,
394
                pg_catalog.pg_namespace pn
395
            WHERE
396
                pc.oid = '{$function_oid}'::oid AND pc.prolang = pl.oid
397
                AND pc.pronamespace = pn.oid
398
            ";
399
400
        return $this->selectSet($sql);
401
    }
402
403
    /**
404
     * Returns plain definition for a particular function.
405
     *
406
     * @param int $function_oid
407
     *
408
     * @return int|\PHPPgAdmin\ADORecordSet
409
     */
410
    public function getFunctionDef($function_oid)
411
    {
412
        $this->clean($function_oid);
413
        $sql = "
414
            SELECT
415
                f.proname as relname,
416
                n.nspname,
417
                u.usename AS relowner,
418
                 pg_catalog.obj_description(f.oid, 'pg_proc') as relcomment,
419
                 (SELECT spcname FROM pg_catalog.pg_tablespace pt WHERE pt.oid=f.pronamespace) AS tablespace,
420
                pg_get_functiondef(f.oid),
421
                pl.lanname AS prolanguage
422
                FROM pg_catalog.pg_proc f
423
                JOIN pg_catalog.pg_namespace n ON (f.pronamespace = n.oid)
424
                JOIN pg_catalog.pg_language pl ON pl.oid = f.prolang
425
                LEFT JOIN pg_catalog.pg_user u ON u.usesysid=f.proowner
426
                WHERE f.oid='{$function_oid}'
427
        ";
428
429
        return $this->selectSet($sql);
430
    }
431
432
    abstract public function fieldClean(&$str);
433
434
    abstract public function beginTransaction();
435
436
    abstract public function rollbackTransaction();
437
438
    abstract public function endTransaction();
439
440
    abstract public function execute($sql);
441
442
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
443
444
    abstract public function selectSet($sql);
445
446
    abstract public function clean(&$str);
447
448
    abstract public function phpBool($parameter);
449
450
    abstract public function hasFunctionAlterOwner();
451
452
    abstract public function hasFunctionAlterSchema();
453
454
    abstract public function arrayClean(&$arr);
455
}
456