diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 9cd53a759..8242715d4 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -1398,4 +1398,8 @@ abstract public function setUTCDatetime(string $value): mixed; */ abstract public function setSupportForAttributes(bool $support): bool; + /** + * @return int + */ + abstract public function getMaxVarcharLength(): int; } diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index ea2f4781f..d6d7a723d 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1934,4 +1934,16 @@ public function getSupportForOptionalSpatialAttributeWithExistingRows(): bool { return true; } + + /** + * @return int + */ + public function getMaxVarcharLength(): int + { + /** + * Max varchar in MySQL:16381 | MariaDB:16382 + * Will return the max the index length can use for smaller page size + */ + return $this->getMaxIndexLength(); + } } diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index 82afb0eaa..1436b32d2 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -3189,4 +3189,9 @@ public function getTenantQuery(string $collection, string $alias = ''): string { return ''; } + + public function getMaxVarcharLength(): int + { + return 0; + } } diff --git a/src/Database/Adapter/Pool.php b/src/Database/Adapter/Pool.php index 6eba933ec..535d4727f 100644 --- a/src/Database/Adapter/Pool.php +++ b/src/Database/Adapter/Pool.php @@ -609,4 +609,9 @@ public function setSupportForAttributes(bool $support): bool { return $this->delegate(__FUNCTION__, \func_get_args()); } + + public function getMaxVarcharLength(): int + { + return $this->delegate(__FUNCTION__, \func_get_args()); + } } diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index 1b7b67fbd..f0b811926 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -2321,4 +2321,12 @@ public function decodePolygon(string $wkb): array return $rings; // array of rings, each ring is array of [x,y] } + + /** + * @return int + */ + public function getMaxVarcharLength(): int + { + return 16383; + } } diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index eac1b3ad1..ba48a5ff0 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -1849,14 +1849,6 @@ public function getHostname(): string } } - /** - * @return int - */ - public function getMaxVarcharLength(): int - { - return 16381; // Floor value for Postgres:16383 | MySQL:16381 | MariaDB:16382 - } - /** * Size of POINT spatial type * diff --git a/tests/e2e/Adapter/Scopes/AttributeTests.php b/tests/e2e/Adapter/Scopes/AttributeTests.php index 8add6b1d8..caa9dfd17 100644 --- a/tests/e2e/Adapter/Scopes/AttributeTests.php +++ b/tests/e2e/Adapter/Scopes/AttributeTests.php @@ -64,7 +64,7 @@ public function testCreateDeleteAttribute(): void $database->createCollection('attributes'); $this->assertEquals(true, $database->createAttribute('attributes', 'string1', Database::VAR_STRING, 128, true)); - $this->assertEquals(true, $database->createAttribute('attributes', 'string2', Database::VAR_STRING, 16382 + 1, true)); + $this->assertEquals(true, $database->createAttribute('attributes', 'string2', Database::VAR_STRING, 20000, true)); $this->assertEquals(true, $database->createAttribute('attributes', 'string3', Database::VAR_STRING, 65535 + 1, true)); $this->assertEquals(true, $database->createAttribute('attributes', 'string4', Database::VAR_STRING, 16777215 + 1, true)); $this->assertEquals(true, $database->createAttribute('attributes', 'integer', Database::VAR_INTEGER, 0, true)); @@ -979,23 +979,27 @@ public function testExceptionWidthLimit(): void return; } + $limit = floor(($database->getAdapter()->getDocumentSizeLimit() / 4) / $database->getAdapter()->getMaxVarcharLength()); + $attributes = []; - $attributes[] = new Document([ - '$id' => ID::custom('varchar_16000'), - 'type' => Database::VAR_STRING, - 'size' => 16000, - 'required' => true, - 'default' => null, - 'signed' => true, - 'array' => false, - 'filters' => [], - ]); + for ($i = 1; $i < $limit; $i++) { + $attributes[] = new Document([ + '$id' => ID::custom('varchar_'.$i), + 'type' => Database::VAR_STRING, + 'size' => $database->getAdapter()->getMaxVarcharLength(), + 'required' => true, + 'default' => null, + 'signed' => true, + 'array' => false, + 'filters' => [], + ]); + } $attributes[] = new Document([ - '$id' => ID::custom('varchar_200'), + '$id' => ID::custom('breaking'), 'type' => Database::VAR_STRING, - 'size' => 200, + 'size' => $database->getAdapter()->getMaxVarcharLength(), 'required' => true, 'default' => null, 'signed' => true, @@ -1022,7 +1026,7 @@ public function testExceptionWidthLimit(): void $attribute = new Document([ '$id' => ID::custom('breaking'), 'type' => Database::VAR_STRING, - 'size' => 200, + 'size' => $database->getAdapter()->getMaxVarcharLength(), 'required' => true, 'default' => null, 'signed' => true, @@ -1039,7 +1043,7 @@ public function testExceptionWidthLimit(): void } try { - $database->createAttribute($collection->getId(), 'breaking', Database::VAR_STRING, 200, true); + $database->createAttribute($collection->getId(), 'breaking', Database::VAR_STRING, $database->getAdapter()->getMaxVarcharLength(), true); $this->fail('Failed to throw exception'); } catch (\Throwable $e) { $this->assertInstanceOf(LimitException::class, $e); @@ -1074,7 +1078,7 @@ public function testUpdateAttributeSize(): void // Go up in size // 0-16381 to 16382-65535 - $document = $this->updateStringAttributeSize(16382, $document); + $document = $this->updateStringAttributeSize(20000, $document); // 16382-65535 to 65536-16777215 $document = $this->updateStringAttributeSize(65536, $document); diff --git a/tests/e2e/Adapter/Scopes/CollectionTests.php b/tests/e2e/Adapter/Scopes/CollectionTests.php index 2f94ff09c..27b3d451e 100644 --- a/tests/e2e/Adapter/Scopes/CollectionTests.php +++ b/tests/e2e/Adapter/Scopes/CollectionTests.php @@ -605,45 +605,19 @@ public function testRowSizeToLarge(): void * 65535 / 4 = 16383 MB4 */ $collection_1 = $database->createCollection('row_size_1'); - $collection_2 = $database->createCollection('row_size_2'); - $this->assertEquals(true, $database->createAttribute($collection_1->getId(), 'attr_1', Database::VAR_STRING, 16000, true)); + $limit = floor(($database->getAdapter()->getDocumentSizeLimit() / 4) / $database->getAdapter()->getMaxVarcharLength()); - try { - $database->createAttribute($collection_1->getId(), 'attr_2', Database::VAR_STRING, Database::LENGTH_KEY, true); - $this->fail('Failed to throw exception'); - } catch (Exception $e) { - $this->assertInstanceOf(LimitException::class, $e); + for ($i = 1; $i < $limit; $i++) { + $this->assertEquals(true, $database->createAttribute($collection_1->getId(), 'attr_'.$i, Database::VAR_STRING, $database->getAdapter()->getMaxVarcharLength(), true)); } - /** - * Relation takes length of Database::LENGTH_KEY so exceeding getDocumentSizeLimit - */ - try { - $database->createRelationship( - collection: $collection_2->getId(), - relatedCollection: $collection_1->getId(), - type: Database::RELATION_ONE_TO_ONE, - twoWay: true, - ); - - $this->fail('Failed to throw exception'); - } catch (Exception $e) { - $this->assertInstanceOf(LimitException::class, $e); - } - - try { - $database->createRelationship( - collection: $collection_1->getId(), - relatedCollection: $collection_2->getId(), - type: Database::RELATION_ONE_TO_ONE, - twoWay: true, - ); - + $this->assertEquals(true, $database->createAttribute($collection_1->getId(), 'attr_100', Database::VAR_STRING, $database->getAdapter()->getMaxVarcharLength(), true)); $this->fail('Failed to throw exception'); } catch (Exception $e) { $this->assertInstanceOf(LimitException::class, $e); + $this->assertEquals('Row width limit reached. Cannot create new attribute.', $e->getMessage()); } }