Fix #9899: Fix caching a MSSQL query with BLOB data type

This commit is contained in:
Wilmer Arambula
2023-07-24 03:03:18 -04:00
committed by GitHub
parent 7d2e2b9e70
commit 79c83ba7db
6 changed files with 111 additions and 15 deletions

View File

@@ -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)

View File

@@ -317,7 +317,7 @@ class DbCache extends Cache
*/
protected function getDataFieldName()
{
return $this->isVarbinaryDataField() ? 'convert(nvarchar(max),[data]) data' : 'data';
return $this->isVarbinaryDataField() ? 'CONVERT(VARCHAR(MAX), [[data]]) data' : 'data';
}
/**

View File

@@ -460,10 +460,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
$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)) . ')');
}
}
}

View File

@@ -134,22 +134,19 @@ class CommandTest extends \yiiunit\framework\db\CommandTest
{
$db = $this->getConnection();
$testData = json_encode(['test' => 'string', 'test2' => 'integer']);
$qb = $db->getQueryBuilder();
$testData = json_encode(['test' => 'string', 'test2' => 'integer'], JSON_THROW_ON_ERROR);
$params = [];
$qb = $db->getQueryBuilder();
$sql = $qb->upsert('T_upsert_varbinary', ['id' => 1, 'blob_col' => $testData] , ['blob_col' => $testData], $params);
$sql = $qb->upsert('T_upsert_varbinary', ['id' => 1, 'blob_col' => $testData], ['blob_col' => $testData], $params);
$result = $db->createCommand($sql, $params)->execute();
$this->assertEquals(1, $result);
$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']);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}