1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Jpina\PdoOci8; |
4
|
|
|
|
5
|
|
|
use Jpina\Oci8\Oci8ConnectionInterface; |
6
|
|
|
use Jpina\Oci8\Oci8FieldInterface; |
7
|
|
|
use Jpina\Oci8\Oci8StatementInterface; |
8
|
|
|
use Iterator; |
9
|
|
|
use Traversable; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Custom PDO_OCI implementation via OCI8 driver |
13
|
|
|
* |
14
|
|
|
* @see http://php.net/manual/en/class.pdostatement.php |
15
|
|
|
*/ |
16
|
|
|
class PdoOci8Statement implements \Iterator |
17
|
|
|
{ |
18
|
|
|
/** @var Oci8ConnectionInterface */ |
19
|
|
|
private $connection; |
20
|
|
|
|
21
|
|
|
/** @var Oci8StatementInterface */ |
22
|
|
|
private $statement; |
23
|
|
|
|
24
|
|
|
/** @var string */ |
25
|
|
|
private $sqlText = ''; |
26
|
|
|
|
27
|
|
|
/** @var array */ |
28
|
|
|
private $boundParameters = array(); |
29
|
|
|
|
30
|
|
|
/** @var array */ |
31
|
|
|
private $options; |
32
|
|
|
|
33
|
|
|
/** @var \ArrayIterator */ |
34
|
|
|
private $iterator; |
35
|
|
|
|
36
|
38 |
|
public function __construct(Oci8ConnectionInterface $connection, $sqlText, $options = array()) |
37
|
|
|
{ |
38
|
38 |
|
if (!is_string($sqlText)) { |
39
|
|
|
throw new PdoOci8Exception('$sqlText is not a string'); |
40
|
|
|
} |
41
|
|
|
|
42
|
38 |
|
$this->connection = $connection; |
43
|
38 |
|
$this->sqlText = $sqlText; |
44
|
|
|
|
45
|
38 |
|
$this->options = array( |
46
|
38 |
|
\PDO::ATTR_AUTOCOMMIT => true, |
47
|
38 |
|
\PDO::ATTR_CASE => \PDO::CASE_NATURAL, |
48
|
38 |
|
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_SILENT, |
49
|
38 |
|
\PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL, |
50
|
38 |
|
\PDO::ATTR_PREFETCH => 100, |
51
|
38 |
|
\PDO::ATTR_TIMEOUT => 600, |
52
|
38 |
|
\PDO::ATTR_STRINGIFY_FETCHES => false, |
53
|
38 |
|
\PDO::ATTR_STATEMENT_CLASS => null, |
54
|
38 |
|
\PDO::ATTR_EMULATE_PREPARES => false, |
55
|
38 |
|
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_BOTH, |
56
|
38 |
|
\PDO::ATTR_FETCH_TABLE_NAMES => false, |
57
|
38 |
|
\PDO::ATTR_FETCH_CATALOG_NAMES => false, |
58
|
38 |
|
\PDO::ATTR_MAX_COLUMN_LEN => 0, |
59
|
38 |
|
PdoOci8::OCI_ATTR_RETURN_LOBS => false, |
60
|
|
|
); |
61
|
|
|
|
62
|
38 |
View Code Duplication |
foreach ($options as $option => $value) { |
|
|
|
|
63
|
4 |
|
if (array_key_exists($option, $this->options)) { |
64
|
4 |
|
$this->options[$option] = $value; |
65
|
4 |
|
} |
66
|
38 |
|
} |
67
|
|
|
|
68
|
38 |
|
foreach ($options as $attribute => $value) { |
69
|
4 |
|
$this->setAttribute($attribute, $value); |
70
|
38 |
|
} |
71
|
|
|
|
72
|
|
|
try { |
73
|
38 |
|
$this->statement = $connection->parse($sqlText); |
74
|
38 |
|
} catch (\Exception $ex) { |
75
|
|
|
throw new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex); |
76
|
|
|
} |
77
|
38 |
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @param int|string $column |
81
|
|
|
* @param mixed $param |
82
|
|
|
* @param int $type |
83
|
|
|
* @param int $maxlen |
84
|
|
|
* @param mixed $driverdata |
85
|
|
|
* |
86
|
|
|
* @link http://php.net/manual/en/pdostatement.bindcolumn.php |
87
|
|
|
* @return bool |
88
|
|
|
*/ |
89
|
2 |
|
public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) |
|
|
|
|
90
|
|
|
{ |
91
|
|
|
try { |
92
|
2 |
|
$type = $type === null ? \PDO::PARAM_STR : $type; |
93
|
2 |
|
$dataType = $this->getDriverDataType($type); |
94
|
2 |
|
return $this->statement->defineByName($column, $param, $dataType); |
95
|
|
|
} catch (\Exception $ex) { |
96
|
|
|
//throw new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex); |
|
|
|
|
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
return false; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* @param string $parameter |
104
|
|
|
* @param mixed $variable |
105
|
|
|
* @param int $data_type |
106
|
|
|
* @param int $length |
107
|
|
|
* @param mixed $driver_options |
108
|
|
|
* |
109
|
|
|
* @link http://php.net/manual/en/pdostatement.bindparam.php |
110
|
|
|
* @return bool |
111
|
|
|
*/ |
112
|
8 |
|
public function bindParam( |
113
|
|
|
$parameter, |
114
|
|
|
&$variable, |
115
|
|
|
$data_type = \PDO::PARAM_STR, |
116
|
|
|
$length = null, |
117
|
|
|
$driver_options = null |
|
|
|
|
118
|
|
|
) { |
119
|
8 |
|
$isBound = false; |
120
|
|
|
try { |
121
|
8 |
|
$data_type = $data_type === null ? \PDO::PARAM_STR : $data_type; |
122
|
8 |
|
$dataType = $this->getDriverDataType($data_type); |
123
|
8 |
|
$length = $length !== null ? $length : -1; |
124
|
8 |
|
$isBound = $this->statement->bindByName($parameter, $variable, $length, $dataType); |
125
|
4 |
|
if ($isBound) { |
126
|
4 |
|
$this->boundParameters[$parameter] = array( |
127
|
4 |
|
'name' => is_int($parameter) ? '' : $parameter, |
128
|
4 |
|
'position' => strrpos($this->sqlText, $parameter), |
129
|
4 |
|
'value' => &$variable, |
130
|
4 |
|
'type' => $data_type, |
131
|
1 |
|
); |
132
|
4 |
|
} |
133
|
8 |
|
} catch (\Exception $ex) { |
134
|
|
|
//throw new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex); |
|
|
|
|
135
|
|
|
} |
136
|
|
|
|
137
|
8 |
|
return $isBound; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* @param string $parameter |
142
|
|
|
* @param $value |
143
|
|
|
* @param int $data_type |
144
|
|
|
* |
145
|
|
|
* @link http://php.net/manual/en/pdostatement.bindvalue.php |
146
|
|
|
* @return bool |
147
|
|
|
*/ |
148
|
3 |
|
public function bindValue($parameter, $value, $data_type = \PDO::PARAM_STR) |
149
|
|
|
{ |
150
|
3 |
|
return $this->bindParam($parameter, $value, $data_type); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @link http://php.net/manual/en/pdostatement.closecursor.php |
155
|
|
|
* @return bool |
156
|
|
|
*/ |
157
|
1 |
|
public function closeCursor() |
158
|
|
|
{ |
159
|
1 |
|
return $this->statement->cancel(); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* @link http://php.net/manual/en/pdostatement.columncount.php |
164
|
|
|
* @return int |
165
|
|
|
*/ |
166
|
1 |
|
public function columnCount() |
167
|
|
|
{ |
168
|
1 |
|
return 0; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* @link http://php.net/manual/en/pdostatement.debugdumpparams.php |
173
|
|
|
*/ |
174
|
2 |
|
public function debugDumpParams() |
175
|
|
|
{ |
176
|
2 |
|
$sqlText = $this->sqlText; |
177
|
2 |
|
$sqlTextLength = strlen($sqlText); |
178
|
2 |
|
$parameters = $this->boundParameters; |
179
|
2 |
|
usort($parameters, function ($a, $b) { |
180
|
2 |
|
if ($a['position'] === $b['position']) { |
181
|
|
|
return 0; |
182
|
|
|
} |
183
|
|
|
|
184
|
2 |
|
return $a['position'] < $b['position'] ? -1 : 1; |
185
|
2 |
|
}); |
186
|
2 |
|
$parametersCount = count($parameters); |
187
|
|
|
|
188
|
2 |
|
echo "SQL: [{$sqlTextLength}] {$sqlText}". PHP_EOL . |
189
|
2 |
|
"Params: {$parametersCount}"; |
190
|
2 |
|
foreach ($parameters as $key => $parameter) { |
191
|
|
|
//TODO Add parameter position and number |
192
|
2 |
|
$position = $parameter['position']; |
193
|
2 |
|
$nameLength = strlen($parameter['name']); |
194
|
2 |
|
$name = $parameter['name']; |
195
|
2 |
|
$index = $key + 1; |
196
|
2 |
|
$dataType = $parameter['type']; |
197
|
|
|
|
198
|
2 |
|
echo PHP_EOL; |
199
|
2 |
|
if ($name === '') { |
200
|
|
|
echo "Key: Position #{$position}:". PHP_EOL; |
201
|
|
|
} else { |
202
|
2 |
|
echo "Key: Name: [{$nameLength}] {$name}". PHP_EOL; |
203
|
|
|
} |
204
|
2 |
|
echo "paramno={$index}". PHP_EOL . |
205
|
2 |
|
"name=[{$nameLength}]{$name}". PHP_EOL . |
206
|
2 |
|
"is_param=1". PHP_EOL . |
207
|
2 |
|
"param_type={$dataType}"; |
208
|
2 |
|
} |
209
|
2 |
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* @link http://php.net/manual/en/pdostatement.errorcode.php |
213
|
|
|
* @return string |
214
|
|
|
*/ |
215
|
2 |
View Code Duplication |
public function errorCode() |
|
|
|
|
216
|
|
|
{ |
217
|
2 |
|
$driverError = $this->statement->getError(); |
218
|
2 |
|
if (!$driverError) { |
|
|
|
|
219
|
1 |
|
return null; |
220
|
|
|
} |
221
|
|
|
|
222
|
1 |
|
$error = $this->errorInfo(); |
223
|
1 |
|
$sqlStateErrorCode = $error[0]; |
224
|
|
|
|
225
|
1 |
|
return $sqlStateErrorCode; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* @link http://php.net/manual/en/pdo.errorinfo.php |
230
|
|
|
* @return array |
231
|
|
|
*/ |
232
|
3 |
|
public function errorInfo() |
233
|
|
|
{ |
234
|
3 |
|
$driverError = $this->statement->getError(); |
235
|
3 |
|
if ($driverError) { |
|
|
|
|
236
|
2 |
|
$driverErrorMessage = $driverError['message']; |
237
|
2 |
|
$driverErrorCode = $driverError['code']; |
238
|
2 |
|
} else { |
239
|
1 |
|
$driverErrorMessage = null; |
240
|
1 |
|
$driverErrorCode = null; |
241
|
|
|
} |
242
|
|
|
|
243
|
3 |
|
$sqlStateErrorCode = OracleSqlStateCode::getSqlStateErrorCode((int)$driverErrorCode); |
244
|
|
|
$error = array( |
245
|
3 |
|
$sqlStateErrorCode, |
246
|
3 |
|
$driverErrorCode, |
247
|
|
|
$driverErrorMessage |
248
|
3 |
|
); |
249
|
|
|
|
250
|
3 |
|
return $error; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* @param array $input_parameters |
255
|
|
|
* |
256
|
|
|
* @link http://php.net/manual/en/pdostatement.execute.php |
257
|
|
|
* @return bool |
258
|
|
|
*/ |
259
|
19 |
|
public function execute($input_parameters = array()) |
260
|
|
|
{ |
261
|
|
|
try { |
262
|
19 |
|
foreach ($input_parameters as $key => $value) { |
263
|
|
|
if (is_int($key)) { |
264
|
|
|
$parameterName = $key + 1; |
265
|
|
|
} else { |
266
|
|
|
$parameterName = $key; |
267
|
|
|
} |
268
|
|
|
$this->bindValue($parameterName, $value); |
269
|
19 |
|
} |
270
|
|
|
|
271
|
19 |
|
if ($this->getAttribute(\PDO::ATTR_AUTOCOMMIT)) { |
272
|
19 |
|
$isCommitOnSuccess = OCI_NO_AUTO_COMMIT; |
273
|
19 |
|
} else { |
274
|
|
|
$isCommitOnSuccess = OCI_COMMIT_ON_SUCCESS; |
275
|
|
|
} |
276
|
|
|
|
277
|
19 |
|
$result = $this->statement->execute($isCommitOnSuccess); |
278
|
|
|
|
279
|
16 |
|
return $result; |
280
|
3 |
|
} catch (\Exception $ex) { |
281
|
|
|
//TODO Handle Exception |
282
|
3 |
|
new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex); |
283
|
|
|
} |
284
|
|
|
|
285
|
3 |
|
return false; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* @param int $fetch_style |
290
|
|
|
* @param int $cursor_orientation |
291
|
|
|
* @param int $cursor_offset |
292
|
|
|
* |
293
|
|
|
* @link http://php.net/manual/en/pdostatement.fetch.php |
294
|
|
|
* @return mixed |
295
|
|
|
*/ |
296
|
9 |
|
public function fetch( |
297
|
|
|
$fetch_style = \PDO::ATTR_DEFAULT_FETCH_MODE, |
298
|
|
|
$cursor_orientation = \PDO::FETCH_ORI_NEXT, |
|
|
|
|
299
|
|
|
$cursor_offset = 0 |
|
|
|
|
300
|
|
|
) { |
301
|
9 |
|
if ($fetch_style === null) { |
302
|
|
|
$fetch_style === \PDO::ATTR_DEFAULT_FETCH_MODE; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
try { |
306
|
|
|
// if ($fetch_style === \PDO::ATTR_DEFAULT_FETCH_MODE) { |
|
|
|
|
307
|
|
|
// $fetch_style = $this->getAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE); |
308
|
|
|
// } |
309
|
|
|
|
310
|
|
|
switch ($fetch_style) { |
311
|
9 |
|
case \PDO::FETCH_ASSOC: |
312
|
2 |
|
$mode = OCI_ASSOC; |
313
|
2 |
|
break; |
314
|
7 |
|
case \PDO::FETCH_BOUND: |
315
|
|
|
// returns TRUE and assigns the values of the columns in your result set to the PHP |
316
|
|
|
// variables to which they were bound with the PDOStatement::bindColumn() method |
317
|
1 |
|
return $this->statement->fetch(); |
318
|
6 |
|
case \PDO::FETCH_CLASS: |
319
|
|
|
// returns a new instance of the requested class, mapping the columns of the result |
320
|
|
|
// set to named properties in the class |
321
|
|
|
break; |
322
|
6 |
|
case \PDO::FETCH_CLASS | \PDO::FETCH_CLASSTYPE: |
323
|
|
|
// the name of the class is determined from a value of the first column. |
324
|
|
|
break; |
325
|
6 |
|
case \PDO::FETCH_INTO: |
326
|
|
|
// updates an existing instance of the requested class, mapping the columns of the |
327
|
|
|
// result set to named properties in the class |
328
|
|
|
break; |
329
|
6 |
|
case \PDO::FETCH_LAZY: |
330
|
6 |
|
case \PDO::FETCH_BOTH + \PDO::FETCH_OBJ: |
331
|
|
|
// combines PDO::FETCH_BOTH and PDO::FETCH_OBJ, creating the object variable names |
332
|
|
|
// as they are accessed |
333
|
|
|
break; |
334
|
6 |
|
case \PDO::FETCH_NAMED: |
335
|
|
|
// returns an array with the same form as PDO::FETCH_ASSOC, except that if there are |
336
|
|
|
// multiple columns with the same name, the value referred to by that key will be an |
337
|
|
|
// array of all the values in the row that had that column name |
338
|
|
|
break; |
339
|
6 |
|
case \PDO::FETCH_NUM: |
340
|
4 |
|
$mode = OCI_NUM; |
341
|
4 |
|
break; |
342
|
2 |
|
case \PDO::FETCH_OBJ: |
343
|
|
|
// returns an anonymous object with property names that correspond to the column names |
344
|
|
|
// returned in your result set |
345
|
1 |
|
return $this->statement->fetchObject(); |
346
|
|
|
break; |
|
|
|
|
347
|
1 |
|
case \PDO::FETCH_BOTH: |
348
|
1 |
|
default: |
349
|
1 |
|
$mode = OCI_BOTH; |
350
|
1 |
|
break; |
351
|
1 |
|
} |
352
|
|
|
// TODO Combine other flags: eg. OCI_NULLS and OCI_LOBS |
353
|
|
|
// TODO update $this->numRows on successfull fetch |
354
|
|
|
// TODO update $this->isIteratorValid on NOT successfull fetch |
355
|
7 |
|
return $this->statement->fetchArray($mode); |
|
|
|
|
356
|
|
|
} catch (\Exception $ex) { |
357
|
|
|
new PdoOci8Exception($ex->getMessage(), $ex->getCode(), $ex); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
return false; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* @param int $fetch_style |
365
|
|
|
* @param mixed $fetch_argument |
366
|
|
|
* @param array $ctor_args |
367
|
|
|
* |
368
|
|
|
* @link http://php.net/manual/en/pdostatement.fetchall.php |
369
|
|
|
* @return array |
370
|
|
|
*/ |
371
|
2 |
|
public function fetchAll($fetch_style = null, $fetch_argument = null, $ctor_args = array()) |
|
|
|
|
372
|
|
|
{ |
373
|
|
|
// TODO Implement properly (use all other fetch modes) |
374
|
2 |
|
$this->statement->fetchAll($rows, 0, -1, OCI_FETCHSTATEMENT_BY_ROW | OCI_ASSOC); |
375
|
|
|
|
376
|
2 |
|
return $rows; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* @param int $column_number |
381
|
|
|
* |
382
|
|
|
* @link http://php.net/manual/en/pdostatement.fetchcolumn.php |
383
|
|
|
* @return mixed |
384
|
|
|
*/ |
385
|
3 |
|
public function fetchColumn($column_number = 0) |
386
|
|
|
{ |
387
|
3 |
|
$row = $this->fetch(\PDO::FETCH_NUM); |
388
|
3 |
|
if ($row === false) { |
389
|
1 |
|
return false; |
390
|
|
|
} |
391
|
|
|
|
392
|
3 |
|
if (array_key_exists($column_number, $row)) { |
393
|
2 |
|
return $row[$column_number]; |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
// TODO Throw Exception |
397
|
1 |
|
return false; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* @param string $class_name |
403
|
|
|
* @param array $ctor_args |
404
|
|
|
* |
405
|
|
|
* @link http://php.net/manual/en/pdostatement.fetchobject.php |
406
|
|
|
* @return bool|object |
407
|
|
|
*/ |
408
|
1 |
|
public function fetchObject($class_name = "stdClass", $ctor_args = array()) |
409
|
|
|
{ |
410
|
1 |
|
$row = $this->fetch(\PDO::FETCH_ASSOC); |
411
|
1 |
|
if ($row === false) { |
412
|
|
|
return false; |
413
|
|
|
} |
414
|
|
|
|
415
|
1 |
|
$reflexionClass = new \ReflectionClass($class_name); |
416
|
1 |
|
$classInstance = $reflexionClass->newInstanceArgs($ctor_args); |
417
|
|
|
|
418
|
1 |
|
foreach ($row as $property => $value) { |
|
|
|
|
419
|
1 |
|
$classInstance->{$property} = $value; |
420
|
1 |
|
} |
421
|
|
|
|
422
|
1 |
|
return $classInstance; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* @param int $attribute |
427
|
|
|
* |
428
|
|
|
* @link http://php.net/manual/en/pdostatement.getattribute.php |
429
|
|
|
* @return mixed |
430
|
|
|
*/ |
431
|
22 |
|
public function getAttribute($attribute) |
432
|
|
|
{ |
433
|
22 |
|
if (array_key_exists($attribute, $this->options)) { |
434
|
22 |
|
return $this->options[$attribute]; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
return null; |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
/** |
441
|
|
|
* @param int $column |
442
|
|
|
* |
443
|
|
|
* @throws PdoOci8Exception |
444
|
|
|
* |
445
|
|
|
* @link http://php.net/manual/en/pdostatement.getcolumnmeta.php |
446
|
|
|
* @return bool|array |
447
|
|
|
*/ |
448
|
4 |
|
public function getColumnMeta($column) |
449
|
|
|
{ |
450
|
4 |
|
$statementType = $this->statement->getType(); |
451
|
4 |
|
if ($statementType !== 'SELECT') { |
452
|
1 |
|
return false; |
453
|
|
|
} |
454
|
|
|
|
455
|
3 |
|
$table = $this->getTableName(); |
456
|
|
|
|
457
|
3 |
|
$sqlText = $this->sqlText; |
458
|
3 |
|
$statement = $this->getConnection()->parse($sqlText); |
459
|
3 |
|
$statement->execute(OCI_DESCRIBE_ONLY); |
460
|
3 |
|
$field = $statement->getField($column + 1); |
461
|
|
|
|
462
|
3 |
|
if ($field instanceof Oci8FieldInterface) { |
463
|
|
|
// Oracle returns attributes in upper case by default |
464
|
3 |
|
$fieldName = $field->getName(); |
465
|
3 |
|
if ($this->getAttribute(\PDO::ATTR_CASE) === \PDO::CASE_LOWER) { |
466
|
|
|
$fieldName = strtolower($fieldName); |
467
|
|
|
} |
468
|
|
|
|
469
|
|
|
return array( |
470
|
3 |
|
'native_type' => $field->getRawType(), |
471
|
3 |
|
'driver:decl_type' => $field->getType(), |
472
|
3 |
|
'flags' => array(), |
473
|
3 |
|
'name' => $fieldName, |
474
|
3 |
|
'table' => $table, |
475
|
3 |
|
'len' => $field->getSize(), |
476
|
3 |
|
'precision' => $field->getPrecision() - $field->getScale(), |
477
|
3 |
|
'pdo_type' => $this->getPDODataType($field->getType()), |
478
|
3 |
|
); |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
return false; |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* @link http://php.net/manual/en/pdostatement.nextrowset.php |
486
|
|
|
* @return bool |
487
|
|
|
*/ |
488
|
|
|
public function nextRowset() |
489
|
|
|
{ |
490
|
|
|
// TODO Implement |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
/** |
494
|
|
|
* @link http://php.net/manual/en/pdostatement.rowcount.php |
495
|
|
|
* @return int |
496
|
|
|
*/ |
497
|
3 |
|
public function rowCount() |
498
|
|
|
{ |
499
|
3 |
|
return $this->statement->getNumRows(); |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* @param $attribute |
505
|
|
|
* @param $value |
506
|
|
|
* |
507
|
|
|
* @link http://php.net/manual/en/pdostatement.setattribute.php |
508
|
|
|
* @return bool |
509
|
|
|
*/ |
510
|
7 |
|
public function setAttribute($attribute, $value) |
511
|
|
|
{ |
512
|
|
|
$readOnlyAttributes = array( |
513
|
7 |
|
\PDO::ATTR_AUTOCOMMIT, |
514
|
7 |
|
); |
515
|
|
|
|
516
|
7 |
View Code Duplication |
if (array_search($attribute, $readOnlyAttributes) !== false || |
|
|
|
|
517
|
7 |
|
!array_key_exists($attribute, $this->options)) { |
518
|
4 |
|
return false; |
519
|
|
|
} |
520
|
|
|
|
521
|
7 |
|
$this->options[$attribute] = $value; |
522
|
|
|
|
523
|
7 |
|
return true; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
/** |
527
|
|
|
* @param int $mode |
528
|
|
|
* @param string|int|object $target |
529
|
|
|
* @param array $ctor_args |
530
|
|
|
* |
531
|
|
|
* @link http://php.net/manual/en/pdostatement.setfetchmode.php |
532
|
|
|
* @return bool |
533
|
|
|
*/ |
534
|
3 |
|
public function setFetchMode($mode, $target = null, $ctor_args = array()) |
535
|
|
|
{ |
536
|
3 |
|
$isSuccess = $this->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, $mode); |
537
|
3 |
|
if ($isSuccess) { |
538
|
3 |
|
$this->fetchTarget = $target; |
|
|
|
|
539
|
3 |
|
$this->fetchTargetConstructorArgs = $ctor_args; |
|
|
|
|
540
|
3 |
|
} |
541
|
|
|
|
542
|
3 |
|
return $isSuccess; |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
/** |
546
|
|
|
* @return string |
547
|
|
|
*/ |
548
|
3 |
|
protected function getTableName() |
549
|
|
|
{ |
550
|
3 |
|
$statementType = $this->statement->getType(); |
551
|
3 |
|
if ($statementType !== 'SELECT') { |
552
|
|
|
return ''; |
553
|
|
|
} |
554
|
|
|
|
555
|
3 |
|
$sqlText = strtoupper($this->sqlText); |
556
|
3 |
|
$idx = strpos($sqlText, ' FROM '); |
557
|
3 |
|
$table = substr($this->sqlText, $idx + 6); |
558
|
3 |
|
$table = trim($table); |
559
|
|
|
|
560
|
3 |
|
if (strpos($table, '(') !== false) { |
561
|
1 |
|
return ''; |
562
|
|
|
} |
563
|
|
|
|
564
|
2 |
|
$idxSpace = strpos($table, ' '); |
565
|
2 |
|
if ($idxSpace !== false) { |
566
|
1 |
|
$table = substr($table, 0, $idxSpace); |
567
|
1 |
|
} |
568
|
|
|
|
569
|
2 |
|
return $table; |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
/** |
573
|
|
|
* @param string $data_type The data type name |
574
|
|
|
* |
575
|
|
|
* @return int |
576
|
|
|
*/ |
577
|
3 |
|
protected function getPDODataType($data_type) |
578
|
|
|
{ |
579
|
|
|
//TODO Add all oracle data types |
580
|
3 |
|
$pdoDataType = \PDO::PARAM_STR; |
581
|
|
|
switch ($data_type) { |
582
|
3 |
|
case 'NUMBER': |
583
|
1 |
|
$pdoDataType = \PDO::PARAM_INT; |
584
|
1 |
|
break; |
585
|
2 |
|
case 'CHAR': |
586
|
2 |
|
case 'VARCHAR2': |
587
|
2 |
|
case 'NVARCHAR2': |
588
|
2 |
|
$pdoDataType = \PDO::PARAM_STR; |
589
|
2 |
|
break; |
590
|
|
|
case 'LOB': |
591
|
|
|
case 'CLOB': |
592
|
|
|
case 'BLOB': |
593
|
|
|
case 'NCLOB': |
594
|
|
|
$pdoDataType = \PDO::PARAM_LOB; |
595
|
|
|
break; |
596
|
|
|
case 'BOOLEAN': |
597
|
|
|
$pdoDataType = \PDO::PARAM_BOOL; |
598
|
|
|
} |
599
|
|
|
|
600
|
3 |
|
return $pdoDataType; |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
/** |
604
|
|
|
* @param int $type |
605
|
|
|
* @throws PdoOci8Exception |
606
|
|
|
* @return int |
607
|
|
|
*/ |
608
|
10 |
|
protected function getDriverDataType($type) |
|
|
|
|
609
|
|
|
{ |
610
|
10 |
|
$dataType = null; |
611
|
|
|
switch ($dataType) { |
612
|
10 |
|
case \PDO::PARAM_BOOL: |
613
|
|
|
$dataType = SQLT_BOL; |
614
|
|
|
break; |
615
|
10 |
|
case \PDO::PARAM_INT: |
616
|
|
|
$dataType = SQLT_INT; |
617
|
|
|
break; |
618
|
10 |
|
case \PDO::PARAM_LOB: |
619
|
|
|
$dataType = SQLT_CLOB; |
620
|
|
|
break; |
621
|
10 |
|
case \PDO::PARAM_STMT: |
622
|
|
|
throw new PdoOci8Exception('Parameter type \PDO::PARAM_STMT is not currently supported.'); |
623
|
10 |
|
case \PDO::PARAM_NULL: |
624
|
10 |
|
case \PDO::PARAM_STR: |
625
|
10 |
|
$dataType = SQLT_CHR; |
626
|
10 |
|
break; |
627
|
|
|
case \PDO::PARAM_INPUT_OUTPUT: |
628
|
|
|
case \PDO::PARAM_INPUT_OUTPUT | \PDO::PARAM_BOOL: |
629
|
|
|
case \PDO::PARAM_INPUT_OUTPUT | \PDO::PARAM_INT: |
630
|
|
|
case \PDO::PARAM_INPUT_OUTPUT | \PDO::PARAM_LOB: |
631
|
|
|
case \PDO::PARAM_INPUT_OUTPUT | \PDO::PARAM_STMT: |
632
|
|
|
case \PDO::PARAM_INPUT_OUTPUT | \PDO::PARAM_NULL: |
633
|
|
|
case \PDO::PARAM_INPUT_OUTPUT | \PDO::PARAM_STR: |
634
|
|
|
throw new PdoOci8Exception('Parameter type \PDO::PARAM_INPUT_OUTPUT is not currently supported.'); |
635
|
|
|
} |
636
|
|
|
|
637
|
10 |
|
return $dataType; |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
/** |
641
|
|
|
* @return Oci8ConnectionInterface |
642
|
|
|
*/ |
643
|
3 |
|
protected function getConnection() |
644
|
|
|
{ |
645
|
3 |
|
return $this->connection; |
646
|
|
|
} |
647
|
|
|
|
648
|
|
|
/** |
649
|
|
|
* @return \Traversable |
650
|
|
|
*/ |
651
|
2 |
|
protected function getInternalIterator() |
652
|
|
|
{ |
653
|
2 |
|
if ($this->iterator instanceof \Traversable) { |
654
|
2 |
|
return $this->iterator; |
655
|
|
|
} |
656
|
|
|
|
657
|
2 |
|
$rows = $this->fetchAll(); |
658
|
2 |
|
if ($rows === false) { |
659
|
|
|
//TODO Throw Exception? |
660
|
|
|
$rows = array(); |
661
|
|
|
} |
662
|
|
|
|
663
|
2 |
|
$this->iterator = new \ArrayIterator($rows); |
664
|
|
|
|
665
|
2 |
|
return $this->iterator; |
666
|
|
|
} |
667
|
|
|
|
668
|
|
|
/** |
669
|
|
|
* @return array |
670
|
|
|
*/ |
671
|
2 |
|
public function current() |
672
|
|
|
{ |
673
|
2 |
|
$iterator = $this->getInternalIterator(); |
674
|
|
|
|
675
|
2 |
|
return $iterator->current(); |
676
|
|
|
} |
677
|
|
|
|
678
|
2 |
|
public function next() |
679
|
|
|
{ |
680
|
2 |
|
$iterator = $this->getInternalIterator(); |
681
|
|
|
|
682
|
2 |
|
$iterator->next(); |
683
|
2 |
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* @return int|null |
687
|
|
|
*/ |
688
|
|
|
public function key() |
689
|
|
|
{ |
690
|
|
|
$iterator = $this->getInternalIterator(); |
691
|
|
|
|
692
|
|
|
return $iterator->key(); |
693
|
|
|
} |
694
|
|
|
|
695
|
|
|
/** |
696
|
|
|
* @return bool |
697
|
|
|
*/ |
698
|
2 |
|
public function valid() |
699
|
|
|
{ |
700
|
2 |
|
$iterator = $this->getInternalIterator(); |
701
|
|
|
|
702
|
2 |
|
return $iterator->valid(); |
703
|
|
|
} |
704
|
|
|
|
705
|
1 |
|
public function rewind() |
706
|
|
|
{ |
707
|
1 |
|
$iterator = $this->getInternalIterator(); |
708
|
|
|
|
709
|
1 |
|
$iterator->rewind(); |
710
|
1 |
|
} |
711
|
|
|
} |
712
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.