From f46d066932eff7bdf86d68797e7a1438173c46d7 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 17 Jun 2026 09:06:21 +0300 Subject: [PATCH 1/4] fix(mysql): DataType::TEXT maps to TEXT instead of TINYTEXT TEXT columns no longer include a size parameter in DDL output. Previously text(1) was generated which MySQL interprets as TINYTEXT. Closes #171 --- WebFiori/Database/MySql/MySQLColumn.php | 4 +++- .../WebFiori/Tests/Database/MySql/MySQLColumnTest.php | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/WebFiori/Database/MySql/MySQLColumn.php b/WebFiori/Database/MySql/MySQLColumn.php index 473ee6b..615ae6d 100644 --- a/WebFiori/Database/MySql/MySQLColumn.php +++ b/WebFiori/Database/MySql/MySQLColumn.php @@ -695,8 +695,10 @@ private function firstColPart() { } else { $retVal .= $colDataType.'('.$this->getSize().') '; } - } else if ($colDataType == 'varchar' || $colDataType == 'text') { + } else if ($colDataType == 'varchar') { $retVal .= $colDataType.'('.$this->getSize().') '; + } else if ($colDataType == 'text') { + $retVal .= 'text '; } else if (in_array($colDataType, Column::BOOL_TYPES)) { $retVal .= 'bit(1) '; } else if ($colDataType == 'decimal' || $colDataType == 'float' || $colDataType == 'double') { diff --git a/tests/WebFiori/Tests/Database/MySql/MySQLColumnTest.php b/tests/WebFiori/Tests/Database/MySql/MySQLColumnTest.php index 57cb799..75d75cd 100644 --- a/tests/WebFiori/Tests/Database/MySql/MySQLColumnTest.php +++ b/tests/WebFiori/Tests/Database/MySql/MySQLColumnTest.php @@ -869,6 +869,16 @@ public function testAutoMapMSSQLVarbinaryToMySQL() { $this->assertInstanceOf(MySQLColumn::class, $col); $this->assertEquals('blob', $col->getDatatype()); } + /** + * @test + * Issue #171: DataType::TEXT should map to MySQL TEXT, not TINYTEXT. + */ + public function testTextTypeMapsToText() { + $col = new MySQLColumn('content', 'text'); + $ddl = $col . ''; + $this->assertStringContainsString('text ', $ddl); + $this->assertStringNotContainsString('text(', $ddl, 'TEXT column should not have a size parameter (text(n) becomes TINYTEXT in MySQL)'); + } /** * @test * Test that native MySQL types are not affected by auto-mapping. From ebd49292a192e4a3b2b6c0dbdc2f67186be0f5db Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 17 Jun 2026 09:16:09 +0300 Subject: [PATCH 2/4] fix(mssql): bind varbinary columns with correct binary type on insert Values for binary/varbinary columns are now wrapped with SQLSRV_PARAM_IN and SQLSRV_ENC_BINARY metadata so sqlsrv_prepare does not attempt nvarchar conversion. Closes #170 --- .../Database/MsSql/MSSQLInsertBuilder.php | 7 +++- .../Database/MsSql/MSSQLQueryBuilderTest.php | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/WebFiori/Database/MsSql/MSSQLInsertBuilder.php b/WebFiori/Database/MsSql/MSSQLInsertBuilder.php index ee49374..930f4f5 100644 --- a/WebFiori/Database/MsSql/MSSQLInsertBuilder.php +++ b/WebFiori/Database/MsSql/MSSQLInsertBuilder.php @@ -26,7 +26,12 @@ public function parseValues(array $values) { foreach ($values as $valsArr) { foreach ($valsArr as $col => $val) { $colObj = $this->getTable()->getColByKey($col); - $arr[] = $val; + + if ($colObj !== null && in_array($colObj->getDatatype(), ['binary', 'varbinary'])) { + $arr[] = [$val, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY('max')]; + } else { + $arr[] = $val; + } } $index++; } diff --git a/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php b/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php index f7dcf6b..0736813 100644 --- a/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php +++ b/tests/WebFiori/Tests/Database/MsSql/MSSQLQueryBuilderTest.php @@ -4,9 +4,11 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use WebFiori\Database\ColOption; use WebFiori\Database\ConnectionInfo; use WebFiori\Database\Database; use WebFiori\Database\DatabaseException; +use WebFiori\Database\DataType; use WebFiori\Database\Query\Expression; use WebFiori\Database\MsSql\MSSQLConnection; use WebFiori\Tests\Database\MsSql\MSSQLTestSchema; @@ -1411,4 +1413,38 @@ public function testUpdateWithNewCol() { $this->assertStringContainsString('update [users] set', $query); $this->assertStringContainsString('[first_name] = ?', $query); } + /** + * @test + * Issue #170: Inserting PHP string into varbinary(max) column should not fail. + */ + public function testInsertVarbinaryData() { + $connInfo = new ConnectionInfo('mssql', 'sa', getenv('SA_SQL_SERVER_PASSWORD'), 'testing_db', SQL_SERVER_HOST, 1433, [ + 'TrustServerCertificate' => 'true' + ]); + $db = new Database($connInfo); + $db->createBlueprint('bin_test')->addColumns([ + 'id' => [ + ColOption::TYPE => DataType::INT, + ColOption::PRIMARY => true, + ], + 'data' => [ + ColOption::TYPE => DataType::VARBINARY, + ColOption::SIZE => -1, + ], + ]); + $db->table('bin_test')->createTable()->execute(); + + try { + $binaryData = random_bytes(16); + $db->table('bin_test')->insert([ + 'id' => 1, + 'data' => $binaryData, + ])->execute(); + + $result = $db->table('bin_test')->select()->where('id', 1)->execute(); + $this->assertCount(1, $result); + } finally { + $db->raw("DROP TABLE [bin_test]")->execute(); + } + } } From 802caf63cbd819122cb5b55ea2b414926259a59a Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 17 Jun 2026 09:24:07 +0300 Subject: [PATCH 3/4] test(mysql): add integration test for BIT(1) column insert Verifies that boolean values can be inserted into BIT(1) columns via the query builder, including explicit true/false and default values. Refs #172 --- .../Database/MySql/MySQLQueryBuilderTest.php | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php b/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php index 9c9b55a..4aa8100 100644 --- a/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php +++ b/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php @@ -2312,4 +2312,48 @@ public function testInsertBoolColumnMultiRowCastsToInt() { $this->assertSame(1, $params['values'][1][2], 'Row 1: true should be cast to int 1'); $this->assertSame(0, $params['values'][1][3], 'Row 1: false should be cast to int 0'); } + /** + * @test + * Issue #172: Inserting values into BIT(1) columns should not fail. + */ + public function testInsertBitColumnIntegration() { + $connInfo = new ConnectionInfo('mysql', 'root', getenv('MYSQL_ROOT_PASSWORD'), 'testing_db', '127.0.0.1'); + $db = new Database($connInfo); + $db->createBlueprint('bit_test')->addColumns([ + 'id' => [ + \WebFiori\Database\ColOption::TYPE => \WebFiori\Database\DataType::INT, + \WebFiori\Database\ColOption::PRIMARY => true, + ], + 'flag' => [ + \WebFiori\Database\ColOption::TYPE => \WebFiori\Database\DataType::BOOL, + \WebFiori\Database\ColOption::DEFAULT => false, + ], + ]); + $db->table('bit_test')->createTable()->execute(); + + try { + // Case 1: Explicit boolean value + $db->table('bit_test')->insert([ + 'id' => 1, + 'flag' => true, + ])->execute(); + + // Case 2: Explicit false value + $db->table('bit_test')->insert([ + 'id' => 2, + 'flag' => false, + ])->execute(); + + // Case 3: Omit flag, rely on default value + $db->table('bit_test')->insert([ + 'id' => 3, + ])->execute(); + + $result = $db->table('bit_test')->select()->execute(); + $this->assertCount(3, $result); + } finally { + $db->raw("DROP TABLE `bit_test`")->execute(); + } + } } + From 8e0b14c3ea08b4ff84043ab7953aa898d5eb3e10 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 17 Jun 2026 09:32:20 +0300 Subject: [PATCH 4/4] fix(query): select() with string column aliases throws TypeError When an alias is passed as a string value in the select array (e.g., ['col' => 'alias']), wrap it in ['alias' => value] before passing to addColumn() which expects ?array. Closes #173 --- WebFiori/Database/Query/SelectExpression.php | 2 ++ .../Tests/Database/MySql/MySQLQueryBuilderTest.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/WebFiori/Database/Query/SelectExpression.php b/WebFiori/Database/Query/SelectExpression.php index baac0aa..9ddd047 100644 --- a/WebFiori/Database/Query/SelectExpression.php +++ b/WebFiori/Database/Query/SelectExpression.php @@ -652,6 +652,8 @@ public function select(array $colsOrExpressions) { } else { if (gettype($index) == 'integer') { $this->addColumn($colArrOrExpr); + } else if (is_string($colArrOrExpr)) { + $this->addColumn($index, ['alias' => $colArrOrExpr]); } else { $this->addColumn($index, $colArrOrExpr); } diff --git a/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php b/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php index 4aa8100..e8d6c6a 100644 --- a/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php +++ b/tests/WebFiori/Tests/Database/MySql/MySQLQueryBuilderTest.php @@ -2355,5 +2355,19 @@ public function testInsertBitColumnIntegration() { $db->raw("DROP TABLE `bit_test`")->execute(); } } + /** + * @test + * Issue #173: select() with column aliases as string values should work. + */ + public function testSelectWithStringAlias() { + $schema = new MySQLTestSchema(); + $schema->table('users')->select([ + 'first-name' => 'full_name', + 'age', + ]); + $query = $schema->getLastQuery(); + $this->assertStringContainsString('`full_name`', $query); + $this->assertStringContainsString('`age`', $query); + } }