Passed
Push — develop ( ec36d3...fcc268 )
by Felipe
09:00
created

FunctionTrait::createFunction()   F

Complexity

Conditions 13
Paths 865

Size

Total Lines 86
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 48
dl 0
loc 86
c 0
b 0
f 0
rs 2.6375
cc 13
nc 865
nop 11

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