1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19:
20: class SqlPreprocessor extends Object
21: {
22:
23: private $connection;
24:
25:
26: private $driver;
27:
28:
29: private $params;
30:
31:
32: private $remaining;
33:
34:
35: private $counter;
36:
37:
38: private $arrayMode;
39:
40:
41:
42: public function __construct(Connection $connection)
43: {
44: $this->connection = $connection;
45: $this->driver = $connection->getSupplementalDriver();
46: }
47:
48:
49:
50: 51: 52: 53: 54:
55: public function process($sql, $params)
56: {
57: $this->params = $params;
58: $this->counter = 0;
59: $this->remaining = array();
60:
61: $cmd = strtoupper(substr(ltrim($sql), 0, 6)); 62: $this->arrayMode = $cmd === 'INSERT' || $cmd === 'REPLAC' ? 'values' : 'assoc';
63:
64: 65: 66: 67: 68:
69: $sql = String::replace($sql, '~\'.*?\'|".*?"|:[a-zA-Z0-9_]+:|\?~s', array($this, 'callback'));
70:
71: while ($this->counter < count($params)) {
72: $sql .= ' ' . $this->formatValue($params[$this->counter++]);
73: }
74:
75: return array($sql, $this->remaining);
76: }
77:
78:
79:
80:
81: public function callback($m)
82: {
83: $m = $m[0];
84: if ($m[0] === "'" || $m[0] === '"') { 85: return $m;
86:
87: } elseif ($m[0] === '?') { 88: return $this->formatValue($this->params[$this->counter++]);
89:
90: } elseif ($m[0] === ':') { 91: $s = substr($m, 1, -1);
92: return isset($this->connection->substitutions[$s]) ? $this->connection->substitutions[$s] : $m;
93: }
94: }
95:
96:
97:
98: private function formatValue($value)
99: {
100: if (is_string($value)) {
101: if (strlen($value) > 20) {
102: $this->remaining[] = $value;
103: return '?';
104:
105: } else {
106: return $this->connection->quote($value);
107: }
108:
109: } elseif (is_int($value)) {
110: return (string) $value;
111:
112: } elseif (is_float($value)) {
113: return rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
114:
115: } elseif (is_bool($value)) {
116: return $value ? 1 : 0;
117:
118: } elseif ($value === NULL) {
119: return 'NULL';
120:
121: } elseif (is_array($value) || $value instanceof Traversable) {
122: $vx = $kx = array();
123:
124: if (isset($value[0])) { 125: foreach ($value as $v) {
126: $vx[] = $this->formatValue($v);
127: }
128: return implode(', ', $vx);
129:
130: } elseif ($this->arrayMode === 'values') { 131: $this->arrayMode = 'multi';
132: foreach ($value as $k => $v) {
133: $kx[] = $this->driver->delimite($k);
134: $vx[] = $this->formatValue($v);
135: }
136: return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
137:
138: } elseif ($this->arrayMode === 'assoc') { 139: foreach ($value as $k => $v) {
140: $vx[] = $this->driver->delimite($k) . '=' . $this->formatValue($v);
141: }
142: return implode(', ', $vx);
143:
144: } elseif ($this->arrayMode === 'multi') { 145: foreach ($value as $k => $v) {
146: $vx[] = $this->formatValue($v);
147: }
148: return ', (' . implode(', ', $vx) . ')';
149: }
150:
151: } elseif ($value instanceof DateTime) {
152: return $this->driver->formatDateTime($value);
153:
154: } elseif ($value instanceof SqlLiteral) {
155: return $value->value;
156:
157: } else {
158: $this->remaining[] = $value;
159: return '?';
160: }
161: }
162:
163: }
164: