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