Skip to content

Commit

Permalink
Merge pull request #506 from utopia-php/calculate-row-size
Browse files Browse the repository at this point in the history
Row size too large.
  • Loading branch information
abnegate authored Jan 16, 2025
2 parents e75b30b + 18f74a2 commit d854206
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 180 deletions.
75 changes: 47 additions & 28 deletions src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,7 @@ public function getCountOfAttributes(Document $collection): int
{
$attributes = \count($collection->getAttribute('attributes') ?? []);

// +1 ==> virtual columns count as total, so add as buffer
return $attributes + static::getCountOfDefaultAttributes() + 1;
return $attributes + static::getCountOfDefaultAttributes();
}

/**
Expand Down Expand Up @@ -473,57 +472,77 @@ public static function getDocumentSizeLimit(): int
*/
public function getAttributeWidth(Document $collection): int
{
// Default collection has:
// `_id` int(11) => 4 bytes
// `_uid` char(255) => 1020 (255 bytes * 4 for utf8mb4)
// but this number seems to vary, so we give a +500 byte buffer
$total = 1500;
/**
* @link https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html
*
* `_id` bigint => 8 bytes
* `_uid` varchar(255) => 1021 (4 * 255 + 1) bytes
* `_tenant` int => 4 bytes
* `_createdAt` datetime(3) => 7 bytes
* `_updatedAt` datetime(3) => 7 bytes
* `_permissions` mediumtext => 20
*/

$total = 1067;

$attributes = $collection->getAttributes()['attributes'];

foreach ($attributes as $attribute) {
/**
* Json / Longtext
* only the pointer contributes 20 bytes
* data is stored externally
*/

if ($attribute['array'] ?? false) {
$total += 20;
continue;
}

switch ($attribute['type']) {
case Database::VAR_STRING:
/**
* Text / Mediumtext / Longtext
* only the pointer contributes 20 bytes to the row size
* data is stored externally
*/

$total += match (true) {
// 8 bytes length + 4 bytes for LONGTEXT
$attribute['size'] > 16777215 => 12,
// 8 bytes length + 3 bytes for MEDIUMTEXT
$attribute['size'] > 65535 => 11,
// 8 bytes length + 2 bytes for TEXT
$attribute['size'] > $this->getMaxVarcharLength() => 10,
// $size = $size * 4; // utf8mb4 up to 4 bytes per char
// 8 bytes length + 2 bytes for VARCHAR(>255)
$attribute['size'] > 255 => ($attribute['size'] * 4) + 2,
// $size = $size * 4; // utf8mb4 up to 4 bytes per char
// 8 bytes length + 1 bytes for VARCHAR(<=255)
default => ($attribute['size'] * 4) + 1,
$attribute['size'] > $this->getMaxVarcharLength() => 20,
$attribute['size'] > 255 => $attribute['size'] * 4 + 2, // VARCHAR(>255) + 2 length
default => $attribute['size'] * 4 + 1, // VARCHAR(<=255) + 1 length
};

break;

case Database::VAR_INTEGER:
if ($attribute['size'] >= 8) {
$total += 8; // BIGINT takes 8 bytes
$total += 8; // BIGINT 8 bytes
} else {
$total += 4; // INT takes 4 bytes
$total += 4; // INT 4 bytes
}
break;

case Database::VAR_FLOAT:
// DOUBLE takes 8 bytes
$total += 8;
$total += 8; // DOUBLE 8 bytes
break;

case Database::VAR_BOOLEAN:
// TINYINT(1) takes one byte
$total += 1;
$total += 1; // TINYINT(1) 1 bytes
break;

case Database::VAR_RELATIONSHIP:
// VARCHAR(255)
$total += Database::LENGTH_KEY * 4 + 2;
$total += Database::LENGTH_KEY * 4 + 1; // VARCHAR(<=255)
break;

case Database::VAR_DATETIME:
$total += 19; // 2022-06-26 14:46:24
/**
* 1 byte year + month
* 1 byte for the day
* 3 bytes for the hour, minute, and second
* 2 bytes miliseconds DATETIME(3)
*/
$total += 7;
break;
default:
throw new DatabaseException('Unknown type: ' . $attribute['type']);
Expand Down
8 changes: 5 additions & 3 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -5918,9 +5918,11 @@ private function validateSelections(Document $collection, array $queries): array
*/
public function getLimitForAttributes(): int
{
// If negative, return 0
// -1 ==> virtual columns count as total, so treat as buffer
return \max($this->adapter->getLimitForAttributes() - $this->adapter->getCountOfDefaultAttributes() - 1, 0);
if ($this->adapter->getLimitForAttributes() === 0) {
return 0;
}

return $this->adapter->getLimitForAttributes() - $this->adapter->getCountOfDefaultAttributes();
}

/**
Expand Down
Loading

0 comments on commit d854206

Please sign in to comment.