2005-07-04 01:07:14 +00:00
< ? php
2005-08-21 06:49:02 +00:00
/* SVN FILE: $Id$ */
2005-06-12 20:50:12 +00:00
/**
2005-08-21 06:49:02 +00:00
* PostgreSQL layer for DBO .
2006-01-12 02:10:47 +00:00
*
2005-08-21 06:49:02 +00:00
* Long description for file
*
* PHP versions 4 and 5
*
* CakePHP : Rapid Development Framework < http :// www . cakephp . org />
2006-01-20 07:46:14 +00:00
* Copyright ( c ) 2006 , Cake Software Foundation , Inc .
2005-12-23 21:57:26 +00:00
* 1785 E . Sahara Avenue , Suite 490 - 204
* Las Vegas , Nevada 89104
2005-08-21 06:49:02 +00:00
*
2005-12-23 21:57:26 +00:00
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
2005-08-21 06:49:02 +00:00
*
2006-01-12 02:10:47 +00:00
* @ filesource
2006-01-20 07:46:14 +00:00
* @ copyright Copyright ( c ) 2006 , Cake Software Foundation , Inc .
2005-12-23 21:57:26 +00:00
* @ link http :// www . cakefoundation . org / projects / info / cakephp CakePHP Project
2005-08-21 06:49:02 +00:00
* @ package cake
2006-02-25 19:20:18 +00:00
* @ subpackage cake . cake . libs . model . dbo
2005-08-21 06:49:02 +00:00
* @ since CakePHP v 0.9 . 1.114
* @ version $Revision $
* @ modifiedby $LastChangedBy $
* @ lastmodified $Date $
* @ license http :// www . opensource . org / licenses / mit - license . php The MIT License
*/
2005-06-12 20:50:12 +00:00
/**
2006-02-18 23:42:21 +00:00
* Include DBO .
*/
2006-01-12 02:10:47 +00:00
uses ( 'model' . DS . 'datasources' . DS . 'dbo_source' );
2005-06-12 20:50:12 +00:00
/**
2005-09-07 01:52:45 +00:00
* PostgreSQL layer for DBO .
2006-01-12 02:10:47 +00:00
*
2005-08-21 06:49:02 +00:00
* Long description for class
*
* @ package cake
2006-02-25 19:20:18 +00:00
* @ subpackage cake . cake . libs . model . dbo
2005-08-21 06:49:02 +00:00
* @ since CakePHP v 0.9 . 1.114
*/
2006-01-12 02:10:47 +00:00
class DboPostgres extends DboSource
2005-06-14 19:57:01 +00:00
{
2006-01-12 02:10:47 +00:00
2006-02-18 23:42:21 +00:00
var $description = " PostgreSQL DBO Driver " ;
2006-01-12 02:10:47 +00:00
2006-02-18 23:42:21 +00:00
var $_baseConfig = array ( 'persistent' => true ,
'host' => 'localhost' ,
2006-01-12 02:10:47 +00:00
'login' => 'root' ,
2006-02-18 23:42:21 +00:00
'password' => '' ,
'database' => 'cake' ,
2006-03-01 19:13:48 +00:00
'port' => 5432 );
2006-01-12 02:10:47 +00:00
2006-02-18 23:42:21 +00:00
var $columns = array (
2006-04-27 10:04:08 +00:00
'primary_key' => array ( 'name' => 'serial NOT NULL' ),
'string' => array ( 'name' => 'varchar' , 'limit' => '255' ),
2006-01-12 02:10:47 +00:00
'text' => array ( 'name' => 'text' ),
'integer' => array ( 'name' => 'integer' ),
2006-04-27 10:04:08 +00:00
'float' => array ( 'name' => 'float' ),
2006-01-12 02:10:47 +00:00
'datetime' => array ( 'name' => 'timestamp' ),
2006-04-27 10:04:08 +00:00
'timestamp' => array ( 'name' => 'timestamp' ),
2006-01-12 02:10:47 +00:00
'time' => array ( 'name' => 'time' ),
'date' => array ( 'name' => 'date' ),
'binary' => array ( 'name' => 'bytea' ),
2006-02-16 09:29:28 +00:00
'boolean' => array ( 'name' => 'boolean' ),
'number' => array ( 'name' => 'numeric' ));
2006-01-12 02:10:47 +00:00
2006-03-26 09:59:40 +00:00
var $startQuote = '"' ;
var $endQuote = '"' ;
2005-06-12 20:50:12 +00:00
/**
2006-02-18 23:42:21 +00:00
* Connects to the database using options in the given configuration array .
*
* @ return True if successfully connected .
*/
function connect ()
{
2006-01-12 02:10:47 +00:00
$config = $this -> config ;
2006-01-17 17:52:23 +00:00
$connect = $config [ 'connect' ];
2005-07-10 05:08:19 +00:00
2006-04-27 10:04:08 +00:00
$this -> connection = $connect ( " host= { $config [ 'host' ] } port= { $config [ 'port' ] } dbname= { $config [ 'database' ] } user= { $config [ 'login' ] } password= { $config [ 'password' ] } " );
2006-01-12 02:10:47 +00:00
if ( $this -> connection )
{
$this -> connected = true ;
}
2005-07-10 05:08:19 +00:00
else
2005-08-21 06:49:02 +00:00
{
2006-01-12 02:10:47 +00:00
$this -> connected = false ;
2005-08-21 06:49:02 +00:00
}
2006-01-12 02:10:47 +00:00
return $this -> connected ;
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
/**
2006-02-18 23:42:21 +00:00
* Disconnects from database .
*
* @ return boolean True if the database could be disconnected , else false
*/
function disconnect ()
{
2006-04-28 05:26:06 +00:00
$this -> connected = !@ pg_close ( $this -> connection );
return ! $this -> connected ;
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Executes given SQL statement .
*
* @ param string $sql SQL statement
* @ return resource Result resource identifier
*/
function _execute ( $sql )
{
2006-04-27 10:04:08 +00:00
return pg_query ( $this -> connection , $sql );
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns a row from given resultset as an array .
*
* @ return array The fetched row as an array
*/
function fetchRow ( $assoc = false )
{
if ( is_resource ( $this -> _result ))
{
$this -> resultSet ( $this -> _result );
$resultRow = $this -> fetchResult ();
2006-03-26 09:59:40 +00:00
return $resultRow ;
2006-02-18 23:42:21 +00:00
}
else
{
return null ;
}
}
2005-06-12 20:50:12 +00:00
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns an array of tables in the database . If there are no tables , an error is raised and the application exits .
*
* @ return array Array of tablenames in the database
*/
function listSources ()
{
2006-04-27 10:04:08 +00:00
$cache = parent :: listSources ();
if ( $cache != null )
{
return $cache ;
}
2005-06-12 20:50:12 +00:00
2006-04-27 10:04:08 +00:00
$sql = " SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = 'public'; " ;
$result = $this -> fetchAll ( $sql );
2005-07-10 05:08:19 +00:00
2006-04-27 10:04:08 +00:00
if ( ! $result )
{
return array ();
}
else
{
$tables = array ();
foreach ( $result as $item )
{
$tables [] = $item [ 0 ][ 'name' ];
}
parent :: listSources ( $tables );
return $tables ;
}
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
2006-02-18 23:42:21 +00:00
/**
2006-02-16 09:29:28 +00:00
* Returns an array of the fields in given table name .
*
* @ param string $tableName Name of database table to inspect
* @ return array Fields in table . Keys are name and type
*/
function & describe ( & $model )
{
$cache = parent :: describe ( $model );
if ( $cache != null )
{
return $cache ;
}
$fields = false ;
2006-04-27 10:04:08 +00:00
$cols = $this -> fetchAll ( " SELECT DISTINCT column_name AS name, data_type AS type, is_nullable AS null, column_default AS default, ordinal_position FROM information_schema.columns WHERE table_name = " . $this -> value ( $model -> table ) . " ORDER BY ordinal_position " );
2006-02-16 09:29:28 +00:00
2006-03-26 09:59:40 +00:00
foreach ( $cols as $column )
{
$colKey = array_keys ( $column );
if ( isset ( $column [ $colKey [ 0 ]]) && ! isset ( $column [ 0 ]))
{
$column [ 0 ] = $column [ $colKey [ 0 ]];
}
if ( isset ( $column [ 0 ]))
{
2006-03-28 02:44:55 +00:00
$fields [] = array ( 'name' => $column [ 0 ][ 'name' ], 'type' => $this -> column ( $column [ 0 ][ 'type' ]), 'null' => $column [ 0 ][ 'null' ], 'default' => $column [ 0 ][ 'default' ]);
2006-03-26 09:59:40 +00:00
}
}
2006-02-16 09:29:28 +00:00
$this -> __cacheDescription ( $model -> table , $fields );
return $fields ;
}
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns a quoted and escaped string of $data for use in an SQL statement .
*
* @ param string $data String to be prepared for use in an SQL statement
* @ return string Quoted and escaped
*/
function name ( $data )
{
2006-03-26 09:59:40 +00:00
if ( $data == '*' )
{
2006-02-18 23:42:21 +00:00
return '*' ;
2006-03-26 09:59:40 +00:00
}
$pos = strpos ( $data , '"' );
if ( $pos === false )
{
$data = '"' . str_replace ( '.' , '"."' , $data ) . '"' ;
}
return $data ;
2006-02-18 23:42:21 +00:00
}
2006-01-12 02:10:47 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns a quoted and escaped string of $data for use in an SQL statement .
*
* @ param string $data String to be prepared for use in an SQL statement
* @ param string $column The column into which this data will be inserted
* @ return string Quoted and escaped
* @ todo Add logic that formats / escapes data based on column type
*/
function value ( $data , $column = null )
{
$parent = parent :: value ( $data , $column );
if ( $parent != null )
{
return $parent ;
}
if ( $data === null )
{
return 'NULL' ;
}
2006-03-26 09:59:40 +00:00
switch ( $column )
2006-02-18 23:42:21 +00:00
{
2006-04-27 10:04:08 +00:00
case 'integer' :
if ( $data == '' )
{
return 'DEFAULT' ;
}
else
{
$data = pg_escape_string ( $data );
}
break ;
2006-03-28 02:44:55 +00:00
case 'binary' :
2006-03-26 09:59:40 +00:00
$data = pg_escape_bytea ( $data );
2006-04-27 10:04:08 +00:00
break ;
2006-03-26 09:59:40 +00:00
case 'boolean' :
2006-03-28 02:44:55 +00:00
$data = $this -> boolean (( bool ) $data );
2006-04-27 10:04:08 +00:00
break ;
2006-03-26 09:59:40 +00:00
default :
if ( ini_get ( 'magic_quotes_gpc' ) == 1 )
{
$data = stripslashes ( $data );
}
$data = pg_escape_string ( $data );
2006-04-27 10:04:08 +00:00
break ;
2006-02-18 23:42:21 +00:00
}
$return = " ' " . $data . " ' " ;
return $return ;
}
2005-06-12 20:50:12 +00:00
2006-03-26 09:59:40 +00:00
/**
* Begin a transaction
*
* @ param unknown_type $model
* @ return boolean True on success , false on fail
* ( i . e . if the database / model does not support transactions ) .
*/
function begin ( & $model )
{
if ( parent :: begin ( $model ))
{
if ( $this -> execute ( 'BEGIN' ))
{
$this -> __transactionStarted = true ;
return true ;
}
}
return false ;
}
/**
* Commit a transaction
*
* @ param unknown_type $model
* @ return boolean True on success , false on fail
* ( i . e . if the database / model does not support transactions ,
* or a transaction has not started ) .
*/
function commit ( & $model )
{
if ( parent :: commit ( $model ))
{
$this -> __transactionStarted ;
return $this -> execute ( 'COMMIT' );
}
return false ;
}
/**
* Rollback a transaction
*
* @ param unknown_type $model
* @ return boolean True on success , false on fail
* ( i . e . if the database / model does not support transactions ,
* or a transaction has not started ) .
*/
function rollback ( & $model )
{
if ( parent :: rollback ( $model ))
{
return $this -> execute ( 'ROLLBACK' );
}
return false ;
}
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns a formatted error message from previous database operation .
*
* @ return string Error message
*/
function lastError ()
{
2006-01-12 02:10:47 +00:00
$last_error = pg_last_error ( $this -> connection );
if ( $last_error )
{
return $last_error ;
}
return null ;
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns number of affected rows in previous database operation . If no previous operation exists , this returns false .
*
* @ return int Number of affected rows
*/
function lastAffected ()
{
2006-01-12 02:10:47 +00:00
if ( $this -> _result )
{
return pg_affected_rows ( $this -> _result );
}
return false ;
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns number of rows in previous resultset . If no previous resultset exists ,
* this returns false .
*
* @ return int Number of rows in resultset
*/
function lastNumRows ()
{
2006-01-12 02:10:47 +00:00
if ( $this -> _result )
{
return pg_num_rows ( $this -> _result );
}
return false ;
2006-02-18 23:42:21 +00:00
}
2005-06-12 20:50:12 +00:00
2005-09-14 04:11:56 +00:00
/**
2006-02-18 23:42:21 +00:00
* Returns the ID generated from the previous INSERT operation .
*
* @ param string $source Name of the database table
* @ param string $field Name of the ID database field . Defaults to " id "
* @ return int
*/
function lastInsertId ( $source , $field = 'id' )
{
2006-04-27 10:04:08 +00:00
$sql = " SELECT last_value AS max FROM { $source } _ { $field } _seq " ;
$res = $this -> rawQuery ( $sql );
$data = $this -> fetchRow ( $res );
return $data [ 0 ][ 'max' ];
2006-02-18 23:42:21 +00:00
}
2005-07-10 05:08:19 +00:00
2006-04-28 05:26:06 +00:00
/**
* Generates the fields list of an SQL query .
*
* @ param Model $model
* @ param string $alias Alias tablename
* @ param mixed $fields
* @ return array
*/
function fields ( & $model , $alias , $fields )
{
if ( is_array ( $fields ))
{
$fields = $fields ;
}
else
{
if ( $fields != null )
{
if ( strpos ( $fields , ',' ))
{
$fields = explode ( ',' , $fields );
}
else
{
$fields = array ( $fields );
}
$fields = array_map ( 'trim' , $fields );
}
else
{
foreach ( $model -> _tableInfo -> value as $field )
{
$fields [] = $field [ 'name' ];
}
}
}
$count = count ( $fields );
if ( $count >= 1 && $fields [ 0 ] != '*' && strpos ( $fields [ 0 ], 'COUNT(*)' ) === false )
{
for ( $i = 0 ; $i < $count ; $i ++ )
{
$dot = strrpos ( $fields [ $i ], '.' );
if ( $dot === false )
{
$fields [ $i ] = $this -> name ( $alias ) . '.' . $this -> name ( $fields [ $i ]) . ' AS ' . $this -> name ( $alias . '__' . $fields [ $i ]);
}
else
{
$build = explode ( '.' , $fields [ $i ]);
$fields [ $i ] = $this -> name ( $build [ 0 ]) . '.' . $this -> name ( $build [ 1 ]) . ' AS ' . $this -> name ( $build [ 0 ] . '__' . $build [ 1 ]);
}
}
}
return $fields ;
}
2005-09-14 04:11:56 +00:00
/**
* Returns a limit statement in the correct format for the particular database .
*
* @ param int $limit Limit of results returned
* @ param int $offset Offset from which to start results
* @ return string SQL limit / offset statement
*/
2006-02-18 23:42:21 +00:00
function limit ( $limit , $offset = null )
{
2006-03-26 09:59:40 +00:00
if ( $limit )
2006-02-18 23:42:21 +00:00
{
$rt = '' ;
2006-03-19 03:26:43 +00:00
if ( ! strpos ( strtolower ( $limit ), 'limit' ) || strpos ( strtolower ( $limit ), 'limit' ) === 0 )
2006-02-18 23:42:21 +00:00
{
$rt = ' LIMIT' ;
}
2006-03-26 09:59:40 +00:00
$rt .= ' ' . $limit ;
2006-02-18 23:42:21 +00:00
if ( $offset )
{
2006-03-26 09:59:40 +00:00
$rt .= ' OFFSET ' . $offset ;
2006-02-18 23:42:21 +00:00
}
return $rt ;
}
return null ;
}
2006-02-25 19:20:18 +00:00
2006-03-08 03:13:32 +00:00
/**
* Converts database - layer column types to basic types
*
* @ param string $real Real database - layer column type ( i . e . " varchar(255) " )
* @ return string Abstract column type ( i . e . " string " )
*/
function column ( $real )
{
2006-04-27 10:04:08 +00:00
if ( is_array ( $real ))
{
$col = $real [ 'name' ];
if ( isset ( $real [ 'limit' ]))
{
$col .= '(' . $real [ 'limit' ] . ')' ;
}
return $col ;
}
2006-03-08 03:13:32 +00:00
$col = r ( ')' , '' , $real );
$limit = null ;
@ list ( $col , $limit ) = explode ( '(' , $col );
2006-03-26 09:59:40 +00:00
if ( in_array ( $col , array ( 'date' , 'time' )))
2006-03-08 03:13:32 +00:00
{
return $col ;
}
2006-03-26 09:59:40 +00:00
if ( strpos ( $col , 'timestamp' ) !== false )
{
return 'datetime' ;
}
2006-03-08 03:13:32 +00:00
if ( $col == 'boolean' )
{
return 'boolean' ;
}
2006-04-27 10:04:08 +00:00
if ( strpos ( $col , 'int' ) !== false && $col != 'interval' )
2006-03-08 03:13:32 +00:00
{
return 'integer' ;
}
if ( strpos ( $col , 'char' ) !== false )
{
return 'string' ;
}
if ( strpos ( $col , 'text' ) !== false )
{
return 'text' ;
}
if ( strpos ( $col , 'bytea' ) !== false )
{
return 'binary' ;
}
2006-04-28 05:26:06 +00:00
if ( in_array ( $col , array ( 'float' , 'float4' , 'float8' , 'double' , 'decimal' , 'real' , 'numeric' )))
2006-03-08 03:13:32 +00:00
{
return 'float' ;
}
return 'text' ;
}
/**
* Enter description here ...
*
* @ param unknown_type $results
*/
2006-02-18 23:42:21 +00:00
function resultSet ( & $results )
{
$this -> results =& $results ;
$this -> map = array ();
$num_fields = pg_num_fields ( $results );
$index = 0 ;
$j = 0 ;
2005-06-14 19:57:01 +00:00
2006-02-18 23:42:21 +00:00
while ( $j < $num_fields )
{
$columnName = pg_field_name ( $results , $j );
2006-02-25 19:20:18 +00:00
2006-02-18 23:42:21 +00:00
if ( strpos ( $columnName , '__' ))
{
$parts = explode ( '__' , $columnName );
$this -> map [ $index ++ ] = array ( $parts [ 0 ], $parts [ 1 ]);
}
else
{
$this -> map [ $index ++ ] = array ( 0 , $columnName );
}
$j ++ ;
}
}
/**
* Fetches the next row from the current result set
*
* @ return unknown
*/
function fetchResult ()
{
if ( $row = pg_fetch_row ( $this -> results ))
{
$resultRow = array ();
$i = 0 ;
foreach ( $row as $index => $field )
{
list ( $table , $column ) = $this -> map [ $index ];
$resultRow [ $table ][ $column ] = $row [ $index ];
$i ++ ;
}
return $resultRow ;
}
else
{
return false ;
}
}
2006-03-28 02:44:55 +00:00
/**
* Translates between PHP boolean values and MySQL ( faked ) boolean values
*
* @ param mixed $data Value to be translated
* @ return mixed Converted boolean value
*/
function boolean ( $data )
{
if ( $data === true || $data === false )
{
if ( $data === true )
{
return 't' ;
}
return 'f' ;
}
else
{
if ( strpos ( $data , 't' ) !== false )
{
return true ;
}
return false ;
}
}
/**
* The " C " in CRUD
*
* @ param Model $model
* @ param array $fields
* @ param array $values
* @ return boolean Success
*/
function create ( & $model , $fields = null , $values = null )
{
if ( $fields == null )
{
unset ( $fields , $values );
$fields = array_keys ( $model -> data );
$values = array_values ( $model -> data );
}
foreach ( $fields as $field )
{
$fieldInsert [] = $this -> name ( $field );
}
$count = 0 ;
foreach ( $values as $value )
{
if ( $value === '' )
{
$columns = $model -> loadInfo ();
$columns = $columns -> value ;
foreach ( $columns as $col )
{
if ( $col [ 'name' ] == $fields [ $count ])
{
$insert = $col [ 'default' ];
break ;
}
}
}
if ( empty ( $insert ))
{
$insert = $this -> value ( $value , $model -> getColumnType ( $fields [ $count ]));
}
2006-04-27 10:04:08 +00:00
if ( $insert === '\'\'' )
{
unset ( $fieldInsert [ $count ]);
}
else
{
$valueInsert [] = $insert ;
}
2006-03-28 02:44:55 +00:00
unset ( $insert );
$count ++ ;
}
if ( $this -> execute ( 'INSERT INTO ' . $model -> table . ' (' . join ( ',' , $fieldInsert ) . ') VALUES (' . join ( ',' , $valueInsert ) . ')' ))
{
return true ;
}
return false ;
}
2005-06-12 20:50:12 +00:00
}
2006-02-18 23:42:21 +00:00
?>