2008-05-30 11:40:08 +00:00
< ? php
/**
2017-06-10 21:33:55 +00:00
* CakePHP ( tm ) : Rapid Development Framework ( https :// cakephp . org )
2017-06-10 22:10:52 +00:00
* Copyright ( c ) Cake Software Foundation , Inc . ( https :// cakefoundation . org )
2008-05-30 11:40:08 +00:00
*
* Licensed under The MIT License
2013-02-08 12:22:51 +00:00
* For full copyright and license information , please see the LICENSE . txt
2008-05-30 11:40:08 +00:00
* Redistributions of files must retain the above copyright notice .
*
2017-06-10 22:10:52 +00:00
* @ copyright Copyright ( c ) Cake Software Foundation , Inc . ( https :// cakefoundation . org )
2017-06-10 21:33:55 +00:00
* @ link https :// cakephp . org CakePHP ( tm ) Project
2011-07-26 06:16:14 +00:00
* @ package Cake . Model . Datasource . Database
2008-10-30 17:30:26 +00:00
* @ since CakePHP ( tm ) v 0.9 . 1.114
2017-06-10 22:23:14 +00:00
* @ license https :// opensource . org / licenses / mit - license . php MIT License
2008-05-30 11:40:08 +00:00
*/
2009-07-24 19:18:37 +00:00
2011-01-06 03:30:33 +00:00
App :: uses ( 'DboSource' , 'Model/Datasource' );
2008-05-30 11:40:08 +00:00
/**
* PostgreSQL layer for DBO .
*
2011-07-26 06:16:14 +00:00
* @ package Cake . Model . Datasource . Database
2008-05-30 11:40:08 +00:00
*/
2011-01-06 03:30:33 +00:00
class Postgres extends DboSource {
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Driver description
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $description = " PostgreSQL DBO Driver " ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2012-12-22 22:48:15 +00:00
* Base driver configuration settings . Merged with user settings .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-04-04 06:36:12 +00:00
protected $_baseConfig = array (
2008-05-30 11:40:08 +00:00
'persistent' => true ,
'host' => 'localhost' ,
'login' => 'root' ,
'password' => '' ,
'database' => 'cake' ,
'schema' => 'public' ,
'port' => 5432 ,
2013-11-24 06:04:17 +00:00
'encoding' => '' ,
2014-11-15 20:10:55 +00:00
'sslmode' => 'allow' ,
2013-11-24 06:04:17 +00:00
'flags' => array ()
2008-05-30 11:40:08 +00:00
);
2011-07-31 21:05:20 +00:00
/**
* Columns
*
* @ var array
2017-03-09 15:45:35 +00:00
* @ link https :// www . postgresql . org / docs / 9.6 / static / datatype . html PostgreSQL Data Types
2011-07-31 21:05:20 +00:00
*/
2010-04-04 07:14:00 +00:00
public $columns = array (
2008-05-30 11:40:08 +00:00
'primary_key' => array ( 'name' => 'serial NOT NULL' ),
2011-12-16 07:00:07 +00:00
'string' => array ( 'name' => 'varchar' , 'limit' => '255' ),
2008-05-30 11:40:08 +00:00
'text' => array ( 'name' => 'text' ),
'integer' => array ( 'name' => 'integer' , 'formatter' => 'intval' ),
2017-03-12 02:41:22 +00:00
'smallinteger' => array ( 'name' => 'smallint' , 'formatter' => 'intval' ),
'tinyinteger' => array ( 'name' => 'smallint' , 'formatter' => 'intval' ),
2012-08-30 11:39:14 +00:00
'biginteger' => array ( 'name' => 'bigint' , 'limit' => '20' ),
2008-05-30 11:40:08 +00:00
'float' => array ( 'name' => 'float' , 'formatter' => 'floatval' ),
2013-09-28 06:07:00 +00:00
'decimal' => array ( 'name' => 'decimal' , 'formatter' => 'floatval' ),
2008-05-30 11:40:08 +00:00
'datetime' => array ( 'name' => 'timestamp' , 'format' => 'Y-m-d H:i:s' , 'formatter' => 'date' ),
'timestamp' => array ( 'name' => 'timestamp' , 'format' => 'Y-m-d H:i:s' , 'formatter' => 'date' ),
'time' => array ( 'name' => 'time' , 'format' => 'H:i:s' , 'formatter' => 'date' ),
'date' => array ( 'name' => 'date' , 'format' => 'Y-m-d' , 'formatter' => 'date' ),
'binary' => array ( 'name' => 'bytea' ),
'boolean' => array ( 'name' => 'boolean' ),
'number' => array ( 'name' => 'numeric' ),
2016-01-14 17:37:06 +00:00
'inet' => array ( 'name' => 'inet' ),
'uuid' => array ( 'name' => 'uuid' )
2008-05-30 11:40:08 +00:00
);
2010-01-05 12:23:23 +00:00
/**
* Starting Quote
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $startQuote = '"' ;
2008-05-30 11:40:08 +00:00
2010-01-05 12:23:23 +00:00
/**
* Ending Quote
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $endQuote = '"' ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Contains mappings of custom auto - increment sequences , if a table uses a sequence name
* other than what is dictated by convention .
*
* @ var array
*/
2010-04-04 06:36:12 +00:00
protected $_sequenceMap = array ();
2009-07-24 19:18:37 +00:00
2013-02-22 01:14:06 +00:00
/**
* The set of valid SQL operations usable in a WHERE statement
*
* @ var array
*/
2015-06-25 03:39:26 +00:00
protected $_sqlOps = array ( 'like' , 'ilike' , 'or' , 'not' , 'in' , 'between' , '~' , '~\*' , '\!~' , '\!~\*' , 'similar to' );
2013-02-22 01:14:06 +00:00
2008-05-30 11:40:08 +00:00
/**
* Connects to the database using options in the given configuration array .
*
2014-07-03 13:36:42 +00:00
* @ return bool True if successfully connected .
2011-07-31 20:55:52 +00:00
* @ throws MissingConnectionException
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function connect () {
2008-05-30 11:40:08 +00:00
$config = $this -> config ;
$this -> connected = false ;
2013-07-15 04:18:09 +00:00
2013-11-24 06:04:17 +00:00
$flags = $config [ 'flags' ] + array (
2013-07-15 04:18:09 +00:00
PDO :: ATTR_PERSISTENT => $config [ 'persistent' ],
PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION
);
2010-10-18 04:06:34 +00:00
try {
$this -> _connection = new PDO (
2014-11-15 20:10:55 +00:00
" pgsql:host= { $config [ 'host' ] } ;port= { $config [ 'port' ] } ;dbname= { $config [ 'database' ] } ;sslmode= { $config [ 'sslmode' ] } " ,
2010-10-18 04:06:34 +00:00
$config [ 'login' ],
$config [ 'password' ],
$flags
);
2010-10-19 04:45:32 +00:00
$this -> connected = true ;
2010-10-18 04:06:34 +00:00
if ( ! empty ( $config [ 'encoding' ])) {
$this -> setEncoding ( $config [ 'encoding' ]);
}
2010-10-19 04:45:32 +00:00
if ( ! empty ( $config [ 'schema' ])) {
2013-12-30 02:43:56 +00:00
$this -> _execute ( 'SET search_path TO "' . $config [ 'schema' ] . '"' );
2010-10-19 04:45:32 +00:00
}
2013-03-07 22:45:42 +00:00
if ( ! empty ( $config [ 'settings' ])) {
foreach ( $config [ 'settings' ] as $key => $value ) {
$this -> _execute ( " SET $key TO $value " );
}
}
2010-10-18 04:06:34 +00:00
} catch ( PDOException $e ) {
2012-09-13 02:31:07 +00:00
throw new MissingConnectionException ( array (
'class' => get_class ( $this ),
'message' => $e -> getMessage ()
));
2008-05-30 11:40:08 +00:00
}
2010-10-18 04:06:34 +00:00
2008-05-30 11:40:08 +00:00
return $this -> connected ;
}
2009-07-24 19:18:37 +00:00
2009-10-20 20:11:31 +00:00
/**
* Check if PostgreSQL is enabled / loaded
*
2014-07-03 13:36:42 +00:00
* @ return bool
2009-11-14 12:19:25 +00:00
*/
2011-05-28 20:38:46 +00:00
public function enabled () {
2010-10-18 04:06:34 +00:00
return in_array ( 'pgsql' , PDO :: getAvailableDrivers ());
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns an array of tables in the database . If there are no tables , an error is raised and the application exits .
*
2014-06-06 18:06:32 +00:00
* @ param mixed $data The sources to list .
2011-12-02 05:58:09 +00:00
* @ return array Array of table names in the database
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function listSources ( $data = null ) {
2008-05-30 11:40:08 +00:00
$cache = parent :: listSources ();
2012-09-21 22:30:43 +00:00
if ( $cache ) {
2008-05-30 11:40:08 +00:00
return $cache ;
}
$schema = $this -> config [ 'schema' ];
2010-10-18 04:38:34 +00:00
$sql = " SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = ? " ;
$result = $this -> _execute ( $sql , array ( $schema ));
2008-05-30 11:40:08 +00:00
if ( ! $result ) {
return array ();
2012-09-21 22:30:43 +00:00
}
2008-05-30 11:40:08 +00:00
2012-09-21 22:30:43 +00:00
$tables = array ();
2008-05-30 11:40:08 +00:00
2012-09-21 22:30:43 +00:00
foreach ( $result as $item ) {
$tables [] = $item -> name ;
2008-05-30 11:40:08 +00:00
}
2012-09-21 22:30:43 +00:00
$result -> closeCursor ();
parent :: listSources ( $tables );
return $tables ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns an array of the fields in given table name .
*
2011-10-15 01:25:14 +00:00
* @ param Model | string $model Name of database table to inspect
2008-05-30 11:40:08 +00:00
* @ return array Fields in table . Keys are name and type
*/
2011-09-03 15:57:58 +00:00
public function describe ( $model ) {
2011-11-05 10:57:08 +00:00
$table = $this -> fullTableName ( $model , false , false );
2012-03-11 14:24:05 +00:00
$fields = parent :: describe ( $table );
2008-05-30 11:40:08 +00:00
$this -> _sequenceMap [ $table ] = array ();
2011-06-01 22:12:25 +00:00
$cols = null ;
2017-03-27 02:22:51 +00:00
$hasPrimary = false ;
2008-05-30 11:40:08 +00:00
if ( $fields === null ) {
2010-10-18 04:53:19 +00:00
$cols = $this -> _execute (
2017-03-27 02:22:51 +00:00
' SELECT DISTINCT table_schema AS schema ,
column_name AS name ,
data_type AS type ,
is_nullable AS null ,
column_default AS default ,
ordinal_position AS position ,
character_maximum_length AS char_length ,
character_octet_length AS oct_length ,
pg_get_serial_sequence ( attr . attrelid :: regclass :: text , attr . attname ) IS NOT NULL AS has_serial
FROM information_schema . columns c
INNER JOIN pg_catalog . pg_namespace ns ON ( ns . nspname = table_schema )
INNER JOIN pg_catalog . pg_class cl ON ( cl . relnamespace = ns . oid AND cl . relname = table_name )
LEFT JOIN pg_catalog . pg_attribute attr ON ( cl . oid = attr . attrelid AND column_name = attr . attname )
WHERE table_name = ? AND table_schema = ? AND table_catalog = ?
ORDER BY ordinal_position ' ,
array ( $table , $this -> config [ 'schema' ], $this -> config [ 'database' ])
2008-08-01 06:33:01 +00:00
);
2008-05-30 11:40:08 +00:00
2012-03-05 03:49:38 +00:00
// @codingStandardsIgnoreStart
// Postgres columns don't match the coding standards.
2010-10-18 04:53:19 +00:00
foreach ( $cols as $c ) {
$type = $c -> type ;
2010-10-19 05:18:08 +00:00
if ( ! empty ( $c -> oct_length ) && $c -> char_length === null ) {
2013-02-12 02:38:08 +00:00
if ( $c -> type === 'character varying' ) {
2010-10-18 04:53:19 +00:00
$length = null ;
$type = 'text' ;
2013-02-12 02:38:08 +00:00
} elseif ( $c -> type === 'uuid' ) {
2016-01-15 19:43:01 +00:00
$type = 'uuid' ;
2012-01-11 22:12:42 +00:00
$length = 36 ;
2008-05-30 11:40:08 +00:00
} else {
2014-09-10 14:40:22 +00:00
$length = ( int ) $c -> oct_length ;
2008-05-30 11:40:08 +00:00
}
2010-10-19 05:18:08 +00:00
} elseif ( ! empty ( $c -> char_length )) {
2014-09-10 14:40:22 +00:00
$length = ( int ) $c -> char_length ;
2010-10-18 04:53:19 +00:00
} else {
$length = $this -> length ( $c -> type );
}
2010-10-26 00:55:07 +00:00
if ( empty ( $length )) {
$length = null ;
}
2010-10-18 04:53:19 +00:00
$fields [ $c -> name ] = array (
2011-12-16 07:00:07 +00:00
'type' => $this -> column ( $type ),
2013-02-12 02:38:08 +00:00
'null' => ( $c -> null === 'NO' ? false : true ),
2010-10-18 04:53:19 +00:00
'default' => preg_replace (
" /^'(.*)' $ / " ,
" $ 1 " ,
2018-10-18 21:16:29 +00:00
preg_replace ( '/::[\w\s]+/' , '' , $c -> default )
2010-10-18 04:53:19 +00:00
),
2017-03-27 02:22:51 +00:00
'length' => $length ,
2010-10-18 04:53:19 +00:00
);
2017-03-27 02:22:51 +00:00
// Serial columns are primary integer keys
if ( $c -> has_serial ) {
$fields [ $c -> name ][ 'key' ] = 'primary' ;
$fields [ $c -> name ][ 'length' ] = 11 ;
$hasPrimary = true ;
}
if ( $hasPrimary === false &&
$model instanceof Model &&
$c -> name === $model -> primaryKey
) {
$fields [ $c -> name ][ 'key' ] = 'primary' ;
if (
$fields [ $c -> name ][ 'type' ] !== 'string' &&
$fields [ $c -> name ][ 'type' ] !== 'uuid'
) {
$fields [ $c -> name ][ 'length' ] = 11 ;
2008-05-30 11:40:08 +00:00
}
2010-10-18 04:53:19 +00:00
}
if (
2013-02-12 02:38:08 +00:00
$fields [ $c -> name ][ 'default' ] === 'NULL' ||
2014-09-24 02:16:18 +00:00
$c -> default === null ||
2010-10-18 04:53:19 +00:00
preg_match ( '/nextval\([\'"]?([\w.]+)/' , $c -> default , $seq )
) {
$fields [ $c -> name ][ 'default' ] = null ;
if ( ! empty ( $seq ) && isset ( $seq [ 1 ])) {
2011-12-15 06:49:48 +00:00
if ( strpos ( $seq [ 1 ], '.' ) === false ) {
$sequenceName = $c -> schema . '.' . $seq [ 1 ];
} else {
$sequenceName = $seq [ 1 ];
}
$this -> _sequenceMap [ $table ][ $c -> name ] = $sequenceName ;
2008-05-30 11:40:08 +00:00
}
}
2014-07-12 03:10:16 +00:00
if ( $fields [ $c -> name ][ 'type' ] === 'timestamp' && $fields [ $c -> name ][ 'default' ] === '' ) {
$fields [ $c -> name ][ 'default' ] = null ;
}
2013-02-12 02:38:08 +00:00
if ( $fields [ $c -> name ][ 'type' ] === 'boolean' && ! empty ( $fields [ $c -> name ][ 'default' ])) {
2011-02-05 17:20:09 +00:00
$fields [ $c -> name ][ 'default' ] = constant ( $fields [ $c -> name ][ 'default' ]);
}
2008-05-30 11:40:08 +00:00
}
2011-08-20 05:39:30 +00:00
$this -> _cacheDescription ( $table , $fields );
2008-05-30 11:40:08 +00:00
}
2012-03-05 03:49:38 +00:00
// @codingStandardsIgnoreEnd
2008-05-30 11:40:08 +00:00
if ( isset ( $model -> sequence )) {
$this -> _sequenceMap [ $table ][ $model -> primaryKey ] = $model -> sequence ;
}
2010-11-17 04:29:24 +00:00
2011-01-02 02:39:22 +00:00
if ( $cols ) {
2011-05-28 20:38:46 +00:00
$cols -> closeCursor ();
2011-01-02 02:39:22 +00:00
}
2008-05-30 11:40:08 +00:00
return $fields ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +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 "
2014-07-03 13:36:42 +00:00
* @ return int
2008-05-30 11:40:08 +00:00
*/
2011-07-30 23:17:20 +00:00
public function lastInsertId ( $source = null , $field = 'id' ) {
2008-05-30 11:40:08 +00:00
$seq = $this -> getSequence ( $source , $field );
2010-10-18 04:38:58 +00:00
return $this -> _connection -> lastInsertId ( $seq );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Gets the associated sequence for the given table / field
*
2012-05-13 00:43:31 +00:00
* @ param string | Model $table Either a full table name ( with prefix ) as a string , or a model object
2008-05-30 11:40:08 +00:00
* @ param string $field Name of the ID database field . Defaults to " id "
* @ return string The associated sequence name from the sequence map , defaults to " { $table } _ { $field } _seq "
*/
2011-05-28 20:38:46 +00:00
public function getSequence ( $table , $field = 'id' ) {
2008-05-30 11:40:08 +00:00
if ( is_object ( $table )) {
2011-11-05 10:57:08 +00:00
$table = $this -> fullTableName ( $table , false , false );
2008-05-30 11:40:08 +00:00
}
2012-10-21 14:32:52 +00:00
if ( ! isset ( $this -> _sequenceMap [ $table ])) {
$this -> describe ( $table );
}
if ( isset ( $this -> _sequenceMap [ $table ][ $field ])) {
2008-05-30 11:40:08 +00:00
return $this -> _sequenceMap [ $table ][ $field ];
}
2013-07-02 23:14:41 +00:00
return " { $table } _ { $field } _seq " ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2012-09-18 00:50:05 +00:00
/**
2012-12-22 22:48:15 +00:00
* Reset a sequence based on the MAX () value of $column . Useful
2012-09-18 00:50:05 +00:00
* for resetting sequences after using insertMulti () .
*
* @ param string $table The name of the table to update .
2013-03-05 07:05:14 +00:00
* @ param string $column The column to use when resetting the sequence value ,
* the sequence name will be fetched using Postgres :: getSequence ();
2014-07-03 13:36:42 +00:00
* @ return bool success .
2012-09-18 00:50:05 +00:00
*/
public function resetSequence ( $table , $column ) {
2012-09-18 18:11:51 +00:00
$tableName = $this -> fullTableName ( $table , false , false );
$fullTable = $this -> fullTableName ( $table );
$sequence = $this -> value ( $this -> getSequence ( $tableName , $column ));
2013-10-31 23:53:42 +00:00
$column = $this -> name ( $column );
2013-10-30 18:25:06 +00:00
$this -> execute ( " SELECT setval( $sequence , (SELECT MAX( $column ) FROM $fullTable )) " );
2012-09-18 00:50:05 +00:00
return true ;
}
2008-05-30 11:40:08 +00:00
/**
* Deletes all the records in a table and drops all associated auto - increment sequences
*
2012-05-13 00:43:31 +00:00
* @ param string | Model $table A string or model class representing the table to be truncated
2014-07-03 13:36:42 +00:00
* @ param bool $reset true for resetting the sequence , false to leave it as is .
2011-12-10 02:14:57 +00:00
* and if 1 , sequences are not modified
2014-07-03 13:36:42 +00:00
* @ return bool SQL TRUNCATE TABLE statement , false if not applicable .
2008-05-30 11:40:08 +00:00
*/
2011-12-10 02:14:57 +00:00
public function truncate ( $table , $reset = false ) {
2011-12-14 07:34:41 +00:00
$table = $this -> fullTableName ( $table , false , false );
if ( ! isset ( $this -> _sequenceMap [ $table ])) {
2010-10-26 00:15:46 +00:00
$cache = $this -> cacheSources ;
$this -> cacheSources = false ;
$this -> describe ( $table );
$this -> cacheSources = $cache ;
}
2011-07-29 02:17:12 +00:00
if ( $this -> execute ( 'DELETE FROM ' . $this -> fullTableName ( $table ))) {
2011-12-14 00:41:57 +00:00
if ( isset ( $this -> _sequenceMap [ $table ]) && $reset != true ) {
2012-12-20 12:47:03 +00:00
foreach ( $this -> _sequenceMap [ $table ] as $sequence ) {
2014-11-18 03:47:07 +00:00
$quoted = $this -> name ( $sequence );
2014-11-19 03:03:21 +00:00
$this -> _execute ( " ALTER SEQUENCE { $quoted } RESTART WITH 1 " );
2008-05-30 11:40:08 +00:00
}
}
return true ;
}
return false ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Prepares field names to be quoted by parent
*
2014-06-06 18:06:32 +00:00
* @ param string $data The name to format .
2008-05-30 11:40:08 +00:00
* @ return string SQL field
*/
2011-05-28 20:38:46 +00:00
public function name ( $data ) {
2008-12-15 02:25:55 +00:00
if ( is_string ( $data )) {
$data = str_replace ( '"__"' , '__' , $data );
}
return parent :: name ( $data );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Generates the fields list of an SQL query .
*
2014-06-06 18:06:32 +00:00
* @ param Model $model The model to get fields for .
* @ param string $alias Alias table name .
* @ param mixed $fields The list of fields to get .
2014-07-03 13:36:42 +00:00
* @ param bool $quote Whether or not to quote identifiers .
2008-05-30 11:40:08 +00:00
* @ return array
*/
2012-02-23 14:10:29 +00:00
public function fields ( Model $model , $alias = null , $fields = array (), $quote = true ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $alias )) {
$alias = $model -> alias ;
}
$fields = parent :: fields ( $model , $alias , $fields , false );
if ( ! $quote ) {
return $fields ;
}
$count = count ( $fields );
2010-11-11 04:18:58 +00:00
if ( $count >= 1 && ! preg_match ( '/^\s*COUNT\(\*/' , $fields [ 0 ])) {
2010-03-25 20:33:34 +00:00
$result = array ();
2008-05-30 11:40:08 +00:00
for ( $i = 0 ; $i < $count ; $i ++ ) {
if ( ! preg_match ( '/^.+\\(.*\\)/' , $fields [ $i ]) && ! preg_match ( '/\s+AS\s+/' , $fields [ $i ])) {
2013-02-12 02:38:08 +00:00
if ( substr ( $fields [ $i ], - 1 ) === '*' ) {
2010-03-25 20:33:34 +00:00
if ( strpos ( $fields [ $i ], '.' ) !== false && $fields [ $i ] != $alias . '.*' ) {
$build = explode ( '.' , $fields [ $i ]);
$AssociatedModel = $model -> { $build [ 0 ]};
} else {
$AssociatedModel = $model ;
}
$_fields = $this -> fields ( $AssociatedModel , $AssociatedModel -> alias , array_keys ( $AssociatedModel -> schema ()));
$result = array_merge ( $result , $_fields );
continue ;
}
2008-05-30 11:40:08 +00:00
$prepend = '' ;
if ( strpos ( $fields [ $i ], 'DISTINCT' ) !== false ) {
$prepend = 'DISTINCT ' ;
$fields [ $i ] = trim ( str_replace ( 'DISTINCT' , '' , $fields [ $i ]));
}
if ( strrpos ( $fields [ $i ], '.' ) === false ) {
$fields [ $i ] = $prepend . $this -> name ( $alias ) . '.' . $this -> name ( $fields [ $i ]) . ' AS ' . $this -> name ( $alias . '__' . $fields [ $i ]);
} else {
$build = explode ( '.' , $fields [ $i ]);
$fields [ $i ] = $prepend . $this -> name ( $build [ 0 ]) . '.' . $this -> name ( $build [ 1 ]) . ' AS ' . $this -> name ( $build [ 0 ] . '__' . $build [ 1 ]);
}
2010-03-25 20:35:45 +00:00
} else {
2012-11-21 14:39:03 +00:00
$fields [ $i ] = preg_replace_callback ( '/\(([\s\.\w]+)\)/' , array ( & $this , '_quoteFunctionField' ), $fields [ $i ]);
2008-05-30 11:40:08 +00:00
}
2010-03-25 20:33:34 +00:00
$result [] = $fields [ $i ];
2008-05-30 11:40:08 +00:00
}
2010-03-25 20:33:34 +00:00
return $result ;
2008-05-30 11:40:08 +00:00
}
return $fields ;
}
2009-07-24 19:18:37 +00:00
2010-03-25 20:35:45 +00:00
/**
* Auxiliary function to quote matched `(Model.fields)` from a preg_replace_callback call
2011-10-22 02:09:45 +00:00
* Quotes the fields in a function call .
2010-03-25 20:35:45 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param string $match matched string
2011-12-02 05:58:09 +00:00
* @ return string quoted string
2010-03-25 20:35:45 +00:00
*/
2011-08-20 04:43:34 +00:00
protected function _quoteFunctionField ( $match ) {
2010-03-25 20:35:45 +00:00
$prepend = '' ;
if ( strpos ( $match [ 1 ], 'DISTINCT' ) !== false ) {
$prepend = 'DISTINCT ' ;
$match [ 1 ] = trim ( str_replace ( 'DISTINCT' , '' , $match [ 1 ]));
}
2011-10-22 02:09:45 +00:00
$constant = preg_match ( '/^\d+|NULL|FALSE|TRUE$/i' , $match [ 1 ]);
if ( ! $constant && strpos ( $match [ 1 ], '.' ) === false ) {
2010-04-07 14:21:29 +00:00
$match [ 1 ] = $this -> name ( $match [ 1 ]);
2011-11-30 15:44:11 +00:00
} elseif ( ! $constant ) {
2010-03-25 20:35:45 +00:00
$parts = explode ( '.' , $match [ 1 ]);
2012-03-11 01:57:18 +00:00
if ( ! Hash :: numeric ( $parts )) {
2010-03-25 20:35:45 +00:00
$match [ 1 ] = $this -> name ( $match [ 1 ]);
}
}
2011-12-16 06:52:07 +00:00
return '(' . $prepend . $match [ 1 ] . ')' ;
2010-03-25 20:35:45 +00:00
}
2008-12-15 02:25:55 +00:00
/**
* Returns an array of the indexes in given datasource name .
*
* @ param string $model Name of model to inspect
* @ return array Fields in table . Keys are column and unique
*/
2011-05-28 20:38:46 +00:00
public function index ( $model ) {
2008-12-15 02:25:55 +00:00
$index = array ();
2011-11-05 10:57:08 +00:00
$table = $this -> fullTableName ( $model , false , false );
2008-12-15 02:25:55 +00:00
if ( $table ) {
$indexes = $this -> query ( " SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, i.indisvalid, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) as statement, c2.reltablespace
FROM pg_catalog . pg_class c , pg_catalog . pg_class c2 , pg_catalog . pg_index i
2009-07-24 19:18:37 +00:00
WHERE c . oid = (
SELECT c . oid
FROM pg_catalog . pg_class c LEFT JOIN pg_catalog . pg_namespace n ON n . oid = c . relnamespace
WHERE c . relname ~ '^(" . $table . ")$'
AND pg_catalog . pg_table_is_visible ( c . oid )
2008-12-15 02:25:55 +00:00
AND n . nspname ~ '^(" . $this->config[' schema '] . ")$'
2009-07-24 19:18:37 +00:00
)
2008-12-15 02:25:55 +00:00
AND c . oid = i . indrelid AND i . indexrelid = c2 . oid
2008-12-16 04:38:48 +00:00
ORDER BY i . indisprimary DESC , i . indisunique DESC , c2 . relname " , false);
2012-09-05 22:22:30 +00:00
foreach ( $indexes as $info ) {
2008-12-15 02:25:55 +00:00
$key = array_pop ( $info );
if ( $key [ 'indisprimary' ]) {
$key [ 'relname' ] = 'PRIMARY' ;
}
preg_match ( '/\(([^\)]+)\)/' , $key [ 'statement' ], $indexColumns );
$parsedColumn = $indexColumns [ 1 ];
if ( strpos ( $indexColumns [ 1 ], ',' ) !== false ) {
$parsedColumn = explode ( ', ' , $indexColumns [ 1 ]);
}
$index [ $key [ 'relname' ]][ 'unique' ] = $key [ 'indisunique' ];
$index [ $key [ 'relname' ]][ 'column' ] = $parsedColumn ;
}
}
return $index ;
}
2009-07-24 19:18:37 +00:00
2008-12-16 04:38:48 +00:00
/**
* Alter the Schema of a table .
*
* @ param array $compare Results of CakeSchema :: compare ()
* @ param string $table name of the table
* @ return array
*/
2011-05-28 20:38:46 +00:00
public function alterSchema ( $compare , $table = null ) {
2008-12-16 04:38:48 +00:00
if ( ! is_array ( $compare )) {
return false ;
}
$out = '' ;
$colList = array ();
foreach ( $compare as $curTable => $types ) {
2010-08-16 02:17:02 +00:00
$indexes = $colList = array ();
2014-04-29 12:19:33 +00:00
if ( ! $table || $table === $curTable ) {
2008-12-16 04:38:48 +00:00
$out .= 'ALTER TABLE ' . $this -> fullTableName ( $curTable ) . " \n " ;
foreach ( $types as $type => $column ) {
if ( isset ( $column [ 'indexes' ])) {
$indexes [ $type ] = $column [ 'indexes' ];
unset ( $column [ 'indexes' ]);
}
switch ( $type ) {
case 'add' :
foreach ( $column as $field => $col ) {
$col [ 'name' ] = $field ;
2011-12-16 06:52:07 +00:00
$colList [] = 'ADD COLUMN ' . $this -> buildColumn ( $col );
2008-12-16 04:38:48 +00:00
}
2013-07-02 22:52:48 +00:00
break ;
2008-12-16 04:38:48 +00:00
case 'drop' :
foreach ( $column as $field => $col ) {
$col [ 'name' ] = $field ;
2011-12-16 06:52:07 +00:00
$colList [] = 'DROP COLUMN ' . $this -> name ( $field );
2008-12-16 04:38:48 +00:00
}
2013-07-02 22:52:48 +00:00
break ;
2008-12-16 04:38:48 +00:00
case 'change' :
2014-01-31 08:11:09 +00:00
$schema = $this -> describe ( $curTable );
2008-12-16 04:38:48 +00:00
foreach ( $column as $field => $col ) {
if ( ! isset ( $col [ 'name' ])) {
$col [ 'name' ] = $field ;
}
2014-01-31 08:11:09 +00:00
$original = $schema [ $field ];
2008-12-16 04:38:48 +00:00
$fieldName = $this -> name ( $field );
2010-03-09 20:39:16 +00:00
$default = isset ( $col [ 'default' ]) ? $col [ 'default' ] : null ;
$nullable = isset ( $col [ 'null' ]) ? $col [ 'null' ] : null ;
2014-04-29 12:19:33 +00:00
$boolToInt = $original [ 'type' ] === 'boolean' && $col [ 'type' ] === 'integer' ;
2010-03-09 20:39:16 +00:00
unset ( $col [ 'default' ], $col [ 'null' ]);
2013-02-13 12:44:49 +00:00
if ( $field !== $col [ 'name' ]) {
$newName = $this -> name ( $col [ 'name' ]);
$out .= " \t RENAME { $fieldName } TO { $newName } ; \n " ;
$out .= 'ALTER TABLE ' . $this -> fullTableName ( $curTable ) . " \n " ;
$fieldName = $newName ;
}
2014-01-31 08:11:09 +00:00
if ( $boolToInt ) {
$colList [] = 'ALTER COLUMN ' . $fieldName . ' SET DEFAULT NULL' ;
$colList [] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace ( array ( $fieldName , 'NOT NULL' ), '' , $this -> buildColumn ( $col )) . ' USING CASE WHEN TRUE THEN 1 ELSE 0 END' ;
} else {
2014-12-30 00:24:31 +00:00
if ( $original [ 'type' ] === 'text' && $col [ 'type' ] === 'integer' ) {
$colList [] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace ( array ( $fieldName , 'NOT NULL' ), '' , $this -> buildColumn ( $col )) . " USING cast( { $fieldName } as INTEGER) " ;
} else {
$colList [] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace ( array ( $fieldName , 'NOT NULL' ), '' , $this -> buildColumn ( $col ));
}
2014-01-31 08:11:09 +00:00
}
2010-03-09 20:39:16 +00:00
if ( isset ( $nullable )) {
$nullable = ( $nullable ) ? 'DROP NOT NULL' : 'SET NOT NULL' ;
2012-03-04 19:18:04 +00:00
$colList [] = 'ALTER COLUMN ' . $fieldName . ' ' . $nullable ;
2010-03-09 20:39:16 +00:00
}
if ( isset ( $default )) {
2014-01-31 08:11:09 +00:00
if ( ! $boolToInt ) {
$colList [] = 'ALTER COLUMN ' . $fieldName . ' SET DEFAULT ' . $this -> value ( $default , $col [ 'type' ]);
}
2010-03-09 20:39:16 +00:00
} else {
2012-03-04 19:18:04 +00:00
$colList [] = 'ALTER COLUMN ' . $fieldName . ' DROP DEFAULT' ;
2010-03-09 20:39:16 +00:00
}
2008-12-16 04:38:48 +00:00
}
2013-07-02 22:52:48 +00:00
break ;
2008-12-16 04:38:48 +00:00
}
}
if ( isset ( $indexes [ 'drop' ][ 'PRIMARY' ])) {
$colList [] = 'DROP CONSTRAINT ' . $curTable . '_pkey' ;
}
if ( isset ( $indexes [ 'add' ][ 'PRIMARY' ])) {
$cols = $indexes [ 'add' ][ 'PRIMARY' ][ 'column' ];
if ( is_array ( $cols )) {
$cols = implode ( ', ' , $cols );
}
$colList [] = 'ADD PRIMARY KEY (' . $cols . ')' ;
}
2009-07-24 19:18:37 +00:00
2008-12-16 04:38:48 +00:00
if ( ! empty ( $colList )) {
2009-11-19 22:13:35 +00:00
$out .= " \t " . implode ( " , \n \t " , $colList ) . " ; \n \n " ;
2008-12-16 04:38:48 +00:00
} else {
$out = '' ;
}
2010-08-16 02:17:02 +00:00
$out .= implode ( " ; \n \t " , $this -> _alterIndexes ( $curTable , $indexes ));
2008-12-16 04:38:48 +00:00
}
}
return $out ;
}
2009-07-24 19:18:37 +00:00
2008-12-16 04:38:48 +00:00
/**
* Generate PostgreSQL index alteration statements for a table .
*
* @ param string $table Table to alter indexes for
2011-07-30 22:38:57 +00:00
* @ param array $indexes Indexes to add and drop
2008-12-16 04:38:48 +00:00
* @ return array Index alteration statements
2009-07-24 19:18:37 +00:00
*/
2011-05-28 20:38:46 +00:00
protected function _alterIndexes ( $table , $indexes ) {
2008-12-16 04:38:48 +00:00
$alter = array ();
if ( isset ( $indexes [ 'drop' ])) {
2011-11-30 15:44:11 +00:00
foreach ( $indexes [ 'drop' ] as $name => $value ) {
2008-12-16 04:38:48 +00:00
$out = 'DROP ' ;
2013-02-12 02:38:08 +00:00
if ( $name === 'PRIMARY' ) {
2008-12-16 04:38:48 +00:00
continue ;
} else {
$out .= 'INDEX ' . $name ;
}
$alter [] = $out ;
}
}
if ( isset ( $indexes [ 'add' ])) {
foreach ( $indexes [ 'add' ] as $name => $value ) {
$out = 'CREATE ' ;
2013-02-12 02:38:08 +00:00
if ( $name === 'PRIMARY' ) {
2008-12-16 04:38:48 +00:00
continue ;
} else {
if ( ! empty ( $value [ 'unique' ])) {
$out .= 'UNIQUE ' ;
}
$out .= 'INDEX ' ;
}
if ( is_array ( $value [ 'column' ])) {
2009-11-19 22:13:35 +00:00
$out .= $name . ' ON ' . $table . ' (' . implode ( ', ' , array_map ( array ( & $this , 'name' ), $value [ 'column' ])) . ')' ;
2008-12-16 04:38:48 +00:00
} else {
$out .= $name . ' ON ' . $table . ' (' . $this -> name ( $value [ 'column' ]) . ')' ;
}
$alter [] = $out ;
}
}
return $alter ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns a limit statement in the correct format for the particular database .
*
2014-07-03 13:36:42 +00:00
* @ param int $limit Limit of results returned
* @ param int $offset Offset from which to start results
2008-05-30 11:40:08 +00:00
* @ return string SQL limit / offset statement
*/
2011-05-28 20:38:46 +00:00
public function limit ( $limit , $offset = null ) {
2008-05-30 11:40:08 +00:00
if ( $limit ) {
2013-05-03 03:27:26 +00:00
$rt = sprintf ( ' LIMIT %u' , $limit );
2008-05-30 11:40:08 +00:00
if ( $offset ) {
2013-05-03 03:27:26 +00:00
$rt .= sprintf ( ' OFFSET %u' , $offset );
2008-05-30 11:40:08 +00:00
}
return $rt ;
}
return null ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +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 " )
*/
2011-05-28 20:38:46 +00:00
public function column ( $real ) {
2008-05-30 11:40:08 +00:00
if ( is_array ( $real )) {
$col = $real [ 'name' ];
if ( isset ( $real [ 'limit' ])) {
$col .= '(' . $real [ 'limit' ] . ')' ;
}
return $col ;
}
$col = str_replace ( ')' , '' , $real );
2008-09-18 00:23:17 +00:00
2008-05-30 11:40:08 +00:00
if ( strpos ( $col , '(' ) !== false ) {
list ( $col , $limit ) = explode ( '(' , $col );
}
2008-09-18 00:23:17 +00:00
$floats = array (
2013-09-28 06:07:00 +00:00
'float' , 'float4' , 'float8' , 'double' , 'double precision' , 'real'
2008-09-18 00:23:17 +00:00
);
switch ( true ) {
case ( in_array ( $col , array ( 'date' , 'time' , 'inet' , 'boolean' ))) :
return $col ;
case ( strpos ( $col , 'timestamp' ) !== false ) :
return 'datetime' ;
case ( strpos ( $col , 'time' ) === 0 ) :
return 'time' ;
2013-02-12 02:38:08 +00:00
case ( $col === 'bigint' ) :
2012-08-30 11:39:14 +00:00
return 'biginteger' ;
2017-03-05 17:25:14 +00:00
case ( $col === 'smallint' ) :
2017-03-12 02:41:22 +00:00
return 'smallinteger' ;
2013-02-12 02:38:08 +00:00
case ( strpos ( $col , 'int' ) !== false && $col !== 'interval' ) :
2008-09-18 00:23:17 +00:00
return 'integer' ;
2016-01-15 19:43:01 +00:00
case ( strpos ( $col , 'char' ) !== false ) :
2008-09-18 00:23:17 +00:00
return 'string' ;
2016-01-15 19:43:01 +00:00
case ( strpos ( $col , 'uuid' ) !== false ) :
return 'uuid' ;
2008-09-18 00:23:17 +00:00
case ( strpos ( $col , 'text' ) !== false ) :
return 'text' ;
case ( strpos ( $col , 'bytea' ) !== false ) :
return 'binary' ;
2013-09-28 06:07:00 +00:00
case ( $col === 'decimal' || $col === 'numeric' ) :
return 'decimal' ;
2008-09-18 00:23:17 +00:00
case ( in_array ( $col , $floats )) :
return 'float' ;
default :
return 'text' ;
2008-05-30 11:40:08 +00:00
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Gets the length of a database - native column description , or null if no length
*
* @ param string $real Real database - layer column type ( i . e . " varchar(255) " )
2014-07-03 13:36:42 +00:00
* @ return int An integer representing the length of the column
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function length ( $real ) {
2016-10-06 02:28:51 +00:00
$col = $real ;
2016-10-05 01:38:26 +00:00
if ( strpos ( $real , '(' ) !== false ) {
2016-10-06 02:28:51 +00:00
list ( $col , $limit ) = explode ( '(' , $real );
2008-05-30 11:40:08 +00:00
}
2016-10-06 02:28:51 +00:00
if ( $col === 'uuid' ) {
2008-08-27 04:21:01 +00:00
return 36 ;
}
2016-10-02 23:12:34 +00:00
return parent :: length ( $real );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2011-08-01 00:33:09 +00:00
* resultSet method
2008-05-30 11:40:08 +00:00
*
2018-08-25 23:58:56 +00:00
* @ param PDOStatement $results The results
2011-07-30 22:38:57 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2018-08-25 23:58:56 +00:00
public function resultSet ( $results ) {
2008-05-30 11:40:08 +00:00
$this -> map = array ();
2010-10-18 05:08:48 +00:00
$numFields = $results -> columnCount ();
2008-05-30 11:40:08 +00:00
$index = 0 ;
$j = 0 ;
2010-10-18 05:08:48 +00:00
while ( $j < $numFields ) {
$column = $results -> getColumnMeta ( $j );
if ( strpos ( $column [ 'name' ], '__' )) {
list ( $table , $name ) = explode ( '__' , $column [ 'name' ]);
$this -> map [ $index ++ ] = array ( $table , $name , $column [ 'native_type' ]);
2008-05-30 11:40:08 +00:00
} else {
2010-10-18 05:08:48 +00:00
$this -> map [ $index ++ ] = array ( 0 , $column [ 'name' ], $column [ 'native_type' ]);
2008-05-30 11:40:08 +00:00
}
$j ++ ;
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Fetches the next row from the current result set
*
2011-08-01 02:57:17 +00:00
* @ return array
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function fetchResult () {
2011-11-25 18:05:32 +00:00
if ( $row = $this -> _result -> fetch ( PDO :: FETCH_NUM )) {
2008-05-30 11:40:08 +00:00
$resultRow = array ();
2010-10-18 05:08:48 +00:00
foreach ( $this -> map as $index => $meta ) {
list ( $table , $column , $type ) = $meta ;
2008-08-27 04:21:01 +00:00
switch ( $type ) {
case 'bool' :
2013-08-16 18:12:49 +00:00
$resultRow [ $table ][ $column ] = $row [ $index ] === null ? null : $this -> boolean ( $row [ $index ]);
2013-07-02 22:52:48 +00:00
break ;
2008-08-27 04:21:01 +00:00
case 'binary' :
case 'bytea' :
2013-08-16 18:12:49 +00:00
$resultRow [ $table ][ $column ] = $row [ $index ] === null ? null : stream_get_contents ( $row [ $index ]);
2013-07-02 22:52:48 +00:00
break ;
2008-08-27 04:21:01 +00:00
default :
$resultRow [ $table ][ $column ] = $row [ $index ];
}
2008-05-30 11:40:08 +00:00
}
return $resultRow ;
}
2013-07-02 22:52:48 +00:00
$this -> _result -> closeCursor ();
return false ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Translates between PHP boolean values and PostgreSQL boolean values
*
2011-05-28 20:38:46 +00:00
* @ param mixed $data Value to be translated
2014-07-03 13:36:42 +00:00
* @ param bool $quote true to quote a boolean to be used in a query , false to return the boolean value
* @ return bool Converted boolean value
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function boolean ( $data , $quote = false ) {
2008-05-30 11:40:08 +00:00
switch ( true ) {
case ( $data === true || $data === false ) :
2010-10-22 01:04:11 +00:00
$result = $data ;
2010-10-27 02:16:29 +00:00
break ;
2008-05-30 11:40:08 +00:00
case ( $data === 't' || $data === 'f' ) :
2010-10-22 01:04:11 +00:00
$result = ( $data === 't' );
2010-10-27 02:16:29 +00:00
break ;
2008-08-27 12:42:13 +00:00
case ( $data === 'true' || $data === 'false' ) :
2010-10-22 01:04:11 +00:00
$result = ( $data === 'true' );
2010-10-27 02:16:29 +00:00
break ;
2008-08-27 12:42:13 +00:00
case ( $data === 'TRUE' || $data === 'FALSE' ) :
2010-10-22 01:04:11 +00:00
$result = ( $data === 'TRUE' );
2010-10-27 02:16:29 +00:00
break ;
2008-05-30 11:40:08 +00:00
default :
2012-03-04 19:18:04 +00:00
$result = ( bool ) $data ;
2008-05-30 11:40:08 +00:00
}
2010-10-22 01:04:11 +00:00
if ( $quote ) {
2010-10-26 00:16:23 +00:00
return ( $result ) ? 'TRUE' : 'FALSE' ;
2010-10-22 01:04:11 +00:00
}
2012-03-04 19:18:04 +00:00
return ( bool ) $result ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Sets the database encoding
*
* @ param mixed $enc Database encoding
2014-07-03 13:36:42 +00:00
* @ return bool True on success , false on failure
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function setEncoding ( $enc ) {
2011-10-04 08:18:52 +00:00
return $this -> _execute ( 'SET NAMES ' . $this -> value ( $enc )) !== false ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Gets the database encoding
*
* @ return string The database encoding
*/
2011-05-28 20:38:46 +00:00
public function getEncoding () {
2011-10-04 08:18:52 +00:00
$result = $this -> _execute ( 'SHOW client_encoding' ) -> fetch ();
if ( $result === false ) {
return false ;
}
return ( isset ( $result [ 'client_encoding' ])) ? $result [ 'client_encoding' ] : false ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Generate a Postgres - native column schema string
*
2008-09-24 23:02:14 +00:00
* @ param array $column An array structured like the following :
* array ( 'name' => 'value' , 'type' => 'value' [, options ]),
2008-05-30 11:40:08 +00:00
* where options can be 'default' , 'length' , or 'key' .
* @ return string
*/
2011-05-28 20:38:46 +00:00
public function buildColumn ( $column ) {
2008-08-01 13:10:37 +00:00
$col = $this -> columns [ $column [ 'type' ]];
if ( ! isset ( $col [ 'length' ]) && ! isset ( $col [ 'limit' ])) {
unset ( $column [ 'length' ]);
}
2012-08-30 11:39:14 +00:00
$out = parent :: buildColumn ( $column );
$out = preg_replace (
'/integer\([0-9]+\)/' ,
'integer' ,
$out
);
$out = preg_replace (
'/bigint\([0-9]+\)/' ,
'bigint' ,
$out
);
2008-05-31 12:36:38 +00:00
$out = str_replace ( 'integer serial' , 'serial' , $out );
2013-12-18 05:58:18 +00:00
$out = str_replace ( 'bigint serial' , 'bigserial' , $out );
2008-11-06 13:22:57 +00:00
if ( strpos ( $out , 'timestamp DEFAULT' )) {
if ( isset ( $column [ 'null' ]) && $column [ 'null' ]) {
$out = str_replace ( 'DEFAULT NULL' , '' , $out );
} else {
$out = str_replace ( 'DEFAULT NOT NULL' , '' , $out );
}
}
2008-06-03 02:26:40 +00:00
if ( strpos ( $out , 'DEFAULT DEFAULT' )) {
if ( isset ( $column [ 'null' ]) && $column [ 'null' ]) {
2008-05-31 12:36:38 +00:00
$out = str_replace ( 'DEFAULT DEFAULT' , 'DEFAULT NULL' , $out );
} elseif ( in_array ( $column [ 'type' ], array ( 'integer' , 'float' ))) {
$out = str_replace ( 'DEFAULT DEFAULT' , 'DEFAULT 0' , $out );
2013-02-12 02:38:08 +00:00
} elseif ( $column [ 'type' ] === 'boolean' ) {
2008-05-31 12:36:38 +00:00
$out = str_replace ( 'DEFAULT DEFAULT' , 'DEFAULT FALSE' , $out );
}
}
return $out ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Format indexes for create table
*
2014-06-06 18:06:32 +00:00
* @ param array $indexes The index to build
* @ param string $table The table name .
2008-05-30 11:40:08 +00:00
* @ return string
*/
2011-05-28 20:38:46 +00:00
public function buildIndex ( $indexes , $table = null ) {
2008-05-30 11:40:08 +00:00
$join = array ();
2008-11-06 13:22:57 +00:00
if ( ! is_array ( $indexes )) {
return array ();
}
2008-05-30 11:40:08 +00:00
foreach ( $indexes as $name => $value ) {
2013-02-12 02:38:08 +00:00
if ( $name === 'PRIMARY' ) {
2008-05-30 11:40:08 +00:00
$out = 'PRIMARY KEY (' . $this -> name ( $value [ 'column' ]) . ')' ;
} else {
$out = 'CREATE ' ;
if ( ! empty ( $value [ 'unique' ])) {
$out .= 'UNIQUE ' ;
}
if ( is_array ( $value [ 'column' ])) {
2009-11-19 22:13:35 +00:00
$value [ 'column' ] = implode ( ', ' , array_map ( array ( & $this , 'name' ), $value [ 'column' ]));
2008-05-30 11:40:08 +00:00
} else {
$value [ 'column' ] = $this -> name ( $value [ 'column' ]);
}
$out .= " INDEX { $name } ON { $table } ( { $value [ 'column' ] } ); " ;
}
$join [] = $out ;
}
return $join ;
}
2009-07-24 19:18:37 +00:00
2016-01-21 19:01:48 +00:00
/**
* { @ inheritDoc }
*/
public function value ( $data , $column = null , $null = true ) {
$value = parent :: value ( $data , $column , $null );
2016-02-11 01:49:34 +00:00
if ( $column === 'uuid' && is_scalar ( $data ) && $data === '' ) {
return 'NULL' ;
2016-01-21 19:01:48 +00:00
}
return $value ;
}
2008-05-30 11:40:08 +00:00
/**
* Overrides DboSource :: renderStatement to handle schema generation with Postgres - style indexes
*
2014-06-06 18:06:32 +00:00
* @ param string $type The query type .
* @ param array $data The array of data to render .
2008-05-30 11:40:08 +00:00
* @ return string
*/
2011-05-28 20:38:46 +00:00
public function renderStatement ( $type , $data ) {
2008-05-30 11:40:08 +00:00
switch ( strtolower ( $type )) {
case 'schema' :
extract ( $data );
foreach ( $indexes as $i => $index ) {
if ( preg_match ( '/PRIMARY KEY/' , $index )) {
unset ( $indexes [ $i ]);
$columns [] = $index ;
break ;
}
}
2008-09-30 18:59:17 +00:00
$join = array ( 'columns' => " , \n \t " , 'indexes' => " \n " );
2008-05-30 11:40:08 +00:00
foreach ( array ( 'columns' , 'indexes' ) as $var ) {
if ( is_array ( ${$var} )) {
2009-11-19 22:13:35 +00:00
${$var} = implode ( $join [ $var ], array_filter ( ${$var} ));
2008-05-30 11:40:08 +00:00
}
}
2008-09-30 18:59:17 +00:00
return " CREATE TABLE { $table } ( \n \t { $columns } \n ); \n { $indexes } " ;
2008-05-30 11:40:08 +00:00
default :
return parent :: renderStatement ( $type , $data );
}
}
2011-11-05 10:57:08 +00:00
/**
* Gets the schema name
*
* @ return string The schema name
*/
2012-02-17 07:13:12 +00:00
public function getSchemaName () {
2011-11-05 10:57:08 +00:00
return $this -> config [ 'schema' ];
}
2012-04-01 02:39:18 +00:00
/**
* Check if the server support nested transactions
*
2014-07-03 13:36:42 +00:00
* @ return bool
2012-04-01 02:39:18 +00:00
*/
2012-04-27 00:19:03 +00:00
public function nestedTransactionSupported () {
2012-04-27 00:53:18 +00:00
return $this -> useNestedTransactions && version_compare ( $this -> getVersion (), '8.0' , '>=' );
2012-04-01 02:39:18 +00:00
}
2008-05-30 11:40:08 +00:00
}