1 | <?php |
||||
2 | /* |
||||
3 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
4 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
5 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
6 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
7 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
8 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
9 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
10 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
11 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
12 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
13 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
14 | * |
||||
15 | * This software consists of voluntary contributions made by many individuals |
||||
16 | * and is licensed under the MIT license. For more information, see |
||||
17 | * <http://www.doctrine-project.org>. |
||||
18 | */ |
||||
19 | |||||
20 | namespace Doctrine\DBAL\Driver\IBMDB2; |
||||
21 | |||||
22 | use Doctrine\DBAL\Driver\Statement; |
||||
23 | use Doctrine\DBAL\Driver\StatementIterator; |
||||
24 | |||||
25 | class DB2Statement implements \IteratorAggregate, Statement |
||||
26 | { |
||||
27 | /** |
||||
28 | * @var resource |
||||
29 | */ |
||||
30 | private $_stmt; |
||||
31 | |||||
32 | /** |
||||
33 | * @var array |
||||
34 | */ |
||||
35 | private $_bindParam = []; |
||||
36 | |||||
37 | /** |
||||
38 | * @var string Name of the default class to instantiate when fetch mode is \PDO::FETCH_CLASS. |
||||
39 | */ |
||||
40 | private $defaultFetchClass = '\stdClass'; |
||||
41 | |||||
42 | /** |
||||
43 | * @var string Constructor arguments for the default class to instantiate when fetch mode is \PDO::FETCH_CLASS. |
||||
44 | */ |
||||
45 | private $defaultFetchClassCtorArgs = []; |
||||
46 | |||||
47 | /** |
||||
48 | * @var integer |
||||
49 | */ |
||||
50 | private $_defaultFetchMode = \PDO::FETCH_BOTH; |
||||
51 | |||||
52 | /** |
||||
53 | * Indicates whether the statement is in the state when fetching results is possible |
||||
54 | * |
||||
55 | * @var bool |
||||
56 | */ |
||||
57 | private $result = false; |
||||
58 | |||||
59 | /** |
||||
60 | * DB2_BINARY, DB2_CHAR, DB2_DOUBLE, or DB2_LONG |
||||
61 | * |
||||
62 | * @var array |
||||
63 | */ |
||||
64 | static private $_typeMap = [ |
||||
65 | \PDO::PARAM_INT => DB2_LONG, |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
66 | \PDO::PARAM_STR => DB2_CHAR, |
||||
0 ignored issues
–
show
|
|||||
67 | ]; |
||||
68 | |||||
69 | /** |
||||
70 | * @param resource $stmt |
||||
71 | */ |
||||
72 | public function __construct($stmt) |
||||
73 | { |
||||
74 | $this->_stmt = $stmt; |
||||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * {@inheritdoc} |
||||
79 | */ |
||||
80 | public function bindValue($param, $value, $type = null) |
||||
81 | { |
||||
82 | return $this->bindParam($param, $value, $type); |
||||
83 | } |
||||
84 | |||||
85 | /** |
||||
86 | * {@inheritdoc} |
||||
87 | */ |
||||
88 | public function bindParam($column, &$variable, $type = null, $length = null) |
||||
89 | { |
||||
90 | $this->_bindParam[$column] =& $variable; |
||||
91 | |||||
92 | if ($type && isset(self::$_typeMap[$type])) { |
||||
93 | $type = self::$_typeMap[$type]; |
||||
94 | } else { |
||||
95 | $type = DB2_CHAR; |
||||
0 ignored issues
–
show
|
|||||
96 | } |
||||
97 | |||||
98 | if (!db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) { |
||||
0 ignored issues
–
show
The function
db2_bind_param was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
99 | throw new DB2Exception(db2_stmt_errormsg()); |
||||
0 ignored issues
–
show
The function
db2_stmt_errormsg was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
100 | } |
||||
101 | |||||
102 | return true; |
||||
103 | } |
||||
104 | |||||
105 | /** |
||||
106 | * {@inheritdoc} |
||||
107 | */ |
||||
108 | public function closeCursor() |
||||
109 | { |
||||
110 | if ( ! $this->_stmt) { |
||||
111 | return false; |
||||
112 | } |
||||
113 | |||||
114 | $this->_bindParam = []; |
||||
115 | |||||
116 | if (!db2_free_result($this->_stmt)) { |
||||
117 | return false; |
||||
118 | } |
||||
119 | |||||
120 | $this->result = false; |
||||
121 | |||||
122 | return true; |
||||
123 | } |
||||
124 | |||||
125 | /** |
||||
126 | * {@inheritdoc} |
||||
127 | */ |
||||
128 | public function columnCount() |
||||
129 | { |
||||
130 | if ( ! $this->_stmt) { |
||||
131 | return false; |
||||
0 ignored issues
–
show
The expression
return false returns the type false which is incompatible with the return type mandated by Doctrine\DBAL\Driver\Res...tatement::columnCount() of integer .
In the issue above, the returned value is violating the contract defined by the mentioned interface. Let's take a look at an example: interface HasName {
/** @return string */
public function getName();
}
class Name {
public $name;
}
class User implements HasName {
/** @return string|Name */
public function getName() {
return new Name('foo'); // This is a violation of the ``HasName`` interface
// which only allows a string value to be returned.
}
}
Loading history...
|
|||||
132 | } |
||||
133 | |||||
134 | return db2_num_fields($this->_stmt); |
||||
0 ignored issues
–
show
The function
db2_num_fields was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
135 | } |
||||
136 | |||||
137 | /** |
||||
138 | * {@inheritdoc} |
||||
139 | */ |
||||
140 | public function errorCode() |
||||
141 | { |
||||
142 | return db2_stmt_error(); |
||||
0 ignored issues
–
show
The function
db2_stmt_error was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
143 | } |
||||
144 | |||||
145 | /** |
||||
146 | * {@inheritdoc} |
||||
147 | */ |
||||
148 | public function errorInfo() |
||||
149 | { |
||||
150 | return [ |
||||
151 | db2_stmt_errormsg(), |
||||
152 | db2_stmt_error(), |
||||
153 | ]; |
||||
154 | } |
||||
155 | |||||
156 | /** |
||||
157 | * {@inheritdoc} |
||||
158 | */ |
||||
159 | public function execute($params = null) |
||||
160 | { |
||||
161 | if ( ! $this->_stmt) { |
||||
162 | return false; |
||||
163 | } |
||||
164 | |||||
165 | if ($params === null) { |
||||
166 | ksort($this->_bindParam); |
||||
167 | |||||
168 | $params = []; |
||||
169 | |||||
170 | foreach ($this->_bindParam as $column => $value) { |
||||
171 | $params[] = $value; |
||||
172 | } |
||||
173 | } |
||||
174 | |||||
175 | $retval = @db2_execute($this->_stmt, $params); |
||||
0 ignored issues
–
show
The function
db2_execute was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
176 | |||||
177 | if ($retval === false) { |
||||
178 | throw new DB2Exception(db2_stmt_errormsg()); |
||||
0 ignored issues
–
show
The function
db2_stmt_errormsg was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
179 | } |
||||
180 | |||||
181 | $this->result = true; |
||||
182 | |||||
183 | return $retval; |
||||
184 | } |
||||
185 | |||||
186 | /** |
||||
187 | * {@inheritdoc} |
||||
188 | */ |
||||
189 | View Code Duplication | public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) |
|||
190 | { |
||||
191 | $this->_defaultFetchMode = $fetchMode; |
||||
192 | $this->defaultFetchClass = $arg2 ? $arg2 : $this->defaultFetchClass; |
||||
193 | $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; |
||||
194 | |||||
195 | return true; |
||||
196 | } |
||||
197 | |||||
198 | /** |
||||
199 | * {@inheritdoc} |
||||
200 | */ |
||||
201 | public function getIterator() |
||||
202 | { |
||||
203 | return new StatementIterator($this); |
||||
204 | } |
||||
205 | |||||
206 | /** |
||||
207 | * {@inheritdoc} |
||||
208 | */ |
||||
209 | View Code Duplication | public function fetch($fetchMode = null, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0) |
|||
210 | { |
||||
211 | // do not try fetching from the statement if it's not expected to contain result |
||||
212 | // in order to prevent exceptional situation |
||||
213 | if (!$this->result) { |
||||
214 | return false; |
||||
215 | } |
||||
216 | |||||
217 | $fetchMode = $fetchMode ?: $this->_defaultFetchMode; |
||||
218 | switch ($fetchMode) { |
||||
219 | case \PDO::FETCH_BOTH: |
||||
220 | return db2_fetch_both($this->_stmt); |
||||
0 ignored issues
–
show
The function
db2_fetch_both was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
221 | case \PDO::FETCH_ASSOC: |
||||
222 | return db2_fetch_assoc($this->_stmt); |
||||
0 ignored issues
–
show
The function
db2_fetch_assoc was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
223 | case \PDO::FETCH_CLASS: |
||||
224 | $className = $this->defaultFetchClass; |
||||
225 | $ctorArgs = $this->defaultFetchClassCtorArgs; |
||||
226 | |||||
227 | if (func_num_args() >= 2) { |
||||
228 | $args = func_get_args(); |
||||
229 | $className = $args[1]; |
||||
230 | $ctorArgs = isset($args[2]) ? $args[2] : []; |
||||
231 | } |
||||
232 | |||||
233 | $result = db2_fetch_object($this->_stmt); |
||||
234 | |||||
235 | if ($result instanceof \stdClass) { |
||||
236 | $result = $this->castObject($result, $className, $ctorArgs); |
||||
237 | } |
||||
238 | |||||
239 | return $result; |
||||
240 | case \PDO::FETCH_NUM: |
||||
241 | return db2_fetch_array($this->_stmt); |
||||
0 ignored issues
–
show
The function
db2_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
242 | case \PDO::FETCH_OBJ: |
||||
243 | return db2_fetch_object($this->_stmt); |
||||
244 | default: |
||||
245 | throw new DB2Exception('Given Fetch-Style ' . $fetchMode . ' is not supported.'); |
||||
246 | } |
||||
247 | } |
||||
248 | |||||
249 | /** |
||||
250 | * {@inheritdoc} |
||||
251 | */ |
||||
252 | View Code Duplication | public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) |
|||
253 | { |
||||
254 | $rows = []; |
||||
255 | |||||
256 | switch ($fetchMode) { |
||||
257 | case \PDO::FETCH_CLASS: |
||||
258 | while ($row = call_user_func_array([$this, 'fetch'], func_get_args())) { |
||||
259 | $rows[] = $row; |
||||
260 | } |
||||
261 | break; |
||||
262 | case \PDO::FETCH_COLUMN: |
||||
263 | while ($row = $this->fetchColumn()) { |
||||
264 | $rows[] = $row; |
||||
265 | } |
||||
266 | break; |
||||
267 | default: |
||||
268 | while ($row = $this->fetch($fetchMode)) { |
||||
269 | $rows[] = $row; |
||||
270 | } |
||||
271 | } |
||||
272 | |||||
273 | return $rows; |
||||
274 | } |
||||
275 | |||||
276 | /** |
||||
277 | * {@inheritdoc} |
||||
278 | */ |
||||
279 | View Code Duplication | public function fetchColumn($columnIndex = 0) |
|||
280 | { |
||||
281 | $row = $this->fetch(\PDO::FETCH_NUM); |
||||
282 | |||||
283 | if (false === $row) { |
||||
284 | return false; |
||||
285 | } |
||||
286 | |||||
287 | return isset($row[$columnIndex]) ? $row[$columnIndex] : null; |
||||
288 | } |
||||
289 | |||||
290 | /** |
||||
291 | * {@inheritdoc} |
||||
292 | */ |
||||
293 | public function rowCount() |
||||
294 | { |
||||
295 | return (@db2_num_rows($this->_stmt)) ? : 0; |
||||
296 | } |
||||
297 | |||||
298 | /** |
||||
299 | * Casts a stdClass object to the given class name mapping its' properties. |
||||
300 | * |
||||
301 | * @param \stdClass $sourceObject Object to cast from. |
||||
302 | * @param string|object $destinationClass Name of the class or class instance to cast to. |
||||
303 | * @param array $ctorArgs Arguments to use for constructing the destination class instance. |
||||
304 | * |
||||
305 | * @return object |
||||
306 | * |
||||
307 | * @throws DB2Exception |
||||
308 | */ |
||||
309 | private function castObject(\stdClass $sourceObject, $destinationClass, array $ctorArgs = []) |
||||
310 | { |
||||
311 | View Code Duplication | if ( ! is_string($destinationClass)) { |
|||
312 | if ( ! is_object($destinationClass)) { |
||||
313 | throw new DB2Exception(sprintf( |
||||
314 | 'Destination class has to be of type string or object, %s given.', gettype($destinationClass) |
||||
315 | )); |
||||
316 | } |
||||
317 | } else { |
||||
318 | $destinationClass = new \ReflectionClass($destinationClass); |
||||
319 | $destinationClass = $destinationClass->newInstanceArgs($ctorArgs); |
||||
320 | } |
||||
321 | |||||
322 | $sourceReflection = new \ReflectionObject($sourceObject); |
||||
323 | $destinationClassReflection = new \ReflectionObject($destinationClass); |
||||
324 | /** @var \ReflectionProperty[] $destinationProperties */ |
||||
325 | $destinationProperties = array_change_key_case($destinationClassReflection->getProperties(), \CASE_LOWER); |
||||
326 | |||||
327 | foreach ($sourceReflection->getProperties() as $sourceProperty) { |
||||
328 | $sourceProperty->setAccessible(true); |
||||
329 | |||||
330 | $name = $sourceProperty->getName(); |
||||
331 | $value = $sourceProperty->getValue($sourceObject); |
||||
332 | |||||
333 | // Try to find a case-matching property. |
||||
334 | if ($destinationClassReflection->hasProperty($name)) { |
||||
335 | $destinationProperty = $destinationClassReflection->getProperty($name); |
||||
336 | |||||
337 | $destinationProperty->setAccessible(true); |
||||
338 | $destinationProperty->setValue($destinationClass, $value); |
||||
339 | |||||
340 | continue; |
||||
341 | } |
||||
342 | |||||
343 | $name = strtolower($name); |
||||
344 | |||||
345 | // Try to find a property without matching case. |
||||
346 | // Fallback for the driver returning either all uppercase or all lowercase column names. |
||||
347 | if (isset($destinationProperties[$name])) { |
||||
348 | $destinationProperty = $destinationProperties[$name]; |
||||
349 | |||||
350 | $destinationProperty->setAccessible(true); |
||||
351 | $destinationProperty->setValue($destinationClass, $value); |
||||
352 | |||||
353 | continue; |
||||
354 | } |
||||
355 | |||||
356 | $destinationClass->$name = $value; |
||||
357 | } |
||||
358 | |||||
359 | return $destinationClass; |
||||
360 | } |
||||
361 | } |
||||
362 |