1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Sludio\HelperBundle\Doctrine\DBAL\Driver\OCI8; |
4
|
|
|
|
5
|
|
|
use PDO; |
6
|
|
|
use PDOStatement; |
7
|
|
|
use OCI_Lob; |
8
|
|
|
|
9
|
|
|
class Oci8Statement extends PDOStatement |
10
|
|
|
{ |
11
|
|
|
private $sth; |
12
|
|
|
|
13
|
|
|
private $connection; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @var boolean flag to convert LOB to string or not |
17
|
|
|
*/ |
18
|
|
|
private $returnLobs = true; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var array Statement options |
22
|
|
|
*/ |
23
|
|
|
private $options = []; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var int Fetch mode selected via setFetchMode() |
27
|
|
|
*/ |
28
|
|
|
private $fetchStyle = PDO::FETCH_ASSOC; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var int Column number for PDO::FETCH_COLUMN fetch mode |
32
|
|
|
*/ |
33
|
|
|
private $fetchColno = 0; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var string Class name for PDO::FETCH_CLASS fetch mode |
37
|
|
|
*/ |
38
|
|
|
private $fetchClassName = \stdClass::class; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var array Constructor arguments for PDO::FETCH_CLASS |
42
|
|
|
*/ |
43
|
|
|
private $fetchCtorargs = []; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var object Object reference for PDO::FETCH_INTO fetch mode |
47
|
|
|
*/ |
48
|
|
|
private $fetchIntoObject; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var OCI_Lob[] Lob object, when need lob->save after oci_execute. |
52
|
|
|
*/ |
53
|
|
|
private $saveLobs = []; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var OCI_Lob[] Lob object, when need lob->write after oci_bind_by_name. |
57
|
|
|
*/ |
58
|
|
|
private $writeLobs = []; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var array Array of param value, which binded in bindParam as lob. |
62
|
|
|
*/ |
63
|
|
|
private $lobsValue = []; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Constructor |
67
|
|
|
* |
68
|
|
|
* @param resource $sth Statement handle created with oci_parse() |
69
|
|
|
* @param Oci8 $connection The Pdo_Oci8 object for this statement |
70
|
|
|
* @param array $options Options for the statement handle |
71
|
|
|
* |
72
|
|
|
* @throws Oci8Exception |
73
|
|
|
*/ |
74
|
|
|
public function __construct($sth, Oci8 $connection, array $options = []) |
75
|
|
|
{ |
76
|
|
|
|
77
|
|
|
if (strtolower(get_resource_type($sth)) !== 'oci8 statement') { |
78
|
|
|
throw new Oci8Exception('Resource expected of type oci8 statement; '.(string)get_resource_type($sth).' received instead'); |
|
|
|
|
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
$this->sth = $sth; |
82
|
|
|
$this->connection = $connection; |
83
|
|
|
$this->options = $options; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Executes a prepared statement |
88
|
|
|
* |
89
|
|
|
* @param array $inputParams An array of values with as many elements as |
90
|
|
|
* there are bound parameters in the SQL statement being executed. |
91
|
|
|
* |
92
|
|
|
* @throws Oci8Exception |
93
|
|
|
* @return bool TRUE on success or FALSE on failure |
94
|
|
|
*/ |
95
|
|
|
public function execute($inputParams = null) |
96
|
|
|
{ |
97
|
|
|
$mode = OCI_COMMIT_ON_SUCCESS; |
98
|
|
|
|
99
|
|
|
$lobTransaction = false; |
100
|
|
|
if ((count($this->saveLobs) > 0 || count($this->writeLobs) > 0) && !$this->connection->inTransaction()) { |
101
|
|
|
$this->connection->beginTransaction(); |
102
|
|
|
$lobTransaction = true; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
if ($this->connection->inTransaction()) { |
106
|
|
|
$mode = OCI_DEFAULT; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
if (is_array($inputParams)) { |
110
|
|
|
foreach ($inputParams as $key => $value) { |
111
|
|
|
$this->bindParam($key, $inputParams[$key]); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
if (count($this->writeLobs) > 0) { |
116
|
|
|
foreach ($this->writeLobs as $lobName => $lob) { |
117
|
|
|
$type = $lob['type'] === Oci8::PARAM_BLOB ? OCI_TEMP_BLOB : OCI_TEMP_CLOB; |
118
|
|
|
$lob['object']->writetemporary($this->lobsValue[$lobName], $type); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
$result = @oci_execute($this->sth, $mode); |
123
|
|
|
|
124
|
|
|
if ($result && count($this->saveLobs) > 0) { |
125
|
|
|
foreach ($this->saveLobs as $lobName => $object) { |
126
|
|
|
$object->save($this->lobsValue[$lobName]); |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
if ($result != true) { |
|
|
|
|
131
|
|
|
$e = oci_error($this->sth); |
132
|
|
|
throw new Oci8Exception($e['message'], $e['code']); |
|
|
|
|
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
if ($lobTransaction) { |
136
|
|
|
return $this->connection->commit(); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return $result; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Fetches the next row from a result set |
144
|
|
|
* |
145
|
|
|
* @param int|null $fetchStyle Controls how the next row will be returned to |
146
|
|
|
* the caller. This value must be one of the PDO::FETCH_* constants, |
147
|
|
|
* defaulting to value of PDO::ATTR_DEFAULT_FETCH_MODE (which defaults to |
148
|
|
|
* PDO::FETCH_BOTH). |
149
|
|
|
* @param int $cursorOrientation For a PDOStatement object representing a |
150
|
|
|
* scrollable cursor, this value determines which row will be returned to |
151
|
|
|
* the caller. This value must be one of the PDO::FETCH_ORI_* constants, |
152
|
|
|
* defaulting to PDO::FETCH_ORI_NEXT. To request a scrollable cursor for |
153
|
|
|
* your PDOStatement object, you must set the PDO::ATTR_CURSOR attribute |
154
|
|
|
* to PDO::CURSOR_SCROLL when you prepare the SQL statement with |
155
|
|
|
* PDO::prepare. |
156
|
|
|
* @param int $cursorOffset [optional] |
157
|
|
|
* |
158
|
|
|
* @return mixed The return value of this function on success depends on the |
159
|
|
|
* fetch type. In all cases, FALSE is returned on failure. |
160
|
|
|
* @todo Implement cursorOrientation and cursorOffset |
161
|
|
|
*/ |
162
|
|
|
public function fetch($fetchStyle = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) |
163
|
|
|
{ |
164
|
|
|
$fetchStyle = $fetchStyle ?: $this->fetchStyle; |
165
|
|
|
|
166
|
|
|
$toLowercase = ($this->getAttribute(PDO::ATTR_CASE) === PDO::CASE_LOWER); |
167
|
|
|
|
168
|
|
|
switch ($fetchStyle) { |
169
|
|
|
case PDO::FETCH_BOTH: |
170
|
|
|
return $this->fetchArray(OCI_BOTH + OCI_RETURN_NULLS, $toLowercase); |
171
|
|
|
|
172
|
|
|
case PDO::FETCH_ASSOC: |
173
|
|
|
return $this->fetchArray(OCI_ASSOC + OCI_RETURN_NULLS, $toLowercase); |
174
|
|
|
|
175
|
|
|
case PDO::FETCH_NUM: |
176
|
|
|
return $this->fetchArray(OCI_NUM + OCI_RETURN_NULLS, false); |
177
|
|
|
|
178
|
|
|
case PDO::FETCH_COLUMN: |
179
|
|
|
return $this->fetchColumn((int)$this->fetchColno); |
180
|
|
|
|
181
|
|
|
case PDO::FETCH_INTO: |
182
|
|
|
$rs = $this->fetchArray(OCI_ASSOC + OCI_RETURN_NULLS, $toLowercase); |
183
|
|
|
if (is_object($this->fetchIntoObject)) { |
184
|
|
|
return $this->populateObject($this->fetchIntoObject, $rs); |
|
|
|
|
185
|
|
|
} else { |
186
|
|
|
return false; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
case PDO::FETCH_OBJ: |
190
|
|
|
case PDO::FETCH_CLASS: |
191
|
|
|
case PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE: |
192
|
|
|
$className = ($fetchStyle === PDO::FETCH_OBJ) ? '\stdClass' : $this->fetchClassName; |
193
|
|
|
$ctorargs = ($fetchStyle === PDO::FETCH_OBJ) ? [] : $this->fetchCtorargs; |
194
|
|
|
|
195
|
|
|
return $this->fetchObject($className, $ctorargs); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
return false; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Set the default fetch mode for this statement |
203
|
|
|
* |
204
|
|
|
* @param int|null $mode The fetch mode must be one of the |
205
|
|
|
* PDO::FETCH_* constants. |
206
|
|
|
* @param mixed|null $modeArg Column number, class name or object. |
207
|
|
|
* @param array|null $ctorArgs Constructor arguments. |
208
|
|
|
* |
209
|
|
|
* @throws Oci8Exception |
210
|
|
|
* @return bool TRUE on success or FALSE on failure. |
211
|
|
|
*/ |
212
|
|
|
public function setFetchMode($mode, $modeArg = null, array $ctorArgs = []) |
213
|
|
|
{ |
214
|
|
|
$this->fetchStyle = $mode; |
215
|
|
|
$this->fetchClassName = '\stdClass'; |
216
|
|
|
$this->fetchCtorargs = []; |
217
|
|
|
$this->fetchColno = 0; |
218
|
|
|
$this->fetchIntoObject = null; |
219
|
|
|
|
220
|
|
|
switch ($mode) { |
221
|
|
|
case PDO::FETCH_CLASS: |
222
|
|
|
case PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE: |
223
|
|
|
if ($modeArg) { |
224
|
|
|
$this->fetchClassName = $modeArg; |
225
|
|
|
} |
226
|
|
|
$this->fetchCtorargs = $ctorArgs; |
227
|
|
|
break; |
228
|
|
|
case PDO::FETCH_INTO: |
229
|
|
|
if (!is_object($modeArg)) { |
230
|
|
|
throw new Oci8Exception('$modeArg must be instance of an object'); |
|
|
|
|
231
|
|
|
} |
232
|
|
|
$this->fetchIntoObject = $modeArg; |
233
|
|
|
break; |
234
|
|
|
case PDO::FETCH_COLUMN: |
235
|
|
|
$this->fetchColno = (int)$modeArg; |
236
|
|
|
break; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
return true; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Returns a single column from the next row of a result set |
244
|
|
|
* |
245
|
|
|
* @param int $colNumber 0-indexed number of the column you wish to retrieve |
246
|
|
|
* from the row. If no value is supplied, it fetches the first column. |
247
|
|
|
* |
248
|
|
|
* @return string Returns a single column in the next row of a result set. |
249
|
|
|
*/ |
250
|
|
|
public function fetchColumn($colNumber = 0) |
251
|
|
|
{ |
252
|
|
|
$rs = oci_fetch_array($this->sth, OCI_NUM + OCI_RETURN_NULLS + ($this->returnLobs ? OCI_RETURN_LOBS : 0)); |
253
|
|
|
if (is_array($rs) && array_key_exists((int)$colNumber, $rs)) { |
254
|
|
|
return $this->returnLobs && is_a($rs[(int)$colNumber], 'OCI-Lob') ? null : $rs[(int)$colNumber]; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
return false; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Returns an array containing all of the result set rows |
262
|
|
|
* |
263
|
|
|
* @param int $fetchMode Controls the contents of the returned array as |
264
|
|
|
* documented in PDOStatement::fetch. |
265
|
|
|
* @param mixed $fetchArgument This argument has a different meaning |
266
|
|
|
* depending on the value of the fetchMode parameter. |
267
|
|
|
* @param array $ctorArgs [optional] Arguments of custom class constructor |
268
|
|
|
* when the fetch_style parameter is PDO::FETCH_CLASS. |
269
|
|
|
* |
270
|
|
|
* @return array Array containing all of the remaining rows in the result |
271
|
|
|
* set. The array represents each row as either an array of column values |
272
|
|
|
* or an object with properties corresponding to each column name. |
273
|
|
|
*/ |
274
|
|
|
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) |
275
|
|
|
{ |
276
|
|
|
if ($fetchMode !== null) { |
277
|
|
|
$this->setFetchMode($fetchMode, $fetchArgument, $ctorArgs ?: []); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
$results = []; |
281
|
|
|
while ($row = $this->fetch()) { |
282
|
|
|
$results[] = $row; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
return $results; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* Fetches the next row and returns it as an object |
290
|
|
|
* |
291
|
|
|
* @param string $className |
292
|
|
|
* @param array $ctorArgs |
293
|
|
|
* |
294
|
|
|
* @return mixed |
295
|
|
|
*/ |
296
|
|
|
public function fetchObject($className = "stdClass", $ctorArgs = null) |
297
|
|
|
{ |
298
|
|
|
$className = $className ?: $this->fetchClassName; |
299
|
|
|
|
300
|
|
|
$toLowercase = ($this->getAttribute(PDO::ATTR_CASE) === PDO::CASE_LOWER); |
301
|
|
|
$rs = $this->fetchArray(OCI_ASSOC + OCI_RETURN_NULLS, $toLowercase); |
302
|
|
|
if ($ctorArgs) { |
303
|
|
|
$reflectionClass = new \ReflectionClass($className); |
304
|
|
|
$object = $reflectionClass->newInstanceArgs($ctorArgs); |
305
|
|
|
} else { |
306
|
|
|
$object = new $className(); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
return $rs ? $this->populateObject($object, $rs) : false; |
|
|
|
|
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* Binds a parameter to the specified variable name |
314
|
|
|
* |
315
|
|
|
* @param string $parameter Parameter identifier. For a prepared statement |
316
|
|
|
* using named placeholders, this will be a parameter name of the form |
317
|
|
|
* :name. For a prepared statement using question mark placeholders, this |
318
|
|
|
* will be the 1-indexed position of the parameter. |
319
|
|
|
* @param mixed $variable Name of the PHP variable to bind to the SQL |
320
|
|
|
* statement parameter. |
321
|
|
|
* @param int $dataType Explicit data type for the parameter using the |
322
|
|
|
* PDO::PARAM_* constants. |
323
|
|
|
* @param int $maxLength Length of the data type. To indicate that a |
324
|
|
|
* parameter is an OUT parameter from a stored procedure, you must |
325
|
|
|
* explicitly set the length. |
326
|
|
|
* @param array $options [optional] |
327
|
|
|
* |
328
|
|
|
* @return bool TRUE on success or FALSE on failure. |
329
|
|
|
* @todo Map PDO datatypes to oci8 datatypes and implement support for |
330
|
|
|
* datatypes and length. |
331
|
|
|
*/ |
332
|
|
|
public function bindParam($parameter, &$variable, $dataType = PDO::PARAM_STR, $maxLength = -1, $options = [Oci8::LOB_SQL]) |
333
|
|
|
{ |
334
|
|
|
if (is_numeric($parameter)) { |
335
|
|
|
throw new Oci8Exception("bind numerical params has not been implemented"); |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
if ($dataType === PDO::PARAM_LOB) { |
339
|
|
|
$dataType = Oci8::PARAM_BLOB; |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
switch ($dataType) { |
343
|
|
|
case PDO::PARAM_BOOL: |
344
|
|
|
$oci_type = SQLT_INT; |
345
|
|
|
break; |
346
|
|
|
|
347
|
|
|
case PDO::PARAM_NULL: |
348
|
|
|
$oci_type = SQLT_CHR; |
349
|
|
|
break; |
350
|
|
|
|
351
|
|
|
case PDO::PARAM_INT: |
352
|
|
|
$oci_type = SQLT_INT; |
353
|
|
|
break; |
354
|
|
|
|
355
|
|
|
case PDO::PARAM_STR: |
356
|
|
|
$oci_type = SQLT_CHR; |
357
|
|
|
break; |
358
|
|
|
|
359
|
|
|
case Oci8::PARAM_BLOB: |
360
|
|
|
case Oci8::PARAM_CLOB: |
361
|
|
|
$oci_type = $dataType; |
362
|
|
|
|
363
|
|
|
$this->lobsValue[$parameter] = $variable; |
364
|
|
|
$variable = $this->connection->getNewDescriptor(OCI_D_LOB); |
365
|
|
|
|
366
|
|
|
if (in_array(Oci8::LOB_SQL, $options)) { |
367
|
|
|
$this->saveLobs[$parameter] = &$variable; |
368
|
|
|
} elseif (in_array(Oci8::LOB_PL_SQL, $options)) { |
369
|
|
|
$this->writeLobs[$parameter] = [ |
370
|
|
|
'type' => $oci_type, |
371
|
|
|
'object' => $variable, |
372
|
|
|
]; |
373
|
|
|
} |
374
|
|
|
break; |
375
|
|
|
|
376
|
|
|
case PDO::PARAM_STMT: |
377
|
|
|
$oci_type = OCI_B_CURSOR; |
378
|
|
|
|
379
|
|
|
$variable = $this->connection->getNewCursor(); |
380
|
|
|
break; |
381
|
|
|
|
382
|
|
|
case SQLT_NTY: |
383
|
|
|
$oci_type = SQLT_NTY; |
384
|
|
|
|
385
|
|
|
$schema = array_key_exists('schema', $options) ? $options['schema'] : ''; |
386
|
|
|
$type_name = array_key_exists('type_name', $options) ? $options['type_name'] : ''; |
387
|
|
|
|
388
|
|
|
$variable = $this->connection->getNewCollection($type_name, $schema); |
389
|
|
|
break; |
390
|
|
|
|
391
|
|
|
default: |
392
|
|
|
$oci_type = SQLT_CHR; |
393
|
|
|
break; |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
return @oci_bind_by_name($this->sth, $parameter, $variable, $maxLength, $oci_type); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* Binds a value to a parameter |
401
|
|
|
* |
402
|
|
|
* @param string $parameter Parameter identifier. For a prepared statement |
403
|
|
|
* using named placeholders, this will be a parameter name of the form |
404
|
|
|
* :name. For a prepared statement using question mark placeholders, this |
405
|
|
|
* will be the 1-indexed position of the parameter. |
406
|
|
|
* @param mixed $variable The value to bind to the parameter. |
407
|
|
|
* @param int $dataType Explicit data type for the parameter using the |
408
|
|
|
* PDO::PARAM_* constants. |
409
|
|
|
* |
410
|
|
|
* @return bool TRUE on success or FALSE on failure. |
411
|
|
|
*/ |
412
|
|
|
public function bindValue($parameter, $variable, $dataType = PDO::PARAM_STR) |
413
|
|
|
{ |
414
|
|
|
if (is_array($variable)) { |
415
|
|
|
$result = true; |
416
|
|
|
foreach ($variable as $var) { |
417
|
|
|
$result = $result && $this->bindParam($parameter, $var, $dataType); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
return $result; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
return $this->bindParam($parameter, $variable, $dataType); |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
/** |
427
|
|
|
* Returns the number of rows affected by the last executed statement |
428
|
|
|
* |
429
|
|
|
* @return int The number of rows. |
430
|
|
|
*/ |
431
|
|
|
public function rowCount() |
432
|
|
|
{ |
433
|
|
|
return oci_num_rows($this->sth); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
/** |
437
|
|
|
* Fetch the SQLSTATE associated with the last operation on the resource |
438
|
|
|
* handle |
439
|
|
|
* While this returns an error code, it merely emulates the action. If |
440
|
|
|
* there are no errors, it returns the success SQLSTATE code (00000). |
441
|
|
|
* If there are errors, it returns HY000. See errorInfo() to retrieve |
442
|
|
|
* the actual Oracle error code and message. |
443
|
|
|
* |
444
|
|
|
* @return string Error code |
445
|
|
|
*/ |
446
|
|
|
public function errorCode() |
447
|
|
|
{ |
448
|
|
|
$error = $this->errorInfo(); |
449
|
|
|
|
450
|
|
|
return $error[0]; |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Fetch extended error information associated with the last operation on |
455
|
|
|
* the resource handle. |
456
|
|
|
* |
457
|
|
|
* @return array Array of error information about the last operation |
458
|
|
|
* performed |
459
|
|
|
*/ |
460
|
|
View Code Duplication |
public function errorInfo() |
|
|
|
|
461
|
|
|
{ |
462
|
|
|
$e = oci_error($this->sth); |
463
|
|
|
|
464
|
|
|
if (is_array($e)) { |
465
|
|
|
return [ |
466
|
|
|
'HY000', |
467
|
|
|
$e['code'], |
468
|
|
|
$e['message'], |
469
|
|
|
]; |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
return [ |
473
|
|
|
'00000', |
474
|
|
|
null, |
475
|
|
|
null, |
476
|
|
|
]; |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
/** |
480
|
|
|
* Sets a statement attribute |
481
|
|
|
* |
482
|
|
|
* @param int $attribute |
483
|
|
|
* @param mixed $value |
484
|
|
|
* |
485
|
|
|
* @return TRUE on success or FALSE on failure. |
486
|
|
|
*/ |
487
|
|
|
public function setAttribute($attribute, $value) |
488
|
|
|
{ |
489
|
|
|
$this->options[$attribute] = $value; |
490
|
|
|
|
491
|
|
|
return true; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* Retrieve a statement attribute |
496
|
|
|
* |
497
|
|
|
* @param int $attribute |
498
|
|
|
* |
499
|
|
|
* @return mixed The attribute value. |
500
|
|
|
*/ |
501
|
|
|
public function getAttribute($attribute) |
502
|
|
|
{ |
503
|
|
|
if (array_key_exists($attribute, $this->options)) { |
504
|
|
|
return $this->options[$attribute]; |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
return null; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* Returns the number of columns in the result set |
512
|
|
|
* |
513
|
|
|
* @return int The number of columns in the statement result set. If there |
514
|
|
|
* is no result set, it returns 0. |
515
|
|
|
*/ |
516
|
|
|
public function columnCount() |
517
|
|
|
{ |
518
|
|
|
return oci_num_fields($this->sth); |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Returns metadata for a column in a result set |
523
|
|
|
* The array returned by this function is patterned after that |
524
|
|
|
* returned by \PDO::getColumnMeta(). It includes the following |
525
|
|
|
* elements: |
526
|
|
|
* native_type |
527
|
|
|
* driver:decl_type |
528
|
|
|
* flags |
529
|
|
|
* name |
530
|
|
|
* table |
531
|
|
|
* len |
532
|
|
|
* precision |
533
|
|
|
* pdo_type |
534
|
|
|
* |
535
|
|
|
* @param int $column The 0-indexed column in the result set. |
536
|
|
|
* |
537
|
|
|
* @return array An associative array containing the above metadata values |
538
|
|
|
* for a single column. |
539
|
|
|
*/ |
540
|
|
|
public function getColumnMeta($column) |
541
|
|
|
{ |
542
|
|
|
if (is_numeric($column)) { |
543
|
|
|
$column++; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
$meta = []; |
547
|
|
|
$meta['native_type'] = oci_field_type($this->sth, $column); |
548
|
|
|
$meta['driver:decl_type'] = oci_field_type_raw($this->sth, $column); |
549
|
|
|
$meta['flags'] = []; |
550
|
|
|
$meta['name'] = oci_field_name($this->sth, $column); |
551
|
|
|
$meta['table'] = null; |
552
|
|
|
$meta['len'] = oci_field_size($this->sth, $column); |
553
|
|
|
$meta['precision'] = oci_field_precision($this->sth, $column); |
554
|
|
|
$meta['pdo_type'] = null; |
555
|
|
|
$meta['is_null'] = oci_field_is_null($this->sth, $column); |
556
|
|
|
|
557
|
|
|
return $meta; |
558
|
|
|
} |
559
|
|
|
|
560
|
|
|
/** |
561
|
|
|
* Fetch row from db |
562
|
|
|
* |
563
|
|
|
* @param integer $mode |
564
|
|
|
* @param bool $keyToLowercase |
565
|
|
|
* |
566
|
|
|
* @return array|bool |
567
|
|
|
*/ |
568
|
|
|
private function fetchArray($mode, $keyToLowercase) |
569
|
|
|
{ |
570
|
|
|
$rs = oci_fetch_array($this->sth, $mode + ($this->returnLobs ? OCI_RETURN_LOBS : 0)); |
571
|
|
|
if ($rs === false) { |
572
|
|
|
return false; |
573
|
|
|
} |
574
|
|
|
if ($keyToLowercase) { |
575
|
|
|
$rs = array_change_key_case($rs); |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
foreach ($rs as $name => $value) { |
579
|
|
|
if (oci_field_type($this->sth, $name) === 'ROWID') { |
580
|
|
|
$rs[$name] = null; |
581
|
|
|
} |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
return $rs; |
585
|
|
|
} |
586
|
|
|
|
587
|
|
|
/** |
588
|
|
|
* @param $object |
589
|
|
|
* @param array $fields |
590
|
|
|
*/ |
591
|
|
|
private function populateObject($object, array $fields) |
592
|
|
|
{ |
593
|
|
|
$nullToString = ($this->getAttribute(PDO::ATTR_ORACLE_NULLS) === PDO::NULL_TO_STRING); |
594
|
|
|
$nullEmptyString = ($this->getAttribute(PDO::ATTR_ORACLE_NULLS) === PDO::NULL_EMPTY_STRING); |
595
|
|
|
|
596
|
|
|
foreach ($fields as $field => $value) { |
597
|
|
|
if ($nullToString && null === $value) { |
598
|
|
|
$value = ''; |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
if ($nullEmptyString && '' === $value) { |
602
|
|
|
$value = null; |
603
|
|
|
} |
604
|
|
|
|
605
|
|
|
$object->$field = $value; |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
return $object; |
609
|
|
|
|
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* Advances to the next rowset in a multi-rowset statement handle |
614
|
|
|
* |
615
|
|
|
* @throws Oci8Exception |
616
|
|
|
* @return bool TRUE on success or FALSE on failure. |
617
|
|
|
* @todo Implement method |
618
|
|
|
*/ |
619
|
|
|
public function nextRowset() |
620
|
|
|
{ |
621
|
|
|
throw new Oci8Exception("nextRowset has not been implemented"); |
|
|
|
|
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
/** |
625
|
|
|
* Closes the cursor, enabling the statement to be executed again. |
626
|
|
|
* |
627
|
|
|
* @throws Oci8Exception |
628
|
|
|
* @return bool TRUE on success or FALSE on failure. |
629
|
|
|
* @todo Implement method |
630
|
|
|
*/ |
631
|
|
|
public function closeCursor() |
632
|
|
|
{ |
633
|
|
|
return oci_free_statement($this->sth); |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
/** |
637
|
|
|
* Dump a SQL prepared command |
638
|
|
|
* |
639
|
|
|
* @throws Oci8Exception |
640
|
|
|
* @return bool TRUE on success or FALSE on failure. |
641
|
|
|
* @todo Implement method |
642
|
|
|
*/ |
643
|
|
|
public function debugDumpParams() |
644
|
|
|
{ |
645
|
|
|
throw new Oci8Exception("debugDumpParams has not been implemented"); |
|
|
|
|
646
|
|
|
} |
647
|
|
|
|
648
|
|
|
/** |
649
|
|
|
* Binds a column to a PHP variable |
650
|
|
|
* |
651
|
|
|
* @param mixed $column Number of the column (1-indexed) or name of the |
652
|
|
|
* column in the result set. If using the column name, be aware that the |
653
|
|
|
* name should match the case of the column, as returned by the driver. |
654
|
|
|
* @param mixed $variable The PHP to which the column should be bound. |
655
|
|
|
* @param int $dataType Data type of the parameter, specified by the |
656
|
|
|
* PDO::PARAM_* constants. |
657
|
|
|
* @param int $maxLength A hint for pre-allocation. |
658
|
|
|
* @param array $options [optional] Optional parameter(s) for the driver. |
659
|
|
|
* |
660
|
|
|
* @throws Oci8Exception |
661
|
|
|
* @return bool TRUE on success or FALSE on failure. |
662
|
|
|
* @todo Implement this functionality by creating a table map of the |
663
|
|
|
* variables passed in here, and, when iterating over the values |
664
|
|
|
* of the query or fetching rows, assign data from each column |
665
|
|
|
* to their respective variable in the map. |
666
|
|
|
*/ |
667
|
|
|
public function bindColumn($column, &$variable, $dataType = null, $maxLength = -1, $options = null) |
668
|
|
|
{ |
669
|
|
|
throw new Oci8Exception("bindColumn has not been implemented"); |
|
|
|
|
670
|
|
|
} |
671
|
|
|
} |
672
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.