diff --git a/mirzaev/baza/system/database.php b/mirzaev/baza/system/database.php index 9da96d3..d3fb0b1 100755 --- a/mirzaev/baza/system/database.php +++ b/mirzaev/baza/system/database.php @@ -227,6 +227,7 @@ class database * Pack the record values * * @param record $record The record + * @const integer ARCH PHP architecture * * @return string Packed values */ @@ -246,10 +247,20 @@ class database // Packing the value and writing into the buffer of packed values $packed .= pack($column->type->value . $column->length, $value); - } else if (ARCH === 64 && - ($column->type === type::integer || - $column->type === type::integer_unsigned) - ) { + } + /** + * PHP builtin pack() ignores 64-bit integer values + * found on 64-bit PHP distributions + * @see https://www.php.net/manual/en/function.pack.php#109382 + * + * In case of integer type on 64-bit PHP distributions + * we got to splice 64-bit integer into two separate longs + * next to each other in binary representation + */ + else if (ARCH === 64 && + ($column->type === type::integer || + $column->type === type::integer_unsigned)) + { // Initialize variables for left and right masks of the 64-bit variable $left = 0xffffffff00000000; $right = 0x00000000ffffffff; @@ -259,7 +270,7 @@ class database // Bitwise and the value with the right mask to get the second half $r = $record->values()[$column->name] & $right; - // Pack into 64bit binary value + // Pack into 64bit binary value with two longs $packed .= pack('NN', $l, $r); } else { // Other types @@ -279,6 +290,7 @@ class database * Unpack binary values and implement them as a `record` instance * * @param array $binaries Binary values in the same order as the columns + * @const integer ARCH PHP architecture * * @return record The unpacked record from binary values */ @@ -307,12 +319,22 @@ class database // Writing into the buffer of read values $unpacked[] = $encoded; - } else if (ARCH === 64 && - ($column->type === type::integer || - $column->type === type::integer_unsigned) - ) { - // Unpacking the integer + } + /** + * PHP builtin pack() ignores 64-bit integer values + * found on 64-bit PHP distributions + * @see https://www.php.net/manual/en/function.pack.php#109382 + * + * In case of integer type on 64-bit PHP distributions + * we got to reconstruct previosly spliced integer value + */ + else if (ARCH === 64 && + ($column->type === type::integer || + $column->type === type::integer_unsigned)) + { + // Unpacking the integer values into array of two longs $value = unpack('N2', $binary ?? "\0"); + // Reconstructing original integer value $unpacked[] = $value[1] << 32 | $value[2]; } else { // Other types diff --git a/mirzaev/baza/system/enumerations/type.php b/mirzaev/baza/system/enumerations/type.php index 4182d25..3b10589 100755 --- a/mirzaev/baza/system/enumerations/type.php +++ b/mirzaev/baza/system/enumerations/type.php @@ -62,6 +62,14 @@ enum type: string { // Exit (success) + /** + * PHP builtin pack() ignores 64-bit integer values + * found on 64-bit PHP distributions + * @see https://www.php.net/manual/en/function.pack.php#109382 + * + * Architecture-specific size should always be returned + */ + // If type is (unsigned) integer, return size of integer return (strtoupper($this->value) === 'I') ? PHP_INT_SIZE