Skip to content

Commit

Permalink
Fix #9899: Fix caching a MSSQL query with BLOB data type
Browse files Browse the repository at this point in the history
  • Loading branch information
terabytesoftw committed Jul 24, 2023
1 parent 7d2e2b9 commit 79c83ba
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 15 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.49 under development
------------------------

- Bug #9899: Fix caching a MSSQL query with BLOB data type (terabytesoftw)
- Bug #16208: Fix `yii\log\FileTarget` to not export empty messages (terabytesoftw)
- Bug #19857: Fix AttributeTypecastBehavior::resetOldAttributes() causes "class has no attribute named" InvalidArgumentException (uaoleg)
- Bug #18859: Fix `yii\web\Controller::bindInjectedParams()` to not throw error when argument of `ReflectionUnionType` type is passed (bizley)
Expand Down
2 changes: 1 addition & 1 deletion framework/caching/DbCache.php
Expand Up @@ -317,7 +317,7 @@ protected function isVarbinaryDataField()
*/
protected function getDataFieldName()
{
return $this->isVarbinaryDataField() ? 'convert(nvarchar(max),[data]) data' : 'data';
return $this->isVarbinaryDataField() ? 'CONVERT(VARCHAR(MAX), [[data]]) data' : 'data';
}

/**
Expand Down
5 changes: 2 additions & 3 deletions framework/db/mssql/QueryBuilder.php
Expand Up @@ -460,10 +460,9 @@ private function normalizeTableRowData($table, $columns, &$params)
$columnSchemas = $tableSchema->columns;
foreach ($columns as $name => $value) {
// @see https://github.com/yiisoft/yii2/issues/12599
if (isset($columnSchemas[$name]) && $columnSchemas[$name]->type === Schema::TYPE_BINARY && $columnSchemas[$name]->dbType === 'varbinary' && (is_string($value) || $value === null)) {
$phName = $this->bindParam($value, $params);
if (isset($columnSchemas[$name]) && $columnSchemas[$name]->type === Schema::TYPE_BINARY && $columnSchemas[$name]->dbType === 'varbinary' && (is_string($value))) {
// @see https://github.com/yiisoft/yii2/issues/12599
$columns[$name] = new Expression("CONVERT(VARBINARY(MAX), $phName)", $params);
$columns[$name] = new Expression('CONVERT(VARBINARY(MAX), ' . ('0x' . bin2hex($value)) . ')');
}
}
}
Expand Down
19 changes: 8 additions & 11 deletions tests/framework/db/mssql/CommandTest.php
Expand Up @@ -134,22 +134,19 @@ public function testUpsertVarbinary()
{
$db = $this->getConnection();

$testData = json_encode(['test' => 'string', 'test2' => 'integer']);
$params = [];

$qb = $db->getQueryBuilder();
$sql = $qb->upsert('T_upsert_varbinary', ['id' => 1, 'blob_col' => $testData] , ['blob_col' => $testData], $params);
$testData = json_encode(['test' => 'string', 'test2' => 'integer'], JSON_THROW_ON_ERROR);

$result = $db->createCommand($sql, $params)->execute();
$params = [];

$this->assertEquals(1, $result);
$sql = $qb->upsert('T_upsert_varbinary', ['id' => 1, 'blob_col' => $testData], ['blob_col' => $testData], $params);
$result = $db->createCommand($sql, $params)->execute();

$query = (new Query())
->select(['convert(nvarchar(max),blob_col) as blob_col'])
->from('T_upsert_varbinary')
->where(['id' => 1]);
$this->assertSame(1, $result);

$query = (new Query())->select(['blob_col'])->from('T_upsert_varbinary')->where(['id' => 1]);
$resultData = $query->createCommand($db)->queryOne();
$this->assertEquals($testData, $resultData['blob_col']);

$this->assertSame($testData, $resultData['blob_col']);
}
}
55 changes: 55 additions & 0 deletions tests/framework/db/mssql/QueryCacheTest.php
@@ -0,0 +1,55 @@
<?php
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/

namespace yiiunit\framework\db\mssql;

use yii\caching\FileCache;
use yii\db\Query;
use yiiunit\framework\db\DatabaseTestCase;

/**
* @group db
* @group mssql
*/
class QueryCacheTest extends DatabaseTestCase
{
protected $driverName = 'sqlsrv';

public function testQueryCacheFileCache()
{
$db = $this->getConnection();
$db->enableQueryCache = true;
$db->queryCache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']);

$db->createCommand()->delete('type')->execute();
$db->createCommand()->insert('type', [
'int_col' => $key = 1,
'char_col' => '',
'char_col2' => '6a3ce1a0bffe8eeb6fa986caf443e24c',
'float_col' => 0.0,
'blob_col' => 'a:1:{s:13:"template";s:1:"1";}',
'bool_col' => true,
])->execute();

$function = function($db) use ($key){
return (new Query())
->select(['blob_col'])
->from('type')
->where(['int_col' => $key])
->createCommand($db)
->queryScalar();
};

// First run return
$result = $db->cache($function);
$this->assertSame('a:1:{s:13:"template";s:1:"1";}', $result);

// After the request has been cached return
$result = $db->cache($function);
$this->assertSame('a:1:{s:13:"template";s:1:"1";}', $result);
}
}
44 changes: 44 additions & 0 deletions tests/framework/db/mssql/type/VarbinaryTest.php
@@ -0,0 +1,44 @@
<?php
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/

namespace yiiunit\framework\db\mssql\Type;

use yii\db\Query;
use yiiunit\framework\db\DatabaseTestCase;

/**
* @group db
* @group mssql
*/
class VarbinaryTest extends DatabaseTestCase
{
protected $driverName = 'sqlsrv';

public function testVarbinary()
{
$db = $this->getConnection();

$db->createCommand()->delete('type')->execute();
$db->createCommand()->insert('type', [
'int_col' => $key = 1,
'char_col' => '',
'char_col2' => '6a3ce1a0bffe8eeb6fa986caf443e24c',
'float_col' => 0.0,
'blob_col' => 'a:1:{s:13:"template";s:1:"1";}',
'bool_col' => true,
])->execute();

$result = (new Query())
->select(['blob_col'])
->from('type')
->where(['int_col' => $key])
->createCommand($db)
->queryScalar();

$this->assertSame('a:1:{s:13:"template";s:1:"1";}', $result);
}
}

0 comments on commit 79c83ba

Please sign in to comment.