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