2003-10-05 12:42:07 +02:00
< ? php
/************************************************************************** \
2004-08-09 15:46:03 +02:00
* eGroupWare API - database support via ADOdb *
2003-10-05 12:42:07 +02:00
* ------------------------------------------------------------------------ *
* This program is free software ; you can redistribute it and / or modify it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation ; either version 2.1 of the License , or *
* any later version . *
\ **************************************************************************/
/* $Id$ */
2003-12-14 17:50:34 +01:00
/*
* Database abstraction library
*
2004-03-15 23:41:55 +01:00
* This allows eGroupWare to use multiple database backends via ADOdb 4.20
2003-12-14 17:50:34 +01:00
*
* @ package phpgwapi
* @ subpackage db
* @ author RalfBecker @ outdoor - training . de
* @ license LGPL
*/
2003-08-28 16:31:11 +02:00
2003-10-19 21:09:36 +02:00
if ( empty ( $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'db_type' ]))
{
$GLOBALS [ 'phpgw_info' ][ 'server' ][ 'db_type' ] = 'mysql' ;
}
2004-07-04 20:46:54 +02:00
include_once ( PHPGW_API_INC . '/adodb/adodb.inc.php' );
2003-10-19 21:09:36 +02:00
2004-07-04 20:46:54 +02:00
class db
2003-08-28 16:31:11 +02:00
{
2003-10-19 21:09:36 +02:00
/**
* @ var string $type database type
*/
2004-04-02 10:15:18 +02:00
var $Type = '' ;
2003-10-19 21:09:36 +02:00
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* @ var string $Host database host to connect to
*/
2003-08-28 16:31:11 +02:00
var $Host = '' ;
2003-10-19 21:09:36 +02:00
2003-12-08 05:50:23 +01:00
/**
* @ var string $Port port number of database to connect to
*/
var $Port = '' ;
2003-10-05 12:42:07 +02:00
/**
* @ var string $Database name of database to use
*/
2003-08-28 16:31:11 +02:00
var $Database = '' ;
2003-10-05 12:42:07 +02:00
/**
* @ var string $User name of database user
*/
2003-08-28 16:31:11 +02:00
var $User = '' ;
2003-10-05 12:42:07 +02:00
/**
* @ var string $Password password for database user
*/
2003-08-28 16:31:11 +02:00
var $Password = '' ;
/**
2003-10-05 12:42:07 +02:00
* @ var bool $auto_stripslashes automatically remove slashes when returning field values - default False
*/
2003-08-28 16:31:11 +02:00
var $auto_stripslashes = False ;
2003-10-05 12:42:07 +02:00
/**
* @ var int $Auto_Free automatically free results - 0 no , 1 yes
*/
2003-08-28 16:31:11 +02:00
var $Auto_Free = 0 ;
2003-10-05 12:42:07 +02:00
/**
* @ var int $Debug enable debuging - 0 no , 1 yes
*/
2003-08-28 16:31:11 +02:00
var $Debug = 0 ;
2003-10-05 12:42:07 +02:00
/**
* @ var string $Halt_On_Error " yes " ( halt with message ), " no " ( ignore errors quietly ), " report " ( ignore errror , but spit a warning )
*/
2003-10-19 21:09:36 +02:00
var $Halt_On_Error = 'no' ; //'yes';
2003-08-28 16:31:11 +02:00
2003-10-05 12:42:07 +02:00
/**
* @ var string $Seq_Table table for storing sequences ? ? ? ?
*/
2003-08-28 16:31:11 +02:00
var $Seq_Table = 'db_sequence' ;
/**
2003-10-05 12:42:07 +02:00
* @ var array $Record current record
*/
2003-08-28 16:31:11 +02:00
var $Record = array ();
2003-10-05 12:42:07 +02:00
/**
* @ var int row number for current record
*/
2003-08-28 16:31:11 +02:00
var $Row ;
/**
2003-10-05 12:42:07 +02:00
* @ var int $Errno internal rdms error number for last error
*/
2003-08-28 16:31:11 +02:00
var $Errno = 0 ;
2003-10-05 12:42:07 +02:00
/**
* @ var string descriptive text from last error
*/
2003-08-28 16:31:11 +02:00
var $Error = '' ;
//i am not documenting private vars - skwashd :)
var $xmlrpc = False ;
var $soap = False ;
2003-10-19 21:09:36 +02:00
var $Link_ID = 0 ;
2004-04-02 10:15:18 +02:00
var $privat_Link_ID = False ; // do we use a privat Link_ID or a reference to the global ADOdb object
2003-10-19 21:09:36 +02:00
var $Query_ID = 0 ;
2004-10-14 22:58:39 +02:00
var $prepared_sql = array (); // sql is the index
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* @ param string $query query to be executed ( optional )
*/
2003-10-19 21:09:36 +02:00
function db ( $query = '' )
2003-08-28 16:31:11 +02:00
{
$this -> query ( $query );
}
/**
2003-10-05 12:42:07 +02:00
* @ return int current connection id
*/
2003-08-28 16:31:11 +02:00
function link_id ()
{
return $this -> Link_ID ;
}
/**
2003-10-05 12:42:07 +02:00
* @ return int id of current query
*/
function query_id ()
2003-08-28 16:31:11 +02:00
{
return $this -> Query_ID ;
}
/**
2003-10-05 12:42:07 +02:00
* Open a connection to a database
*
* @ param string $Database name of database to use ( optional )
* @ param string $Host database host to connect to ( optional )
2004-04-02 09:34:41 +02:00
* @ param string $Port database port to connect to ( optional )
2003-10-05 12:42:07 +02:00
* @ param string $User name of database user ( optional )
2004-04-02 09:34:41 +02:00
* @ param string $Password password for database user ( optional )
2003-10-05 12:42:07 +02:00
*/
2004-04-02 09:34:41 +02:00
function connect ( $Database = NULL , $Host = NULL , $Port = NULL , $User = NULL , $Password = NULL , $Type = NULL )
2003-10-19 21:09:36 +02:00
{
/* Handle defaults */
2004-04-02 09:34:41 +02:00
if ( ! is_null ( $Database ) && $Database )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
$this -> Database = $Database ;
2003-10-19 21:09:36 +02:00
}
2004-04-02 09:34:41 +02:00
if ( ! is_null ( $Host ) && $Host )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
$this -> Host = $Host ;
2003-10-19 21:09:36 +02:00
}
2004-04-02 09:34:41 +02:00
if ( ! is_null ( $Port ) && $Port )
2003-12-08 05:50:23 +01:00
{
2004-04-02 09:34:41 +02:00
$this -> Port = $Port ;
2003-12-08 05:50:23 +01:00
}
2004-04-02 09:34:41 +02:00
if ( ! is_null ( $User ) && $User )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
$this -> User = $User ;
2003-10-19 21:09:36 +02:00
}
2004-04-02 09:34:41 +02:00
if ( ! is_null ( $Password ) && $Password )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
$this -> Password = $Password ;
}
if ( ! is_null ( $Type ) && $Type )
{
$this -> Type = $Type ;
2003-10-19 21:09:36 +02:00
}
2004-04-02 10:15:18 +02:00
elseif ( ! $this -> Type )
{
$this -> Type = $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'db_type' ];
}
2003-12-08 05:50:23 +01:00
2003-10-19 21:09:36 +02:00
if ( ! $this -> Link_ID )
{
2004-07-25 03:41:37 +02:00
foreach ( array ( 'Host' , 'Database' , 'User' , 'Password' ) as $name )
{
$$name = $this -> $name ;
}
$type = $this -> Type ;
2004-04-02 09:34:41 +02:00
switch ( $this -> Type ) // convert to ADO db-type-names
{
case 'pgsql' :
$type = 'postgres' ;
// create our own pgsql connection-string, to allow unix domain soccets if !$Host
2004-04-03 14:58:43 +02:00
$Host = " dbname= $this->Database " . ( $this -> Host ? " host= $this->Host " . ( $this -> Port ? " port= $this->Port " : '' ) : '' ) .
2004-04-02 09:34:41 +02:00
" user= $this->User " . ( $this -> Password ? " password=' " . addslashes ( $this -> Password ) . " ' " : '' );
2004-04-03 14:58:43 +02:00
$User = $Password = $Database = '' ; // to indicate $Host is a connection-string
2004-04-02 09:34:41 +02:00
break ;
2004-07-25 03:41:37 +02:00
case 'mssql' :
if ( $this -> Port ) $Host .= ',' . $this -> Port ;
break ;
2004-04-02 09:34:41 +02:00
default :
2004-07-25 03:41:37 +02:00
if ( $this -> Port ) $Host .= ':' . $this -> Port ;
break ;
2004-04-02 09:34:41 +02:00
}
if ( ! is_object ( $GLOBALS [ 'phpgw' ] -> ADOdb ) || // we have no connection so far
( is_object ( $GLOBALS [ 'phpgw' ] -> db ) && // we connect to a different db, then the global one
( $this -> Type != $GLOBALS [ 'phpgw' ] -> db -> Type ||
$this -> Database != $GLOBALS [ 'phpgw' ] -> db -> Database ||
$this -> User != $GLOBALS [ 'phpgw' ] -> db -> User ||
$this -> Host != $GLOBALS [ 'phpgw' ] -> db -> Host ||
$this -> Port != $GLOBALS [ 'phpgw' ] -> db -> Port )))
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! is_object ( $GLOBALS [ 'phpgw' ] -> ADOdb )) // use the global object to store the connection
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
$this -> Link_ID = & $GLOBALS [ 'phpgw' ] -> ADOdb ;
2003-10-19 21:09:36 +02:00
}
2004-04-02 10:15:18 +02:00
else
{
$this -> privat_Link_ID = True ; // remember that we use a privat Link_ID for disconnect
}
2004-04-02 09:34:41 +02:00
$this -> Link_ID = ADONewConnection ( $type );
if ( ! $this -> Link_ID )
2003-10-19 21:09:36 +02:00
{
$this -> halt ( " No ADOdb support for ' $type ' !!! " );
2004-04-02 09:34:41 +02:00
return 0 ; // in case error-reporting = 'no'
2003-10-19 21:09:36 +02:00
}
$connect = $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'db_persistent' ] ? 'PConnect' : 'Connect' ;
2004-04-03 14:58:43 +02:00
if ( ! $this -> Link_ID -> $connect ( $Host , $User , $Password , $Database ))
2003-10-19 21:09:36 +02:00
{
2004-04-03 14:58:43 +02:00
$this -> halt ( " ADOdb:: $connect ( $Host , $User , \$ Password, $Database ) failed. " );
2004-02-08 12:19:52 +01:00
return 0 ; // in case error-reporting = 'no'
2003-10-19 21:09:36 +02:00
}
2004-04-02 09:34:41 +02:00
//echo "new ADOdb connection<pre>".print_r($GLOBALS['phpgw']->ADOdb,True)."</pre>\n";
2004-07-25 03:41:37 +02:00
if ( $this -> Type == 'mssql' )
{
// this is the format ADOdb expects
$this -> Link_ID -> Execute ( 'SET DATEFORMAT ymd' );
// sets the limit to the maximum
ini_set ( 'mssql.textlimit' , 2147483647 );
ini_set ( 'mssql.sizelimit' , 2147483647 );
}
2004-04-02 09:34:41 +02:00
}
else
{
$this -> Link_ID = & $GLOBALS [ 'phpgw' ] -> ADOdb ;
2003-10-19 21:09:36 +02:00
}
}
2004-08-04 01:06:37 +02:00
//echo "<p>".print_r($this->Link_ID->ServerInfo(),true)."</p>\n";
2003-10-19 21:09:36 +02:00
return $this -> Link_ID ;
}
2003-08-28 16:31:11 +02:00
/**
2004-02-08 12:19:52 +01:00
* Close a connection to a database
2003-10-05 12:42:07 +02:00
*/
2003-08-28 16:31:11 +02:00
function disconnect ()
2003-10-19 21:09:36 +02:00
{
2004-04-02 10:15:18 +02:00
if ( ! $this -> privat_Link_ID )
{
unset ( $GLOBALS [ 'phpgw' ] -> ADOdb );
}
2004-02-08 12:19:52 +01:00
unset ( $this -> Link_ID );
$this -> Link_ID = 0 ;
2003-10-19 21:09:36 +02:00
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Escape strings before sending them to the database
*
* @ param string $str the string to be escaped
* @ return string escaped sting
*/
function db_addslashes ( $str )
2003-08-28 16:31:11 +02:00
{
if ( ! isset ( $str ) || $str == '' )
{
return '' ;
}
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
2003-10-20 21:02:32 +02:00
{
2004-04-02 09:34:41 +02:00
return False ;
2003-10-20 21:02:32 +02:00
}
2004-08-22 22:30:12 +02:00
return $this -> Link_ID -> addq ( $str );
2003-08-28 16:31:11 +02:00
}
/**
2003-10-05 12:42:07 +02:00
* Convert a unix timestamp to a rdms specific timestamp
*
* @ param int unix timestamp
* @ return string rdms specific timestamp
*/
function to_timestamp ( $epoch )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-21 12:08:48 +02:00
// the substring is needed as the string is already in quotes
return substr ( $this -> Link_ID -> DBTimeStamp ( $epoch ), 1 , - 1 );
2003-10-19 21:09:36 +02:00
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Convert a rdms specific timestamp to a unix timestamp
*
* @ param string rdms specific timestamp
* @ return int unix timestamp
*/
function from_timestamp ( $timestamp )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:09:36 +02:00
return $this -> Link_ID -> UnixTimeStamp ( $timestamp );
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Discard the current query result
*/
2003-08-28 16:31:11 +02:00
function free ()
{
2003-10-19 23:41:47 +02:00
unset ( $this -> Query_ID ); // else copying of the db-object does not work
2003-08-28 16:31:11 +02:00
$this -> Query_ID = 0 ;
}
/**
2003-10-05 12:42:07 +02:00
* Execute a query
*
* @ param string $Query_String the query to be executed
2004-10-14 22:58:39 +02:00
* @ param int $line the line method was called from - use __LINE__
2003-10-05 12:42:07 +02:00
* @ param string $file the file method was called from - use __FILE__
2004-10-14 22:58:39 +02:00
* @ param int $offset row to start from , default 0
* @ param int $num_rows number of rows to return ( optional ), default - 1 = all , 0 will use $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'maxmatchs' ]
* @ param array / boolean $inputarr array for binding variables to parameters or false ( default )
2004-08-07 13:58:05 +02:00
* @ return ADORecordSet or false , if the query fails
2003-10-05 12:42:07 +02:00
*/
2004-10-14 22:58:39 +02:00
function query ( $Query_String , $line = '' , $file = '' , $offset = 0 , $num_rows =- 1 , $inputarr = false )
2003-10-19 21:09:36 +02:00
{
if ( $Query_String == '' )
{
return 0 ;
}
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
return False ;
2003-12-14 17:50:34 +01:00
}
2003-10-19 21:09:36 +02:00
# New query, discard previous result.
if ( $this -> Query_ID )
{
$this -> free ();
}
if ( $this -> Link_ID -> fetchMode != ADODB_FETCH_BOTH )
{
$this -> Link_ID -> SetFetchMode ( ADODB_FETCH_BOTH );
}
2004-10-14 22:58:39 +02:00
if ( ! $num_rows )
2003-10-19 21:09:36 +02:00
{
$num_rows = $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'maxmatchs' ];
}
if ( $num_rows > 0 )
{
2004-10-14 22:58:39 +02:00
$this -> Query_ID = $this -> Link_ID -> SelectLimit ( $Query_String , $num_rows ,( int ) $offset , $inputarr );
2003-10-19 21:09:36 +02:00
}
else
{
2004-10-14 22:58:39 +02:00
$this -> Query_ID = $this -> Link_ID -> Execute ( $Query_String , $inputarr );
2003-10-19 21:09:36 +02:00
}
$this -> Row = 0 ;
$this -> Errno = $this -> Link_ID -> ErrorNo ();
$this -> Error = $this -> Link_ID -> ErrorMsg ();
2003-10-19 23:41:47 +02:00
2003-10-19 21:09:36 +02:00
if ( ! $this -> Query_ID )
{
2004-10-14 22:58:39 +02:00
$this -> halt ( " Invalid SQL: " . ( is_array ( $Query_String ) ? $Query_String [ 0 ] : $Query_String ) .
( $inputarr ? " <br>Parameters: ' " . implode ( " ',' " , $inputarr ) . " ' " : '' ),
$line , $file );
2003-10-19 21:09:36 +02:00
}
return $this -> Query_ID ;
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Execute a query with limited result set
*
* @ param string $Query_String the query to be executed
2004-10-14 22:58:39 +02:00
* @ param int $offset row to start from , default 0
* @ param int $line the line method was called from - use __LINE__
2003-10-05 12:42:07 +02:00
* @ param string $file the file method was called from - use __FILE__
2004-10-14 22:58:39 +02:00
* @ param int $num_rows number of rows to return ( optional ), default - 1 = all , 0 will use $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'maxmatchs' ]
* @ param array / boolean $inputarr array for binding variables to parameters or false ( default )
2004-08-07 13:58:05 +02:00
* @ return ADORecordSet or false , if the query fails
2003-10-05 12:42:07 +02:00
*/
2004-10-14 22:58:39 +02:00
function limit_query ( $Query_String , $offset , $line = '' , $file = '' , $num_rows = '' , $inputarr = false )
2003-10-19 21:09:36 +02:00
{
2004-10-14 22:58:39 +02:00
return $this -> query ( $Query_String , $line , $file , $offset , $num_rows , $inputarr );
2003-10-19 21:09:36 +02:00
}
2003-08-28 16:31:11 +02:00
2003-10-05 12:42:07 +02:00
/**
* Move to the next row in the results set
*
2004-11-07 15:33:24 +01:00
* Specifying a fetch_mode only works for newly fetched rows , the first row always gets fetched by query !!!
*
* @ param int $fetch_mode ADODB_FETCH_BOTH = numerical + assoc keys ( eGW default ), ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
2003-10-05 12:42:07 +02:00
* @ return bool was another row found ?
*/
2004-11-07 15:33:24 +01:00
function next_record ( $fetch_mode = ADODB_FETCH_BOTH )
2003-10-19 21:09:36 +02:00
{
if ( ! $this -> Query_ID )
{
$this -> halt ( 'next_record called with no query pending.' );
return 0 ;
}
2004-11-07 15:33:24 +01:00
if ( $this -> Link_ID -> fetchMode != $fetch_mode )
{
$this -> Link_ID -> SetFetchMode ( $fetch_mode );
}
2003-10-19 21:09:36 +02:00
if ( $this -> Row ) // first row is already fetched
{
$this -> Query_ID -> MoveNext ();
}
++ $this -> Row ;
2003-10-21 20:08:22 +02:00
$this -> Record = $this -> Query_ID -> fields ;
2004-08-04 01:06:37 +02:00
2003-10-21 20:08:22 +02:00
if ( $this -> Query_ID -> EOF || ! $this -> Query_ID -> RecordCount () || ! is_array ( $this -> Record ))
2003-10-19 21:09:36 +02:00
{
return False ;
}
2005-02-07 17:56:19 +01:00
switch ( $this -> Type )
2004-08-04 01:06:37 +02:00
{
2005-02-07 17:56:19 +01:00
case 'sapdb' :
case 'maxdb' :
case 'oracle' :
foreach ( $this -> Record as $column => $value )
2004-11-07 15:33:24 +01:00
{
2005-02-07 17:56:19 +01:00
// add a lowercase version
$this -> Record [ strtolower ( $column )] = $value ;
// add a numeric version
$this -> Record [] = $value ;
}
if ( ! function_exists ( 'array_change_key_case' ))
{
define ( 'CASE_LOWER' , 0 );
define ( 'CASE_UPPER' , 1 );
function array_change_key_case ( $arr , $mode = CASE_LOWER )
2004-11-07 15:33:24 +01:00
{
2005-02-07 17:56:19 +01:00
foreach ( $arr as $key => $val )
{
$changed [ $mode == CASE_LOWER ? strtolower ( $key ) : strtoupper ( $key )] = $val ;
}
return $changed ;
2004-11-07 15:33:24 +01:00
}
}
2005-02-07 17:56:19 +01:00
switch ( $fetch_mode )
{
case ADODB_FETCH_ASSOC :
$this -> Record = array_change_key_case ( $this -> Record );
break ;
case ADODB_FETCH_NUM :
$this -> Record = array_values ( $this -> Record );
break ;
default :
$this -> Record = array_change_key_case ( $this -> Record );
$this -> Record += array_values ( $this -> Record );
break ;
}
break ;
2004-08-04 01:06:37 +02:00
}
2003-10-19 21:09:36 +02:00
return True ;
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Move to position in result set
*
* @ param int $pos required row ( optional ), default first row
2004-08-09 00:31:41 +02:00
* @ return boolean true if sucessful or false if not found
2003-10-05 12:42:07 +02:00
*/
2003-08-28 16:31:11 +02:00
function seek ( $pos = 0 )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Query_ID || ! $this -> Query_ID -> Move ( $this -> Row = $pos ))
2003-10-19 21:09:36 +02:00
{
$this -> halt ( " seek( $pos ) failed: resultset has " . $this -> num_rows () . " rows " );
$this -> Query_ID -> Move ( $this -> num_rows () );
$this -> Row = $this -> num_rows ();
return False ;
}
return True ;
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Begin Transaction
*
2004-08-09 00:31:41 +02:00
* @ return int / boolean current transaction - id , of false if no connection
2003-10-05 12:42:07 +02:00
*/
function transaction_begin ()
2003-08-28 16:31:11 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:36:50 +02:00
//return $this->Link_ID->BeginTrans();
return $this -> Link_ID -> StartTrans ();
2003-08-28 16:31:11 +02:00
}
2003-10-05 12:42:07 +02:00
/**
* Complete the transaction
*
* @ return bool True if sucessful , False if fails
*/
2003-08-28 16:31:11 +02:00
function transaction_commit ()
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:36:50 +02:00
//return $this->Link_ID->CommitTrans();
return $this -> Link_ID -> CompleteTrans ();
2003-08-28 16:31:11 +02:00
}
2003-10-05 12:42:07 +02:00
/**
* Rollback the current transaction
*
* @ return bool True if sucessful , False if fails
*/
2003-08-28 16:31:11 +02:00
function transaction_abort ()
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:36:50 +02:00
//return $this->Link_ID->RollbackTrans();
return $this -> Link_ID -> FailTrans ();
2003-08-28 16:31:11 +02:00
}
/**
2003-10-05 12:42:07 +02:00
* Find the primary key of the last insertion on the current db connection
*
* @ param string $table name of table the insert was performed on
* @ param string $field the autoincrement primary key of the table
* @ return int the id , - 1 if fails
*/
function get_last_insert_id ( $table , $field )
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2004-08-04 01:06:37 +02:00
//$id = $this->Link_ID->PO_Insert_ID($table,$field);
$id = $this -> Link_ID -> PO_Insert_ID ( $table , $field ); // simulates Insert_ID with "SELECT MAX($field) FROM $table" if not native availible
2003-10-19 23:41:47 +02:00
if ( $id === False ) // function not supported
{
2004-09-19 12:35:54 +02:00
echo " <p>db::get_last_insert_id(table=' $table ',field=' $field ') not yet implemented for db-type ' $this->Type ' OR no insert operation before</p> \n " ;
function_backtrace ();
2003-10-19 23:41:47 +02:00
return - 1 ;
}
2004-08-04 01:06:37 +02:00
return $id ;
2003-10-19 21:09:36 +02:00
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Lock a table
*
* @ param string $table name of table to lock
* @ param string $mode type of lock required ( optional ), default write
* @ return bool True if sucessful , False if fails
*/
2003-08-28 16:31:11 +02:00
function lock ( $table , $mode = 'write' )
{}
2003-10-05 12:42:07 +02:00
/**
* Unlock a table
*
* @ return bool True if sucessful , False if fails
*/
2003-08-28 16:31:11 +02:00
function unlock ()
{}
/**
2003-10-05 12:42:07 +02:00
* Get the number of rows affected by last update
*
* @ return int number of rows
*/
2003-08-28 16:31:11 +02:00
function affected_rows ()
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:09:36 +02:00
return $this -> Link_ID -> Affected_Rows ();
}
2003-08-28 16:31:11 +02:00
2003-10-05 12:42:07 +02:00
/**
* Number of rows in current result set
*
* @ return int number of rows
*/
2003-08-28 16:31:11 +02:00
function num_rows ()
2003-10-19 21:09:36 +02:00
{
2004-02-08 12:19:52 +01:00
return $this -> Query_ID ? $this -> Query_ID -> RecordCount () : False ;
2003-10-19 21:09:36 +02:00
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* Number of fields in current row
*
* @ return int number of fields
*/
function num_fields ()
2003-10-19 21:09:36 +02:00
{
2004-04-02 09:34:41 +02:00
return $this -> Query_ID ? $this -> Query_ID -> FieldCount () : False ;
2003-10-19 21:09:36 +02:00
}
2003-08-28 16:31:11 +02:00
/**
2003-10-05 12:42:07 +02:00
* short hand for @ see num_rows ()
*/
2003-08-28 16:31:11 +02:00
function nf ()
{
return $this -> num_rows ();
}
/**
2003-10-05 12:42:07 +02:00
* short hand for print @ see num_rows
*/
function np ()
2003-08-28 16:31:11 +02:00
{
print $this -> num_rows ();
}
2003-10-05 12:42:07 +02:00
/**
* Return the value of a column
*
* @ param string / integer $Name name of field or positional index starting from 0
* @ param bool $strip_slashes string escape chars from field ( optional ), default false
* @ return string the field value
*/
2003-08-28 16:31:11 +02:00
function f ( $Name , $strip_slashes = False )
{
if ( $strip_slashes || ( $this -> auto_stripslashes && ! $strip_slashes ))
{
return stripslashes ( $this -> Record [ $Name ]);
}
else
{
return $this -> Record [ $Name ];
}
}
/**
2003-10-05 12:42:07 +02:00
* Print the value of a field
*
* @ param string $Name name of field to print
* @ param bool $strip_slashes string escape chars from field ( optional ), default false
*/
function p ( $Name , $strip_slashes = True )
2003-08-28 16:31:11 +02:00
{
print $this -> f ( $Name , $strip_slashes );
}
/**
2003-10-05 12:42:07 +02:00
* Returns a query - result - row as an associative array ( no numerical keys !!! )
*
* @ param bool $do_next_record should next_record () be called or not ( default not )
2004-11-07 15:33:24 +01:00
* @ param string $strip string to strip of the column - name , default ''
2003-10-05 12:42:07 +02:00
* @ return array / bool the associative array or False if no ( more ) result - row is availible
*/
2004-11-07 15:33:24 +01:00
function row ( $do_next_record = False , $strip = '' )
2003-10-05 12:42:07 +02:00
{
2004-11-07 15:33:24 +01:00
if ( $do_next_record && ! $this -> next_record ( ADODB_FETCH_ASSOC ) || ! is_array ( $this -> Record ))
2003-10-05 12:42:07 +02:00
{
return False ;
}
$result = array ();
foreach ( $this -> Record as $column => $value )
{
if ( ! is_numeric ( $column ))
{
2004-11-07 15:33:24 +01:00
if ( $strip ) $column = str_replace ( $strip , '' , $column );
2004-08-04 01:06:37 +02:00
2003-10-05 12:42:07 +02:00
$result [ $column ] = $value ;
}
}
return $result ;
}
/**
* Get the id for the next sequence - not implemented !
*
2003-10-20 18:36:03 +02:00
* This seems not to be used anywhere in eGroupWhere !!!
*
2003-10-05 12:42:07 +02:00
* @ param string $seq_name name of the sequence
* @ return int sequence id
*/
2003-08-28 16:31:11 +02:00
function nextid ( $seq_name )
{
2003-10-19 21:09:36 +02:00
echo " <p>db::nextid(sequence=' $seq_name ') not yet implemented</p> \n " ;
2003-08-28 16:31:11 +02:00
}
/**
2003-10-05 12:42:07 +02:00
* Error handler
*
* @ param string $msg error message
* @ param int $line line of calling method / function ( optional )
* @ param string $file file of calling method / function ( optional )
*/
2003-08-28 16:31:11 +02:00
function halt ( $msg , $line = '' , $file = '' )
2003-10-19 21:09:36 +02:00
{
if ( $this -> Link_ID ) // only if we have a link, else infinite loop
{
2003-11-02 16:19:14 +01:00
$this -> Error = $this -> Link_ID -> ErrorMsg (); // need to be BEFORE unlock,
$this -> Errno = $this -> Link_ID -> ErrorNo (); // else we get its error or none
2003-10-19 21:09:36 +02:00
$this -> unlock (); /* Just in case there is a table currently locked */
}
if ( $this -> Halt_On_Error == " no " )
{
return ;
}
$this -> haltmsg ( $msg );
if ( $file )
{
printf ( " <br><b>File:</b> %s " , $file );
}
if ( $line )
{
printf ( " <br><b>Line:</b> %s " , $line );
}
printf ( " <br><b>Function:</b> %s \n " , function_backtrace ( 2 ));
if ( $this -> Halt_On_Error != " report " )
{
echo " <p><b>Session halted.</b> " ;
2004-08-04 01:06:37 +02:00
if ( is_object ( $GLOBALS [ 'phpgw' ] -> common ))
{
$GLOBALS [ 'phpgw' ] -> common -> phpgw_exit ( True );
}
else // happens eg. in setup
{
exit ();
}
2003-10-19 21:09:36 +02:00
}
}
function haltmsg ( $msg )
{
printf ( " <p><b>Database error:</b> %s<br> \n " , $msg );
2004-07-25 03:41:37 +02:00
if (( $this -> Errno || $this -> Error ) && $this -> Error != " () " )
2003-10-19 21:09:36 +02:00
{
2004-04-02 10:15:18 +02:00
printf ( " <b> $this->Type Error</b>: %s (%s)<br> \n " , $this -> Errno , $this -> Error );
2003-10-19 21:09:36 +02:00
}
}
/**
* Get description of a table
*
* Beside the column - name all other data depends on the db - type !!!
*
* @ param string $table name of table to describe
* @ param bool $full optional , default False summary information , True full information
* @ return array table meta data
*/
function metadata ( $table = '' , $full = false )
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:09:36 +02:00
$columns = $this -> Link_ID -> MetaColumns ( $table );
2004-04-02 09:34:41 +02:00
//$columns = $this->Link_ID->MetaColumnsSQL($table);
2003-10-19 21:09:36 +02:00
//echo "<b>metadata</b>('$table')=<pre>\n".print_r($columns,True)."</pre>\n";
$metadata = array ();
$i = 0 ;
foreach ( $columns as $column )
{
2004-04-02 09:34:41 +02:00
// for backwards compatibilty (depreciated)
unset ( $flags );
if ( $column -> auto_increment ) $flags .= " auto_increment " ;
if ( $column -> primary_key ) $flags .= " primary_key " ;
if ( $column -> binary ) $flags .= " binary " ;
// _debug_array($column);
2004-02-15 14:54:18 +01:00
$metadata [ $i ] = array (
'table' => $table ,
'name' => $column -> name ,
'type' => $column -> type ,
2004-04-02 09:34:41 +02:00
'len' => $column -> max_length ,
'flags' => $flags , // for backwards compatibilty (depreciated) used by JiNN atm
2004-02-15 14:54:18 +01:00
'not_null' => $column -> not_null ,
2004-04-02 09:34:41 +02:00
'auto_increment' => $column -> auto_increment ,
'primary_key' => $column -> primary_key ,
'binary' => $column -> binary ,
2004-02-15 14:54:18 +01:00
'has_default' => $column -> has_default ,
'default' => $column -> default_value ,
);
2003-10-19 21:09:36 +02:00
$metadata [ $i ][ 'table' ] = $table ;
if ( $full )
{
2004-02-15 14:54:18 +01:00
$metadata [ 'meta' ][ $column -> name ] = $i ;
2003-10-19 21:09:36 +02:00
}
++ $i ;
}
if ( $full )
{
$metadata [ 'num_fields' ] = $i ;
}
return $metadata ;
}
2003-08-28 16:31:11 +02:00
2003-10-05 12:42:07 +02:00
/**
* Get a list of table names in the current database
*
* @ return array list of the tables
*/
2003-08-28 16:31:11 +02:00
function table_names ()
{
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
2003-10-19 21:09:36 +02:00
$result = array ();
$tables = $this -> Link_ID -> MetaTables ( 'TABLES' );
if ( is_array ( $tables ))
{
foreach ( $tables as $table )
{
2005-02-07 17:56:19 +01:00
switch ( $this -> Type )
2004-08-04 01:06:37 +02:00
{
2005-02-07 17:56:19 +01:00
case 'sapdb' :
case 'maxdb' :
case 'oracle' :
$table = strtolower ( $table );
break ;
2004-08-04 01:06:37 +02:00
}
2003-10-19 21:09:36 +02:00
$result [] = array (
'table_name' => $table ,
'tablespace_name' => $this -> Database ,
'database' => $this -> Database
2003-12-14 17:50:34 +01:00
);
2003-10-19 21:09:36 +02:00
}
}
return $result ;
2003-08-28 16:31:11 +02:00
}
2003-10-05 12:42:07 +02:00
/**
* Return a list of indexes in current database
*
* @ return array list of indexes
*/
2003-08-28 16:31:11 +02:00
function index_names ()
{
2004-05-24 16:22:45 +02:00
$indices = array ();
if ( $this -> Type != 'pgsql' )
{
echo " <p>db::index_names() not yet implemented for db-type ' $this->Type '</p> \n " ;
return $indices ;
}
$this -> query ( " SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relkind ='i' ORDER BY relname " );
while ( $this -> next_record ())
{
$indices [] = array (
'index_name' => $this -> f ( 0 ),
'tablespace_name' => $this -> Database ,
'database' => $this -> Database ,
);
}
return $indices ;
2003-08-28 16:31:11 +02:00
}
2004-04-26 00:58:37 +02:00
/**
* Returns an array containing column names that are the primary keys of $tablename .
*
* @ return array of columns
*/
function pkey_columns ( $tablename )
{
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
return $this -> Link_ID -> MetaPrimaryKeys ( $tablename );
}
2003-10-05 12:42:07 +02:00
/**
* Create a new database
*
* @ param string $adminname name of database administrator user ( optional )
* @ param string $adminpasswd password for the database administrator user ( optional )
*/
2003-08-28 16:31:11 +02:00
function create_database ( $adminname = '' , $adminpasswd = '' )
2003-10-19 21:09:36 +02:00
{
2004-03-28 14:10:08 +02:00
$currentUser = $this -> User ;
$currentPassword = $this -> Password ;
$currentDatabase = $this -> Database ;
2004-02-08 12:19:52 +01:00
$extra = array ();
2004-04-02 10:15:18 +02:00
switch ( $this -> Type )
2004-02-08 12:19:52 +01:00
{
case 'pgsql' :
$meta_db = 'template1' ;
break ;
case 'mysql' :
$meta_db = 'mysql' ;
$extra [] = " grant all on $currentDatabase .* to $currentUser @localhost identified by ' $currentPassword ' " ;
break ;
default :
2004-04-02 10:15:18 +02:00
echo " <p>db::create_database(user=' $adminname ', \$ pw) not yet implemented for DB-type ' $this->Type '</p> \n " ;
2004-02-08 12:19:52 +01:00
break ;
}
if ( $adminname != '' )
{
$this -> User = $adminname ;
$this -> Password = $adminpasswd ;
$this -> Database = $meta_db ;
}
$this -> disconnect ();
$this -> query ( " CREATE DATABASE $currentDatabase " );
foreach ( $extra as $sql )
{
$this -> query ( $sql );
}
$this -> disconnect ();
$this -> User = $currentUser ;
$this -> Password = $currentPassword ;
$this -> Database = $currentDatabase ;
$this -> connect ();
2003-10-19 21:09:36 +02:00
}
2003-10-05 12:42:07 +02:00
2004-05-24 01:34:32 +02:00
/**
* concat a variable number of strings together , to be used in a query
*
* Example : $db -> concat ( $db -> quote ( 'Hallo ' ), 'username' ) would return
* for mysql " concat('Hallo ',username) " or " 'Hallo ' || username " for postgres
2004-08-09 00:31:41 +02:00
* @ param string $str1 already quoted stringliteral or column - name , variable number of arguments
2004-05-24 01:34:32 +02:00
* @ return string to be used in a query
*/
function concat ( $str1 )
{
$args = func_get_args ();
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
return call_user_func_array ( array ( & $this -> Link_ID , 'concat' ), $args );
}
2004-05-02 19:18:38 +02:00
/**
* Correctly Quote Identifiers like table - or colmnnames for use in SQL - statements
*
* This is mostly copy & paste from adodb ' s datadict class
2004-05-31 18:32:22 +02:00
* @ param $name string
2004-05-02 19:18:38 +02:00
* @ return string quoted string
*/
function name_quote ( $name = NULL )
{
if ( ! is_string ( $name )) {
return FALSE ;
}
$name = trim ( $name );
if ( ! $this -> Link_ID && ! $this -> connect ())
{
return False ;
}
$quote = $this -> Link_ID -> nameQuote ;
// if name is of the form `name`, quote it
if ( preg_match ( '/^`(.+)`$/' , $name , $matches ) ) {
return $quote . $matches [ 1 ] . $quote ;
}
// if name contains special characters, quote it
if ( preg_match ( '/\W/' , $name ) ) {
return $quote . $name . $quote ;
}
return $name ;
}
2004-02-19 09:45:31 +01:00
/**
* Escape values before sending them to the database - prevents SQL injunction and SQL errors ; - )
*
* Please note that the quote function already returns necessary quotes : quote ( 'Hello' ) === " 'Hello' " .
* Int and Auto types are casted to int : quote ( '1' , 'int' ) === 1 , quote ( '' , 'int' ) === 0 , quote ( 'Hello' , 'int' ) === 0
2004-05-31 18:32:22 +02:00
*
2004-08-09 00:31:41 +02:00
* @ param mixed $value the value to be escaped
* @ param string / boolean $type string the type of the db - column , default False === varchar
* @ param boolean $not_null is column NOT NULL , default true , else php null values are written as SQL NULL
2004-02-19 09:45:31 +01:00
* @ return string escaped sting
*/
2004-08-09 00:31:41 +02:00
function quote ( $value , $type = False , $not_null = true )
2004-02-19 09:45:31 +01:00
{
2004-10-14 22:58:39 +02:00
if ( $this -> Debug ) echo " <p>db::quote( " . ( is_null ( $value ) ? 'NULL' : " ' $value ' " ) . " ,' $type ',' $not_null ')</p> \n " ;
2004-08-07 13:58:05 +02:00
2004-09-19 12:35:54 +02:00
if ( ! $not_null && is_null ( $value )) // writing unset php-variables and those set to NULL now as SQL NULL
2004-08-07 13:58:05 +02:00
{
return 'NULL' ;
}
2004-02-19 09:45:31 +01:00
switch ( $type )
{
case 'int' :
case 'auto' :
return ( int ) $value ;
}
2004-04-02 09:34:41 +02:00
if ( ! $this -> Link_ID && ! $this -> connect ())
2004-02-19 09:45:31 +01:00
{
2004-04-02 09:34:41 +02:00
return False ;
2004-02-19 09:45:31 +01:00
}
2004-03-17 13:42:24 +01:00
switch ( $type )
{
case 'blob' :
2004-09-18 16:56:18 +02:00
switch ( $this -> Link_ID -> blobEncodeType )
2004-04-14 11:28:18 +02:00
{
2004-09-18 16:56:18 +02:00
case 'C' : // eg. postgres
return " ' " . $this -> Link_ID -> BlobEncode ( $value ) . " ' " ;
case 'I' :
return $this -> Link_ID -> BlobEncode ( $value );
2004-04-14 11:28:18 +02:00
}
2004-09-18 17:18:48 +02:00
break ; // handled like strings
2004-07-25 03:41:37 +02:00
case 'date' :
return $this -> Link_ID -> DBDate ( $value );
case 'timestamp' :
return $this -> Link_ID -> DBTimeStamp ( $value );
2004-03-17 13:42:24 +01:00
}
2004-08-22 22:30:12 +02:00
return $this -> Link_ID -> qstr ( $value );
2004-02-19 09:45:31 +01:00
}
2003-10-05 12:42:07 +02:00
/**
* Implodes an array of column - value pairs for the use in sql - querys .
2004-02-19 09:45:31 +01:00
* All data is run through quote ( does either addslashes () or ( int )) - prevents SQL injunction and SQL errors ; - ) .
2003-10-05 12:42:07 +02:00
*
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param string $glue in most cases this will be either ',' or ' AND ' , depending you your query
* @ param array $array column - name / value pairs , if the value is an array all its array - values will be quoted
2004-05-31 11:25:35 +02:00
* according to the type of the column , and the whole array with be formatted like ( val1 , val2 , ... )
2004-05-31 18:32:22 +02:00
* If $use_key == True , an ' IN ' instead a '=' is used . Good for category - or user - lists .
* If the key is numerical ( no key given in the array - definition ) the value is used as is , eg .
* array ( 'visits=visits+1' ) gives just " visits=visits+1 " ( no quoting at all !!! )
2004-08-09 00:31:41 +02:00
* @ param boolean / string $use_key If $use_key === True a " $key = " prefix each value ( default ), typically set to False
2004-04-12 09:19:24 +02:00
* or 'VALUES' for insert querys , on 'VALUES' " (key1,key2,...) VALUES (val1,val2,...) " is returned
2004-08-09 00:31:41 +02:00
* @ param array / boolean $only if set to an array only colums which are set ( as data !!! ) are written
2004-04-12 09:19:24 +02:00
* typicaly used to form a WHERE - clause from the primary keys .
* If set to True , only columns from the colum_definitons are written .
2004-08-09 00:31:41 +02:00
* @ param array / boolean $column_definitions this can be set to the column - definitions - array
2003-10-05 12:42:07 +02:00
* of your table ( $tables_baseline [ $table ][ 'fd' ] of the setup / tables_current . inc . php file ) .
2003-12-14 17:50:34 +01:00
* If its set , the column - type - data determinates if ( int ) or addslashes is used .
2004-08-09 00:31:41 +02:00
* @ return string SQL
2003-10-05 12:42:07 +02:00
*/
function column_data_implode ( $glue , $array , $use_key = True , $only = False , $column_definitions = False )
{
2004-08-04 17:33:42 +02:00
if ( ! is_array ( $array )) // this allows to give an SQL-string for delete or update
{
return $array ;
}
2003-10-05 12:42:07 +02:00
if ( ! $column_definitions )
{
$column_definitions = $this -> column_definitions ;
}
2004-04-14 11:28:18 +02:00
if ( $this -> Debug ) echo " <p>db::column_data_implode(' $glue ', " . print_r ( $array , True ) . " ,' $use_key ', " . print_r ( $only , True ) . " ,<pre> " . print_r ( $column_definitions , True ) . " </pre> \n " ;
2004-04-12 09:19:24 +02:00
$keys = $values = array ();
2003-10-05 12:42:07 +02:00
foreach ( $array as $key => $data )
{
2004-04-12 09:19:24 +02:00
if ( ! $only || $only === True && isset ( $column_definitions [ $key ]) || is_array ( $only ) && in_array ( $key , $only ))
2003-10-05 12:42:07 +02:00
{
2004-07-22 10:22:52 +02:00
$keys [] = $this -> name_quote ( $key );
2004-08-05 17:31:55 +02:00
if ( ! is_int ( $key ) && is_array ( $column_definitions ) && ! isset ( $column_definitions [ $key ]))
{
// give a warning that we have no column-type
$this -> halt ( " db::column_data_implode(' $glue ', " . print_r ( $array , True ) . " ,' $use_key ', " . print_r ( $only , True ) . " ,<pre> " . print_r ( $column_definitions , True ) . " </pre><b>nothing known about column ' $key '!</b> " );
}
2004-02-29 00:56:13 +01:00
$column_type = is_array ( $column_definitions ) ? @ $column_definitions [ $key ][ 'type' ] : False ;
2004-10-14 22:58:39 +02:00
$not_null = is_array ( $column_definitions ) && isset ( $column_definitions [ $key ][ 'nullable' ]) ? ! $column_definitions [ $key ][ 'nullable' ] : false ;
2004-05-31 11:25:35 +02:00
if ( is_array ( $data ))
{
foreach ( $data as $k => $v )
{
2004-08-09 00:31:41 +02:00
$data [ $k ] = $this -> quote ( $v , $column_type , $not_null );
2004-05-31 11:25:35 +02:00
}
$values [] = ( $use_key === True ? $key . ' IN ' : '' ) . '(' . implode ( ',' , $data ) . ')' ;
}
2004-05-31 18:32:22 +02:00
elseif ( is_int ( $key ) && $use_key === True )
{
$values [] = $data ;
}
2004-05-31 11:25:35 +02:00
else
{
2004-08-09 00:31:41 +02:00
$values [] = ( $use_key === True ? $this -> name_quote ( $key ) . '=' : '' ) . $this -> quote ( $data , $column_type , $not_null );
2004-05-31 11:25:35 +02:00
}
2003-10-05 12:42:07 +02:00
}
}
2004-04-12 09:19:24 +02:00
return ( $use_key === 'VALUES' ? '(' . implode ( ',' , $keys ) . ') VALUES (' : '' ) .
implode ( $glue , $values ) . ( $use_key === 'VALUES' ? ')' : '' );
2003-10-05 12:42:07 +02:00
}
/**
* Sets the default column - definitions for use with column_data_implode ()
*
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param array / boolean $column_definitions this can be set to the column - definitions - array
2003-10-05 12:42:07 +02:00
* of your table ( $tables_baseline [ $table ][ 'fd' ] of the setup / tables_current . inc . php file ) .
2003-12-14 17:50:34 +01:00
* If its set , the column - type - data determinates if ( int ) or addslashes is used .
2003-10-05 12:42:07 +02:00
*/
function set_column_definitions ( $column_definitions = False )
{
$this -> column_definitions = $column_definitions ;
}
2004-08-09 00:31:41 +02:00
/**
* Sets the application in which the db - class looks for table - defintions
*
* Used by table_definitions , insert , update , select , expression and delete . If the app is not set via set_app ,
* it need to be set for these functions on every call
*
* @ param string $app the app - name
*/
2004-05-31 18:32:22 +02:00
function set_app ( $app )
{
$this -> app = $app ;
}
2003-10-05 12:42:07 +02:00
/**
* reads the table - definitions from the app ' s setup / tables_current . inc . php file
*
2004-05-31 18:32:22 +02:00
* The already read table - definitions are shared between all db - instances via $GLOBALS [ 'phpgw_info' ][ 'apps' ][ $app ][ 'table_defs' ]
*
2003-10-05 12:42:07 +02:00
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param bool / string $app name of the app or default False to use the app set by db :: set_app or the current app
* @ param bool / string $table if set return only defintions of that table , else return all defintions
2004-05-31 18:32:22 +02:00
* @ return mixed array with table - defintions or False if file not found
2003-10-05 12:42:07 +02:00
*/
2004-05-31 18:32:22 +02:00
function get_table_definitions ( $app = False , $table = False )
2003-10-05 12:42:07 +02:00
{
2004-05-31 18:32:22 +02:00
if ( ! $app )
{
$app = $this -> app ? $this -> app : $GLOBALS [ 'phpgw_info' ][ 'flags' ][ 'currentapp' ];
}
2004-07-04 19:31:12 +02:00
if ( isset ( $GLOBALS [ 'phpgw_info' ][ 'apps' ])) // this happens during the eGW startup, dont set it then !!!
{
2004-08-04 17:33:42 +02:00
$this -> app_data = & $GLOBALS [ 'phpgw_info' ][ 'apps' ][ $app ];
2004-07-04 19:31:12 +02:00
}
2004-08-04 17:33:42 +02:00
if ( ! isset ( $this -> app_data [ 'table_defs' ]))
2003-10-05 12:42:07 +02:00
{
$tables_current = PHPGW_INCLUDE_ROOT . " / $app /setup/tables_current.inc.php " ;
if ( !@ file_exists ( $tables_current ))
{
2004-08-04 17:33:42 +02:00
return $this -> app_data [ 'table_defs' ] = False ;
2003-10-05 12:42:07 +02:00
}
include ( $tables_current );
2004-08-04 17:33:42 +02:00
$this -> app_data [ 'table_defs' ] = & $phpgw_baseline ;
2003-10-05 12:42:07 +02:00
}
2004-08-04 17:33:42 +02:00
if ( $table && ( ! $this -> app_data [ 'table_defs' ] || ! isset ( $this -> app_data [ 'table_defs' ][ $table ])))
2003-10-05 12:42:07 +02:00
{
return False ;
}
2004-08-04 17:33:42 +02:00
return $table ? $this -> app_data [ 'table_defs' ][ $table ] : $this -> app_data [ 'table_defs' ];
2004-05-31 18:32:22 +02:00
}
/**
2004-08-13 20:59:00 +02:00
* Insert a row of data into a table or updates it if $where is given , all data is quoted according to it ' s type
2004-05-31 18:32:22 +02:00
*
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param string $table name of the table
* @ param array $data with column - name / value pairs
* @ param mixed $where string with where clause or array with column - name / values pairs to check if a row with that keys already exists , or false for an unconditional insert
2004-05-31 18:32:22 +02:00
* if the row exists db :: update is called else a new row with $date merged with $where gets inserted ( data has precedence )
2004-08-09 00:31:41 +02:00
* @ param int $line line - number to pass to query
* @ param string $file file - name to pass to query
* @ param string / boolean $app string with name of app or False to use the current - app
* @ return ADORecordSet or false , if the query fails
2004-05-31 18:32:22 +02:00
*/
2004-10-14 22:58:39 +02:00
function insert ( $table , $data , $where , $line , $file , $app = False , $use_prepared_statement = false )
2004-05-31 18:32:22 +02:00
{
2004-06-21 12:25:14 +02:00
if ( $this -> Debug ) echo " <p>db::insert(' $table ', " . print_r ( $data , True ) . " , " . print_r ( $where , True ) . " , $line , $file ,' $app ')</p> \n " ;
2004-05-31 18:32:22 +02:00
$table_def = $this -> get_table_definitions ( $app , $table );
2004-08-04 01:06:37 +02:00
$sql_append = '' ;
2004-09-18 17:18:48 +02:00
$cmd = 'INSERT' ;
2004-05-31 18:32:22 +02:00
if ( is_array ( $where ) && count ( $where ))
{
2004-08-05 17:31:55 +02:00
switch ( $this -> Type )
2004-05-31 18:32:22 +02:00
{
2004-08-05 17:31:55 +02:00
case 'sapdb' : case 'maxdb' :
$sql_append = ' UPDATE DUPLICATES' ;
break ;
2004-09-18 17:18:48 +02:00
case 'mysql' :
2004-09-22 12:24:39 +02:00
// use replace if primary keys are included
2004-11-12 08:39:07 +01:00
if ( count ( array_intersect ( array_keys ( $where ),( array ) $table_def [ 'pk' ])) == count ( $table_def [ 'pk' ]))
2004-09-22 12:24:39 +02:00
{
$cmd = 'REPLACE' ;
break ;
}
// fall through !!!
2004-08-05 17:31:55 +02:00
default :
$this -> select ( $table , 'count(*)' , $where , $line , $file );
if ( $this -> next_record () && $this -> f ( 0 ))
{
return !! $this -> update ( $table , $data , $where , $line , $file , $app );
}
break ;
2004-05-31 18:32:22 +02:00
}
2004-06-21 12:25:14 +02:00
$data = array_merge ( $where , $data ); // the checked values need to be inserted too, value in data has precedence
2004-05-31 18:32:22 +02:00
}
2004-10-14 22:58:39 +02:00
$inputarr = false ;
if ( $use_prepared_statement && $this -> Link_ID -> _bindInputArray ) // eg. MaxDB
{
$this -> Link_ID -> Param ( false ); // reset param-counter
$cols = array_keys ( $data );
foreach ( $cols as $col )
{
$params [] = $this -> Link_ID -> Param ( $col );
}
$sql = " $cmd INTO $table ( " . implode ( ',' , $cols ) . ') VALUES (' . implode ( ',' , $params ) . ')' . $sql_append ;
// check if we already prepared that statement
if ( ! isset ( $this -> prepared_sql [ $sql ]))
{
$this -> prepared_sql [ $sql ] = $this -> Link_ID -> Prepare ( $sql );
}
$sql = $this -> prepared_sql [ $sql ];
$inputarr = & $data ;
}
else
{
$sql = " $cmd INTO $table " . $this -> column_data_implode ( ',' , $data , 'VALUES' , False , $table_def [ 'fd' ]) . $sql_append ;
}
2004-09-18 16:56:18 +02:00
if ( $this -> Debug ) echo " <p>db::insert(' $table ', " . print_r ( $data , True ) . " , " . print_r ( $where , True ) . " , $line , $file ,' $app ') sql=' $sql '</p> \n " ;
2004-10-14 22:58:39 +02:00
return $this -> query ( $sql , $line , $file , 0 , - 1 , $inputarr );
2004-05-31 18:32:22 +02:00
}
/**
* Updates the data of one or more rows in a table , all data is quoted according to it ' s type
*
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param string $table name of the table
* @ param array $data with column - name / value pairs
* @ param array $where column - name / values pairs and ' ed together for the where clause
* @ param int $line line - number to pass to query
* @ param string $file file - name to pass to query
* @ param string / boolean $app string with name of app or False to use the current - app
* @ return ADORecordSet or false , if the query fails
2004-05-31 18:32:22 +02:00
*/
2004-10-14 22:58:39 +02:00
function update ( $table , $data , $where , $line , $file , $app = False , $use_prepared_statement = false )
2004-05-31 18:32:22 +02:00
{
2004-08-05 17:31:55 +02:00
if ( $this -> Debug ) echo " <p>db::update(' $table ', " . print_r ( $data , true ) . ',' . print_r ( $where , true ) . " , $line , $file ,' $app ')</p> \n " ;
$table_def = $this -> get_table_definitions ( $app , $table );
2004-09-18 16:56:18 +02:00
$blobs2update = array ();
// SapDB/MaxDB cant update LONG columns / blob's: if a blob-column is included in the update we remember it in $blobs2update
// and remove it from $data
2004-10-14 22:58:39 +02:00
switch ( $this -> Type )
2004-08-04 01:06:37 +02:00
{
2004-10-14 22:58:39 +02:00
case 'sapdb' :
case 'maxdb' :
if ( $use_prepared_statement ) break ;
// check if data contains any LONG columns
foreach ( $data as $col => $val )
2004-08-05 17:31:55 +02:00
{
2004-10-14 22:58:39 +02:00
switch ( $table_def [ 'fd' ][ $col ][ 'type' ])
{
case 'text' :
case 'longtext' :
case 'blob' :
$blobs2update [ $col ] = & $data [ $col ];
unset ( $data [ $col ]);
break ;
}
2004-08-05 17:31:55 +02:00
}
2004-10-14 22:58:39 +02:00
break ;
2004-08-04 01:06:37 +02:00
}
2004-09-18 16:56:18 +02:00
$where = $this -> column_data_implode ( ' AND ' , $where , True , False , $table_def [ 'fd' ]);
2004-05-31 18:32:22 +02:00
2004-09-18 16:56:18 +02:00
if ( count ( $data ))
{
2004-10-14 22:58:39 +02:00
$inputarr = false ;
if ( $use_prepared_statement && $this -> Link_ID -> _bindInputArray ) // eg. MaxDB
{
$this -> Link_ID -> Param ( false ); // reset param-counter
foreach ( $data as $col => $val )
{
$params [] = $this -> name_quote ( $col ) . '=' . $this -> Link_ID -> Param ( $col );
}
$sql = " UPDATE $table SET " . implode ( ',' , $params ) . ' WHERE ' . $where ;
// check if we already prepared that statement
if ( ! isset ( $this -> prepared_sql [ $sql ]))
{
$this -> prepared_sql [ $sql ] = $this -> Link_ID -> Prepare ( $sql );
}
$sql = $this -> prepared_sql [ $sql ];
$inputarr = & $data ;
}
else
{
$sql = " UPDATE $table SET " .
$this -> column_data_implode ( ',' , $data , True , False , $table_def [ 'fd' ]) . ' WHERE ' . $where ;
}
$ret = $this -> query ( $sql , $line , $file , 0 , - 1 , $inputarr );
2004-09-19 12:35:54 +02:00
if ( $this -> Debug ) echo " <p>db::query(' $sql ', $line , $file ) = ' $ret '</p> \n " ;
2004-09-18 16:56:18 +02:00
}
// if we have any blobs to update, we do so now
if (( $ret || ! count ( $data )) && count ( $blobs2update ))
{
foreach ( $blobs2update as $col => $val )
{
$ret = $this -> Link_ID -> UpdateBlob ( $table , $col , $val , $where , $table_def [ 'fd' ][ $col ][ 'type' ] == 'blob' ? 'BLOB' : 'CLOB' );
2004-09-19 12:35:54 +02:00
if ( $this -> Debug ) echo " <p>adodb::UpdateBlob(' $table ',' $col ',' $val ',' $where ') = ' $ret '</p> \n " ;
if ( ! $ret ) $this -> halt ( " Error in UpdateBlob( $table , $col , \$ val, $where ) " , $line , $file );
2004-09-18 16:56:18 +02:00
}
}
return $ret ;
2004-05-31 18:32:22 +02:00
}
/**
* Deletes one or more rows in table , all data is quoted according to it ' s type
*
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param string $table name of the table
* @ param array $where column - name / values pairs and ' ed together for the where clause
* @ param int $line line - number to pass to query
* @ param string $file file - name to pass to query
* @ param string / boolean $app string with name of app or False to use the current - app
* @ return ADORecordSet or false , if the query fails
2004-05-31 18:32:22 +02:00
*/
function delete ( $table , $where , $line , $file , $app = False )
{
$table_def = $this -> get_table_definitions ( $app , $table );
$sql = " DELETE FROM $table WHERE " .
$this -> column_data_implode ( ' AND ' , $where , True , False , $table_def [ 'fd' ]);
return $this -> query ( $sql , $line , $file );
}
/**
* Formats and quotes a sql expression to be used eg . as where - clause
*
* The function has a variable number of arguments , from which the expession gets constructed
* eg . db :: expression ( 'my_table' , '(' , array ( 'name' => " test'ed " , 'lang' => 'en' ), ') OR ' , array ( 'owner' => array ( '' , 4 , 10 )))
* gives " (name='test \ 'ed' AND lang='en') OR 'owner' IN (0,4,5,6,10) " if name , lang are strings and owner is an integer
* @ param $table string name of the table
* @ param $args mixed variable number of arguments of the following types :
* string : get ' s as is into the result
* array : column - name / value pairs : the value gets quoted according to the type of the column and prefixed
* with column - name = , multiple pairs are AND ' ed together , see db :: column_data_implode
* bool : If False or is_null ( $arg ) : the next 2 ( ! ) arguments gets ignored
* @ return string the expression generated from the arguments
*/
function expression ( $table , $args )
{
$table_def = $this -> get_table_definitions ( $app , $table );
$sql = '' ;
$ignore_next = 0 ;
foreach ( func_get_args () as $n => $arg )
{
if ( $n < 1 ) continue ; // table-name
if ( $ignore_next )
{
-- $ignore_next ;
continue ;
}
if ( is_null ( $arg )) $arg = False ;
switch ( gettype ( $arg ))
{
case 'string' :
$sql .= $arg ;
break ;
case 'boolean' :
$ignore_next += ! $arg ? 2 : 0 ;
break ;
case 'array' :
2004-08-05 17:31:55 +02:00
$sql .= $this -> column_data_implode ( ' AND ' , $arg , True , False , $table_def [ 'fd' ]);
2004-05-31 18:32:22 +02:00
break ;
}
}
2004-06-21 12:25:14 +02:00
if ( $this -> Debug ) echo " <p>db::expression( $table ,<pre> " . print_r ( func_get_args (), True ) . " </pre>) =' $sql '</p> \n " ;
2004-05-31 18:32:22 +02:00
return $sql ;
}
/**
* Selects one or more rows in table depending on where , all data is quoted according to it ' s type
*
* @ author RalfBecker < at > outdoor - training . de
*
2004-08-09 00:31:41 +02:00
* @ param string $table name of the table
* @ param array / string $cols string or array of column - names / select - expressions
* @ param array / string $where string or array with column - name / values pairs AND ' ed together for the where clause
* @ param int $line line - number to pass to query
* @ param string $file file - name to pass to query
* @ param int / bool $offset offset for a limited query or False ( default )
2004-08-05 17:31:55 +02:00
* @ param string $append string to append to the end of the query , eg . ORDER BY ...
2004-08-09 00:31:41 +02:00
* @ param string / boolean $app string with name of app or False to use the current - app
* @ param int $num_rows number of rows to return if offset set , default 0 = use default in user prefs
* @ return ADORecordSet or false , if the query fails
2004-05-31 18:32:22 +02:00
*/
2004-08-09 00:31:41 +02:00
function select ( $table , $cols , $where , $line , $file , $offset = False , $append = '' , $app = False , $num_rows = 0 )
2004-05-31 18:32:22 +02:00
{
2004-06-21 12:25:14 +02:00
if ( $this -> Debug ) echo " <p>db::select(' $table ', " . print_r ( $cols , True ) . " , " . print_r ( $where , True ) . " , $line , $file , $offset ,' $app ')</p> \n " ;
2004-05-31 18:32:22 +02:00
$table_def = $this -> get_table_definitions ( $app , $table );
if ( is_array ( $cols ))
{
$cols = implode ( ',' , $cols );
}
if ( is_array ( $where ))
{
$where = $this -> column_data_implode ( ' AND ' , $where , True , False , $table_def [ 'fd' ]);
}
2004-08-05 17:31:55 +02:00
$sql = " SELECT $cols FROM $table WHERE " . ( $where ? $where : '1=1' ) .
( $append ? ' ' . $append : '' );
2004-05-31 18:32:22 +02:00
2004-06-21 12:25:14 +02:00
if ( $this -> Debug ) echo " <p>sql=' $sql '</p> " ;
2004-08-09 00:31:41 +02:00
return $this -> query ( $sql , $line , $file , $offset , $offset === False ? - 1 : ( int ) $num_rows );
2003-10-05 12:42:07 +02:00
}
2003-08-28 16:31:11 +02:00
}