fix: initialize SQL Server ANSI session

This commit is contained in:
WuYongJie 2026-08-14 13:50:08 +08:00
parent 63b278e149
commit b0b22b22f1
2 changed files with 50 additions and 2 deletions

View File

@ -176,12 +176,14 @@ PHP;
throw new ServiceUnavailableHttpException(60, '上游数据库配置不完整,请联系管理员。');
}
return new PDO(
$pdo = new PDO(
self::pdoDblibDsn($host, $port, $db, $tdsVersion),
$user,
$pass,
self::pdoOptions($queryTimeout),
);
return self::initializeSqlServerSession($pdo);
}
$dsn = self::odbcDsn(
@ -197,7 +199,9 @@ PHP;
$applicationIntent,
);
return new PDO($dsn, null, null, self::pdoOptions($queryTimeout));
return self::initializeSqlServerSession(
new PDO($dsn, null, null, self::pdoOptions($queryTimeout)),
);
} catch (PDOException $exception) {
Log::warning('上游数据库连接失败。', [
'source' => $source,
@ -303,6 +307,20 @@ PHP;
];
}
/**
* SQL Server 的跨库/异构只读视图要求这两个会话选项保持开启。
*
* 这里在连接创建后统一初始化,避免各 Repository 拼接 SET 多语句,
* 也继续让 UpstreamReadOnlyQuery 只接受单条 SELECT/WITH。
*/
private static function initializeSqlServerSession(PDO $pdo): PDO
{
$pdo->exec('SET ANSI_NULLS ON');
$pdo->exec('SET ANSI_WARNINGS ON');
return $pdo;
}
private static function encryptionAttributes(string $driver, string $mode): string
{
if (strcasecmp($driver, 'FreeTDS') === 0) {

View File

@ -3,6 +3,7 @@
namespace Tests\Unit\EcommerceFinance;
use Modules\EcommerceFinance\Services\UpstreamOdbcConnection;
use PDO;
use ReflectionMethod;
use Tests\TestCase;
@ -41,4 +42,33 @@ class UpstreamOdbcConnectionTest extends TestCase
$this->assertFalse($jiansun);
$this->assertFalse($method->invoke(null, 'operations_replica', 'FreeTDS', 'strict'));
}
public function test_sql_server_connection_enables_required_ansi_session_options(): void
{
$pdo = new class extends PDO
{
/** @var array<int,string> */
public array $statements = [];
public function __construct()
{
}
public function exec(string $statement): int|false
{
$this->statements[] = $statement;
return 0;
}
};
$method = new ReflectionMethod(UpstreamOdbcConnection::class, 'initializeSqlServerSession');
$result = $method->invoke(null, $pdo);
$this->assertSame($pdo, $result);
$this->assertSame([
'SET ANSI_NULLS ON',
'SET ANSI_WARNINGS ON',
], $pdo->statements);
}
}