1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: require_once dirname(__FILE__) . '/mssql.reflector.php';
13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
29: class DibiMsSqlDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
30: {
31:
32: private $connection;
33:
34:
35: private $resultSet;
36:
37:
38:
39: 40: 41:
42: public function __construct()
43: {
44: if (!extension_loaded('mssql')) {
45: throw new DibiNotSupportedException("PHP extension 'mssql' is not loaded.");
46: }
47: }
48:
49:
50:
51: 52: 53: 54: 55:
56: public function connect(array &$config)
57: {
58: if (isset($config['resource'])) {
59: $this->connection = $config['resource'];
60: } elseif (empty($config['persistent'])) {
61: $this->connection = @mssql_connect($config['host'], $config['username'], $config['password'], TRUE);
62: } else {
63: $this->connection = @mssql_pconnect($config['host'], $config['username'], $config['password']);
64: }
65:
66: if (!is_resource($this->connection)) {
67: throw new DibiDriverException("Can't connect to DB.");
68: }
69:
70: if (isset($config['database']) && !@mssql_select_db($this->escape($config['database'], dibi::IDENTIFIER), $this->connection)) {
71: throw new DibiDriverException("Can't select DB '$config[database]'.");
72: }
73: }
74:
75:
76:
77: 78: 79: 80:
81: public function disconnect()
82: {
83: mssql_close($this->connection);
84: }
85:
86:
87:
88: 89: 90: 91: 92: 93:
94: public function query($sql)
95: {
96: $res = @mssql_query($sql, $this->connection);
97:
98: if ($res === FALSE) {
99: throw new DibiDriverException(mssql_get_last_message(), 0, $sql);
100:
101: } elseif (is_resource($res)) {
102: return $this->createResultDriver($res);
103: }
104: }
105:
106:
107:
108: 109: 110: 111:
112: public function getAffectedRows()
113: {
114: return mssql_rows_affected($this->connection);
115: }
116:
117:
118:
119: 120: 121: 122:
123: public function getInsertId($sequence)
124: {
125: $res = mssql_query('SELECT @@IDENTITY', $this->connection);
126: if (is_resource($res)) {
127: $row = mssql_fetch_row($res);
128: return $row[0];
129: }
130: return FALSE;
131: }
132:
133:
134:
135: 136: 137: 138: 139: 140:
141: public function begin($savepoint = NULL)
142: {
143: $this->query('BEGIN TRANSACTION');
144: }
145:
146:
147:
148: 149: 150: 151: 152: 153:
154: public function commit($savepoint = NULL)
155: {
156: $this->query('COMMIT');
157: }
158:
159:
160:
161: 162: 163: 164: 165: 166:
167: public function rollback($savepoint = NULL)
168: {
169: $this->query('ROLLBACK');
170: }
171:
172:
173:
174: 175: 176: 177:
178: public function getResource()
179: {
180: return $this->connection;
181: }
182:
183:
184:
185: 186: 187: 188:
189: public function getReflector()
190: {
191: return new DibiMsSqlReflector($this);
192: }
193:
194:
195:
196: 197: 198: 199: 200:
201: public function createResultDriver($resource)
202: {
203: $res = clone $this;
204: $res->resultSet = $resource;
205: return $res;
206: }
207:
208:
209:
210:
211:
212:
213:
214: 215: 216: 217: 218: 219: 220:
221: public function escape($value, $type)
222: {
223: switch ($type) {
224: case dibi::TEXT:
225: case dibi::BINARY:
226: return "'" . str_replace("'", "''", $value) . "'";
227:
228: case dibi::IDENTIFIER:
229:
230: return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
231:
232: case dibi::BOOL:
233: return $value ? 1 : 0;
234:
235: case dibi::DATE:
236: return $value instanceof DateTime ? $value->format("'Y-m-d'") : date("'Y-m-d'", $value);
237:
238: case dibi::DATETIME:
239: return $value instanceof DateTime ? $value->format("'Y-m-d H:i:s'") : date("'Y-m-d H:i:s'", $value);
240:
241: default:
242: throw new InvalidArgumentException('Unsupported type.');
243: }
244: }
245:
246:
247:
248: 249: 250: 251: 252: 253:
254: public function escapeLike($value, $pos)
255: {
256: $value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
257: return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
258: }
259:
260:
261:
262: 263: 264: 265: 266: 267: 268:
269: public function unescape($value, $type)
270: {
271: if ($type === dibi::BINARY) {
272: return $value;
273: }
274: throw new InvalidArgumentException('Unsupported type.');
275: }
276:
277:
278:
279: 280: 281: 282: 283: 284: 285:
286: public function applyLimit(&$sql, $limit, $offset)
287: {
288:
289: if ($limit >= 0) {
290: $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t';
291: }
292:
293: if ($offset) {
294: throw new DibiNotImplementedException('Offset is not implemented.');
295: }
296: }
297:
298:
299:
300:
301:
302:
303:
304: 305: 306: 307:
308: public function __destruct()
309: {
310: $this->resultSet && @$this->free();
311: }
312:
313:
314:
315: 316: 317: 318:
319: public function getRowCount()
320: {
321: return mssql_num_rows($this->resultSet);
322: }
323:
324:
325:
326: 327: 328: 329: 330:
331: public function fetch($assoc)
332: {
333: return mssql_fetch_array($this->resultSet, $assoc ? MSSQL_ASSOC : MSSQL_NUM);
334: }
335:
336:
337:
338: 339: 340: 341: 342:
343: public function seek($row)
344: {
345: return mssql_data_seek($this->resultSet, $row);
346: }
347:
348:
349:
350: 351: 352: 353:
354: public function free()
355: {
356: mssql_free_result($this->resultSet);
357: $this->resultSet = NULL;
358: }
359:
360:
361:
362: 363: 364: 365:
366: public function getResultColumns()
367: {
368: $count = mssql_num_fields($this->resultSet);
369: $columns = array();
370: for ($i = 0; $i < $count; $i++) {
371: $row = (array) mssql_fetch_field($this->resultSet, $i);
372: $columns[] = array(
373: 'name' => $row['name'],
374: 'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'],
375: 'table' => $row['column_source'],
376: 'nativetype' => $row['type'],
377: );
378: }
379: return $columns;
380: }
381:
382:
383:
384: 385: 386: 387:
388: public function getResultResource()
389: {
390: return $this->resultSet;
391: }
392:
393:
394: }
395: