dbo_firebird.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: dbo_firebird.php 7847 2008-11-08 02:54:07Z renan.saddam $ */
00003 /**
00004  * Firebird/Interbase layer for DBO
00005  *
00006  * Long description for file
00007  *
00008  * PHP versions 4 and 5
00009  *
00010  * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
00011  * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00012  *
00013  * Licensed under The MIT License
00014  * Redistributions of files must retain the above copyright notice.
00015  *
00016  * @filesource
00017  * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00018  * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00019  * @package       cake
00020  * @subpackage    cake.cake.libs.model.dbo
00021  * @since         CakePHP(tm) v 1.2.0.5152
00022  * @version       $Revision: 7847 $
00023  * @modifiedby    $LastChangedBy: renan.saddam $
00024  * @lastmodified  $Date: 2008-11-07 21:54:07 -0500 (Fri, 07 Nov 2008) $
00025  * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
00026  */
00027 /**
00028  * Short description for class.
00029  *
00030  * Long description for class
00031  *
00032  * @package       cake
00033  * @subpackage    cake.cake.libs.model.dbo
00034  */
00035 class DboFirebird extends DboSource {
00036 /**
00037  * Enter description here...
00038  *
00039  * @var unknown_type
00040  */
00041     var $description = "Firebird/Interbase DBO Driver";
00042 /**
00043  * Saves the original table name
00044  *
00045  * @var unknown_type
00046  */
00047     var $modeltmp = array();
00048 /**
00049  * Enter description here...
00050  *
00051  * @var unknown_type
00052  */
00053     var $startQuote = "\'";
00054 /**
00055  * Enter description here...
00056  *
00057  * @var unknown_type
00058  */
00059     var $endQuote = "\'";
00060 /**
00061  * Enter description here...
00062  *
00063  * @var unknown_type
00064  */
00065     var $alias = ' ';
00066 /**
00067  * Enter description here...
00068  *
00069  * @var unknown_type
00070  */
00071     var $goofyLimit = true;
00072 /**
00073  * Creates a map between field aliases and numeric indexes.
00074  *
00075  * @var array
00076  */
00077     var $__fieldMappings = array();
00078 /**
00079  * Base configuration settings for Firebird driver
00080  *
00081  * @var array
00082  */
00083     var $_baseConfig = array(
00084         'persistent' => true,
00085         'host' => 'localhost',
00086         'login' => 'SYSDBA',
00087         'password' => 'masterkey',
00088         'database' => 'c:\\CAKE.FDB',
00089         'port' => '3050',
00090         'connect' => 'ibase_connect'
00091     );
00092 /**
00093  * Firebird column definition
00094  *
00095  * @var array
00096  */
00097     var $columns = array(
00098         'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
00099         'string'    => array('name'  => 'varchar', 'limit' => '255'),
00100         'text'      => array('name' => 'BLOB SUB_TYPE 1 SEGMENT SIZE 100 CHARACTER SET NONE'),
00101         'integer'   => array('name' => 'integer'),
00102         'float'     => array('name' => 'float', 'formatter' => 'floatval'),
00103         'datetime'  => array('name' => 'timestamp', 'format'    => 'd.m.Y H:i:s', 'formatter' => 'date'),
00104         'timestamp' => array('name' => 'timestamp', 'format'     => 'd.m.Y H:i:s', 'formatter' => 'date'),
00105         'time'      => array('name' => 'time', 'format'    => 'H:i:s', 'formatter' => 'date'),
00106         'date'      => array('name' => 'date', 'format'    => 'd.m.Y', 'formatter' => 'date'),
00107         'binary'    => array('name' => 'blob'),
00108         'boolean'   => array('name' => 'smallint')
00109     );
00110 /**
00111  * Firebird Transaction commands.
00112  *
00113  * @var array
00114  **/
00115     var $_commands = array(
00116         'begin'    => 'SET TRANSACTION',
00117         'commit'   => 'COMMIT',
00118         'rollback' => 'ROLLBACK'
00119     );
00120 /**
00121  * Connects to the database using options in the given configuration array.
00122  *
00123  * @return boolean True if the database could be connected, else false
00124  */
00125     function connect() {
00126         $config = $this->config;
00127         $connect = $config['connect'];
00128 
00129         $this->connected = false;
00130         $this->connection = $connect($config['host'] . ':' . $config['database'], $config['login'], $config['password']);
00131         $this->connected = true;
00132     }
00133 /**
00134  * Disconnects from database.
00135  *
00136  * @return boolean True if the database could be disconnected, else false
00137  */
00138     function disconnect() {
00139         $this->connected = false;
00140         return @ibase_close($this->connection);
00141     }
00142 /**
00143  * Executes given SQL statement.
00144  *
00145  * @param string $sql SQL statement
00146  * @return resource Result resource identifier
00147  * @access protected
00148  */
00149     function _execute($sql) {
00150         return @ibase_query($this->connection,  $sql);
00151     }
00152 /**
00153  * Returns a row from given resultset as an array .
00154  *
00155  * @return array The fetched row as an array
00156  */
00157     function fetchRow() {
00158         if ($this->hasResult()) {
00159             $this->resultSet($this->_result);
00160             $resultRow = $this->fetchResult();
00161             return $resultRow;
00162         } else {
00163             return null;
00164         }
00165     }
00166 /**
00167  * Returns an array of sources (tables) in the database.
00168  *
00169  * @return array Array of tablenames in the database
00170  */
00171     function listSources() {
00172         $cache = parent::listSources();
00173 
00174         if ($cache != null) {
00175             return $cache;
00176         }
00177         $sql = "select RDB" . "$" . "RELATION_NAME as name
00178                 FROM RDB" ."$" . "RELATIONS
00179                 Where RDB" . "$" . "SYSTEM_FLAG =0";
00180 
00181         $result = @ibase_query($this->connection,$sql);
00182         $tables = array();
00183         while ($row = ibase_fetch_row ($result)) {
00184             $tables[] = strtolower(trim($row[0]));
00185         }
00186         parent::listSources($tables);
00187         return $tables;
00188     }
00189 /**
00190  * Returns an array of the fields in given table name.
00191  *
00192  * @param Model $model Model object to describe
00193  * @return array Fields in table. Keys are name and type
00194  */
00195     function describe(&$model) {
00196         $this->modeltmp[$model->table] = $model->alias;
00197         $cache = parent::describe($model);
00198 
00199         if ($cache != null) {
00200             return $cache;
00201         }
00202         $fields = false;
00203         $sql = "SELECT * FROM " . $this->fullTableName($model, false);
00204         $rs = ibase_query($sql);
00205         $coln = ibase_num_fields($rs);
00206         $fields = false;
00207 
00208         for ($i = 0; $i < $coln; $i++) {
00209             $col_info = ibase_field_info($rs, $i);
00210             $fields[strtolower($col_info['name'])] = array(
00211                     'type' => $this->column($col_info['type']),
00212                     'null' => '',
00213                     'length' => $col_info['length']
00214                 );
00215         }
00216         $this->__cacheDescription($this->fullTableName($model, false), $fields);
00217         return $fields;
00218     }
00219 /**
00220  * Returns a quoted name of $data for use in an SQL statement.
00221  *
00222  * @param string $data Name (table.field) to be prepared for use in an SQL statement
00223  * @return string Quoted for Firebird
00224  */
00225     function name($data) {
00226         if ($data == '*') {
00227                 return '*';
00228         }
00229         $pos = strpos($data, '"');
00230 
00231         if ($pos === false) {
00232             if (!strpos($data, ".")) {
00233                 $data = '"' . strtoupper($data) . '"';
00234             } else {
00235                 $build = explode('.', $data);
00236                 $data = '"' . strtoupper($build[0]) . '"."' . strtoupper($build[1]) . '"';
00237             }
00238         }
00239         return $data;
00240     }
00241 /**
00242  * Returns a quoted and escaped string of $data for use in an SQL statement.
00243  *
00244  * @param string $data String to be prepared for use in an SQL statement
00245  * @param string $column The column into which this data will be inserted
00246  * @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
00247  * @return string Quoted and escaped data
00248  */
00249     function value($data, $column = null, $safe = false) {
00250         $parent = parent::value($data, $column, $safe);
00251 
00252         if ($parent != null) {
00253             return $parent;
00254         }
00255         if ($data === null) {
00256             return 'NULL';
00257         }
00258         if ($data === '') {
00259             return "''";
00260         }
00261 
00262         switch($column) {
00263             case 'boolean':
00264                 $data = $this->boolean((bool)$data);
00265             break;
00266             default:
00267                 if (get_magic_quotes_gpc()) {
00268                     $data = stripslashes(str_replace("'", "''", $data));
00269                 } else {
00270                     $data = str_replace("'", "''", $data);
00271                 }
00272             break;
00273         }
00274         return "'" . $data . "'";
00275     }
00276 /**
00277  * Removes Identity (primary key) column from update data before returning to parent
00278  *
00279  * @param Model $model
00280  * @param array $fields
00281  * @param array $values
00282  * @return array
00283  */
00284     function update(&$model, $fields = array(), $values = array()) {
00285         foreach ($fields as $i => $field) {
00286             if ($field == $model->primaryKey) {
00287                 unset ($fields[$i]);
00288                 unset ($values[$i]);
00289                 break;
00290             }
00291         }
00292         return parent::update($model, $fields, $values);
00293     }
00294 /**
00295  * Returns a formatted error message from previous database operation.
00296  *
00297  * @return string Error message with error number
00298  */
00299     function lastError() {
00300         $error = ibase_errmsg();
00301 
00302         if ($error !== false) {
00303             return $error;
00304         }
00305         return null;
00306     }
00307 /**
00308  * Returns number of affected rows in previous database operation. If no previous operation exists,
00309  * this returns false.
00310  *
00311  * @return integer Number of affected rows
00312  */
00313     function lastAffected() {
00314         if ($this->_result) {
00315             return ibase_affected_rows($this->connection);
00316         }
00317         return null;
00318     }
00319 /**
00320  * Returns number of rows in previous resultset. If no previous resultset exists,
00321  * this returns false.
00322  *
00323  * @return integer Number of rows in resultset
00324  */
00325     function lastNumRows() {
00326         return $this->_result? /*ibase_affected_rows($this->_result)*/ 1: false;
00327     }
00328 /**
00329  * Returns the ID generated from the previous INSERT operation.
00330  *
00331  * @param unknown_type $source
00332  * @return in
00333  */
00334     function lastInsertId($source = null, $field = 'id') {
00335         $query = "SELECT RDB\$TRIGGER_SOURCE
00336         FROM RDB\$TRIGGERS WHERE RDB\$RELATION_NAME = '".  strtoupper($source) .  "' AND
00337         RDB\$SYSTEM_FLAG IS NULL AND  RDB\$TRIGGER_TYPE = 1 ";
00338 
00339         $result = @ibase_query($this->connection,$query);
00340         $generator = "";
00341 
00342         while ($row = ibase_fetch_row($result, IBASE_TEXT)) {
00343             if (strpos($row[0], "NEW." . strtoupper($field))) {
00344                 $pos = strpos($row[0], "GEN_ID(");
00345 
00346                 if ($pos > 0) {
00347                     $pos2 = strpos($row[0],",",$pos + 7);
00348 
00349                     if ($pos2 > 0) {
00350                         $generator = substr($row[0], $pos +7, $pos2 - $pos- 7);
00351                     }
00352                 }
00353                 break;
00354             }
00355         }
00356 
00357         if (!empty($generator)) {
00358             $sql = "SELECT GEN_ID(". $generator  . ",0) AS maxi FROM RDB" . "$" . "DATABASE";
00359             $res = $this->rawQuery($sql);
00360             $data = $this->fetchRow($res);
00361             return $data['maxi'];
00362         } else {
00363             return false;
00364         }
00365     }
00366 /**
00367  * Returns a limit statement in the correct format for the particular database.
00368  *
00369  * @param integer $limit Limit of results returned
00370  * @param integer $offset Offset from which to start results
00371  * @return string SQL limit/offset statement
00372  */
00373     function limit($limit, $offset = null) {
00374         if ($limit) {
00375             $rt = '';
00376 
00377             if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) {
00378                 $rt = ' FIRST';
00379             }
00380             $rt .= ' ' . $limit;
00381 
00382             if (is_int($offset) && $offset > 0) {
00383                 $rt .= ' SKIP ' . $offset;
00384             }
00385             return $rt;
00386         }
00387         return null;
00388     }
00389 /**
00390  * Converts database-layer column types to basic types
00391  *
00392  * @param string $real Real database-layer column type (i.e. "varchar(255)")
00393  * @return string Abstract column type (i.e. "string")
00394  */
00395     function column($real) {
00396         if (is_array($real)) {
00397             $col = $real['name'];
00398 
00399             if (isset($real['limit'])) {
00400                 $col .= '(' . $real['limit'] . ')';
00401             }
00402             return $col;
00403         }
00404 
00405         $col = str_replace(')', '', $real);
00406         $limit = null;
00407         if (strpos($col, '(') !== false) {
00408             list($col, $limit) = explode('(', $col);
00409         }
00410 
00411         if (in_array($col, array('DATE', 'TIME'))) {
00412             return strtolower($col);
00413         }
00414         if ($col == 'TIMESTAMP') {
00415             return 'datetime';
00416         }
00417         if ($col == 'SMALLINT') {
00418             return 'boolean';
00419         }
00420         if (strpos($col, 'int') !== false || $col == 'numeric' || $col == 'INTEGER') {
00421             return 'integer';
00422         }
00423         if (strpos($col, 'char') !== false) {
00424             return 'string';
00425         }
00426         if (strpos($col, 'text') !== false) {
00427             return 'text';
00428         }
00429         if (strpos($col, 'VARCHAR') !== false) {
00430             return 'string';
00431         }
00432         if (strpos($col, 'BLOB') !== false) {
00433             return 'text';
00434         }
00435         if (in_array($col, array('FLOAT', 'NUMERIC', 'DECIMAL'))) {
00436             return 'float';
00437         }
00438         return 'text';
00439     }
00440 /**
00441  * Enter description here...
00442  *
00443  * @param unknown_type $results
00444  */
00445     function resultSet(&$results) {
00446         $this->results =& $results;
00447         $this->map = array();
00448         $num_fields = ibase_num_fields($results);
00449         $index = 0;
00450         $j = 0;
00451 
00452         while ($j < $num_fields) {
00453             $column = ibase_field_info($results, $j);
00454             if (!empty($column[2])) {
00455                 $this->map[$index++] = array(ucfirst(strtolower($this->modeltmp[strtolower($column[2])])), strtolower($column[1]));
00456             } else {
00457                 $this->map[$index++] = array(0, strtolower($column[1]));
00458             }
00459             $j++;
00460         }
00461     }
00462 /**
00463  * Builds final SQL statement
00464  *
00465  * @param string $type Query type
00466  * @param array $data Query data
00467  * @return string
00468  */
00469     function renderStatement($type, $data) {
00470         extract($data);
00471 
00472         if (strtolower($type) == 'select') {
00473             if (preg_match('/offset\s+([0-9]+)/i', $limit, $offset)) {
00474                 $limit = preg_replace('/\s*offset.*$/i', '', $limit);
00475                 preg_match('/top\s+([0-9]+)/i', $limit, $limitVal);
00476                 $offset = intval($offset[1]) + intval($limitVal[1]);
00477                 $rOrder = $this->__switchSort($order);
00478                 list($order2, $rOrder) = array($this->__mapFields($order), $this->__mapFields($rOrder));
00479                 return "SELECT * FROM (SELECT {$limit} * FROM (SELECT TOP {$offset} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$order}) AS Set1 {$rOrder}) AS Set2 {$order2}";
00480             } else {
00481                 return "SELECT {$limit} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$order}";
00482             }
00483         } else {
00484             return parent::renderStatement($type, $data);
00485         }
00486     }
00487 /**
00488  * Fetches the next row from the current result set
00489  *
00490  * @return unknown
00491  */
00492     function fetchResult() {
00493         if ($row = ibase_fetch_row($this->results, IBASE_TEXT)) {
00494             $resultRow = array();
00495             $i = 0;
00496 
00497             foreach ($row as $index => $field) {
00498                 list($table, $column) = $this->map[$index];
00499 
00500                 if (trim($table) == "") {
00501                     $resultRow[0][$column] = $row[$index];
00502                 } else {
00503                     $resultRow[$table][$column] = $row[$index];
00504                     $i++;
00505                 }
00506             }
00507             return $resultRow;
00508         } else {
00509             return false;
00510         }
00511     }
00512 }
00513 ?>

Generated on Sun Nov 22 00:30:53 2009 for CakePHP 1.2.x.x (v1.2.4.8284) by doxygen 1.4.7