Skip to content

Commit 79c83ba

Browse files
Fix #9899: Fix caching a MSSQL query with BLOB data type
1 parent 7d2e2b9 commit 79c83ba

File tree

6 files changed

+111
-15
lines changed

6 files changed

+111
-15
lines changed

framework/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Yii Framework 2 Change Log
44
2.0.49 under development
55
------------------------
66

7+
- Bug #9899: Fix caching a MSSQL query with BLOB data type (terabytesoftw)
78
- Bug #16208: Fix `yii\log\FileTarget` to not export empty messages (terabytesoftw)
89
- Bug #19857: Fix AttributeTypecastBehavior::resetOldAttributes() causes "class has no attribute named" InvalidArgumentException (uaoleg)
910
- Bug #18859: Fix `yii\web\Controller::bindInjectedParams()` to not throw error when argument of `ReflectionUnionType` type is passed (bizley)

framework/caching/DbCache.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ protected function isVarbinaryDataField()
317317
*/
318318
protected function getDataFieldName()
319319
{
320-
return $this->isVarbinaryDataField() ? 'convert(nvarchar(max),[data]) data' : 'data';
320+
return $this->isVarbinaryDataField() ? 'CONVERT(VARCHAR(MAX), [[data]]) data' : 'data';
321321
}
322322

323323
/**

framework/db/mssql/QueryBuilder.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,9 @@ private function normalizeTableRowData($table, $columns, &$params)
460460
$columnSchemas = $tableSchema->columns;
461461
foreach ($columns as $name => $value) {
462462
// @see https://github.com/yiisoft/yii2/issues/12599
463-
if (isset($columnSchemas[$name]) && $columnSchemas[$name]->type === Schema::TYPE_BINARY && $columnSchemas[$name]->dbType === 'varbinary' && (is_string($value) || $value === null)) {
464-
$phName = $this->bindParam($value, $params);
463+
if (isset($columnSchemas[$name]) && $columnSchemas[$name]->type === Schema::TYPE_BINARY && $columnSchemas[$name]->dbType === 'varbinary' && (is_string($value))) {
465464
// @see https://github.com/yiisoft/yii2/issues/12599
466-
$columns[$name] = new Expression("CONVERT(VARBINARY(MAX), $phName)", $params);
465+
$columns[$name] = new Expression('CONVERT(VARBINARY(MAX), ' . ('0x' . bin2hex($value)) . ')');
467466
}
468467
}
469468
}

tests/framework/db/mssql/CommandTest.php

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,22 +134,19 @@ public function testUpsertVarbinary()
134134
{
135135
$db = $this->getConnection();
136136

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

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

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

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

147+
$query = (new Query())->select(['blob_col'])->from('T_upsert_varbinary')->where(['id' => 1]);
152148
$resultData = $query->createCommand($db)->queryOne();
153-
$this->assertEquals($testData, $resultData['blob_col']);
149+
150+
$this->assertSame($testData, $resultData['blob_col']);
154151
}
155152
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/**
3+
* @link https://www.yiiframework.com/
4+
* @copyright Copyright (c) 2008 Yii Software LLC
5+
* @license https://www.yiiframework.com/license/
6+
*/
7+
8+
namespace yiiunit\framework\db\mssql;
9+
10+
use yii\caching\FileCache;
11+
use yii\db\Query;
12+
use yiiunit\framework\db\DatabaseTestCase;
13+
14+
/**
15+
* @group db
16+
* @group mssql
17+
*/
18+
class QueryCacheTest extends DatabaseTestCase
19+
{
20+
protected $driverName = 'sqlsrv';
21+
22+
public function testQueryCacheFileCache()
23+
{
24+
$db = $this->getConnection();
25+
$db->enableQueryCache = true;
26+
$db->queryCache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']);
27+
28+
$db->createCommand()->delete('type')->execute();
29+
$db->createCommand()->insert('type', [
30+
'int_col' => $key = 1,
31+
'char_col' => '',
32+
'char_col2' => '6a3ce1a0bffe8eeb6fa986caf443e24c',
33+
'float_col' => 0.0,
34+
'blob_col' => 'a:1:{s:13:"template";s:1:"1";}',
35+
'bool_col' => true,
36+
])->execute();
37+
38+
$function = function($db) use ($key){
39+
return (new Query())
40+
->select(['blob_col'])
41+
->from('type')
42+
->where(['int_col' => $key])
43+
->createCommand($db)
44+
->queryScalar();
45+
};
46+
47+
// First run return
48+
$result = $db->cache($function);
49+
$this->assertSame('a:1:{s:13:"template";s:1:"1";}', $result);
50+
51+
// After the request has been cached return
52+
$result = $db->cache($function);
53+
$this->assertSame('a:1:{s:13:"template";s:1:"1";}', $result);
54+
}
55+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/**
3+
* @link https://www.yiiframework.com/
4+
* @copyright Copyright (c) 2008 Yii Software LLC
5+
* @license https://www.yiiframework.com/license/
6+
*/
7+
8+
namespace yiiunit\framework\db\mssql\Type;
9+
10+
use yii\db\Query;
11+
use yiiunit\framework\db\DatabaseTestCase;
12+
13+
/**
14+
* @group db
15+
* @group mssql
16+
*/
17+
class VarbinaryTest extends DatabaseTestCase
18+
{
19+
protected $driverName = 'sqlsrv';
20+
21+
public function testVarbinary()
22+
{
23+
$db = $this->getConnection();
24+
25+
$db->createCommand()->delete('type')->execute();
26+
$db->createCommand()->insert('type', [
27+
'int_col' => $key = 1,
28+
'char_col' => '',
29+
'char_col2' => '6a3ce1a0bffe8eeb6fa986caf443e24c',
30+
'float_col' => 0.0,
31+
'blob_col' => 'a:1:{s:13:"template";s:1:"1";}',
32+
'bool_col' => true,
33+
])->execute();
34+
35+
$result = (new Query())
36+
->select(['blob_col'])
37+
->from('type')
38+
->where(['int_col' => $key])
39+
->createCommand($db)
40+
->queryScalar();
41+
42+
$this->assertSame('a:1:{s:13:"template";s:1:"1";}', $result);
43+
}
44+
}

0 commit comments

Comments
 (0)