OciPdoStubStatement   D
last analyzed

Complexity

Total Complexity 86

Size/Duplication

Total Lines 644
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 644
rs 4.6921
c 0
b 0
f 0
wmc 86
lcom 1
cbo 1

31 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 2
A bindValue() 0 11 2
A bindParam() 0 11 2
A _getBindVar() 0 13 3
C execute() 0 32 8
A rowCount() 0 12 2
A closeCursor() 0 11 2
C fetch() 0 31 8
C fetchAll() 0 66 16
A fetchColumn() 0 5 1
A fetchObject() 0 9 2
B _createObjectFromData() 0 16 5
A insertMarks() 0 11 3
A getStatement() 0 4 1
A current() 0 11 3
A key() 0 4 1
A next() 0 8 2
A rewind() 0 4 1
A valid() 0 5 1
A setFetchMode() 0 5 1
A getFetchMode() 0 4 1
A bindColumn() 0 5 2
B _checkBinds() 0 17 5
A columnCount() 0 11 3
A debugDumpParams() 0 11 2
A errorCode() 0 4 1
A errorInfo() 0 4 1
A setAttribute() 0 4 1
A getAttribute() 0 4 1
A getColumnMeta() 0 11 2
A nextRowSet() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like OciPdoStubStatement often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use OciPdoStubStatement, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
/**
3
 * PDOOCI
4
 *
5
 * PHP version 5.3
6
 *
7
 * @category PDOOCI
8
 * @package  PDOOCI
9
 * @author   Eustáquio Rangel <[email protected]>
10
 * @license  http://www.gnu.org/licenses/gpl-2.0.html GPLv2
11
 * @link     http://github.com/taq/pdooci
12
 */
13
14
namespace Terah\FluentPdoModel\Drivers;
15
16
use \PDO;
17
18
/**
19
 * Statement class of PDOOCI
20
 *
21
 * PHP version 5.3
22
 *
23
 * @category FluentPdoModel
24
 * @package  PDOOCI
25
 * @author   Eustáquio Rangel <[email protected]>
26
 * @license  http://www.gnu.org/licenses/gpl-2.0.html GPLv2
27
 * @link     http://github.com/taq/pdooci
28
 */
29
class OciPdoStubStatement extends \PDOStatement
30
{
31
    /**
32
     * @var PDO
33
     */
34
    private $_pdooci = null;
35
    /**
36
     * @var resource
37
     */
38
    private $_con = null;
39
    /**
40
     * @var string
41
     */
42
    private $_statement = null;
43
    /**
44
     * @var resource
45
     */
46
    private $_stmt = null;
47
    /**
48
     * @var int
49
     */
50
    private $_fetch_sty = null;
51
    /**
52
     * @var mixed
53
     */
54
    private $_current = null;
55
    /**
56
     * @var int
57
     */
58
    private $_pos = 0;
59
    /**
60
     * @var array
61
     */
62
    private $_binds = [];
63
    /**
64
     * @var string
65
     */
66
    protected $_queryString = '';
67
68
    /**
69
     * Constructor
70
     *
71
     * @param OciStubPdo    $pdooci    PDOOCI connection
72
     * @param string $statement sql statement
73
     *
74
     * @throws \PDOException
75
     */
76
    public function __construct(OciStubPdo $pdooci, $statement)
77
    {
78
        try {
79
            $this->_pdooci    = $pdooci;
80
            $this->_con       = $pdooci->getConnection();
81
            $this->_statement = OciPdoStubStatement::insertMarks($statement);
82
            $this->_stmt      = \oci_parse($this->_con, $this->_statement);
83
            $this->_fetch_sty = \PDO::FETCH_BOTH;
84
85
            $this->_queryString = $this->_statement;
86
        } catch ( \Exception $e ) {
87
            throw new \PDOException($e->getMessage());
88
        }
89
    }
90
91
    /**
92
     * Binds a value
93
     *
94
     * @param mixed $param param (column)
95
     * @param mixed $value value for param
96
     * @param mixed $type  optional data type
97
     *
98
     * @return bool bound
99
     * @throws \PDOException
100
     */
101
    public function bindValue($param, $value, $type = null)
102
    {
103
        try {
104
            $param                = $this->_getBindVar($param);
105
            $ok                   = \oci_bind_by_name($this->_stmt, $param, $value);
106
            $this->_binds[$param] = $value;
107
        } catch ( \Exception $e ) {
108
            throw new \PDOException($e->getMessage());
109
        }
110
        return $ok;
111
    }
112
113
    /**
114
     * Binds a param
115
     *
116
     * @param mixed $paramno
117
     * @param mixed $param
118
     * @param null  $type
119
     * @param null  $maxlen
120
     * @param null  $driverdata
121
     *
122
     * @return bool
123
     */
124
    public function bindParam($paramno, &$param, $type = null, $maxlen = null, $driverdata = null)
125
    {
126
        try {
127
            $paramno                = $this->_getBindVar($paramno);
128
            $ok                     = \oci_bind_by_name($this->_stmt, $paramno, $param);
129
            $this->_binds[$paramno] = $param;
130
        } catch ( \Exception $e ) {
131
            throw new \PDOException($e->getMessage());
132
        }
133
        return $ok;
134
    }
135
136
    /**
137
     * Get the variable name for binding
138
     *
139
     * @param mixed $val variable value
140
     *
141
     * @return string correct name for binding
142
     */
143
    private function _getBindVar($val)
144
    {
145
        if ( preg_match('/^\d+$/', (string)$val) )
146
        {
147
            $val = ":pdooci_m" . ( intval($val) - 1 );
148
            return $val;
149
        }
150
        else if ( preg_match('/^:/', (string)$val) )
151
        {
152
            return $val;
153
        }
154
        return ":{$val}";
155
    }
156
157
    /**
158
     * Execute statement
159
     *
160
     * @param mixed $values optional values
161
     *
162
     * @return boolean
163
     * @throws \PDOException
164
     */
165
    public function execute($values = null)
166
    {
167
        set_error_handler([$this->_pdooci, "errorHandler"]);
168
        try {
169
            $this->_pdooci->getAutoCommit();
0 ignored issues
show
Bug introduced by
The method getAutoCommit() does not exist on PDO. Did you maybe mean commit()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
170
            $auto = $this->_pdooci->getAutoCommit() ? \OCI_COMMIT_ON_SUCCESS : \OCI_NO_AUTO_COMMIT;
0 ignored issues
show
Bug introduced by
The method getAutoCommit() does not exist on PDO. Did you maybe mean commit()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
171
172
            if ( $values && sizeof($values) > 0 )
173
            {
174
                foreach ( $values as $key => $val )
175
                {
176
                    $parm = $key;
177
                    if ( preg_match('/^\d+$/', (string)$key) )
178
                    {
179
                        $parm++;
180
                    }
181
                    $this->bindValue($parm, $values[$key]);
182
                    $this->_pdooci->setError();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PDO as the method setError() does only exist in the following sub-classes of PDO: Terah\FluentPdoModel\Drivers\OciStubPdo. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
183
                }
184
            }
185
            $ok = \oci_execute($this->_stmt, $auto);
186
            if (!$ok) {
187
                $this->_pdooci->setError($this->_stmt);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PDO as the method setError() does only exist in the following sub-classes of PDO: Terah\FluentPdoModel\Drivers\OciStubPdo. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
188
                $error = $this->_pdooci->errorInfo();
189
                throw new \PDOException($error[2]);
190
            }
191
        } catch ( \Exception $e ) {
192
            throw new \PDOException($e->getMessage());
193
        }
194
        restore_error_handler();
195
        return $ok;
196
    }
197
198
    /**
199
     * Get the number of affected rows
200
     *
201
     * @return int number of rows
202
     * @throws \PDOException
203
     */
204
    public function rowCount()
205
    {
206
        set_error_handler([$this->_pdooci, "errorHandler"]);
207
        $rows = null;
208
        try {
209
            $rows = \oci_num_rows($this->_stmt);
210
        } catch ( \Exception $e ) {
211
            throw new \PDOException($e->getMessage());
212
        }
213
        restore_error_handler();
214
        return $rows;
215
    }
216
217
    /**
218
     * Close the current cursor
219
     *
220
     * @return null
221
     * @throws \PDOException
222
     */
223
    public function closeCursor()
224
    {
225
        set_error_handler([$this->_pdooci, "errorHandler"]);
226
        try {
227
            \oci_free_statement($this->_stmt);
228
        } catch ( \Exception $e ) {
229
            throw new \PDOException($e->getMessage());
230
        }
231
        restore_error_handler();
232
        $this->_stmt = null;
233
    }
234
235
    /**
236
     * Fetch a value
237
     *
238
     * @param null $how
239
     * @param null $orientation
240
     * @param null $offset
241
     *
242
     * @return array|mixed|null|object
243
     */
244
    public function fetch($how = null, $orientation = null, $offset = null)
245
    {
246
        set_error_handler([$this->_pdooci, "errorHandler"]);
247
        try {
248
            $style            = !$how ? $this->_fetch_sty : $how;
249
            $this->_fetch_sty = $style;
250
            $rst              = null;
251
252
            switch ($style) {
253
                case \PDO::FETCH_BOTH:
254
                case \PDO::FETCH_BOUND:
255
                    $rst = \oci_fetch_array($this->_stmt, \OCI_BOTH + \OCI_RETURN_NULLS);
256
                    break;
257
                case \PDO::FETCH_ASSOC:
258
                    $rst = \oci_fetch_array($this->_stmt, \OCI_ASSOC + \OCI_RETURN_NULLS);
259
                    break;
260
                case \PDO::FETCH_NUM:
261
                    $rst = \oci_fetch_array($this->_stmt, \OCI_NUM + OCI_RETURN_NULLS);
262
                    break;
263
                case \PDO::FETCH_OBJ:
264
                    $rst = \oci_fetch_object($this->_stmt);
265
                    break;
266
            }
267
            $this->_current = $rst;
268
            $this->_checkBinds();
269
        } catch ( \Exception $e ) {
270
            throw new \PDOException($e->getMessage());
271
        }
272
        restore_error_handler();
273
        return $rst;
274
    }
275
276
    /**
277
     * Fetch all
278
     *
279
     * @param null $how
280
     * @param null $class_name
281
     * @param null $ctor_args
282
     *
283
     * @return array|null
284
     */
285
    public function fetchAll($how = null, $class_name = null, $ctor_args = null)
286
    {
287
        $style = is_null($how) ? \PDO::FETCH_BOTH : $how;
288
        $rst   = null;
289
        try {
290
            switch ($style) {
291
                case \PDO::FETCH_ASSOC:
292
                    \oci_fetch_all($this->_stmt, $rst, 0, -1, \OCI_FETCHSTATEMENT_BY_ROW + \OCI_ASSOC);
293
                    break;
294
295
                case \PDO::FETCH_BOTH:
296
                    \oci_fetch_all($this->_stmt, $rst, 0, -1, \OCI_FETCHSTATEMENT_BY_ROW + \OCI_NUM + \OCI_ASSOC);
297
                    break;
298
299
                case \PDO::FETCH_COLUMN:
300
                    \oci_fetch_all($this->_stmt, $rst, 0, -1, \OCI_FETCHSTATEMENT_BY_ROW + \OCI_NUM);
301
                    $rst = array_map(function ($vals) use ($class_name) {
302
                        return $vals[intval($class_name)];
303
                    }, $rst);
304
                    break;
305
306
                case \PDO::FETCH_COLUMN | \PDO::FETCH_GROUP:
307
                    \oci_fetch_all($this->_stmt, $rst, 0, -1, \OCI_FETCHSTATEMENT_BY_ROW + \OCI_NUM);
308
                    $temp = [];
309
                    foreach ($rst as $value) {
310
                        if (!array_key_exists($value[0], $temp)) {
311
                            $temp[$value[0]] = [];
312
                        }
313
                        array_push($temp[$value[0]], $value[1]);
314
                    }
315
                    $rst = $temp;
316
                    break;
317
318
                case \PDO::FETCH_CLASS:
319
                    \oci_fetch_all($this->_stmt, $rst, 0, -1, \OCI_FETCHSTATEMENT_BY_ROW + \OCI_ASSOC);
320
                    $temp = [];
321
                    foreach ($rst as $data) {
322
                        array_push($temp, $this->_createObjectFromData($class_name, $data));
323
                    }
324
                    $rst = $temp;
325
                    break;
326
327
                case \PDO::FETCH_FUNC:
328
                    if (!function_exists($class_name)) {
329
                        throw new \PDOException("Function $class_name does not exists");
330
                    }
331
                    $ref  = new \ReflectionFunction($class_name);
332
                    $args = $ref->getNumberOfParameters();
333
                    if ($args < 1) {
334
                        throw new \PDOException("Function $class_name can't receive parameters");
335
                    }
336
                    \oci_fetch_all($this->_stmt, $rst, 0, -1, \OCI_FETCHSTATEMENT_BY_ROW + \OCI_NUM);
337
                    foreach ($rst as $value) {
338
                        $temp = [];
339
                        foreach ($value as $key => $data) {
340
                            array_push($temp, $data);
341
                        }
342
                        call_user_func_array($class_name, $temp);
343
                    }
344
                    break;
345
            }
346
        } catch ( \Exception $e ) {
347
            throw new \PDOException($e->getMessage());
348
        }
349
        return $rst;
350
    }
351
352
    /**
353
     * Fetch column
354
     *
355
     * @param int $colnum optional column number
356
     *
357
     * @return mixed column value
358
     */
359
    public function fetchColumn($colnum = 0)
360
    {
361
        $rst = $this->fetch(\PDO::FETCH_NUM);
362
        return $rst[$colnum];
363
    }
364
365
    /**
366
     * Fetch data and create an object
367
     *
368
     * @param string $class_name
369
     * @param null   $ctor_args
370
     *
371
     * @return \stdClass|null
372
     */
373
    public function fetchObject($class_name = 'stdClass', $ctor_args = null)
374
    {
375
        try {
376
            $data = $this->fetch(\PDO::FETCH_ASSOC);
377
            return $this->_createObjectFromData($class_name, $data);
378
        } catch ( \Exception $e ) {
379
            return null;
380
        }
381
    }
382
383
    /**
384
     * Create a new object from data
385
     *
386
     * @param string $name class name
387
     * @param mixed  $data data to use on class
388
     *
389
     * @return \stdClass
390
     */
391
    private function _createObjectFromData($name, $data)
392
    {
393
        try {
394
            $cls = new $name();
395
            foreach ($data as $key => $value) {
396
                if ($name !== 'stdClass' && !array_key_exists(strtolower($key), get_object_vars($cls))) {
397
                    continue;
398
                }
399
                $key       = strtolower($key);
400
                $cls->$key = $value;
401
            }
402
            return $cls;
403
        } catch ( \Exception $e ) {
404
            return null;
405
        }
406
    }
407
408
    /**
409
     * Convert a query to use bind marks
410
     *
411
     * @param string $query to insert bind marks
412
     *
413
     * @return string query with bind marks
414
     */
415
    public static function insertMarks($query)
416
    {
417
        preg_match_all('/\?/', $query, $marks);
418
        if (sizeof($marks[0]) < 1) {
419
            return $query;
420
        }
421
        foreach ($marks[0] as $idx => $mark) {
422
            $query = preg_replace("/\?/", ":pdooci_m$idx", $query, 1);
423
        }
424
        return $query;
425
    }
426
427
    /**
428
     * Return the current statement
429
     *
430
     * @return string statement
431
     */
432
    public function getStatement()
433
    {
434
        return $this->_statement;
435
    }
436
437
    /**
438
     * Return the current value
439
     *
440
     * @return null
441
     */
442
    public function current()
443
    {
444
        if (!$this->_current) {
445
            $this->next();
446
            if (!$this->_current) {
447
                $this->_pos = -1;
448
                $this->closeCursor();
449
            }
450
        }
451
        return $this->_current;
452
    }
453
454
    /**
455
     * Return the current key/position
456
     *
457
     * @return integer
458
     */
459
    public function key()
460
    {
461
        return $this->_pos;
462
    }
463
464
    /**
465
     * Return the next value
466
     *
467
     * @return null
468
     */
469
    public function next()
470
    {
471
        $this->_current = $this->fetch(\PDO::FETCH_ASSOC);
472
        if (!$this->_current) {
473
            $this->_pos = -1;
474
        }
475
        $this->_checkBinds();
476
    }
477
478
    /**
479
     * Rewind
480
     *
481
     * @return null
482
     */
483
    public function rewind()
484
    {
485
        $this->_pos = 0;
486
    }
487
488
    /**
489
     * Check if the current value is valid
490
     *
491
     * @return boolean
492
     */
493
    public function valid()
494
    {
495
        $valid = $this->_pos >= 0;
496
        return $valid;
497
    }
498
499
    /**
500
     * Set the fetch mode
501
     *
502
     * @param int   $mode fetch mode
503
     * @param mixed $p1   first optional parameter
504
     * @param mixed $p2   second optional parameter
505
     *
506
     * @return null
507
     */
508
    public function setFetchMode($mode, $p1 = null, $p2 = null)
509
    {
510
        unset($p1, $p2);
511
        $this->_fetch_sty = $mode;
512
    }
513
514
    /**
515
     * Return the fetch mode
516
     *
517
     * @return int mode
518
     */
519
    public function getFetchMode()
520
    {
521
        return $this->_fetch_sty;
522
    }
523
524
    /**
525
     * Bind column
526
     *
527
     * @param mixed $column as index (1-based) or name
528
     * @param mixed &$param variable
529
     * @param int   $type   type
530
     * @param int   $maxlen max length
531
     * @param mixed $driver data
532
     *
533
     * @return boolean|null if was bound
534
     */
535
    public function bindColumn($column, &$param, $type = null, $maxlen = null, $driver = null)
536
    {
537
        $column                = is_numeric($column) ? $column : strtoupper($column);
538
        $this->_binds[$column] = &$param;
539
    }
540
541
    /**
542
     * Check what binds are needed
543
     *
544
     * @return null
545
     */
546
    private function _checkBinds()
547
    {
548
        if ($this->_fetch_sty != \PDO::FETCH_BOUND) {
549
            return;
550
        }
551
        foreach ($this->_binds as $key => &$value) {
552
            if (is_numeric($key)) {
553
                $key--;
554
            } else {
555
                $key = strtoupper($key);
556
            }
557
            if (!array_key_exists($key, $this->_current)) {
558
                continue;
559
            }
560
            $value = $this->_current[$key];
561
        }
562
    }
563
564
    /**
565
     * Column count
566
     *
567
     * @return int column count or zero if not executed
568
     * @throws \PDOException
569
     */
570
    public function columnCount()
571
    {
572
        if (!$this->_stmt) {
573
            return 0;
574
        }
575
        try {
576
            return \oci_num_fields($this->_stmt);
577
        } catch ( \Exception $e ) {
578
            throw new \PDOException($e->getMessage());
579
        }
580
    }
581
582
    /**
583
     * Debug dump params
584
     *
585
     * @return string params
586
     */
587
    public function debugDumpParams()
588
    {
589
        $str = "SQL: [" . strlen($this->_statement) . "] " . $this->_statement . "\n";
590
        $str .= "Params: " . sizeof($this->_binds) . "\n";
591
        foreach ($this->_binds as $key => $value) {
592
            $str .= "Key: Name: [" . strlen($key) . "] $key\n";
593
            $str .= "name=[" . strlen($key) . "] \"$key\"\n";
594
            $str .= "is_param=1\n";
595
        }
596
        echo substr($str, 0, strlen($str) - 1);
597
    }
598
599
    /**
600
     * Return error code
601
     *
602
     * @return mixed error code
603
     */
604
    public function errorCode()
605
    {
606
        return $this->_pdooci->errorCode();
607
    }
608
609
    /**
610
     * Return error info
611
     *
612
     * @return mixed error info
613
     */
614
    public function errorInfo()
615
    {
616
        return $this->_pdooci->errorInfo();
617
    }
618
619
    /**
620
     * Set an attribute
621
     *
622
     * @param int   $attr  attribute
623
     * @param mixed $value value
624
     *
625
     * @return true if setted
626
     */
627
    public function setAttribute($attr, $value)
628
    {
629
        // nothing to see here
630
    }
631
632
    /**
633
     * Get an attribute
634
     *
635
     * @param int $attr attribute
636
     *
637
     * @return mixed value
638
     */
639
    public function getAttribute($attr)
640
    {
641
        // nothing to see here
642
    }
643
644
    /**
645
     * Get column meta data
646
     *
647
     * @param int $colnum column number
648
     *
649
     * @return mixed column meta data
650
     */
651
    public function getColumnMeta($colnum = 0)
652
    {
653
        if (!$this->_stmt) {
654
            return null;
655
        }
656
        $name = \oci_field_name($this->_stmt, $colnum + 1);
657
        $len  = \oci_field_size($this->_stmt, $colnum + 1);
658
        $prec = \oci_field_scale($this->_stmt, $colnum + 1);
659
        $type = \oci_field_type($this->_stmt, $colnum + 1);
660
        return ["name" => $name, "len" => $len, "precision" => $prec, "driver:decl_type" => $type];
661
    }
662
663
    /**
664
     * Dummy method for nextRowSet
665
     *
666
     * @return boolean|null
667
     */
668
    public function nextRowSet()
669
    {
670
        // TODO: insert some code here if needed
671
    }
672
}
673