Completed
Push — develop ( 361a2b...a96e4b )
by Marco
20s queued 14s
created

SQLAnywhereStatement::errorInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 1
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Driver\SQLAnywhere;
6
7
use Doctrine\DBAL\DBALException;
8
use Doctrine\DBAL\Driver\Statement;
9
use Doctrine\DBAL\Driver\StatementIterator;
10
use Doctrine\DBAL\FetchMode;
11
use Doctrine\DBAL\ParameterType;
12
use IteratorAggregate;
13
use ReflectionClass;
14
use ReflectionObject;
15
use stdClass;
16
use const SASQL_BOTH;
0 ignored issues
show
Bug introduced by
The constant SASQL_BOTH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
17
use function array_key_exists;
18
use function count;
19
use function func_get_args;
20
use function gettype;
21
use function is_array;
22
use function is_int;
23
use function is_object;
24
use function is_resource;
25
use function is_string;
26
use function sasql_fetch_array;
0 ignored issues
show
introduced by
The function sasql_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
27
use function sasql_fetch_assoc;
0 ignored issues
show
introduced by
The function sasql_fetch_assoc was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
28
use function sasql_fetch_object;
0 ignored issues
show
introduced by
The function sasql_fetch_object was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
29
use function sasql_fetch_row;
0 ignored issues
show
introduced by
The function sasql_fetch_row was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
30
use function sasql_prepare;
0 ignored issues
show
introduced by
The function sasql_prepare was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
31
use function sasql_stmt_affected_rows;
0 ignored issues
show
introduced by
The function sasql_stmt_affected_rows was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
32
use function sasql_stmt_bind_param_ex;
0 ignored issues
show
introduced by
The function sasql_stmt_bind_param_ex was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
33
use function sasql_stmt_execute;
0 ignored issues
show
introduced by
The function sasql_stmt_execute was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
34
use function sasql_stmt_field_count;
0 ignored issues
show
introduced by
The function sasql_stmt_field_count was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
35
use function sasql_stmt_reset;
0 ignored issues
show
introduced by
The function sasql_stmt_reset was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
36
use function sasql_stmt_result_metadata;
0 ignored issues
show
introduced by
The function sasql_stmt_result_metadata was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
37
use function sprintf;
38
39
/**
40
 * SAP SQL Anywhere implementation of the Statement interface.
41
 */
42
class SQLAnywhereStatement implements IteratorAggregate, Statement
43
{
44
    /** @var resource The connection resource. */
45
    private $conn;
46
47
    /** @var string Name of the default class to instantiate when fetching class instances. */
48
    private $defaultFetchClass = '\stdClass';
49
50
    /** @var mixed[] Constructor arguments for the default class to instantiate when fetching class instances. */
51
    private $defaultFetchClassCtorArgs = [];
52
53
    /** @var int Default fetch mode to use. */
54
    private $defaultFetchMode = FetchMode::MIXED;
55
56
    /** @var resource The result set resource to fetch. */
57
    private $result;
58
59
    /** @var resource The prepared SQL statement to execute. */
60
    private $stmt;
61
62
    /** @var mixed[] The references to bound parameter values. */
63
    private $boundValues = [];
64
65
    /**
66
     * Prepares given statement for given connection.
67
     *
68
     * @param resource $conn The connection resource to use.
69
     * @param string   $sql  The SQL statement to prepare.
70
     *
71
     * @throws SQLAnywhereException
72
     */
73
    public function __construct($conn, $sql)
74
    {
75
        if (! is_resource($conn)) {
76
            throw new SQLAnywhereException('Invalid SQL Anywhere connection resource: ' . $conn);
77
        }
78
79
        $this->conn = $conn;
80
        $this->stmt = sasql_prepare($conn, $sql);
0 ignored issues
show
Bug introduced by
The function sasql_prepare 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 ignore-call  annotation

80
        $this->stmt = /** @scrutinizer ignore-call */ sasql_prepare($conn, $sql);
Loading history...
81
82
        if (! is_resource($this->stmt)) {
83
            throw SQLAnywhereException::fromSQLAnywhereError($conn);
84
        }
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     *
90
     * @throws SQLAnywhereException
91
     */
92
    public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) : void
93
    {
94
        switch ($type) {
95
            case ParameterType::INTEGER:
96
            case ParameterType::BOOLEAN:
97
                $type = 'i';
98
                break;
99
100
            case ParameterType::LARGE_OBJECT:
101
                $type = 'b';
102
                break;
103
104
            case ParameterType::NULL:
105
            case ParameterType::STRING:
106
            case ParameterType::BINARY:
107
                $type = 's';
108
                break;
109
110
            default:
111
                throw new SQLAnywhereException('Unknown type: ' . $type);
112
        }
113
114
        $this->boundValues[$column] =& $variable;
115
116
        if (! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
0 ignored issues
show
Bug introduced by
The function sasql_stmt_bind_param_ex 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 ignore-call  annotation

116
        if (! /** @scrutinizer ignore-call */ sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
Loading history...
117
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
118
        }
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function bindValue($param, $value, $type = ParameterType::STRING) : void
125
    {
126
        $this->bindParam($param, $value, $type);
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function closeCursor() : void
133
    {
134
        sasql_stmt_reset($this->stmt);
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function columnCount()
141
    {
142
        return sasql_stmt_field_count($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_field_count 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 ignore-call  annotation

142
        return /** @scrutinizer ignore-call */ sasql_stmt_field_count($this->stmt);
Loading history...
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     *
148
     * @throws SQLAnywhereException
149
     */
150
    public function execute($params = null) : void
151
    {
152
        if (is_array($params)) {
153
            $hasZeroIndex = array_key_exists(0, $params);
154
155
            foreach ($params as $key => $val) {
156
                if ($hasZeroIndex && is_int($key)) {
157
                    $this->bindValue($key + 1, $val);
158
                } else {
159
                    $this->bindValue($key, $val);
160
                }
161
            }
162
        }
163
164
        if (! sasql_stmt_execute($this->stmt)) {
0 ignored issues
show
Bug introduced by
The function sasql_stmt_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 ignore-call  annotation

164
        if (! /** @scrutinizer ignore-call */ sasql_stmt_execute($this->stmt)) {
Loading history...
165
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
166
        }
167
168
        $this->result = sasql_stmt_result_metadata($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_result_metadata 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 ignore-call  annotation

168
        $this->result = /** @scrutinizer ignore-call */ sasql_stmt_result_metadata($this->stmt);
Loading history...
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     *
174
     * @throws SQLAnywhereException
175
     */
176
    public function fetch($fetchMode = null, ...$args)
177
    {
178
        if (! is_resource($this->result)) {
179
            return false;
180
        }
181
182
        $fetchMode = $fetchMode ?: $this->defaultFetchMode;
183
184
        switch ($fetchMode) {
185
            case FetchMode::COLUMN:
186
                return $this->fetchColumn();
187
188
            case FetchMode::ASSOCIATIVE:
189
                return sasql_fetch_assoc($this->result);
0 ignored issues
show
Bug introduced by
The function sasql_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 ignore-call  annotation

189
                return /** @scrutinizer ignore-call */ sasql_fetch_assoc($this->result);
Loading history...
190
191
            case FetchMode::MIXED:
192
                return sasql_fetch_array($this->result, SASQL_BOTH);
0 ignored issues
show
Bug introduced by
The function sasql_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 ignore-call  annotation

192
                return /** @scrutinizer ignore-call */ sasql_fetch_array($this->result, SASQL_BOTH);
Loading history...
Bug introduced by
The constant SASQL_BOTH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
193
194
            case FetchMode::CUSTOM_OBJECT:
195
                $className = $this->defaultFetchClass;
196
                $ctorArgs  = $this->defaultFetchClassCtorArgs;
197
198
                if (count($args) > 0) {
199
                    $className = $args[0];
200
                    $ctorArgs  = $args[1] ?? [];
201
                }
202
203
                $result = sasql_fetch_object($this->result);
0 ignored issues
show
Bug introduced by
The function sasql_fetch_object 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 ignore-call  annotation

203
                $result = /** @scrutinizer ignore-call */ sasql_fetch_object($this->result);
Loading history...
204
205
                if ($result instanceof stdClass) {
206
                    $result = $this->castObject($result, $className, $ctorArgs);
207
                }
208
209
                return $result;
210
211
            case FetchMode::NUMERIC:
212
                return sasql_fetch_row($this->result);
0 ignored issues
show
Bug introduced by
The function sasql_fetch_row 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 ignore-call  annotation

212
                return /** @scrutinizer ignore-call */ sasql_fetch_row($this->result);
Loading history...
213
214
            case FetchMode::STANDARD_OBJECT:
215
                return sasql_fetch_object($this->result);
216
217
            default:
218
                throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode);
219
        }
220
    }
221
222
    /**
223
     * {@inheritdoc}
224
     */
225
    public function fetchAll($fetchMode = null, ...$args)
226
    {
227
        $rows = [];
228
229
        switch ($fetchMode) {
230
            case FetchMode::CUSTOM_OBJECT:
231
                while (($row = $this->fetch(...func_get_args())) !== false) {
232
                    $rows[] = $row;
233
                }
234
                break;
235
236
            case FetchMode::COLUMN:
237
                while (($row = $this->fetchColumn()) !== false) {
238
                    $rows[] = $row;
239
                }
240
                break;
241
242
            default:
243
                while (($row = $this->fetch($fetchMode)) !== false) {
244
                    $rows[] = $row;
245
                }
246
        }
247
248
        return $rows;
249
    }
250
251
    /**
252
     * {@inheritdoc}
253
     */
254
    public function fetchColumn($columnIndex = 0)
255
    {
256
        $row = $this->fetch(FetchMode::NUMERIC);
257
258
        if ($row === false) {
259
            return false;
260
        }
261
262
        if (! array_key_exists($columnIndex, $row)) {
263
            throw DBALException::invalidColumnIndex($columnIndex, count($row));
264
        }
265
    }
266
267
    /**
268
     * {@inheritdoc}
269
     */
270
    public function getIterator()
271
    {
272
        return new StatementIterator($this);
273
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function rowCount() : int
279
    {
280
        return sasql_stmt_affected_rows($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_affected_rows 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 ignore-call  annotation

280
        return /** @scrutinizer ignore-call */ sasql_stmt_affected_rows($this->stmt);
Loading history...
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286 50
    public function setFetchMode($fetchMode, ...$args) : void
287
    {
288 50
        $this->defaultFetchMode = $fetchMode;
289
290
        if (isset($args[0])) {
291
            $this->defaultFetchClass = $args[0];
292
        }
293
294
        if (! isset($args[1])) {
295
            return;
296
        }
297
298
        $this->defaultFetchClassCtorArgs = (array) $args[1];
299
    }
300
301
    /**
302
     * Casts a stdClass object to the given class name mapping its' properties.
303
     *
304
     * @param stdClass      $sourceObject     Object to cast from.
305
     * @param string|object $destinationClass Name of the class or class instance to cast to.
306
     * @param mixed[]       $ctorArgs         Arguments to use for constructing the destination class instance.
307
     *
308
     * @return object
309
     *
310
     * @throws SQLAnywhereException
311
     */
312
    private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = [])
313
    {
314
        if (! is_string($destinationClass)) {
315
            if (! is_object($destinationClass)) {
316
                throw new SQLAnywhereException(sprintf(
317
                    'Destination class has to be of type string or object, %s given.',
318
                    gettype($destinationClass)
319
                ));
320
            }
321
        } else {
322
            $destinationClass = new ReflectionClass($destinationClass);
323
            $destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
324
        }
325
326
        $sourceReflection           = new ReflectionObject($sourceObject);
327
        $destinationClassReflection = new ReflectionObject($destinationClass);
328
329
        foreach ($sourceReflection->getProperties() as $sourceProperty) {
330
            $sourceProperty->setAccessible(true);
331
332
            $name  = $sourceProperty->getName();
333
            $value = $sourceProperty->getValue($sourceObject);
334
335
            if ($destinationClassReflection->hasProperty($name)) {
336
                $destinationProperty = $destinationClassReflection->getProperty($name);
337
338
                $destinationProperty->setAccessible(true);
339
                $destinationProperty->setValue($destinationClass, $value);
340
            } else {
341
                $destinationClass->$name = $value;
342
            }
343
        }
344
345
        return $destinationClass;
346
    }
347
}
348