2010-04-21 12:01:32 +00:00
< ? php
2010-10-29 13:24:06 +00:00
$drivers [ " pgsql " ] = " PostgreSQL " ;
2010-04-21 12:01:32 +00:00
if ( isset ( $_GET [ " pgsql " ])) {
2010-10-29 13:24:06 +00:00
$possible_drivers = array ( " PgSQL " , " PDO_PgSQL " );
2010-04-21 12:01:32 +00:00
define ( " DRIVER " , " pgsql " );
if ( extension_loaded ( " pgsql " )) {
class Min_DB {
var $extension = " PgSQL " , $_link , $_result , $_string , $_database = true , $server_info , $affected_rows , $error ;
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function _error ( $errno , $error ) {
if ( ini_bool ( " html_errors " )) {
$error = html_entity_decode ( strip_tags ( $error ));
}
2013-07-24 23:26:41 +00:00
$error = preg_replace ( '~^[^:]*: ~' , '' , $error );
2010-04-21 12:01:32 +00:00
$this -> error = $error ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function connect ( $server , $username , $password ) {
2011-07-19 15:58:44 +00:00
global $adminer ;
$db = $adminer -> database ();
2010-04-21 12:01:32 +00:00
set_error_handler ( array ( $this , '_error' ));
$this -> _string = " host=' " . str_replace ( " : " , " ' port=' " , addcslashes ( $server , " ' \\ " )) . " ' user=' " . addcslashes ( $username , " ' \\ " ) . " ' password=' " . addcslashes ( $password , " ' \\ " ) . " ' " ;
2012-02-24 05:47:26 +00:00
$this -> _link = @ pg_connect ( " $this->_string dbname=' " . ( $db != " " ? addcslashes ( $db , " ' \\ " ) : " postgres " ) . " ' " , PGSQL_CONNECT_FORCE_NEW );
2011-07-19 15:58:44 +00:00
if ( ! $this -> _link && $db != " " ) {
2010-04-21 12:01:32 +00:00
// try to connect directly with database for performance
$this -> _database = false ;
2012-02-24 05:47:26 +00:00
$this -> _link = @ pg_connect ( " $this->_string dbname='postgres' " , PGSQL_CONNECT_FORCE_NEW );
2010-04-21 12:01:32 +00:00
}
restore_error_handler ();
if ( $this -> _link ) {
$version = pg_version ( $this -> _link );
$this -> server_info = $version [ " server " ];
pg_set_client_encoding ( $this -> _link , " UTF8 " );
}
return ( bool ) $this -> _link ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function quote ( $string ) {
return " ' " . pg_escape_string ( $this -> _link , $string ) . " ' " ; //! bytea
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function select_db ( $database ) {
2011-07-19 15:58:44 +00:00
global $adminer ;
if ( $database == $adminer -> database ()) {
2010-04-21 12:01:32 +00:00
return $this -> _database ;
}
2010-08-03 13:08:14 +00:00
$return = @ pg_connect ( " $this->_string dbname=' " . addcslashes ( $database , " ' \\ " ) . " ' " , PGSQL_CONNECT_FORCE_NEW );
2010-05-14 13:51:54 +00:00
if ( $return ) {
$this -> _link = $return ;
2010-04-21 12:01:32 +00:00
}
2010-05-14 13:51:54 +00:00
return $return ;
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-22 23:02:28 +00:00
function close () {
2012-02-24 05:47:26 +00:00
$this -> _link = @ pg_connect ( " $this->_string dbname='postgres' " );
2010-04-22 23:02:28 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function query ( $query , $unbuffered = false ) {
$result = @ pg_query ( $this -> _link , $query );
2012-07-15 16:21:22 +00:00
$this -> error = " " ;
2010-04-21 12:01:32 +00:00
if ( ! $result ) {
$this -> error = pg_last_error ( $this -> _link );
return false ;
} elseif ( ! pg_num_fields ( $result )) {
$this -> affected_rows = pg_affected_rows ( $result );
return true ;
}
return new Min_Result ( $result );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function multi_query ( $query ) {
return $this -> _result = $this -> query ( $query );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function store_result () {
return $this -> _result ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function next_result () {
// PgSQL extension doesn't support multiple results
return false ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function result ( $query , $field = 0 ) {
$result = $this -> query ( $query );
2011-02-01 15:26:21 +00:00
if ( ! $result || ! $result -> num_rows ) {
2010-04-21 12:01:32 +00:00
return false ;
}
return pg_fetch_result ( $result -> _result , 0 , $field );
}
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
class Min_Result {
var $_result , $_offset = 0 , $num_rows ;
2013-07-24 23:26:41 +00:00
2015-08-15 15:04:21 +00:00
function __construct ( $result ) {
2010-04-21 12:01:32 +00:00
$this -> _result = $result ;
$this -> num_rows = pg_num_rows ( $result );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function fetch_assoc () {
return pg_fetch_assoc ( $this -> _result );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function fetch_row () {
return pg_fetch_row ( $this -> _result );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function fetch_field () {
$column = $this -> _offset ++ ;
2010-05-14 13:51:54 +00:00
$return = new stdClass ;
2010-04-21 22:22:23 +00:00
if ( function_exists ( 'pg_field_table' )) {
2010-05-14 13:51:54 +00:00
$return -> orgtable = pg_field_table ( $this -> _result , $column );
2010-04-21 22:22:23 +00:00
}
2010-05-14 13:51:54 +00:00
$return -> name = pg_field_name ( $this -> _result , $column );
$return -> orgname = $return -> name ;
$return -> type = pg_field_type ( $this -> _result , $column );
$return -> charsetnr = ( $return -> type == " bytea " ? 63 : 0 ); // 63 - binary
return $return ;
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function __destruct () {
pg_free_result ( $this -> _result );
}
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
} elseif ( extension_loaded ( " pdo_pgsql " )) {
class Min_DB extends Min_PDO {
var $extension = " PDO_PgSQL " ;
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function connect ( $server , $username , $password ) {
2011-07-19 15:58:44 +00:00
global $adminer ;
$db = $adminer -> database ();
2010-04-21 12:01:32 +00:00
$string = " pgsql:host=' " . str_replace ( " : " , " ' port=' " , addcslashes ( $server , " ' \\ " )) . " ' options='-c client_encoding=utf8' " ;
2012-02-24 05:47:26 +00:00
$this -> dsn ( " $string dbname=' " . ( $db != " " ? addcslashes ( $db , " ' \\ " ) : " postgres " ) . " ' " , $username , $password );
2010-04-21 12:01:32 +00:00
//! connect without DB in case of an error
return true ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function select_db ( $database ) {
2011-07-19 15:58:44 +00:00
global $adminer ;
return ( $adminer -> database () == $database );
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-22 23:02:28 +00:00
function close () {
}
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
}
2013-07-05 16:04:06 +00:00
class Min_Driver extends Min_SQL {
2013-07-24 23:26:41 +00:00
2013-07-09 18:34:12 +00:00
function insertUpdate ( $table , $rows , $primary ) {
2013-07-05 16:04:06 +00:00
global $connection ;
2013-07-09 18:34:12 +00:00
foreach ( $rows as $set ) {
$update = array ();
$where = array ();
foreach ( $set as $key => $val ) {
$update [] = " $key = $val " ;
if ( isset ( $primary [ idf_unescape ( $key )])) {
$where [] = " $key = $val " ;
}
}
if ( ! (( $where && queries ( " UPDATE " . table ( $table ) . " SET " . implode ( " , " , $update ) . " WHERE " . implode ( " AND " , $where )) && $connection -> affected_rows )
|| queries ( " INSERT INTO " . table ( $table ) . " ( " . implode ( " , " , array_keys ( $set )) . " ) VALUES ( " . implode ( " , " , $set ) . " ) " )
)) {
return false ;
2013-07-05 16:04:06 +00:00
}
}
2013-07-09 18:34:12 +00:00
return true ;
2013-07-05 16:04:06 +00:00
}
2013-07-24 23:26:41 +00:00
2013-07-05 16:04:06 +00:00
}
2010-04-21 12:01:32 +00:00
function idf_escape ( $idf ) {
return '"' . str_replace ( '"' , '""' , $idf ) . '"' ;
}
2010-05-11 14:45:04 +00:00
function table ( $idf ) {
return idf_escape ( $idf );
}
2010-04-21 12:01:32 +00:00
function connect () {
2017-04-08 17:59:13 +00:00
global $adminer , $types , $structured_types ;
2010-04-21 12:01:32 +00:00
$connection = new Min_DB ;
$credentials = $adminer -> credentials ();
if ( $connection -> connect ( $credentials [ 0 ], $credentials [ 1 ], $credentials [ 2 ])) {
2011-08-23 12:23:48 +00:00
if ( $connection -> server_info >= 9 ) {
$connection -> query ( " SET application_name = 'Adminer' " );
2017-04-08 17:59:13 +00:00
if ( $connection -> server_info >= 9.2 ) {
$structured_types [ lang ( 'Strings' )][] = " json " ;
$types [ " json " ] = 4294967295 ;
if ( $connection -> server_info >= 9.2 ) {
$structured_types [ lang ( 'Strings' )][] = " jsonb " ;
$types [ " jsonb " ] = 4294967295 ;
}
}
2011-08-23 12:23:48 +00:00
}
2010-04-21 12:01:32 +00:00
return $connection ;
}
return $connection -> error ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function get_databases () {
2015-06-07 19:52:43 +00:00
return get_vals ( " SELECT datname FROM pg_database WHERE has_database_privilege(datname, 'CONNECT') ORDER BY datname " );
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-05-14 13:51:54 +00:00
function limit ( $query , $where , $limit , $offset = 0 , $separator = " " ) {
2012-05-14 06:54:07 +00:00
return " $query $where " . ( $limit !== null ? $separator . " LIMIT $limit " . ( $offset ? " OFFSET $offset " : " " ) : " " );
2010-04-21 12:01:32 +00:00
}
2010-05-14 13:51:54 +00:00
function limit1 ( $query , $where ) {
return " $query $where " ;
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function db_collation ( $db , $collations ) {
global $connection ;
return $connection -> result ( " SHOW LC_COLLATE " ); //! respect $db
}
function engines () {
return array ();
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function logged_user () {
global $connection ;
return $connection -> result ( " SELECT user " );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function tables_list () {
2014-05-11 10:20:08 +00:00
$query = " SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = current_schema() " ;
if ( support ( 'materializedview' )) {
$query .= "
2014-05-10 01:57:35 +00:00
UNION ALL
SELECT matviewname , 'MATERIALIZED VIEW'
FROM pg_matviews
2015-01-06 10:20:40 +00:00
WHERE schemaname = current_schema () " ;
2014-05-11 10:20:08 +00:00
}
2015-01-06 10:20:40 +00:00
$query .= "
ORDER BY 1 " ;
2014-05-11 10:20:08 +00:00
return get_key_vals ( $query );
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function count_tables ( $databases ) {
return array (); // would require reconnect
}
function table_status ( $name = " " ) {
$return = array ();
2017-04-08 17:32:29 +00:00
foreach ( get_rows ( " SELECT c.relname AS \" Name \" , CASE c.relkind WHEN 'r' THEN 'table' WHEN 'm' THEN 'materialized view' ELSE 'view' END AS \" Engine \" , pg_relation_size(c.oid) AS \" Data_length \" , pg_total_relation_size(c.oid) - pg_relation_size(c.oid) AS \" Index_length \" , obj_description(c.oid, 'pg_class') AS \" Comment \" , c.relhasoids::int AS \" Oid \" , c.reltuples as \" Rows \" , n.nspname
2014-07-10 10:34:08 +00:00
FROM pg_class c
JOIN pg_namespace n ON ( n . nspname = current_schema () AND n . oid = c . relnamespace )
2017-02-20 11:13:09 +00:00
WHERE relkind IN ( 'r' , 'm' , 'v' )
2017-04-06 16:15:06 +00:00
" . ( $name != " " ? " AND relname = " . q( $name ) : " ORDER BY c . oid " )
2010-10-13 15:53:59 +00:00
) as $row ) { //! Index_length, Auto_increment
2010-04-21 12:01:32 +00:00
$return [ $row [ " Name " ]] = $row ;
}
return ( $name != " " ? $return [ $name ] : $return );
}
2013-07-24 23:26:41 +00:00
2010-05-27 11:31:08 +00:00
function is_view ( $table_status ) {
2014-05-10 01:57:35 +00:00
return in_array ( $table_status [ " Engine " ], array ( " view " , " materialized view " ));
2010-05-27 11:31:08 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function fk_support ( $table_status ) {
return true ;
}
2013-07-24 23:26:41 +00:00
2010-11-11 09:47:32 +00:00
function fields ( $table ) {
2010-04-21 12:01:32 +00:00
$return = array ();
2013-05-30 00:24:27 +00:00
$aliases = array (
'timestamp without time zone' => 'timestamp' ,
'timestamp with time zone' => 'timestamptz' ,
);
2013-05-13 15:39:10 +00:00
foreach ( get_rows ( " SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, d.adsrc AS default, a.attnotnull::int, col_description(c.oid, a.attnum) AS comment
2010-05-21 13:07:59 +00:00
FROM pg_class c
JOIN pg_namespace n ON c . relnamespace = n . oid
JOIN pg_attribute a ON c . oid = a . attrelid
LEFT JOIN pg_attrdef d ON c . oid = d . adrelid AND a . attnum = d . adnum
2010-10-13 16:04:40 +00:00
WHERE c . relname = " . q( $table ) . "
2010-05-21 13:07:59 +00:00
AND n . nspname = current_schema ()
2010-05-21 14:23:44 +00:00
AND NOT a . attisdropped
2010-11-11 09:47:32 +00:00
AND a . attnum > 0
ORDER BY a . attnum "
2010-10-13 15:53:59 +00:00
) as $row ) {
//! collation, primary
2014-07-10 10:26:04 +00:00
preg_match ( '~([^([]+)(\((.*)\))?([a-z ]+)?((\[[0-9]*])*)$~' , $row [ " full_type " ], $match );
list (, $type , $length , $row [ " length " ], $addon , $array ) = $match ;
2013-08-06 22:48:45 +00:00
$row [ " length " ] .= $array ;
2014-07-10 10:26:04 +00:00
$check_type = $type . $addon ;
if ( isset ( $aliases [ $check_type ])) {
$row [ " type " ] = $aliases [ $check_type ];
$row [ " full_type " ] = $row [ " type " ] . $length . $array ;
} else {
$row [ " type " ] = $type ;
$row [ " full_type " ] = $row [ " type " ] . $length . $addon . $array ;
}
2013-05-13 15:39:10 +00:00
$row [ " null " ] = ! $row [ " attnotnull " ];
2013-07-24 23:26:41 +00:00
$row [ " auto_increment " ] = preg_match ( '~^nextval\\(~i' , $row [ " default " ]);
2010-10-13 15:53:59 +00:00
$row [ " privileges " ] = array ( " insert " => 1 , " select " => 1 , " update " => 1 );
2013-07-02 16:20:06 +00:00
if ( preg_match ( '~(.+)::[^)]+(.*)~' , $row [ " default " ], $match )) {
$row [ " default " ] = ( $match [ 1 ][ 0 ] == " ' " ? idf_unescape ( $match [ 1 ]) : $match [ 1 ]) . $match [ 2 ];
2011-05-18 14:52:23 +00:00
}
2010-10-13 15:53:59 +00:00
$return [ $row [ " field " ]] = $row ;
2010-04-21 12:01:32 +00:00
}
return $return ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function indexes ( $table , $connection2 = null ) {
global $connection ;
if ( ! is_object ( $connection2 )) {
$connection2 = $connection ;
}
$return = array ();
2012-06-29 21:59:04 +00:00
$table_oid = $connection2 -> result ( " SELECT oid FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema()) AND relname = " . q ( $table ));
2010-04-21 12:01:32 +00:00
$columns = get_key_vals ( " SELECT attnum, attname FROM pg_attribute WHERE attrelid = $table_oid AND attnum > 0 " , $connection2 );
2017-01-17 09:25:35 +00:00
foreach ( get_rows ( " SELECT relname, indisunique::int, indisprimary::int, indkey, indoption , (indpred IS NOT NULL)::int as indispartial FROM pg_index i, pg_class ci WHERE i.indrelid = $table_oid AND ci.oid = i.indexrelid " , $connection2 ) as $row ) {
2013-06-25 16:42:47 +00:00
$relname = $row [ " relname " ];
2014-07-10 10:34:08 +00:00
$return [ $relname ][ " type " ] = ( $row [ " indispartial " ] ? " INDEX " : ( $row [ " indisprimary " ] ? " PRIMARY " : ( $row [ " indisunique " ] ? " UNIQUE " : " INDEX " )));
2013-06-25 16:42:47 +00:00
$return [ $relname ][ " columns " ] = array ();
2010-04-21 12:01:32 +00:00
foreach ( explode ( " " , $row [ " indkey " ]) as $indkey ) {
2013-06-25 16:42:47 +00:00
$return [ $relname ][ " columns " ][] = $columns [ $indkey ];
2010-04-21 12:01:32 +00:00
}
2013-06-25 16:42:47 +00:00
$return [ $relname ][ " descs " ] = array ();
foreach ( explode ( " " , $row [ " indoption " ]) as $indoption ) {
2013-06-25 22:01:38 +00:00
$return [ $relname ][ " descs " ][] = ( $indoption & 1 ? '1' : null ); // 1 - INDOPTION_DESC
2013-06-25 16:42:47 +00:00
}
$return [ $relname ][ " lengths " ] = array ();
2010-04-21 12:01:32 +00:00
}
return $return ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function foreign_keys ( $table ) {
2011-08-02 15:34:21 +00:00
global $on_actions ;
2010-04-21 12:01:32 +00:00
$return = array ();
2014-07-10 10:34:08 +00:00
foreach ( get_rows ( " SELECT conname, condeferrable::int AS deferrable, pg_get_constraintdef(oid) AS definition
2011-08-01 08:47:45 +00:00
FROM pg_constraint
2011-12-22 05:59:24 +00:00
WHERE conrelid = ( SELECT pc . oid FROM pg_class AS pc INNER JOIN pg_namespace AS pn ON ( pn . oid = pc . relnamespace ) WHERE pc . relname = " . q( $table ) . " AND pn . nspname = current_schema ())
2011-08-01 08:47:45 +00:00
AND contype = 'f' :: char
ORDER BY conkey , conname " ) as $row ) {
if ( preg_match ( '~FOREIGN KEY\s*\((.+)\)\s*REFERENCES (.+)\((.+)\)(.*)$~iA' , $row [ 'definition' ], $match )) {
$row [ 'source' ] = array_map ( 'trim' , explode ( ',' , $match [ 1 ]));
2013-12-21 02:43:14 +00:00
if ( preg_match ( '~^(("([^"]|"")+"|[^"]+)\.)?"?("([^"]|"")+"|[^"]+)$~' , $match [ 2 ], $match2 )) {
$row [ 'ns' ] = str_replace ( '""' , '"' , preg_replace ( '~^"(.+)"$~' , '\1' , $match2 [ 2 ]));
$row [ 'table' ] = str_replace ( '""' , '"' , preg_replace ( '~^"(.+)"$~' , '\1' , $match2 [ 4 ]));
2011-08-02 15:36:12 +00:00
}
2011-08-01 08:47:45 +00:00
$row [ 'target' ] = array_map ( 'trim' , explode ( ',' , $match [ 3 ]));
2011-08-29 11:21:02 +00:00
$row [ 'on_delete' ] = ( preg_match ( " ~ON DELETE ( $on_actions )~ " , $match [ 4 ], $match2 ) ? $match2 [ 1 ] : 'NO ACTION' );
$row [ 'on_update' ] = ( preg_match ( " ~ON UPDATE ( $on_actions )~ " , $match [ 4 ], $match2 ) ? $match2 [ 1 ] : 'NO ACTION' );
2011-08-01 08:47:45 +00:00
$return [ $row [ 'conname' ]] = $row ;
2010-04-21 12:01:32 +00:00
}
}
return $return ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function view ( $name ) {
global $connection ;
2017-02-20 11:13:09 +00:00
return array ( " select " => trim ( $connection -> result ( " SELECT pg_get_viewdef( " . q ( $name ) . " ) " )));
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function collations () {
//! supported in CREATE DATABASE
return array ();
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function information_schema ( $db ) {
return ( $db == " information_schema " );
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function error () {
global $connection ;
$return = h ( $connection -> error );
if ( preg_match ( '~^(.*\\n)?([^\\n]*)\\n( *)\\^(\\n.*)?$~s' , $return , $match )) {
$return = $match [ 1 ] . preg_replace ( '~((?:[^&]|&[^;]*;){' . strlen ( $match [ 3 ]) . '})(.*)~' , '\\1<b>\\2</b>' , $match [ 2 ]) . $match [ 4 ];
}
return nl_br ( $return );
}
2013-07-24 23:26:41 +00:00
2010-04-22 23:02:28 +00:00
function create_database ( $db , $collation ) {
return queries ( " CREATE DATABASE " . idf_escape ( $db ) . ( $collation ? " ENCODING " . idf_escape ( $collation ) : " " ));
}
2013-07-24 23:26:41 +00:00
2010-04-22 23:02:28 +00:00
function drop_databases ( $databases ) {
global $connection ;
$connection -> close ();
2010-05-17 16:18:32 +00:00
return apply_queries ( " DROP DATABASE " , $databases , 'idf_escape' );
2010-04-22 23:02:28 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function rename_database ( $name , $collation ) {
//! current database cannot be renamed
return queries ( " ALTER DATABASE " . idf_escape ( DB ) . " RENAME TO " . idf_escape ( $name ));
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function auto_increment () {
2010-05-05 20:42:25 +00:00
return " " ;
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function alter_table ( $table , $name , $fields , $foreign , $comment , $engine , $collation , $auto_increment , $partitioning ) {
$alter = array ();
$queries = array ();
foreach ( $fields as $field ) {
$column = idf_escape ( $field [ 0 ]);
$val = $field [ 1 ];
if ( ! $val ) {
$alter [] = " DROP $column " ;
} else {
$val5 = $val [ 5 ];
unset ( $val [ 5 ]);
2010-05-05 20:42:25 +00:00
if ( isset ( $val [ 6 ]) && $field [ 0 ] == " " ) { // auto_increment
$val [ 1 ] = ( $val [ 1 ] == " bigint " ? " big " : " " ) . " serial " ;
2010-04-21 12:01:32 +00:00
}
if ( $field [ 0 ] == " " ) {
2010-05-07 16:10:35 +00:00
$alter [] = ( $table != " " ? " ADD " : " " ) . implode ( $val );
2010-04-21 12:01:32 +00:00
} else {
if ( $column != $val [ 0 ]) {
2010-05-11 14:45:04 +00:00
$queries [] = " ALTER TABLE " . table ( $table ) . " RENAME $column TO $val[0] " ;
2010-04-21 12:01:32 +00:00
}
2010-05-05 20:42:25 +00:00
$alter [] = " ALTER $column TYPE $val[1] " ;
2010-04-21 12:01:32 +00:00
if ( ! $val [ 6 ]) {
2013-07-02 16:20:06 +00:00
$alter [] = " ALTER $column " . ( $val [ 3 ] ? " SET $val[3] " : " DROP DEFAULT " );
2010-04-21 12:01:32 +00:00
$alter [] = " ALTER $column " . ( $val [ 2 ] == " NULL " ? " DROP NOT " : " SET " ) . $val [ 2 ];
}
}
2010-05-05 20:42:25 +00:00
if ( $field [ 0 ] != " " || $val5 != " " ) {
2010-05-11 14:45:04 +00:00
$queries [] = " COMMENT ON COLUMN " . table ( $table ) . " . $val[0] IS " . ( $val5 != " " ? substr ( $val5 , 9 ) : " '' " );
2010-04-21 12:01:32 +00:00
}
}
}
$alter = array_merge ( $alter , $foreign );
if ( $table == " " ) {
2010-05-11 14:45:04 +00:00
array_unshift ( $queries , " CREATE TABLE " . table ( $name ) . " ( \n " . implode ( " , \n " , $alter ) . " \n ) " );
2010-04-21 12:01:32 +00:00
} elseif ( $alter ) {
2010-05-11 14:45:04 +00:00
array_unshift ( $queries , " ALTER TABLE " . table ( $table ) . " \n " . implode ( " , \n " , $alter ));
2010-04-21 12:01:32 +00:00
}
if ( $table != " " && $table != $name ) {
2010-05-11 14:45:04 +00:00
$queries [] = " ALTER TABLE " . table ( $table ) . " RENAME TO " . table ( $name );
2010-04-21 12:01:32 +00:00
}
if ( $table != " " || $comment != " " ) {
2010-10-13 16:04:40 +00:00
$queries [] = " COMMENT ON TABLE " . table ( $name ) . " IS " . q ( $comment );
2010-04-21 12:01:32 +00:00
}
if ( $auto_increment != " " ) {
2010-10-13 16:04:40 +00:00
//! $queries[] = "SELECT setval(pg_get_serial_sequence(" . q($name) . ", ), $auto_increment)";
2010-04-21 12:01:32 +00:00
}
foreach ( $queries as $query ) {
if ( ! queries ( $query )) {
return false ;
}
}
return true ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function alter_indexes ( $table , $alter ) {
$create = array ();
$drop = array ();
2013-06-25 00:37:59 +00:00
$queries = array ();
2010-04-21 12:01:32 +00:00
foreach ( $alter as $val ) {
if ( $val [ 0 ] != " INDEX " ) {
2013-06-25 16:42:47 +00:00
//! descending UNIQUE indexes results in syntax error
2011-07-13 13:13:00 +00:00
$create [] = ( $val [ 2 ] == " DROP "
? " \n DROP CONSTRAINT " . idf_escape ( $val [ 1 ])
2014-01-12 03:22:44 +00:00
: " \n ADD " . ( $val [ 1 ] != " " ? " CONSTRAINT " . idf_escape ( $val [ 1 ]) : " " ) . " $val[0] " . ( $val [ 0 ] == " PRIMARY " ? " KEY " : " " ) . " ( " . implode ( " , " , $val [ 2 ]) . " ) "
2011-07-13 13:13:00 +00:00
);
} elseif ( $val [ 2 ] == " DROP " ) {
$drop [] = idf_escape ( $val [ 1 ]);
2013-06-25 00:37:59 +00:00
} else {
2014-01-12 03:22:44 +00:00
$queries [] = " CREATE INDEX " . idf_escape ( $val [ 1 ] != " " ? $val [ 1 ] : uniqid ( $table . " _ " )) . " ON " . table ( $table ) . " ( " . implode ( " , " , $val [ 2 ]) . " ) " ;
2013-06-25 00:37:59 +00:00
}
}
if ( $create ) {
array_unshift ( $queries , " ALTER TABLE " . table ( $table ) . implode ( " , " , $create ));
}
if ( $drop ) {
array_unshift ( $queries , " DROP INDEX " . implode ( " , " , $drop ));
}
foreach ( $queries as $query ) {
if ( ! queries ( $query )) {
2010-04-21 12:01:32 +00:00
return false ;
}
}
2013-06-25 00:37:59 +00:00
return true ;
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function truncate_tables ( $tables ) {
2010-05-11 14:45:04 +00:00
return queries ( " TRUNCATE " . implode ( " , " , array_map ( 'table' , $tables )));
2010-04-21 12:01:32 +00:00
return true ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function drop_views ( $views ) {
2014-05-10 01:57:35 +00:00
return drop_tables ( $views );
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function drop_tables ( $tables ) {
2014-05-10 01:57:35 +00:00
foreach ( $tables as $table ) {
2014-07-10 10:34:08 +00:00
$status = table_status ( $table );
2014-05-10 01:57:35 +00:00
if ( ! queries ( " DROP " . strtoupper ( $status [ " Engine " ]) . " " . table ( $table ))) {
return false ;
}
}
return true ;
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-05-05 20:11:24 +00:00
function move_tables ( $tables , $views , $target ) {
2014-05-10 01:57:35 +00:00
foreach ( array_merge ( $tables , $views ) as $table ) {
$status = table_status ( $table );
if ( ! queries ( " ALTER " . strtoupper ( $status [ " Engine " ]) . " " . table ( $table ) . " SET SCHEMA " . idf_escape ( $target ))) {
2010-05-05 20:11:24 +00:00
return false ;
}
}
return true ;
}
2013-07-24 23:26:41 +00:00
2014-07-10 10:34:08 +00:00
function trigger ( $name , $table = null ) {
2011-08-08 16:18:16 +00:00
if ( $name == " " ) {
return array ( " Statement " => " EXECUTE PROCEDURE () " );
}
2014-07-10 10:34:08 +00:00
if ( $table === null ) {
$table = $_GET [ 'trigger' ];
}
$rows = get_rows ( 'SELECT t.trigger_name AS "Trigger", t.action_timing AS "Timing", (SELECT STRING_AGG(event_manipulation, \' OR \') FROM information_schema.triggers WHERE event_object_table = t.event_object_table AND trigger_name = t.trigger_name ) AS "Events", t.event_manipulation AS "Event", \'FOR EACH \' || t.action_orientation AS "Type", t.action_statement AS "Statement" FROM information_schema.triggers t WHERE t.event_object_table = ' . q ( $table ) . ' AND t.trigger_name = ' . q ( $name ));
2010-10-13 15:53:59 +00:00
return reset ( $rows );
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function triggers ( $table ) {
$return = array ();
2010-10-13 16:04:40 +00:00
foreach ( get_rows ( " SELECT * FROM information_schema.triggers WHERE event_object_table = " . q ( $table )) as $row ) {
2014-07-10 10:34:08 +00:00
$return [ $row [ " trigger_name " ]] = array ( $row [ " action_timing " ], $row [ " event_manipulation " ]);
2010-04-21 12:01:32 +00:00
}
return $return ;
}
2013-07-24 23:26:41 +00:00
2010-04-22 15:53:42 +00:00
function trigger_options () {
return array (
" Timing " => array ( " BEFORE " , " AFTER " ),
2014-03-15 17:58:24 +00:00
" Event " => array ( " INSERT " , " UPDATE " , " DELETE " ),
2010-04-22 19:43:36 +00:00
" Type " => array ( " FOR EACH ROW " , " FOR EACH STATEMENT " ),
2010-04-22 15:53:42 +00:00
);
}
2013-07-24 23:26:41 +00:00
2011-06-03 13:52:55 +00:00
/*
function routine ( $name , $type ) {
//! there can be more functions with the same name differing only in parameters, it must be also passed to DROP FUNCTION
//! no procedures, only functions
//! different syntax of CREATE FUNCTION
$rows = get_rows ( ' SELECT pg_catalog . format_type ( p . prorettype , NULL ) AS " returns " , p . prosrc AS " definition "
FROM pg_catalog . pg_namespace n
JOIN pg_catalog . pg_proc p ON p . pronamespace = n . oid
WHERE n . nspname = current_schema () AND p . proname = ' . q ( $name ));
$rows [ 0 ][ " fields " ] = array (); //!
return $rows [ 0 ];
}
*/
2013-07-24 23:26:41 +00:00
2011-06-03 13:52:55 +00:00
function routines () {
return get_rows ( ' SELECT p . proname AS " ROUTINE_NAME " , p . proargtypes AS " ROUTINE_TYPE " , pg_catalog . format_type ( p . prorettype , NULL ) AS " DTD_IDENTIFIER "
FROM pg_catalog . pg_namespace n
JOIN pg_catalog . pg_proc p ON p . pronamespace = n . oid
WHERE n . nspname = current_schema ()
ORDER BY p . proname ' );
}
2013-07-24 23:26:41 +00:00
2011-06-03 13:52:55 +00:00
function routine_languages () {
return get_vals ( " SELECT langname FROM pg_catalog.pg_language " );
}
2013-07-24 23:26:41 +00:00
2010-05-12 16:07:46 +00:00
function last_id () {
return 0 ; // there can be several sequences
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function explain ( $connection , $query ) {
return $connection -> query ( " EXPLAIN $query " );
}
2013-07-24 23:26:41 +00:00
2011-07-29 15:08:06 +00:00
function found_rows ( $table_status , $where ) {
global $connection ;
2013-07-24 23:26:41 +00:00
if ( preg_match (
" ~ rows=([0-9]+)~ " ,
2011-07-29 15:08:06 +00:00
$connection -> result ( " EXPLAIN SELECT * FROM " . idf_escape ( $table_status [ " Name " ]) . ( $where ? " WHERE " . implode ( " AND " , $where ) : " " )),
$regs
)) {
return $regs [ 1 ];
}
return false ;
}
2013-07-24 23:26:41 +00:00
2010-05-21 14:07:22 +00:00
function types () {
return get_vals ( " SELECT typname
FROM pg_type
WHERE typnamespace = ( SELECT oid FROM pg_namespace WHERE nspname = current_schema ())
AND typtype IN ( 'b' , 'd' , 'e' )
AND typelem = 0 "
);
}
2013-07-24 23:26:41 +00:00
2010-05-05 16:30:55 +00:00
function schemas () {
2011-07-29 15:59:14 +00:00
return get_vals ( " SELECT nspname FROM pg_namespace ORDER BY nspname " );
2010-05-05 16:30:55 +00:00
}
2013-07-24 23:26:41 +00:00
2010-05-05 16:30:55 +00:00
function get_schema () {
global $connection ;
return $connection -> result ( " SELECT current_schema() " );
}
2013-07-24 23:26:41 +00:00
2010-05-05 16:30:55 +00:00
function set_schema ( $schema ) {
2010-05-21 13:07:59 +00:00
global $connection , $types , $structured_types ;
2010-05-21 14:07:22 +00:00
$return = $connection -> query ( " SET search_path TO " . idf_escape ( $schema ));
foreach ( types () as $type ) { //! get types from current_schemas('t')
2010-05-21 13:07:59 +00:00
if ( ! isset ( $types [ $type ])) {
$types [ $type ] = 0 ;
$structured_types [ lang ( 'User types' )][] = $type ;
}
}
2010-05-21 14:07:22 +00:00
return $return ;
2010-05-05 16:30:55 +00:00
}
2013-07-24 23:26:41 +00:00
2014-07-10 10:34:08 +00:00
/** Get SQL command to create table
* @ param string
* @ param bool
* @ return string
*/
function create_sql ( $table , $auto_increment ) {
global $connection ;
$return = '' ;
$return_parts = array ();
$sequences = array ();
$status = table_status ( $table );
$fields = fields ( $table );
$indexes = indexes ( $table );
ksort ( $indexes );
$fkeys = foreign_keys ( $table );
ksort ( $fkeys );
$triggers = triggers ( $table );
if ( ! $status || empty ( $fields )) {
return false ;
}
$return = " CREATE TABLE " . idf_escape ( $status [ 'nspname' ]) . " . " . idf_escape ( $status [ 'Name' ]) . " ( \n " ;
// fields' definitions
foreach ( $fields as $field_name => $field ) {
$part = idf_escape ( $field [ 'field' ]) . ' ' . $field [ 'full_type' ]
. ( is_null ( $field [ 'default' ]) ? " " : " DEFAULT $field[default] " )
2017-04-06 15:39:25 +00:00
. ( $field [ 'attnotnull' ] ? " NOT NULL " : " " );
2014-07-10 10:34:08 +00:00
$return_parts [] = $part ;
// sequences for fields
if ( preg_match ( '~nextval\(\'([^\']+)\'\)~' , $field [ 'default' ], $matches )) {
$sequence_name = $matches [ 1 ];
$sq = reset ( get_rows ( " SELECT * FROM $sequence_name " ));
$sequences [] = " CREATE SEQUENCE $sequence_name INCREMENT $sq[increment_by] MINVALUE $sq[min_value] MAXVALUE $sq[max_value] START " . ( $auto_increment ? $sq [ 'last_value' ] : 1 ) . " CACHE $sq[cache_value] ; " ;
}
}
// adding sequences before table definition
if ( ! empty ( $sequences )) {
$return = implode ( " \n \n " , $sequences ) . " \n \n $return " ;
}
// primary + unique keys
foreach ( $indexes as $index_name => $index ) {
switch ( $index [ 'type' ]) {
case 'UNIQUE' : $return_parts [] = " CONSTRAINT " . idf_escape ( $index_name ) . " UNIQUE ( " . implode ( ', ' , array_map ( 'idf_escape' , $index [ 'columns' ])) . " ) " ; break ;
case 'PRIMARY' : $return_parts [] = " CONSTRAINT " . idf_escape ( $index_name ) . " PRIMARY KEY ( " . implode ( ', ' , array_map ( 'idf_escape' , $index [ 'columns' ])) . " ) " ; break ;
}
}
// foreign keys
foreach ( $fkeys as $fkey_name => $fkey ) {
$return_parts [] = " CONSTRAINT " . idf_escape ( $fkey_name ) . " $fkey[definition] " . ( $fkey [ 'deferrable' ] ? 'DEFERRABLE' : 'NOT DEFERRABLE' );
}
$return .= implode ( " , \n " , $return_parts ) . " \n ) WITH (oids = " . ( $status [ 'Oid' ] ? 'true' : 'false' ) . " ); " ;
// "basic" indexes after table definition
foreach ( $indexes as $index_name => $index ) {
if ( $index [ 'type' ] == 'INDEX' ) {
$return .= " \n \n CREATE INDEX " . idf_escape ( $index_name ) . " ON " . idf_escape ( $status [ 'nspname' ]) . " . " . idf_escape ( $status [ 'Name' ]) . " USING btree ( " . implode ( ', ' , array_map ( 'idf_escape' , $index [ 'columns' ])) . " ); " ;
}
}
// coments for table & fields
if ( $status [ 'Comment' ]) {
$return .= " \n \n COMMENT ON TABLE " . idf_escape ( $status [ 'nspname' ]) . " . " . idf_escape ( $status [ 'Name' ]) . " IS " . q ( $status [ 'Comment' ]) . " ; " ;
}
foreach ( $fields as $field_name => $field ) {
if ( $field [ 'comment' ]) {
$return .= " \n \n COMMENT ON COLUMN " . idf_escape ( $status [ 'nspname' ]) . " . " . idf_escape ( $status [ 'Name' ]) . " . " . idf_escape ( $field_name ) . " IS " . q ( $field [ 'comment' ]) . " ; " ;
}
}
// triggers
foreach ( $triggers as $trg_id => $trg ) {
$trigger = trigger ( $trg_id , $status [ 'Name' ]);
$return .= " \n \n CREATE TRIGGER " . idf_escape ( $trigger [ 'Trigger' ]) . " $trigger[Timing] $trigger[Events] ON " . idf_escape ( $status [ " nspname " ]) . " . " . idf_escape ( $status [ 'Name' ]) . " $trigger[Type] $trigger[Statement] ; " ;
}
return rtrim ( $return , ';' );
}
/** Get SQL commands to create triggers
* @ param string
* @ param string
* @ return string
*/
//@TODO
function trigger_sql ( $table , $style ) {
$return = " " ;
//foreach (get_rows("SHOW TRIGGERS LIKE " . q(addcslashes($table, "%_\\")), null, "-- ") as $row) {
// $return .= "\n" . ($style == 'CREATE+ALTER' ? "DROP TRIGGER IF EXISTS " . idf_escape($row["Trigger"]) . ";;\n" : "")
// . "CREATE TRIGGER " . idf_escape($row["Trigger"]) . " $row[Timing] $row[Event] ON " . table($row["Table"]) . " FOR EACH ROW\n$row[Statement];;\n";
//}
//return $return;
return false ;
}
2010-04-21 22:37:16 +00:00
function use_sql ( $database ) {
return " \ connect " . idf_escape ( $database );
}
2013-07-24 23:26:41 +00:00
2010-05-05 16:31:39 +00:00
function show_variables () {
return get_key_vals ( " SHOW ALL " );
}
2011-05-11 09:48:51 +00:00
function process_list () {
2012-10-20 16:58:56 +00:00
global $connection ;
return get_rows ( " SELECT * FROM pg_stat_activity ORDER BY " . ( $connection -> server_info < 9.2 ? " procpid " : " pid " ));
2011-05-11 09:48:51 +00:00
}
2013-07-24 23:26:41 +00:00
2010-08-03 15:15:45 +00:00
function show_status () {
}
2013-07-24 23:26:41 +00:00
2012-09-09 05:56:34 +00:00
function convert_field ( $field ) {
}
2013-07-24 23:26:41 +00:00
2012-09-09 05:56:34 +00:00
function unconvert_field ( $field , $return ) {
return $return ;
}
2013-07-24 23:26:41 +00:00
2010-04-21 12:01:32 +00:00
function support ( $feature ) {
2014-05-11 10:20:08 +00:00
global $connection ;
2014-07-10 10:34:08 +00:00
return preg_match ( '~^(database|table|columns|sql|indexes|comment|view|' . ( $connection -> server_info >= 9.3 ? 'materializedview|' : '' ) . 'scheme|processlist|sequence|trigger|type|variables|drop_col|kill|dump)$~' , $feature ); //! routine|
2010-04-21 12:01:32 +00:00
}
2013-07-24 23:26:41 +00:00
2015-03-18 09:34:35 +00:00
function kill_process ( $val ) {
2014-07-10 10:34:08 +00:00
return queries ( " SELECT pg_terminate_backend( " . number ( $val ) . " ) " );
2015-03-18 09:34:35 +00:00
}
2017-01-16 16:03:02 +00:00
function connection_id (){
return " SELECT pg_backend_pid() " ;
}
2015-03-18 09:34:35 +00:00
function max_connections () {
global $connection ;
return $connection -> result ( " SHOW max_connections " );
}
2010-05-07 13:44:22 +00:00
$jush = " pgsql " ;
2010-04-21 12:01:32 +00:00
$types = array ();
$structured_types = array ();
foreach ( array ( //! arrays
lang ( 'Numbers' ) => array ( " smallint " => 5 , " integer " => 10 , " bigint " => 19 , " boolean " => 1 , " numeric " => 0 , " real " => 7 , " double precision " => 16 , " money " => 20 ),
2012-08-30 04:13:30 +00:00
lang ( 'Date and time' ) => array ( " date " => 13 , " time " => 17 , " timestamp " => 20 , " timestamptz " => 21 , " interval " => 0 ),
2010-04-21 12:01:32 +00:00
lang ( 'Strings' ) => array ( " character " => 0 , " character varying " => 0 , " text " => 0 , " tsquery " => 0 , " tsvector " => 0 , " uuid " => 0 , " xml " => 0 ),
lang ( 'Binary' ) => array ( " bit " => 0 , " bit varying " => 0 , " bytea " => 0 ),
lang ( 'Network' ) => array ( " cidr " => 43 , " inet " => 43 , " macaddr " => 17 , " txid_snapshot " => 0 ),
lang ( 'Geometry' ) => array ( " box " => 0 , " circle " => 0 , " line " => 0 , " lseg " => 0 , " path " => 0 , " point " => 0 , " polygon " => 0 ),
2010-05-21 13:07:59 +00:00
) as $key => $val ) { //! can be retrieved from pg_type
2010-04-21 12:01:32 +00:00
$types += $val ;
$structured_types [ $key ] = array_keys ( $val );
}
$unsigned = array ();
2015-01-19 08:38:10 +00:00
$operators = array ( " = " , " < " , " > " , " <= " , " >= " , " != " , " ~ " , " !~ " , " LIKE " , " LIKE %% " , " ILIKE " , " ILIKE %% " , " IN " , " IS NULL " , " NOT LIKE " , " NOT IN " , " IS NOT NULL " ); // no "SQL" to avoid SQL injection
2010-04-21 12:01:32 +00:00
$functions = array ( " char_length " , " lower " , " round " , " to_hex " , " to_timestamp " , " upper " );
$grouping = array ( " avg " , " count " , " count distinct " , " max " , " min " , " sum " );
$edit_functions = array (
array (
" char " => " md5 " ,
" date|time " => " now " ,
), array (
" int|numeric|real|money " => " +/- " ,
" date|time " => " + interval/- interval " , //! escape
" char|text " => " || " ,
)
);
}