GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 8ad259...6078a4 )
by Charlotte
02:26
created

StatementExecuteCommand::parseTime()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5.0342

Importance

Changes 0
Metric Value
cc 5
eloc 19
nc 5
nop 1
dl 0
loc 29
ccs 16
cts 18
cp 0.8889
crap 5.0342
rs 9.3222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Plasma Driver MySQL component
4
 * Copyright 2018 PlasmaPHP, All Rights Reserved
5
 *
6
 * Website: https://github.com/PlasmaPHP
7
 * License: https://github.com/PlasmaPHP/driver-mysql/blob/master/LICENSE
8
*/
9
10
namespace Plasma\Drivers\MySQL\Commands;
11
12
/**
13
 * Statement Execute command.
14
 * @internal
15
 */
16
class StatementExecuteCommand extends QueryCommand {
17
    /**
18
     * The identifier for this command.
19
     * @var int
20
     * @source
21
     */
22
    const COMMAND_ID = 0x17;
23
    
24
    /**
25
     * @var mixed
26
     */
27
    protected $id;
28
    
29
    /**
30
     * @var array
31
     */
32
    protected $params;
33
    
34
    /**
35
     * Constructor.
36
     * @param \Plasma\DriverInterface  $driver
37
     * @param mixed                    $id
38
     * @param string                   $query
39
     * @param array                    $params
40
     */
41 37
    function __construct(\Plasma\DriverInterface $driver, $id, string $query, array $params) {
42 37
        parent::__construct($driver, $query);
43
        
44 37
        $this->id = $id;
45 37
        $this->params = $params;
46 37
    }
47
    
48
    /**
49
     * Get the encoded message for writing to the database connection.
50
     * @return string
51
     */
52 36
    function getEncodedMessage(): string {
53 36
        $packet = \chr(static::COMMAND_ID);
54 36
        $packet .= \Plasma\BinaryBuffer::writeInt4($this->id);
55
        
56 36
        $packet .= "\x00"; // Cursor type flag
57 36
        $packet .= \Plasma\BinaryBuffer::writeInt4(1); // Iteration count is always 1
58
        
59 36
        $bitmapOffset = \strlen($packet);
60 36
        $packet .= \str_repeat("\x00", ((\count($this->params) + 7) >> 3));
61
        
62 36
        $bound = 0;
63
        
64 36
        $types = '';
65 36
        $values = '';
66
        
67 36
        foreach($this->params as $id => $param) {
68 36
            if($param === null) {
69 1
                $offset = $bitmapOffset + ($id >> 3);
70 1
                $packet[$offset] = $packet[$offset] | \chr((1 << ($id % 8)));
71
            } else {
72 36
                $bound = 1;
73
            }
74
            
75
            try {
76 36
                $manager = \Plasma\Types\TypeExtensionsManager::getManager('driver-mysql');
77
                $encode = $manager->encodeType($param);
78
                
79
                $unsigned = $encode->isUnsigned();
80
                $type = $encode->getSQLType();
81
                $value = $encode->getValue();
82 36
            } catch (\Plasma\Exception $e) {
83 36
                [ $unsigned, $type, $value ] = $this->stdEncodeValue($param);
84
            }
85
            
86 35
            $types .= \chr($type).($unsigned ? "\x80" : "\x00");
87 35
            $values .= $value;
88
        }
89
        
90 35
        $packet .= \chr($bound);
91
        
92 35
        if($bound) {
93 35
            $packet .= $types;
94 35
            $packet .= $values;
95
        }
96
        
97 35
        return $packet;
98
    }
99
    
100
    /**
101
     * Whether the sequence ID should be resetted.
102
     * @return bool
103
     */
104 36
    function resetSequence(): bool {
105 36
        return true;
106
    }
107
    
108
    /**
109
     * Parses the binary resultset row and returns the row.
110
     * @param \Plasma\BinaryBuffer  $buffer
111
     * @return array
112
     */
113 35
    protected function parseResultsetRow(\Plasma\BinaryBuffer $buffer): array {
114 35
        $buffer->read(1); // remove packet header
115
        
116 35
        $nullRow = array();
117 35
        $i = 0;
118
        
119
        /** @var \Plasma\ColumnDefinitionInterface  $column */
120 35
        foreach($this->fields as $column) { // Handle NULL-bitmap
121 35
            if((\ord($buffer[(($i + 2) >> 3)]) & (1 << (($i + 2) % 8))) !== 0) {
122 2
                $nullRow[$column->getName()] = null;
123
            }
124
            
125 35
            $i++;
126
        }
127
        
128 35
        $buffer->read(((\count($this->fields) + 9) >> 3)); // Remove NULL-bitmap
129 35
        $row = array();
130
        
131
        /** @var \Plasma\ColumnDefinitionInterface  $column */
132 35
        foreach($this->fields as $column) {
133 35
            if(\array_key_exists($column->getName(), $nullRow)) {
134 2
                $row[$column->getName()] = null;
135 2
                continue;
136
            }
137
            
138 35
            $value = $this->stdDecodeBinaryValue($column, $buffer);
139 35
            $parsedValue = $column->parseValue($value);
140
            
141 35
            if($value !== $parsedValue) {
142
                $value = $parsedValue;
143
            }
144
            
145 35
            $row[$column->getName()] = $value;
146
        }
147
        
148 35
        return $row;
149
    }
150
    
151
    /**
152
     * Standard encode value, if type extensions failed.
153
     * @param mixed  $param
154
     * @return array
155
     * @throws \Plasma\Exception
156
     */
157 36
    protected function stdEncodeValue($param): array {
158 36
        $unsigned = false;
159
        
160 36
        switch(\gettype($param)) {
161
            case 'boolean':
162 1
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_TINY;
163 1
                $value = ($param ? "\x01" : "\0");
164 1
            break;
165
            case 'integer':
166 7
                if($param >= 0) {
167 7
                    $unsigned = true;
168
                }
169
                
170 7
                if($param >= 0 && $param < (1 << 15)) {
171 7
                    $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_SHORT;
172 7
                    $value = \Plasma\BinaryBuffer::writeInt2($param);
173 3
                } elseif(\PHP_INT_SIZE === 4) {
174
                    $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_LONG;
175
                    $value = \Plasma\BinaryBuffer::writeInt4($param);
176
                } else {
177 3
                    $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_LONGLONG;
178 3
                    $value = \Plasma\BinaryBuffer::writeInt8($param);
179
                }
180 7
            break;
181
            case 'double':
182 2
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_DOUBLE;
183 2
                $value = \Plasma\BinaryBuffer::writeDouble($param);
184 2
            break;
185
            case 'string':
186 26
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_LONG_BLOB;
187 26
                $value = \Plasma\BinaryBuffer::writeStringLength($param);
188 26
            break;
189
            case 'NULL':
190 1
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_NULL;
191 1
                $value = '';
192 1
            break;
193
            default:
194 1
                throw new \Plasma\Exception('Unexpected type for binding parameter: '.\gettype($param));
195
            break;
196
        }
197
        
198 35
        return array($unsigned, $type, $value);
199
    }
200
    
201
    /**
202
     * Standard decode value, if type extensions failed.
203
     * @param \Plasma\ColumnDefinitionInterface  $column
204
     * @param \Plasma\BinaryBuffer               $buffer
205
     * @return mixed
206
     * @throws \Plasma\Exception
207
     */
208 35
    protected function stdDecodeBinaryValue(\Plasma\ColumnDefinitionInterface $column, \Plasma\BinaryBuffer $buffer) {
209 35
        $flags = $column->getFlags();
210 35
        $type = $column->getType();
211
        
212
        switch(true) {
213 35
            case $this->isTypeString($type):
214 18
                $value = $buffer->readStringLength();
215 18
            break;
216 17
            case ($type === 'TINY'):
217 7
                $value = $buffer->readInt1();
218 7
                $value = $this->zeroFillInts($column, $value);
219 7
            break;
220 17
            case $this->isTypeShortOrYear($type):
221 7
                $value = $buffer->readInt2();
222 7
                $value = $this->zeroFillInts($column, $value);
223 7
            break;
224 17
            case $this->isTypeInt24orLong($type):
225 7
                $value = $buffer->readInt4();
226
                
227 7
                if(($flags & \Plasma\Drivers\MySQL\FieldFlags::UNSIGNED_FLAG) !== 0 && \PHP_INT_SIZE <= 4) {
228
                    $value = \bcadd($value, '18446744073709551616');
229
                }
230
                
231 7
                $value = $this->zeroFillInts($column, $value);
232 7
            break;
233 17
            case ($type === 'LONGLONG'):
234 7
                $value = $buffer->readInt8();
235
                
236 7
                if(($flags & \Plasma\Drivers\MySQL\FieldFlags::UNSIGNED_FLAG) !== 0) {
237
                    $value = \bcadd($value, '18446744073709551616');
238 7
                } elseif(\PHP_INT_SIZE > 4) {
239 7
                    $value = (int) $value;
240
                }
241
                
242 7
                $value = $this->zeroFillInts($column, $value);
243 7
            break;
244 10
            case ($type === 'FLOAT'):
245 2
                $value = $buffer->readFloat();
246 2
            break;
247 10
            case ($type === 'DOUBLE'):
248 2
                $value = $buffer->readDouble();
249 2
            break;
250 8
            case $this->isTypeDate($type):
251 8
                $length = $buffer->readIntLength();
252 8
                if($length > 0) {
253 1
                    $year = $buffer->readInt2();
254 1
                    $month = $buffer->readInt1();
255 1
                    $day = $buffer->readInt1();
256
                    
257 1
                    $value = \sprintf('%04d-%02d-%02d', $year, $month, $day);
258
                } else {
259 7
                    $value = '0000-00-00';
260
                }
261 8
            break;
262 8
            case $this->isTypeDateTime($type):
263 8
                $value = $this->parseDateTime($type, $buffer);
264 8
            break;
1 ignored issue
show
Coding Style introduced by
Case breaking statement indented incorrectly; expected 16 spaces, found 12
Loading history...
265 8
            case ($type === 'TIME'):
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
266 8
                $value = $this->parseTime($buffer);
267 8
            break;
1 ignored issue
show
Coding Style introduced by
Case breaking statement indented incorrectly; expected 16 spaces, found 12
Loading history...
268
            default:
269
                throw new \InvalidArgumentException('Unknown column type (flags: '.$flags.', type: '.$type.')');
270
            break;
271
        }
272
        
273 35
        return $value;
274
    }
275
    
276
    /**
277
     * @param string  $type
278
     * @return bool
279
     */
280 35
    protected function isTypeString(string $type): bool {
281
        $types = array(
282 35
            'STRING', 'VARCHAR', 'VARSTRING', 'ENUM', 'SET', 'LONGBLOB',
283
            'MEDIUMBLOB', 'BLOB', 'TINYBLOB', 'GEMOTERY', 'BIT', 'DECIMAL',
284
            'NEWDECIMAL', 'JSON'
285
        );
286
        
287 35
        return \in_array($type, $types, true);
288
    }
289
    
290
    /**
291
     * @param string  $type
292
     * @return bool
293
     */
294 17
    protected function isTypeShortOrYear(string $type): bool {
295 17
        $types = array('SHORT', 'YEAR');
296 17
        return \in_array($type, $types, true);
297
    }
298
    
299
    /**
300
     * @param string  $type
301
     * @return bool
302
     */
303 17
    protected function isTypeInt24orLong(string $type): bool {
304 17
        $types = array('INT24', 'LONG');
305 17
        return \in_array($type, $types, true);
306
    }
307
    
308
    /**
309
     * @param string  $type
310
     * @return bool
311
     */
312 8
    protected function isTypeDate(string $type): bool {
313 8
        $types = array('DATE', 'NEWDATE');
314 8
        return \in_array($type, $types, true);
315
    }
316
    
317
    /**
318
     * @param string  $type
319
     * @return bool
320
     */
321 8
    protected function isTypeDateTime(string $type): bool {
322 8
        $types = array('DATETIME', 'TIMESTAMP');
323 8
        return \in_array($type, $types, true);
324
    }
325
    
326
    /**
327
     * Parses a DATETIME or TIMESTAMP value.
328
     * @param string                $type
329
     * @param \Plasma\BinaryBuffer  $buffer
330
     * @return mixed
331
     */
332 8
    function parseDateTime(string $type, \Plasma\BinaryBuffer $buffer) {
333 8
        $length = $buffer->readIntLength();
334 8
        if($length > 0) {
335 2
            $year = $buffer->readInt2();
336 2
            $month = $buffer->readInt1();
337 2
            $day = $buffer->readInt1();
338
            
339 2
            if($length > 4) {
340 1
                $hour = $buffer->readInt1();
341 1
                $min = $buffer->readInt1();
342 1
                $sec = $buffer->readInt1();
343
            } else {
344 1
                $hour = 0;
345 1
                $min = 0;
346 1
                $sec = 0;
347
            }
348
            
349 2
            if($length > 7) {
350
                $microI = $buffer->readInt4();
351
            } else {
352 2
                $microI = 0;
353
            }
354
            
355 2
            $micro = \str_pad($microI, 6, '0', \STR_PAD_LEFT);
356 2
            $micro = \substr($micro, 0, 3).' '.\substr($micro, 3);
357
            
358 2
            $value = \sprintf('%04d-%02d-%02d %02d:%02d:%02d'.($microI > 0 ? '.%s' : ''), $year, $month, $day, $hour, $min, $sec, $micro);
359
            
360 2
            if($type === 'TIMESTAMP') {
361 2
                $value = \DateTime::createFromFormat('Y-m-d H:i:s'.($microI > 0 ? '.u' : ''), $value)->getTimestamp();
362
            }
363
        } else {
364 8
            $value = '0000-00-00 00:00:00.000 000';
365
        }
366
        
367 8
        return $value;
368
    }
369
    
370
    /**
371
     * Parses a TIME value.
372
     * @param \Plasma\BinaryBuffer  $buffer
373
     * @return mixed
374
     */
375 8
    function parseTime(\Plasma\BinaryBuffer $buffer) {
376 8
        $length = $buffer->readIntLength();
377 8
        if($length > 1) {
378 1
            $sign = $buffer->readInt1();
379 1
            $days = $buffer->readInt4();
380
            
381 1
            if($sign === 1) {
382
                $days *= -1;
383
            }
384
            
385 1
            $hour = $buffer->readInt1();
386 1
            $min = $buffer->readInt1();
387 1
            $sec = $buffer->readInt1();
388
            
389 1
            if($length > 8) {
390
                $microI = $buffer->readInt4();
391
            } else {
392 1
                $microI = 0;
393
            }
394
            
395 1
            $micro = \str_pad($microI, 6, '0', \STR_PAD_LEFT);
396 1
            $micro = \substr($micro, 0, 3).' '.\substr($micro, 3);
397
            
398 1
            $value = \sprintf('%dd %02d:%02d:%02d'.($microI > 0 ? '.%s' : ''), $days, $hour, $min, $sec, $micro);
399
        } else {
400 7
            $value = '0d 00:00:00';
401
        }
402
        
403 8
        return $value;
404
    }
405
    
406
    /**
407
     * @param \Plasma\ColumnDefinitionInterface  $column
408
     * @param string|int                         $value
409
     * @return string|int
410
     */
411 7
    protected function zeroFillInts(\Plasma\ColumnDefinitionInterface $column, $value) {
412 7
        $flags = $column->getFlags();
413
        
414 7
        if(($flags & \Plasma\Drivers\MySQL\FieldFlags::ZEROFILL_FLAG) !== 0) {
415 7
            $value = \str_pad(((string) $value), $column->getLength(), '0', \STR_PAD_LEFT);
416
        }
417
        
418 7
        return $value;
419
    }
420
}
421