-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathExpressionTrait.php
106 lines (87 loc) · 3.13 KB
/
ExpressionTrait.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<?php
declare(strict_types=1);
namespace Atk4\Data\Persistence\Sql\Mssql;
use Doctrine\DBAL\Result as DbalResult;
trait ExpressionTrait
{
protected function escapeIdentifier(string $value): string
{
return $this->fixOpenEscapeChar(parent::escapeIdentifier($value));
}
protected function escapeIdentifierSoft(string $value): string
{
return $this->fixOpenEscapeChar(parent::escapeIdentifierSoft($value));
}
private function fixOpenEscapeChar(string $v): string
{
return preg_replace('~(?:\'(?:\'\'|\\\\\'|[^\'])*\')?+\K\]([^\[\]\'"(){}]*?)\]~s', '[$1]', $v);
}
private function _render(): string
{
// convert all SQL strings to NVARCHAR, eg 'text' to N'text'
return preg_replace_callback('~(^|.)(\'(?:\'\'|\\\\\'|[^\'])*\')~s', function ($matches) {
return $matches[1] . (!in_array($matches[1], ['N', '\'', '\\'], true) ? 'N' : '') . $matches[2];
}, parent::render());
}
// {{{ MSSQL does not support named parameters, so convert them to numerical inside execute
/** @var array|null */
private $numQueryParamsBackup;
/** @var string|null */
private $numQueryRender;
/**
* @return DbalResult|\PDOStatement PDOStatement iff for DBAL 2.x
*/
public function execute(object $connection = null): object
{
if ($this->numQueryParamsBackup !== null) {
return parent::execute($connection);
}
$this->numQueryParamsBackup = $this->params;
try {
$numParams = [];
$i = 0;
$j = 0;
$this->numQueryRender = preg_replace_callback(
'~(?:\'(?:\'\'|\\\\\'|[^\'])*\')?+\K(?:\?|:\w+)~s',
function ($matches) use (&$numParams, &$i, &$j) {
$numParams[++$i] = $this->params[$matches[0] === '?' ? ++$j : $matches[0]];
return '?';
},
$this->_render()
);
$this->params = $numParams;
return parent::execute($connection);
} finally {
$this->params = $this->numQueryParamsBackup;
$this->numQueryParamsBackup = null;
$this->numQueryRender = null;
}
}
public function render(): string
{
if ($this->numQueryParamsBackup !== null) {
return $this->numQueryRender;
}
return $this->_render();
}
public function getDebugQuery(): string
{
if ($this->numQueryParamsBackup === null) {
return parent::getDebugQuery();
}
$paramsBackup = $this->params;
$numQueryRenderBackupBackup = $this->numQueryParamsBackup;
$numQueryRenderBackup = $this->numQueryRender;
try {
$this->params = $this->numQueryParamsBackup;
$this->numQueryParamsBackup = null;
$this->numQueryRender = null;
return parent::getDebugQuery();
} finally {
$this->params = $paramsBackup;
$this->numQueryParamsBackup = $numQueryRenderBackupBackup;
$this->numQueryRender = $numQueryRenderBackup;
}
}
/// }}}
}