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: 30: 31: 32: 33:
34: class DboFirebird extends DboSource {
35: 36: 37: 38: 39:
40: var $description = "Firebird/Interbase DBO Driver";
41: 42: 43: 44: 45:
46: var $modeltmp = array();
47: 48: 49: 50: 51:
52: var $startQuote = "\'";
53: 54: 55: 56: 57:
58: var $endQuote = "\'";
59: 60: 61: 62: 63:
64: var $alias = ' ';
65: 66: 67: 68: 69:
70: var $goofyLimit = true;
71: 72: 73: 74: 75:
76: var $__fieldMappings = array();
77: 78: 79: 80: 81:
82: var $_baseConfig = array(
83: 'persistent' => true,
84: 'host' => 'localhost',
85: 'login' => 'SYSDBA',
86: 'password' => 'masterkey',
87: 'database' => 'c:\\CAKE.FDB',
88: 'port' => '3050',
89: 'connect' => 'ibase_connect'
90: );
91: 92: 93: 94: 95:
96: var $columns = array(
97: 'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
98: 'string' => array('name' => 'varchar', 'limit' => '255'),
99: 'text' => array('name' => 'BLOB SUB_TYPE 1 SEGMENT SIZE 100 CHARACTER SET NONE'),
100: 'integer' => array('name' => 'integer'),
101: 'float' => array('name' => 'float', 'formatter' => 'floatval'),
102: 'datetime' => array('name' => 'timestamp', 'format' => 'd.m.Y H:i:s', 'formatter' => 'date'),
103: 'timestamp' => array('name' => 'timestamp', 'format' => 'd.m.Y H:i:s', 'formatter' => 'date'),
104: 'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
105: 'date' => array('name' => 'date', 'format' => 'd.m.Y', 'formatter' => 'date'),
106: 'binary' => array('name' => 'blob'),
107: 'boolean' => array('name' => 'smallint')
108: );
109: 110: 111: 112: 113:
114: var $_commands = array(
115: 'begin' => 'SET TRANSACTION',
116: 'commit' => 'COMMIT',
117: 'rollback' => 'ROLLBACK'
118: );
119: 120: 121: 122: 123:
124: function connect() {
125: $config = $this->config;
126: $connect = $config['connect'];
127:
128: $this->connected = false;
129:
130: $this->connection = $connect($config['host'] . ':' . $config['database'], $config['login'], $config['password']);
131: $this->connected = true;
132: }
133: 134: 135: 136: 137:
138: function enabled() {
139: return extension_loaded('interbase');
140: }
141: 142: 143: 144: 145:
146: function disconnect() {
147: $this->connected = false;
148: return @ibase_close($this->connection);
149: }
150: 151: 152: 153: 154: 155: 156:
157: function _execute($sql) {
158: return @ibase_query($this->connection, $sql);
159: }
160: 161: 162: 163: 164:
165: function fetchRow() {
166: if ($this->hasResult()) {
167: $this->resultSet($this->_result);
168: $resultRow = $this->fetchResult();
169: return $resultRow;
170: } else {
171: return null;
172: }
173: }
174: 175: 176: 177: 178:
179: function listSources() {
180: $cache = parent::listSources();
181:
182: if ($cache != null) {
183: return $cache;
184: }
185: $sql = "select RDB" . "$" . "RELATION_NAME as name
186: FROM RDB" ."$" . "RELATIONS
187: Where RDB" . "$" . "SYSTEM_FLAG =0";
188:
189: $result = @ibase_query($this->connection,$sql);
190: $tables = array();
191: while ($row = ibase_fetch_row ($result)) {
192: $tables[] = strtolower(trim($row[0]));
193: }
194: parent::listSources($tables);
195: return $tables;
196: }
197: 198: 199: 200: 201: 202:
203: function describe(&$model) {
204: $this->modeltmp[$model->table] = $model->alias;
205: $cache = parent::describe($model);
206:
207: if ($cache != null) {
208: return $cache;
209: }
210: $fields = false;
211: $sql = "SELECT * FROM " . $this->fullTableName($model, false);
212: $rs = ibase_query($sql);
213: $coln = ibase_num_fields($rs);
214: $fields = false;
215:
216: for ($i = 0; $i < $coln; $i++) {
217: $col_info = ibase_field_info($rs, $i);
218: $fields[strtolower($col_info['name'])] = array(
219: 'type' => $this->column($col_info['type']),
220: 'null' => '',
221: 'length' => $col_info['length']
222: );
223: }
224: $this->__cacheDescription($this->fullTableName($model, false), $fields);
225: return $fields;
226: }
227: 228: 229: 230: 231: 232:
233: function name($data) {
234: if ($data == '*') {
235: return '*';
236: }
237: $pos = strpos($data, '"');
238:
239: if ($pos === false) {
240: if (!strpos($data, ".")) {
241: $data = '"' . strtoupper($data) . '"';
242: } else {
243: $build = explode('.', $data);
244: $data = '"' . strtoupper($build[0]) . '"."' . strtoupper($build[1]) . '"';
245: }
246: }
247: return $data;
248: }
249: 250: 251: 252: 253: 254: 255: 256:
257: function value($data, $column = null, $safe = false) {
258: $parent = parent::value($data, $column, $safe);
259:
260: if ($parent != null) {
261: return $parent;
262: }
263: if ($data === null) {
264: return 'NULL';
265: }
266: if ($data === '') {
267: return "''";
268: }
269:
270: switch($column) {
271: case 'boolean':
272: $data = $this->boolean((bool)$data);
273: break;
274: default:
275: if (get_magic_quotes_gpc()) {
276: $data = stripslashes(str_replace("'", "''", $data));
277: } else {
278: $data = str_replace("'", "''", $data);
279: }
280: break;
281: }
282: return "'" . $data . "'";
283: }
284: 285: 286: 287: 288: 289: 290: 291:
292: function update(&$model, $fields = array(), $values = array()) {
293: foreach ($fields as $i => $field) {
294: if ($field == $model->primaryKey) {
295: unset ($fields[$i]);
296: unset ($values[$i]);
297: break;
298: }
299: }
300: return parent::update($model, $fields, $values);
301: }
302: 303: 304: 305: 306:
307: function lastError() {
308: $error = ibase_errmsg();
309:
310: if ($error !== false) {
311: return $error;
312: }
313: return null;
314: }
315: 316: 317: 318: 319: 320:
321: function lastAffected() {
322: if ($this->_result) {
323: return ibase_affected_rows($this->connection);
324: }
325: return null;
326: }
327: 328: 329: 330: 331: 332:
333: function lastNumRows() {
334: return $this->_result? 1: false;
335: }
336: 337: 338: 339: 340: 341:
342: function lastInsertId($source = null, $field = 'id') {
343: $query = "SELECT RDB\$TRIGGER_SOURCE
344: FROM RDB\$TRIGGERS WHERE RDB\$RELATION_NAME = '". strtoupper($source) . "' AND
345: RDB\$SYSTEM_FLAG IS NULL AND RDB\$TRIGGER_TYPE = 1 ";
346:
347: $result = @ibase_query($this->connection,$query);
348: $generator = "";
349:
350: while ($row = ibase_fetch_row($result, IBASE_TEXT)) {
351: if (strpos($row[0], "NEW." . strtoupper($field))) {
352: $pos = strpos($row[0], "GEN_ID(");
353:
354: if ($pos > 0) {
355: $pos2 = strpos($row[0],",",$pos + 7);
356:
357: if ($pos2 > 0) {
358: $generator = substr($row[0], $pos +7, $pos2 - $pos- 7);
359: }
360: }
361: break;
362: }
363: }
364:
365: if (!empty($generator)) {
366: $sql = "SELECT GEN_ID(". $generator . ",0) AS maxi FROM RDB" . "$" . "DATABASE";
367: $res = $this->rawQuery($sql);
368: $data = $this->fetchRow($res);
369: return $data['maxi'];
370: } else {
371: return false;
372: }
373: }
374: 375: 376: 377: 378: 379: 380:
381: function limit($limit, $offset = null) {
382: if ($limit) {
383: $rt = '';
384:
385: if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) {
386: $rt = ' FIRST';
387: }
388: $rt .= ' ' . $limit;
389:
390: if (is_int($offset) && $offset > 0) {
391: $rt .= ' SKIP ' . $offset;
392: }
393: return $rt;
394: }
395: return null;
396: }
397: 398: 399: 400: 401: 402:
403: function column($real) {
404: if (is_array($real)) {
405: $col = $real['name'];
406:
407: if (isset($real['limit'])) {
408: $col .= '(' . $real['limit'] . ')';
409: }
410: return $col;
411: }
412:
413: $col = str_replace(')', '', $real);
414: $limit = null;
415: if (strpos($col, '(') !== false) {
416: list($col, $limit) = explode('(', $col);
417: }
418:
419: if (in_array($col, array('DATE', 'TIME'))) {
420: return strtolower($col);
421: }
422: if ($col == 'TIMESTAMP') {
423: return 'datetime';
424: }
425: if ($col == 'SMALLINT') {
426: return 'boolean';
427: }
428: if (strpos($col, 'int') !== false || $col == 'numeric' || $col == 'INTEGER') {
429: return 'integer';
430: }
431: if (strpos($col, 'char') !== false) {
432: return 'string';
433: }
434: if (strpos($col, 'text') !== false) {
435: return 'text';
436: }
437: if (strpos($col, 'VARCHAR') !== false) {
438: return 'string';
439: }
440: if (strpos($col, 'BLOB') !== false) {
441: return 'text';
442: }
443: if (in_array($col, array('FLOAT', 'NUMERIC', 'DECIMAL'))) {
444: return 'float';
445: }
446: return 'text';
447: }
448: 449: 450: 451: 452:
453: function resultSet(&$results) {
454: $this->results =& $results;
455: $this->map = array();
456: $num_fields = ibase_num_fields($results);
457: $index = 0;
458: $j = 0;
459:
460: while ($j < $num_fields) {
461: $column = ibase_field_info($results, $j);
462: if (!empty($column[2])) {
463: $this->map[$index++] = array(ucfirst(strtolower($this->modeltmp[strtolower($column[2])])), strtolower($column[1]));
464: } else {
465: $this->map[$index++] = array(0, strtolower($column[1]));
466: }
467: $j++;
468: }
469: }
470: 471: 472: 473: 474: 475: 476:
477: function renderStatement($type, $data) {
478: extract($data);
479:
480: if (strtolower($type) == 'select') {
481: if (preg_match('/offset\s+([0-9]+)/i', $limit, $offset)) {
482: $limit = preg_replace('/\s*offset.*$/i', '', $limit);
483: preg_match('/top\s+([0-9]+)/i', $limit, $limitVal);
484: $offset = intval($offset[1]) + intval($limitVal[1]);
485: $rOrder = $this->__switchSort($order);
486: list($order2, $rOrder) = array($this->__mapFields($order), $this->__mapFields($rOrder));
487: return "SELECT * FROM (SELECT {$limit} * FROM (SELECT TOP {$offset} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$order}) AS Set1 {$rOrder}) AS Set2 {$order2}";
488: } else {
489: return "SELECT {$limit} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$order}";
490: }
491: } else {
492: return parent::renderStatement($type, $data);
493: }
494: }
495: 496: 497: 498: 499:
500: function fetchResult() {
501: if ($row = ibase_fetch_row($this->results, IBASE_TEXT)) {
502: $resultRow = array();
503: $i = 0;
504:
505: foreach ($row as $index => $field) {
506: list($table, $column) = $this->map[$index];
507:
508: if (trim($table) == "") {
509: $resultRow[0][$column] = $row[$index];
510: } else {
511: $resultRow[$table][$column] = $row[$index];
512: $i++;
513: }
514: }
515: return $resultRow;
516: } else {
517: return false;
518: }
519: }
520: }
521: ?>