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