From af321ee78d1ed61b31dd25f5c797aff9072d47ef Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 16:11:19 +0530 Subject: [PATCH 01/17] Implement BIGINT support across database adapters and add getLimitForBigInt method - Added abstract method getLimitForBigInt to Adapter class. - Implemented getLimitForBigInt in Mongo, Pool, and SQL classes. - Updated MariaDB and Postgres adapters to handle VAR_BIGINT type. - Enhanced error messages for unknown types to include VAR_BIGINT. --- src/Database/Adapter.php | 7 +++++++ src/Database/Adapter/MariaDB.php | 11 +++++------ src/Database/Adapter/Mongo.php | 13 +++++++++++++ src/Database/Adapter/Pool.php | 5 +++++ src/Database/Adapter/Postgres.php | 10 ++++------ src/Database/Adapter/SQL.php | 23 ++++++++++++++++++----- 6 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index a0c1c238a..6a9560190 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -880,6 +880,13 @@ abstract public function getLimitForString(): int; */ abstract public function getLimitForInt(): int; + /** + * Get max BIGINT limit + * + * @return int + */ + abstract public function getLimitForBigInt(): int; + /** * Get maximum attributes limit. * diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 223f91e71..a3c4cad05 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1727,13 +1727,12 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool case Database::VAR_INTEGER: // We don't support zerofill: https://stackoverflow.com/a/5634147/2299554 $signed = ($signed) ? '' : ' UNSIGNED'; - - if ($size >= 8) { // INT = 4 bytes, BIGINT = 8 bytes - return 'BIGINT' . $signed; - } - return 'INT' . $signed; + case Database::VAR_BIGINT: + $signed = ($signed) ? '' : ' UNSIGNED'; + return 'BIGINT' . $signed; + case Database::VAR_FLOAT: $signed = ($signed) ? '' : ' UNSIGNED'; return 'DOUBLE' . $signed; @@ -1748,7 +1747,7 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool return 'DATETIME(3)'; default: - throw new DatabaseException('Unknown type: ' . $type . '. Must be one of ' . Database::VAR_STRING . ', ' . Database::VAR_VARCHAR . ', ' . Database::VAR_TEXT . ', ' . Database::VAR_MEDIUMTEXT . ', ' . Database::VAR_LONGTEXT . ', ' . Database::VAR_INTEGER . ', ' . Database::VAR_FLOAT . ', ' . Database::VAR_BOOLEAN . ', ' . Database::VAR_DATETIME . ', ' . Database::VAR_RELATIONSHIP . ', ' . Database::VAR_POINT . ', ' . Database::VAR_LINESTRING . ', ' . Database::VAR_POLYGON); + throw new DatabaseException('Unknown type: ' . $type . '. Must be one of ' . Database::VAR_STRING . ', ' . Database::VAR_VARCHAR . ', ' . Database::VAR_TEXT . ', ' . Database::VAR_MEDIUMTEXT . ', ' . Database::VAR_LONGTEXT . ', ' . Database::VAR_INTEGER . ', ' . Database::VAR_BIGINT . ', ' . Database::VAR_FLOAT . ', ' . Database::VAR_BOOLEAN . ', ' . Database::VAR_DATETIME . ', ' . Database::VAR_RELATIONSHIP . ', ' . Database::VAR_POINT . ', ' . Database::VAR_LINESTRING . ', ' . Database::VAR_POLYGON); } } diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index a61a59c3a..340dca1b6 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -1310,6 +1310,7 @@ public function castingAfter(Document $collection, Document $document): Document foreach ($value as &$node) { switch ($type) { case Database::VAR_INTEGER: + case Database::VAR_BIGINT: $node = (int)$node; break; case Database::VAR_DATETIME: @@ -2211,6 +2212,7 @@ private function getMongoTypeCode(string $appwriteType): string Database::VAR_MEDIUMTEXT => 'string', Database::VAR_LONGTEXT => 'string', Database::VAR_INTEGER => 'int', + Database::VAR_BIGINT => 'int', Database::VAR_FLOAT => 'double', Database::VAR_BOOLEAN => 'bool', Database::VAR_DATETIME => 'date', @@ -3004,6 +3006,17 @@ public function getLimitForInt(): int return 4294967295; } + /** + * Get max BIGINT limit + * + * @return int + */ + public function getLimitForBigInt(): int + { + // Mongo does not handle integers directly, so using MariaDB limit for now + return 18446744073709551615; + } + /** * Get maximum column limit. * Returns 0 to indicate no limit diff --git a/src/Database/Adapter/Pool.php b/src/Database/Adapter/Pool.php index e89be89ac..5c6073a36 100644 --- a/src/Database/Adapter/Pool.php +++ b/src/Database/Adapter/Pool.php @@ -328,6 +328,11 @@ public function getLimitForInt(): int return $this->delegate(__FUNCTION__, \func_get_args()); } + public function getLimitForBigInt(): int + { + return $this->delegate(__FUNCTION__, \func_get_args()); + } + public function getLimitForAttributes(): int { return $this->delegate(__FUNCTION__, \func_get_args()); diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index 8dcf72025..06f2b8086 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -1965,13 +1965,11 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool return 'TEXT'; // PostgreSQL doesn't have MEDIUMTEXT/LONGTEXT, use TEXT case Database::VAR_INTEGER: // We don't support zerofill: https://stackoverflow.com/a/5634147/2299554 - - if ($size >= 8) { // INT = 4 bytes, BIGINT = 8 bytes - return 'BIGINT'; - } - return 'INTEGER'; + case Database::VAR_BIGINT: + return 'BIGINT'; + case Database::VAR_FLOAT: return 'DOUBLE PRECISION'; @@ -2000,7 +1998,7 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool return "VECTOR({$size})"; default: - throw new DatabaseException('Unknown Type: ' . $type . '. Must be one of ' . Database::VAR_STRING . ', ' . Database::VAR_VARCHAR . ', ' . Database::VAR_TEXT . ', ' . Database::VAR_MEDIUMTEXT . ', ' . Database::VAR_LONGTEXT . ', ' . Database::VAR_INTEGER . ', ' . Database::VAR_FLOAT . ', ' . Database::VAR_BOOLEAN . ', ' . Database::VAR_DATETIME . ', ' . Database::VAR_RELATIONSHIP . ', ' . Database::VAR_OBJECT . ', ' . Database::VAR_POINT . ', ' . Database::VAR_LINESTRING . ', ' . Database::VAR_POLYGON); + throw new DatabaseException('Unknown Type: ' . $type . '. Must be one of ' . Database::VAR_STRING . ', ' . Database::VAR_VARCHAR . ', ' . Database::VAR_TEXT . ', ' . Database::VAR_MEDIUMTEXT . ', ' . Database::VAR_LONGTEXT . ', ' . Database::VAR_INTEGER . ', ' . Database::VAR_BIGINT . ', ' . Database::VAR_FLOAT . ', ' . Database::VAR_BOOLEAN . ', ' . Database::VAR_DATETIME . ', ' . Database::VAR_RELATIONSHIP . ', ' . Database::VAR_OBJECT . ', ' . Database::VAR_POINT . ', ' . Database::VAR_LINESTRING . ', ' . Database::VAR_POLYGON); } } diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index 8f0bd2db2..5efbf1a17 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -896,6 +896,19 @@ public function getLimitForInt(): int return 4294967295; } + /** + * Get max BIGINT limit + * + * @return int + */ + public function getLimitForBigInt(): int + { + // 2^64 - 1 + // 18446744073709551615 is the maximum value for a 64-bit unsigned integer + // 9223372036854775807 is the maximum value for a 64-bit signed integer + return 18446744073709551615; + } + /** * Get maximum column limit. * https://mariadb.com/kb/en/innodb-limitations/#limitations-on-schema @@ -1157,11 +1170,11 @@ public function getAttributeWidth(Document $collection): int break; case Database::VAR_INTEGER: - if ($attribute['size'] >= 8) { - $total += 8; // BIGINT 8 bytes - } else { - $total += 4; // INT 4 bytes - } + $total += 4; // INT 4 bytes + break; + + case Database::VAR_BIGINT: + $total += 8; // BIGINT 8 bytes break; case Database::VAR_FLOAT: From 3137084889c458f7d1224b45cfb7083ffad65398 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 16:11:51 +0530 Subject: [PATCH 02/17] Add support for VAR_BIGINT in Database and Attribute classes - Introduced VAR_BIGINT constant in Database class. - Updated Attribute class to include maxBigIntLength parameter and handle it in validation. - Ensured backwards compatibility for existing validator construction. - Enhanced validation logic to enforce size limits for VAR_BIGINT type. --- src/Database/Database.php | 2 ++ src/Database/Validator/Attribute.php | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index ac58d72f0..84fffaf7f 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -42,6 +42,7 @@ class Database // Simple Types public const VAR_STRING = 'string'; public const VAR_INTEGER = 'integer'; + public const VAR_BIGINT = 'bigint'; public const VAR_FLOAT = 'double'; public const VAR_BOOLEAN = 'boolean'; public const VAR_DATETIME = 'datetime'; @@ -2512,6 +2513,7 @@ private function validateAttribute( maxStringLength: $this->adapter->getLimitForString(), maxVarcharLength: $this->adapter->getMaxVarcharLength(), maxIntLength: $this->adapter->getLimitForInt(), + maxBigIntLength: $this->adapter->getLimitForBigInt(), supportForSchemaAttributes: $this->adapter->getSupportForSchemaAttributes(), supportForVectors: $this->adapter->getSupportForVectors(), supportForSpatialAttributes: $this->adapter->getSupportForSpatialAttributes(), diff --git a/src/Database/Validator/Attribute.php b/src/Database/Validator/Attribute.php index 021a85d97..16bd52dd8 100644 --- a/src/Database/Validator/Attribute.php +++ b/src/Database/Validator/Attribute.php @@ -31,6 +31,7 @@ class Attribute extends Validator * @param int $maxStringLength * @param int $maxVarcharLength * @param int $maxIntLength + * @param int $maxBigIntLength * @param bool $supportForSchemaAttributes * @param bool $supportForVectors * @param bool $supportForSpatialAttributes @@ -49,6 +50,7 @@ public function __construct( protected int $maxStringLength = 0, protected int $maxVarcharLength = 0, protected int $maxIntLength = 0, + protected int $maxBigIntLength = 0, protected bool $supportForSchemaAttributes = false, protected bool $supportForVectors = false, protected bool $supportForSpatialAttributes = false, @@ -59,6 +61,11 @@ public function __construct( protected bool $isMigrating = false, protected bool $sharedTables = false, ) { + // Keep backwards compatibility for existing validator construction sites. + if ($this->maxBigIntLength === 0) { + $this->maxBigIntLength = $this->maxIntLength; + } + foreach ($attributes as $attribute) { $key = \strtolower($attribute->getAttribute('key', $attribute->getAttribute('$id'))); $this->attributes[$key] = $attribute; @@ -337,6 +344,14 @@ public function checkType(Document $attribute): bool } break; + case Database::VAR_BIGINT: + $limit = ($signed) ? $this->maxBigIntLength / 2 : $this->maxBigIntLength; + if ($size > $limit) { + $this->message = 'Max size allowed for bigint is: ' . number_format($limit); + throw new DatabaseException($this->message); + } + break; + case Database::VAR_FLOAT: case Database::VAR_BOOLEAN: case Database::VAR_DATETIME: From b5c74471c907f336ac547f63c02d639ae4c8b4b1 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 16:12:05 +0530 Subject: [PATCH 03/17] Add tests for BIGINT attribute handling and validation limits - Introduced testCreateAttributesBigIntSizeLimit to verify exception handling for oversized BIGINT attributes. - Added testCreateDocumentWithBigIntType to ensure correct document creation and retrieval with BIGINT attributes. - Implemented testBigIntSizeTooLarge and testUnsignedBigIntSizeLimit to validate size constraints in the Attribute validator. --- tests/e2e/Adapter/Scopes/AttributeTests.php | 29 ++++++++++++ tests/e2e/Adapter/Scopes/DocumentTests.php | 28 +++++++++++ tests/unit/Validator/AttributeTest.php | 52 +++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/tests/e2e/Adapter/Scopes/AttributeTests.php b/tests/e2e/Adapter/Scopes/AttributeTests.php index bf376d101..4f5d6361c 100644 --- a/tests/e2e/Adapter/Scopes/AttributeTests.php +++ b/tests/e2e/Adapter/Scopes/AttributeTests.php @@ -2221,6 +2221,35 @@ public function testCreateAttributesIntegerSizeLimit(): void } } + public function testCreateAttributesBigIntSizeLimit(): void + { + /** @var Database $database */ + $database = $this->getDatabase(); + + if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { + $this->expectNotToPerformAssertions(); + return; + } + + $database->createCollection(__FUNCTION__); + + $limit = $database->getAdapter()->getLimitForBigInt() / 2; + + $attributes = [[ + '$id' => 'foo', + 'type' => Database::VAR_BIGINT, + 'size' => (int)$limit + 1, + 'required' => false + ]]; + + try { + $database->createAttributes(__FUNCTION__, $attributes); + $this->fail('Expected DatabaseException not thrown'); + } catch (\Throwable $e) { + $this->assertInstanceOf(DatabaseException::class, $e); + } + } + public function testCreateAttributesSuccessMultiple(): void { /** @var Database $database */ diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index d16004d32..90184fc8d 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -103,6 +103,34 @@ public function testBigintSequence(): void } } + public function testCreateDocumentWithBigIntType(): void + { + /** @var Database $database */ + $database = $this->getDatabase(); + + $database->createCollection(__FUNCTION__); + $this->assertEquals(true, $database->createAttribute(__FUNCTION__, 'bigint_signed', Database::VAR_BIGINT, 0, true)); + $this->assertEquals(true, $database->createAttribute(__FUNCTION__, 'bigint_unsigned', Database::VAR_BIGINT, 0, true, signed: false)); + + $document = $database->createDocument(__FUNCTION__, new Document([ + '$id' => 'bigint-type-doc', + '$permissions' => [Permission::read(Role::any())], + 'bigint_signed' => -Database::MAX_BIG_INT, + 'bigint_unsigned' => Database::MAX_BIG_INT, + ])); + + $this->assertIsInt($document->getAttribute('bigint_signed')); + $this->assertEquals(-Database::MAX_BIG_INT, $document->getAttribute('bigint_signed')); + $this->assertIsInt($document->getAttribute('bigint_unsigned')); + $this->assertEquals(Database::MAX_BIG_INT, $document->getAttribute('bigint_unsigned')); + + $results = $database->find(__FUNCTION__, [ + Query::equal('bigint_unsigned', [Database::MAX_BIG_INT]) + ]); + $this->assertCount(1, $results); + $this->assertEquals('bigint-type-doc', $results[0]->getId()); + } + public function testCreateDocument(): Document { /** @var Database $database */ diff --git a/tests/unit/Validator/AttributeTest.php b/tests/unit/Validator/AttributeTest.php index 2f7303cd1..2fba4441f 100644 --- a/tests/unit/Validator/AttributeTest.php +++ b/tests/unit/Validator/AttributeTest.php @@ -1139,6 +1139,58 @@ public function testUnsignedIntegerSizeTooLarge(): void $validator->isValid($attribute); } + public function testBigIntSizeTooLarge(): void + { + $validator = new Attribute( + attributes: [], + maxStringLength: 16777216, + maxVarcharLength: 65535, + maxIntLength: PHP_INT_MAX, + maxBigIntLength: 200, + ); + + $attribute = new Document([ + '$id' => ID::custom('counter'), + 'key' => 'counter', + 'type' => Database::VAR_BIGINT, + 'size' => 101, + 'required' => false, + 'default' => null, + 'signed' => true, + 'array' => false, + 'filters' => [], + ]); + + $this->expectException(DatabaseException::class); + $this->expectExceptionMessage('Max size allowed for bigint is: 100'); + $validator->isValid($attribute); + } + + public function testUnsignedBigIntSizeLimit(): void + { + $validator = new Attribute( + attributes: [], + maxStringLength: 16777216, + maxVarcharLength: 65535, + maxIntLength: PHP_INT_MAX, + maxBigIntLength: 200, + ); + + $attribute = new Document([ + '$id' => ID::custom('counter'), + 'key' => 'counter', + 'type' => Database::VAR_BIGINT, + 'size' => 200, + 'required' => false, + 'default' => null, + 'signed' => false, + 'array' => false, + 'filters' => [], + ]); + + $this->assertTrue($validator->isValid($attribute)); + } + public function testDuplicateAttributeIdCaseInsensitive(): void { $validator = new Attribute( From bd14576c2f387a676f8e11411fc62d73e312d025 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 17:56:33 +0530 Subject: [PATCH 04/17] Update getLimitForBigInt method to return 4294967295 for Mongo and SQL adapters - Adjusted the getLimitForBigInt method in both Mongo and SQL classes to return 4294967295, reflecting the maximum value for a 32-bit unsigned integer. - Updated comments to clarify the handling of integer limits in PHP. --- src/Database/Adapter/Mongo.php | 2 +- src/Database/Adapter/SQL.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index 340dca1b6..509316bdd 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -3014,7 +3014,7 @@ public function getLimitForInt(): int public function getLimitForBigInt(): int { // Mongo does not handle integers directly, so using MariaDB limit for now - return 18446744073709551615; + return 4294967295; } /** diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index 5efbf1a17..f767c7fe2 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -906,7 +906,8 @@ public function getLimitForBigInt(): int // 2^64 - 1 // 18446744073709551615 is the maximum value for a 64-bit unsigned integer // 9223372036854775807 is the maximum value for a 64-bit signed integer - return 18446744073709551615; + // in php we can't represent 64-bit integer, so greater than 4294967295 will be treated as bigint + return 4294967295; } /** From acfeae1aa37f29bb84381eec5c7d70a3565ea4ae Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 18:00:44 +0530 Subject: [PATCH 05/17] updated bigint mongo --- src/Database/Adapter/Mongo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index 509316bdd..4596f4027 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -2212,7 +2212,7 @@ private function getMongoTypeCode(string $appwriteType): string Database::VAR_MEDIUMTEXT => 'string', Database::VAR_LONGTEXT => 'string', Database::VAR_INTEGER => 'int', - Database::VAR_BIGINT => 'int', + Database::VAR_BIGINT => 'long', Database::VAR_FLOAT => 'double', Database::VAR_BOOLEAN => 'bool', Database::VAR_DATETIME => 'date', From 07358a5c2f6b7d50ba284700900ec6c1416a9ba4 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 18:06:27 +0530 Subject: [PATCH 06/17] Enhance BIGINT handling in MariaDB and SQL adapters - Updated MariaDB adapter to return 'BIGINT' for sizes greater than or equal to 8 bytes. - Modified SQL adapter to correctly calculate total size for VAR_INTEGER based on the attribute size, distinguishing between INT and BIGINT. --- src/Database/Adapter/MariaDB.php | 5 +++++ src/Database/Adapter/SQL.php | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index a3c4cad05..0faaa8622 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1727,6 +1727,11 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool case Database::VAR_INTEGER: // We don't support zerofill: https://stackoverflow.com/a/5634147/2299554 $signed = ($signed) ? '' : ' UNSIGNED'; + + if ($size >= 8) { // INT = 4 bytes, BIGINT = 8 bytes + return 'BIGINT' . $signed; + } + return 'INT' . $signed; case Database::VAR_BIGINT: diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index f767c7fe2..a64dbec39 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -1171,7 +1171,11 @@ public function getAttributeWidth(Document $collection): int break; case Database::VAR_INTEGER: - $total += 4; // INT 4 bytes + if ($attribute['size'] >= 8) { + $total += 8; // BIGINT 8 bytes + } else { + $total += 4; // INT 4 bytes + } break; case Database::VAR_BIGINT: From 909d8a502dc7e7050b7cf18e974004d7ce4cf6bd Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 18:13:50 +0530 Subject: [PATCH 07/17] Add VAR_BIGINT to Database class attribute types - Included VAR_BIGINT in the list of attribute types in the Database class. - Ensured consistency in handling BIGINT attributes across the database implementation. --- src/Database/Database.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index 84fffaf7f..e96b9a479 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -2609,6 +2609,7 @@ protected function validateDefaultTypes(string $type, mixed $default): void self::VAR_MEDIUMTEXT, self::VAR_LONGTEXT, self::VAR_INTEGER, + self::VAR_BIGINT, self::VAR_FLOAT, self::VAR_BOOLEAN, self::VAR_DATETIME, @@ -2977,6 +2978,7 @@ public function updateAttribute(string $collection, string $id, ?string $type = self::VAR_MEDIUMTEXT, self::VAR_LONGTEXT, self::VAR_INTEGER, + self::VAR_BIGINT, self::VAR_FLOAT, self::VAR_BOOLEAN, self::VAR_DATETIME, From f2acd8c0787955f72f70ac675ff2d953363b452f Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 18:18:14 +0530 Subject: [PATCH 08/17] Enhance BIGINT size limit validation in Database class - Added handling for VAR_BIGINT in the size limit validation logic. - Implemented exception throwing for oversized BIGINT attributes to ensure proper error handling. --- src/Database/Database.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index e96b9a479..5aa61d4e3 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -2584,6 +2584,7 @@ protected function validateDefaultTypes(string $type, mixed $default): void } break; case self::VAR_INTEGER: + case self::VAR_BIGINT: case self::VAR_FLOAT: case self::VAR_BOOLEAN: if ($type !== $defaultType) { @@ -2912,6 +2913,12 @@ public function updateAttribute(string $collection, string $id, ?string $type = throw new DatabaseException('Max size allowed for int is: ' . number_format($limit)); } break; + case self::VAR_BIGINT: + $limit = ($signed) ? $this->adapter->getLimitForBigInt() / 2 : $this->adapter->getLimitForBigInt(); + if ($size > $limit) { + throw new DatabaseException('Max size allowed for bigint is: ' . number_format($limit)); + } + break; case self::VAR_FLOAT: case self::VAR_BOOLEAN: case self::VAR_DATETIME: From 602eefcf8ea251b239ae84bce3ce4284d7aecade Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 18:19:53 +0530 Subject: [PATCH 09/17] Refine BIGINT handling in Structure and Filter validators - Updated validation logic to correctly determine bit size for VAR_BIGINT and VAR_INTEGER based on attribute size. - Ensured consistent handling of signed and unsigned integers across both validators. --- src/Database/Validator/Query/Filter.php | 3 ++- src/Database/Validator/Structure.php | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Database/Validator/Query/Filter.php b/src/Database/Validator/Query/Filter.php index dd07e44c8..83f40fba6 100644 --- a/src/Database/Validator/Query/Filter.php +++ b/src/Database/Validator/Query/Filter.php @@ -153,9 +153,10 @@ protected function isValidAttributeAndValues(string $attribute, array $values, s break; case Database::VAR_INTEGER: + case Database::VAR_BIGINT: $size = $attributeSchema['size'] ?? 4; $signed = $attributeSchema['signed'] ?? true; - $bits = $size >= 8 ? 64 : 32; + $bits = ($attributeType === Database::VAR_BIGINT || $size >= 8) ? 64 : 32; // For 64-bit unsigned, use signed since PHP doesn't support true 64-bit unsigned $unsigned = !$signed && $bits < 64; $validator = new Integer(false, $bits, $unsigned); diff --git a/src/Database/Validator/Structure.php b/src/Database/Validator/Structure.php index a65734dbd..09c4efd29 100644 --- a/src/Database/Validator/Structure.php +++ b/src/Database/Validator/Structure.php @@ -352,13 +352,15 @@ protected function checkForInvalidAttributeValues(array $structure, array $keys) break; case Database::VAR_INTEGER: + case Database::VAR_BIGINT: // Determine bit size based on attribute size in bytes - $bits = $size >= 8 ? 64 : 32; + // BIGINT is always 64-bit in SQL adapters; VAR_INTEGER uses size to decide. + $bits = ($type === Database::VAR_BIGINT || $size >= 8) ? 64 : 32; // For 64-bit unsigned, use signed since PHP doesn't support true 64-bit unsigned // The Range validator will restrict to positive values only $unsigned = !$signed && $bits < 64; $validators[] = new Integer(false, $bits, $unsigned); - $max = $size >= 8 ? Database::MAX_BIG_INT : Database::MAX_INT; + $max = $bits === 64 ? Database::MAX_BIG_INT : Database::MAX_INT; $min = $signed ? -$max : 0; $validators[] = new Range($min, $max, Database::VAR_INTEGER); break; From 14828d9dae2503fa73d1bbfa7a54efb3319755e3 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Fri, 27 Mar 2026 18:32:38 +0530 Subject: [PATCH 10/17] Refine BIGINT type determination in Postgres adapter - Updated Postgres adapter to return 'BIGINT' for sizes greater than or equal to 8 bytes in the type determination logic for VAR_INTEGER. - Ensured consistent handling of integer types across the database implementation. --- src/Database/Adapter/Postgres.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index 06f2b8086..7362dc265 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -1965,6 +1965,11 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool return 'TEXT'; // PostgreSQL doesn't have MEDIUMTEXT/LONGTEXT, use TEXT case Database::VAR_INTEGER: // We don't support zerofill: https://stackoverflow.com/a/5634147/2299554 + + if ($size >= 8) { // INT = 4 bytes, BIGINT = 8 bytes + return 'BIGINT'; + } + return 'INTEGER'; case Database::VAR_BIGINT: From 080de0e82e30a48c7368e6180bb58a88a62dded1 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 11:37:06 +0530 Subject: [PATCH 11/17] Remove BIGINT size limit validation from Database and Validator classes - Eliminated size limit checks for VAR_BIGINT in the Database and Attribute classes to allow larger values. - Updated Mongo and SQL adapters to return a constant for BIGINT limits, ensuring consistent handling across implementations. - Refactored tests to reflect the removal of size constraints and validate successful attribute creation without exceptions. --- src/Database/Adapter/Mongo.php | 3 +-- src/Database/Adapter/SQL.php | 6 +----- src/Database/Database.php | 4 ---- src/Database/Validator/Attribute.php | 5 ----- tests/e2e/Adapter/Scopes/AttributeTests.php | 20 ++++++++++++-------- tests/unit/Validator/AttributeTest.php | 6 ++---- 6 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index 4596f4027..84fbaf80a 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -3013,8 +3013,7 @@ public function getLimitForInt(): int */ public function getLimitForBigInt(): int { - // Mongo does not handle integers directly, so using MariaDB limit for now - return 4294967295; + return Database::MAX_BIG_INT; } /** diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index a64dbec39..199cfcce0 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -903,11 +903,7 @@ public function getLimitForInt(): int */ public function getLimitForBigInt(): int { - // 2^64 - 1 - // 18446744073709551615 is the maximum value for a 64-bit unsigned integer - // 9223372036854775807 is the maximum value for a 64-bit signed integer - // in php we can't represent 64-bit integer, so greater than 4294967295 will be treated as bigint - return 4294967295; + return Database::MAX_BIG_INT; } /** diff --git a/src/Database/Database.php b/src/Database/Database.php index 5aa61d4e3..a2c8ca7c2 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -2914,10 +2914,6 @@ public function updateAttribute(string $collection, string $id, ?string $type = } break; case self::VAR_BIGINT: - $limit = ($signed) ? $this->adapter->getLimitForBigInt() / 2 : $this->adapter->getLimitForBigInt(); - if ($size > $limit) { - throw new DatabaseException('Max size allowed for bigint is: ' . number_format($limit)); - } break; case self::VAR_FLOAT: case self::VAR_BOOLEAN: diff --git a/src/Database/Validator/Attribute.php b/src/Database/Validator/Attribute.php index 16bd52dd8..83e1f7174 100644 --- a/src/Database/Validator/Attribute.php +++ b/src/Database/Validator/Attribute.php @@ -345,11 +345,6 @@ public function checkType(Document $attribute): bool break; case Database::VAR_BIGINT: - $limit = ($signed) ? $this->maxBigIntLength / 2 : $this->maxBigIntLength; - if ($size > $limit) { - $this->message = 'Max size allowed for bigint is: ' . number_format($limit); - throw new DatabaseException($this->message); - } break; case Database::VAR_FLOAT: diff --git a/tests/e2e/Adapter/Scopes/AttributeTests.php b/tests/e2e/Adapter/Scopes/AttributeTests.php index 4f5d6361c..7543fad73 100644 --- a/tests/e2e/Adapter/Scopes/AttributeTests.php +++ b/tests/e2e/Adapter/Scopes/AttributeTests.php @@ -2221,7 +2221,8 @@ public function testCreateAttributesIntegerSizeLimit(): void } } - public function testCreateAttributesBigIntSizeLimit(): void + + public function testCreateAttributesBigIntIgnoresSizeLimit(): void { /** @var Database $database */ $database = $this->getDatabase(); @@ -2234,20 +2235,23 @@ public function testCreateAttributesBigIntSizeLimit(): void $database->createCollection(__FUNCTION__); $limit = $database->getAdapter()->getLimitForBigInt() / 2; + $size = (int)$limit + 1; $attributes = [[ '$id' => 'foo', 'type' => Database::VAR_BIGINT, - 'size' => (int)$limit + 1, + 'size' => $size, 'required' => false ]]; - try { - $database->createAttributes(__FUNCTION__, $attributes); - $this->fail('Expected DatabaseException not thrown'); - } catch (\Throwable $e) { - $this->assertInstanceOf(DatabaseException::class, $e); - } + $result = $database->createAttributes(__FUNCTION__, $attributes); + $this->assertTrue($result); + + $collection = $database->getCollection(__FUNCTION__); + $attrs = $collection->getAttribute('attributes'); + $this->assertCount(1, $attrs); + $this->assertEquals('foo', $attrs[0]['$id']); + $this->assertEquals($size, $attrs[0]['size']); } public function testCreateAttributesSuccessMultiple(): void diff --git a/tests/unit/Validator/AttributeTest.php b/tests/unit/Validator/AttributeTest.php index 2fba4441f..fd82c1fd8 100644 --- a/tests/unit/Validator/AttributeTest.php +++ b/tests/unit/Validator/AttributeTest.php @@ -1139,7 +1139,7 @@ public function testUnsignedIntegerSizeTooLarge(): void $validator->isValid($attribute); } - public function testBigIntSizeTooLarge(): void + public function testBigIntSizeNotLimited(): void { $validator = new Attribute( attributes: [], @@ -1161,9 +1161,7 @@ public function testBigIntSizeTooLarge(): void 'filters' => [], ]); - $this->expectException(DatabaseException::class); - $this->expectExceptionMessage('Max size allowed for bigint is: 100'); - $validator->isValid($attribute); + $this->assertTrue($validator->isValid($attribute)); } public function testUnsignedBigIntSizeLimit(): void From 73e917e57f287778d78694308252f5ad05de8bdd Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 11:43:36 +0530 Subject: [PATCH 12/17] Add support for VAR_BIGINT in Database class and corresponding tests - Included VAR_BIGINT in the whitelist for attribute types in the Database class. - Implemented a new test to validate the creation, updating, and atomic operations for BIGINT attributes in the DocumentTests. - Ensured that the new tests confirm correct behavior for incrementing and decrementing BIGINT values. --- src/Database/Database.php | 2 ++ tests/e2e/Adapter/Scopes/DocumentTests.php | 39 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index a2c8ca7c2..77246d884 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -7430,6 +7430,7 @@ public function increaseDocumentAttribute( $whiteList = [ self::VAR_INTEGER, + self::VAR_BIGINT, self::VAR_FLOAT ]; @@ -7528,6 +7529,7 @@ public function decreaseDocumentAttribute( $whiteList = [ self::VAR_INTEGER, + self::VAR_BIGINT, self::VAR_FLOAT ]; diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index 90184fc8d..5567ce844 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -1495,6 +1495,45 @@ public function testIncreaseDecrease(): Document return $document; } + public function testCreateUpdateBigIntAndIncrementDecrement(): void + { + /** @var Database $database */ + $database = $this->getDatabase(); + + $collection = 'bigint_update_increase_decrease'; + $database->createCollection($collection); + + $this->assertEquals(true, $database->createAttribute($collection, 'inc', Database::VAR_BIGINT, 8, true)); + $this->assertEquals(true, $database->createAttribute($collection, 'dec', Database::VAR_BIGINT, 8, true)); + + $document = $database->createDocument($collection, new Document([ + 'inc' => 10, + 'dec' => 10, + '$permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ] + ])); + + $this->assertIsInt($document->getAttribute('inc')); + $this->assertEquals(10, $document->getAttribute('inc')); + + // Verify regular update works for bigint attributes + $updated = $database->updateDocument($collection, $document->getId(), new Document([ + 'inc' => 20, + ])); + $this->assertEquals(20, $updated->getAttribute('inc')); + + // Verify atomic increment/decrement supports bigint schema attributes + $afterInc = $database->increaseDocumentAttribute($collection, $document->getId(), 'inc', 5, 30); + $this->assertEquals(25, $afterInc->getAttribute('inc')); + + $afterDec = $database->decreaseDocumentAttribute($collection, $document->getId(), 'dec', 3, 7); + $this->assertEquals(7, $afterDec->getAttribute('dec')); + } + /** * @depends testIncreaseDecrease */ From ef5c77972a95129eb929cce6c8f7c674db930ec9 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 12:01:05 +0530 Subject: [PATCH 13/17] updated tests --- src/Database/Database.php | 3 +++ tests/e2e/Adapter/Scopes/AttributeTests.php | 2 +- tests/e2e/Adapter/Scopes/DocumentTests.php | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 77246d884..0e15f26f8 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -8941,6 +8941,9 @@ public function casting(Document $collection, Document $document): Document case self::VAR_INTEGER: $node = (int)$node; break; + case self::VAR_BIGINT: + $node = (int)$node; + break; case self::VAR_FLOAT: $node = (float)$node; break; diff --git a/tests/e2e/Adapter/Scopes/AttributeTests.php b/tests/e2e/Adapter/Scopes/AttributeTests.php index 7543fad73..3c5633734 100644 --- a/tests/e2e/Adapter/Scopes/AttributeTests.php +++ b/tests/e2e/Adapter/Scopes/AttributeTests.php @@ -2222,7 +2222,7 @@ public function testCreateAttributesIntegerSizeLimit(): void } - public function testCreateAttributesBigIntIgnoresSizeLimit(): void + public function testCreateAttributesBigInt(): void { /** @var Database $database */ $database = $this->getDatabase(); diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index 5567ce844..673f57409 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -1522,7 +1522,7 @@ public function testCreateUpdateBigIntAndIncrementDecrement(): void // Verify regular update works for bigint attributes $updated = $database->updateDocument($collection, $document->getId(), new Document([ - 'inc' => 20, + 'inc' => 20 ])); $this->assertEquals(20, $updated->getAttribute('inc')); From 4490a49ac3f451386ba65c473afe25d36394fdb1 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 19:45:12 +0530 Subject: [PATCH 14/17] big int validator for attribute --- src/Database/Validator/Attribute.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Database/Validator/Attribute.php b/src/Database/Validator/Attribute.php index 83e1f7174..c2f0f54df 100644 --- a/src/Database/Validator/Attribute.php +++ b/src/Database/Validator/Attribute.php @@ -430,6 +430,7 @@ public function checkType(Document $attribute): bool Database::VAR_MEDIUMTEXT, Database::VAR_LONGTEXT, Database::VAR_INTEGER, + Database::VAR_BIGINT, Database::VAR_FLOAT, Database::VAR_BOOLEAN, Database::VAR_DATETIME, From 4c5aeb1ff936db19acfd93add8a86efc397a43ab Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 19:48:18 +0530 Subject: [PATCH 15/17] updated --- src/Database/Validator/Attribute.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Database/Validator/Attribute.php b/src/Database/Validator/Attribute.php index c2f0f54df..97fdb4c3e 100644 --- a/src/Database/Validator/Attribute.php +++ b/src/Database/Validator/Attribute.php @@ -431,6 +431,7 @@ public function checkType(Document $attribute): bool Database::VAR_LONGTEXT, Database::VAR_INTEGER, Database::VAR_BIGINT, + Database::VAR_BIGINT, Database::VAR_FLOAT, Database::VAR_BOOLEAN, Database::VAR_DATETIME, @@ -526,6 +527,7 @@ protected function validateDefaultTypes(string $type, mixed $default): void } break; case Database::VAR_INTEGER: + case Database::VAR_BIGINT: case Database::VAR_FLOAT: case Database::VAR_BOOLEAN: if ($type !== $defaultType) { @@ -554,6 +556,7 @@ protected function validateDefaultTypes(string $type, mixed $default): void Database::VAR_MEDIUMTEXT, Database::VAR_LONGTEXT, Database::VAR_INTEGER, + Database::VAR_BIGINT, Database::VAR_FLOAT, Database::VAR_BOOLEAN, Database::VAR_DATETIME, From 8137486414bd19f73e5ef93e3a160269596b8b57 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 19:56:32 +0530 Subject: [PATCH 16/17] updated attribute validator --- src/Database/Validator/Attribute.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Database/Validator/Attribute.php b/src/Database/Validator/Attribute.php index 97fdb4c3e..a924f189b 100644 --- a/src/Database/Validator/Attribute.php +++ b/src/Database/Validator/Attribute.php @@ -527,7 +527,6 @@ protected function validateDefaultTypes(string $type, mixed $default): void } break; case Database::VAR_INTEGER: - case Database::VAR_BIGINT: case Database::VAR_FLOAT: case Database::VAR_BOOLEAN: if ($type !== $defaultType) { @@ -535,6 +534,12 @@ protected function validateDefaultTypes(string $type, mixed $default): void throw new DatabaseException($this->message); } break; + case Database::VAR_BIGINT: + if ($defaultType !== 'integer') { + $this->message = 'Default value ' . $default . ' does not match given type ' . $type; + throw new DatabaseException($this->message); + } + break; case Database::VAR_DATETIME: if ($defaultType !== Database::VAR_STRING) { $this->message = 'Default value ' . $default . ' does not match given type ' . $type; From b87cf3a9727f24cf080d8d2c21f376b88b308668 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 30 Mar 2026 20:06:08 +0530 Subject: [PATCH 17/17] updated --- src/Database/Database.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 0e15f26f8..44ea8013b 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -2584,13 +2584,17 @@ protected function validateDefaultTypes(string $type, mixed $default): void } break; case self::VAR_INTEGER: - case self::VAR_BIGINT: case self::VAR_FLOAT: case self::VAR_BOOLEAN: if ($type !== $defaultType) { throw new DatabaseException('Default value ' . $default . ' does not match given type ' . $type); } break; + case Database::VAR_BIGINT: + if ($defaultType !== 'integer') { + throw new DatabaseException('Default value ' . $default . ' does not match given type ' . $type); + } + break; case self::VAR_DATETIME: if ($defaultType !== self::VAR_STRING) { throw new DatabaseException('Default value ' . $default . ' does not match given type ' . $type);