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