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: class DibiOdbcDriver extends DibiObject implements IDibiDriver, IDibiResultDriver, IDibiReflector
28: {
29:
30: private $connection;
31:
32:
33: private $resultSet;
34:
35:
36: private $affectedRows = FALSE;
37:
38:
39: private $row = 0;
40:
41:
42:
43: 44: 45:
46: public function __construct()
47: {
48: if (!extension_loaded('odbc')) {
49: throw new DibiNotSupportedException("PHP extension 'odbc' is not loaded.");
50: }
51: }
52:
53:
54:
55: 56: 57: 58: 59:
60: public function connect(array &$config)
61: {
62: if (isset($config['resource'])) {
63: $this->connection = $config['resource'];
64: } else {
65:
66: if (!isset($config['username'])) $config['username'] = ini_get('odbc.default_user');
67: if (!isset($config['password'])) $config['password'] = ini_get('odbc.default_pw');
68: if (!isset($config['dsn'])) $config['dsn'] = ini_get('odbc.default_db');
69:
70: if (empty($config['persistent'])) {
71: $this->connection = @odbc_connect($config['dsn'], $config['username'], $config['password']);
72: } else {
73: $this->connection = @odbc_pconnect($config['dsn'], $config['username'], $config['password']);
74: }
75: }
76:
77: if (!is_resource($this->connection)) {
78: throw new DibiDriverException(odbc_errormsg() . ' ' . odbc_error());
79: }
80: }
81:
82:
83:
84: 85: 86: 87:
88: public function disconnect()
89: {
90: odbc_close($this->connection);
91: }
92:
93:
94:
95: 96: 97: 98: 99: 100:
101: public function query($sql)
102: {
103: $this->affectedRows = FALSE;
104: $res = @odbc_exec($this->connection, $sql);
105:
106: if ($res === FALSE) {
107: throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection), 0, $sql);
108:
109: } elseif (is_resource($res)) {
110: $this->affectedRows = odbc_num_rows($res);
111: return $this->createResultDriver($res);
112: }
113: }
114:
115:
116:
117: 118: 119: 120:
121: public function getAffectedRows()
122: {
123: return $this->affectedRows;
124: }
125:
126:
127:
128: 129: 130: 131:
132: public function getInsertId($sequence)
133: {
134: throw new DibiNotSupportedException('ODBC does not support autoincrementing.');
135: }
136:
137:
138:
139: 140: 141: 142: 143: 144:
145: public function begin($savepoint = NULL)
146: {
147: if (!odbc_autocommit($this->connection, FALSE)) {
148: throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
149: }
150: }
151:
152:
153:
154: 155: 156: 157: 158: 159:
160: public function commit($savepoint = NULL)
161: {
162: if (!odbc_commit($this->connection)) {
163: throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
164: }
165: odbc_autocommit($this->connection, TRUE);
166: }
167:
168:
169:
170: 171: 172: 173: 174: 175:
176: public function rollback($savepoint = NULL)
177: {
178: if (!odbc_rollback($this->connection)) {
179: throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
180: }
181: odbc_autocommit($this->connection, TRUE);
182: }
183:
184:
185:
186: 187: 188: 189:
190: public function inTransaction()
191: {
192: return !odbc_autocommit($this->connection);
193: }
194:
195:
196:
197: 198: 199: 200:
201: public function getResource()
202: {
203: return $this->connection;
204: }
205:
206:
207:
208: 209: 210: 211:
212: public function getReflector()
213: {
214: return $this;
215: }
216:
217:
218:
219: 220: 221: 222: 223:
224: public function createResultDriver($resource)
225: {
226: $res = clone $this;
227: $res->resultSet = $resource;
228: return $res;
229: }
230:
231:
232:
233:
234:
235:
236:
237: 238: 239: 240: 241: 242: 243:
244: public function escape($value, $type)
245: {
246: switch ($type) {
247: case dibi::TEXT:
248: case dibi::BINARY:
249: return "'" . str_replace("'", "''", $value) . "'";
250:
251: case dibi::IDENTIFIER:
252: return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
253:
254: case dibi::BOOL:
255: return $value ? 1 : 0;
256:
257: case dibi::DATE:
258: return $value instanceof DateTime ? $value->format("#m/d/Y#") : date("#m/d/Y#", $value);
259:
260: case dibi::DATETIME:
261: return $value instanceof DateTime ? $value->format("#m/d/Y H:i:s#") : date("#m/d/Y H:i:s#", $value);
262:
263: default:
264: throw new InvalidArgumentException('Unsupported type.');
265: }
266: }
267:
268:
269:
270: 271: 272: 273: 274: 275:
276: public function escapeLike($value, $pos)
277: {
278: $value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
279: return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
280: }
281:
282:
283:
284: 285: 286: 287: 288: 289: 290:
291: public function unescape($value, $type)
292: {
293: if ($type === dibi::BINARY) {
294: return $value;
295: }
296: throw new InvalidArgumentException('Unsupported type.');
297: }
298:
299:
300:
301: 302: 303: 304: 305: 306: 307:
308: public function applyLimit(&$sql, $limit, $offset)
309: {
310:
311: if ($limit >= 0) {
312: $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
313: }
314:
315: if ($offset) throw new DibiNotSupportedException('Offset is not implemented in driver odbc.');
316: }
317:
318:
319:
320:
321:
322:
323:
324: 325: 326: 327:
328: public function __destruct()
329: {
330: $this->resultSet && @$this->free();
331: }
332:
333:
334:
335: 336: 337: 338:
339: public function getRowCount()
340: {
341:
342: return odbc_num_rows($this->resultSet);
343: }
344:
345:
346:
347: 348: 349: 350: 351:
352: public function fetch($assoc)
353: {
354: if ($assoc) {
355: return odbc_fetch_array($this->resultSet, ++$this->row);
356: } else {
357: $set = $this->resultSet;
358: if (!odbc_fetch_row($set, ++$this->row)) return FALSE;
359: $count = odbc_num_fields($set);
360: $cols = array();
361: for ($i = 1; $i <= $count; $i++) $cols[] = odbc_result($set, $i);
362: return $cols;
363: }
364: }
365:
366:
367:
368: 369: 370: 371: 372:
373: public function seek($row)
374: {
375: $this->row = $row;
376: return TRUE;
377: }
378:
379:
380:
381: 382: 383: 384:
385: public function free()
386: {
387: odbc_free_result($this->resultSet);
388: $this->resultSet = NULL;
389: }
390:
391:
392:
393: 394: 395: 396:
397: public function getResultColumns()
398: {
399: $count = odbc_num_fields($this->resultSet);
400: $columns = array();
401: for ($i = 1; $i <= $count; $i++) {
402: $columns[] = array(
403: 'name' => odbc_field_name($this->resultSet, $i),
404: 'table' => NULL,
405: 'fullname' => odbc_field_name($this->resultSet, $i),
406: 'nativetype'=> odbc_field_type($this->resultSet, $i),
407: );
408: }
409: return $columns;
410: }
411:
412:
413:
414: 415: 416: 417:
418: public function getResultResource()
419: {
420: return $this->resultSet;
421: }
422:
423:
424:
425:
426:
427:
428:
429: 430: 431: 432:
433: public function getTables()
434: {
435: $res = odbc_tables($this->connection);
436: $tables = array();
437: while ($row = odbc_fetch_array($res)) {
438: if ($row['TABLE_TYPE'] === 'TABLE' || $row['TABLE_TYPE'] === 'VIEW') {
439: $tables[] = array(
440: 'name' => $row['TABLE_NAME'],
441: 'view' => $row['TABLE_TYPE'] === 'VIEW',
442: );
443: }
444: }
445: odbc_free_result($res);
446: return $tables;
447: }
448:
449:
450:
451: 452: 453: 454: 455:
456: public function getColumns($table)
457: {
458: $res = odbc_columns($this->connection);
459: $columns = array();
460: while ($row = odbc_fetch_array($res)) {
461: if ($row['TABLE_NAME'] === $table) {
462: $columns[] = array(
463: 'name' => $row['COLUMN_NAME'],
464: 'table' => $table,
465: 'nativetype' => $row['TYPE_NAME'],
466: 'size' => $row['COLUMN_SIZE'],
467: 'nullable' => (bool) $row['NULLABLE'],
468: 'default' => $row['COLUMN_DEF'],
469: );
470: }
471: }
472: odbc_free_result($res);
473: return $columns;
474: }
475:
476:
477:
478: 479: 480: 481: 482:
483: public function getIndexes($table)
484: {
485: throw new DibiNotImplementedException;
486: }
487:
488:
489:
490: 491: 492: 493: 494:
495: public function getForeignKeys($table)
496: {
497: throw new DibiNotImplementedException;
498: }
499:
500: }
501: