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