Skip to content

Commit a6c9295

Browse files
committed
Merge pull request #149 from diepxuan/fix/procedurecaller-direct-unicode-build
fix: build Unicode literals trực tiếp trong ProcedureCaller (fix partial match bug)
1 parent b675835 commit a6c9295

1 file changed

Lines changed: 15 additions & 31 deletions

File tree

src/StoredProcedures/ProcedureCaller.php

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @author Tran Ngoc Duc <ductn@diepxuan.com>
99
* @author Tran Ngoc Duc <caothu91@gmail.com>
1010
*
11-
* @lastupdate 2026-04-07 13:04:50
11+
* @lastupdate 2026-04-07 13:49:23
1212
*/
1313

1414
namespace Diepxuan\Simba\StoredProcedures;
@@ -36,12 +36,15 @@ class ProcedureCaller
3636
* @param null|string $connection Optional connection name
3737
*
3838
* @return mixed kết quả trả về từ procedure (tùy thuộc vào procedure)
39+
*
40+
* @note UTF-8 Support: Build trực tiếp Unicode literals (N'...') vào SQL
41+
* Tránh lỗi partial match khi replace placeholders
42+
* Tham khảo: docs/SQLSRV-UTF8-ROOT-CAUSE.md
3943
*/
4044
public static function call(string $name, array $params = [], ?string $connection = null)
4145
{
4246
$declareSql = [];
4347
$execParts = [];
44-
$bindings = [];
4548
$selectOut = [];
4649
$hasOutput = false;
4750
$outputTypes = [];
@@ -59,8 +62,9 @@ public static function call(string $name, array $params = [], ?string $connectio
5962
$execParts[] = "@{$key} = @{$key} OUTPUT";
6063
$selectOut[] = "@{$key} as {$key}";
6164
} else {
62-
$execParts[] = "@{$key} = :{$key}";
63-
$bindings[$key] = $value;
65+
// INPUT param - Build trực tiếp Unicode literal vào SQL (không dùng placeholder)
66+
$literal = self::toUnicodeLiteral($value);
67+
$execParts[] = "@{$key} = {$literal}";
6468
}
6569
}
6670

@@ -83,14 +87,8 @@ public static function call(string $name, array $params = [], ?string $connectio
8387

8488
$conn = $connection ? DB::connection($connection) : DB::connection();
8589

86-
// Dùng select() để execute toàn bộ batch và fetch kết quả
87-
if (empty($bindings)) {
88-
$rows = $conn->select($sql);
89-
} else {
90-
// Replace :placeholder với Unicode literal (fix UTF-8 cho SQL Server)
91-
$processedQuery = self::replacePlaceholders($sql, $bindings);
92-
$rows = $conn->select($processedQuery);
93-
}
90+
// Execute trực tiếp (không cần bindings vì đã build Unicode literal vào SQL)
91+
$rows = $conn->select($sql);
9492

9593
// Tự động ép kiểu các giá trị output trả về dựa trên type đã khai báo
9694
if ($hasOutput && !empty($rows)) {
@@ -122,7 +120,11 @@ public static function escape(string $value): string
122120

123121
/**
124122
* Chuyển giá trị sang dạng Unicode literal (N'...')
125-
* Dùng cho parameter binding bị lỗi UTF-8.
123+
* Build trực tiếp vào SQL, không qua parameter binding.
124+
*
125+
* @param mixed $value Giá trị cần convert
126+
*
127+
* @return string Unicode literal (N'...' cho strings, NULL cho null, v.v.)
126128
*/
127129
public static function toUnicodeLiteral(mixed $value): string
128130
{
@@ -144,22 +146,4 @@ public static function toUnicodeLiteral(mixed $value): string
144146

145147
return "N'" . self::escape((string) $value) . "'";
146148
}
147-
148-
/**
149-
* Replace :placeholder với Unicode literals (N'...')
150-
* Fix UTF-8 cho SQL Server parameter binding trên Linux.
151-
*
152-
* @param string $query SQL query với :named placeholders
153-
* @param array $bindings Associative array [paramName => value]
154-
*/
155-
private static function replacePlaceholders(string $query, array $bindings): string
156-
{
157-
foreach ($bindings as $key => $value) {
158-
$literal = self::toUnicodeLiteral($value);
159-
$pattern = '/:' . preg_quote($key, '/') . '/';
160-
$query = preg_replace($pattern, $literal, $query);
161-
}
162-
163-
return $query;
164-
}
165149
}

0 commit comments

Comments
 (0)