2004-07-03 13:00:24 +02:00
< ? php
2004-08-13 21:01:03 +02:00
/************************************************************************** \
* eGroupWare - Setup - db - schema - processor *
* http :// www . egroupware . org *
* -------------------------------------------- *
* Rewritten and adopted to ADOdb ' s data - dictionary by Ralf Becker *
* < RalfBecker @ outdoor - training . de > *
* This file was originaly written by *
* - Michael Dean < mdean @ users . sourceforge . net > *
* - Miles Lott < milosch @ groupwhere . org > *
* -------------------------------------------- *
* This program is free software ; you can redistribute it and / or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation ; either version 2 of the License , or ( at your *
* option ) any later version . *
\ **************************************************************************/
/* $Id$ */
/**
* eGW ' s ADOdb based schema - processor
*
2005-11-04 19:35:09 +01:00
* @ package phpgwapi
* @ subpackage db
2004-08-13 21:01:03 +02:00
* @ author RalfBecker - AT - outdoor - training . de and others
* @ license GPL
*/
2002-03-03 22:48:34 +01:00
class schema_proc
{
2005-11-20 16:40:28 +01:00
/**
* @ deprecated formerly used translator class , now a reference to ourself
*/
2002-03-03 22:48:34 +01:00
var $m_oTranslator ;
2005-11-20 16:40:28 +01:00
/**
* @ var egw_db - object $m_odb db - object
*/
2002-03-03 22:48:34 +01:00
var $m_odb ;
2005-11-20 16:40:28 +01:00
/**
* @ var adodb - object $adodb reference to the global ADOdb object
*/
var $adodb ;
/**
* @ var datadictionary - object $dict adodb ' s datadictionary object for the used db - type
*/
var $dict ;
/**
* @ var $debug = 0 0 = Off , 1 = some , eg . primary function calls , 2 = lots incl . the SQL used
*/
var $debug = 0 ;
/**
* @ var array $max_index_length db => max . length of indexes pairs ( if there is a considerable low limit for a db )
*/
var $max_index_length = array (
2004-08-13 21:01:03 +02:00
'sapdb' => 32 ,
2005-02-07 21:28:05 +01:00
'oracle' => 30 ,
2004-08-13 21:01:03 +02:00
);
2005-11-20 16:40:28 +01:00
/**
* @ var string $sType type of the database , set by the the constructor
*/
var $sType ;
/**
* @ var int $max_varchar_length maximum length of a varchar column , everything above get converted to text
*/
var $max_varchar_length = 255 ;
/**
* @ var string $system_charset system - charset if set
*/
2005-11-04 19:35:09 +01:00
var $system_charset ;
2005-11-20 16:40:28 +01:00
/**
* @ var array $capabilities reference to the array of the db - class
*/
var $capabilities ;
2006-01-06 17:21:51 +01:00
/**
* @ var int $pgsql_old_seq preserve value of old sequences in PostgreSQL
*/
var $pgsql_old_seq ;
2004-08-13 21:01:03 +02:00
/**
* Constructor of schema - processor
*
* @ param string $dbms type of the database : 'mysql' , 'pgsql' , 'mssql' , 'sapdb'
*/
2004-10-23 17:00:44 +02:00
function schema_proc ( $dbms = False )
2002-03-03 22:48:34 +01:00
{
2005-06-21 00:07:40 +02:00
$this -> m_odb = is_object ( $GLOBALS [ 'egw' ] -> db ) ? $GLOBALS [ 'egw' ] -> db : $GLOBALS [ 'egw_setup' ] -> db ;
2004-08-15 17:43:52 +02:00
$this -> m_odb -> connect ();
2005-11-20 16:40:28 +01:00
$this -> capabilities =& $this -> m_odb -> capabilities ;
2005-06-20 13:04:20 +02:00
2004-10-14 22:55:52 +02:00
$this -> sType = $dbms ? $dmbs : $this -> m_odb -> Type ;
2005-06-20 09:51:01 +02:00
$this -> adodb = & $GLOBALS [ 'egw' ] -> ADOdb ;
2004-08-13 21:01:03 +02:00
$this -> dict = NewDataDictionary ( $this -> adodb );
2005-06-20 13:04:20 +02:00
2004-08-13 21:01:03 +02:00
// enable the debuging in ADOdb's datadictionary if the debug-level is greater then 1
if ( $this -> debug > 1 ) $this -> dict -> debug = True ;
// to allow some of the former translator-functions to be called, we assign ourself as the translator
$this -> m_oTranslator = & $this ;
2004-10-14 22:55:52 +02:00
switch ( $this -> sType )
{
case 'sapdb' :
case 'maxdb' :
$this -> max_varchar_length = 8000 ;
break ;
}
2005-11-04 19:35:09 +01:00
if ( is_object ( $GLOBALS [ 'egw_setup' ]))
{
$this -> system_charset =& $GLOBALS [ 'egw_setup' ] -> system_charset ;
}
elseif ( isset ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'system_charset' ]))
{
$this -> system_charset = $GLOBALS [ 'egw_info' ][ 'server' ][ 'system_charset' ];
}
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Created a table named $sTableName as defined in $aTableDef
*
* @ param string $sTableName
* @ param array $aTableDef
2006-01-06 17:21:51 +01:00
* @ param bool $preserveSequence
2004-08-13 21:01:03 +02:00
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2006-01-06 17:21:51 +01:00
function CreateTable ( $sTableName , $aTableDef , $preserveSequence = False )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
if ( $this -> debug )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$this -> debug_message ( 'schema_proc::CreateTable(%1,%2)' , False , $sTableName , $aTableDef );
2002-03-03 22:48:34 +01:00
}
2005-11-04 19:35:09 +01:00
// for mysql 4.0+ we set the charset for the table
if ( $this -> system_charset && substr ( $this -> sType , 0 , 5 ) == 'mysql' &&
( float ) $this -> m_odb -> ServerInfo [ 'version' ] >= 4.0 && $this -> m_odb -> Link_ID -> charset2mysql [ $this -> system_charset ])
{
$set_table_charset = array ( $this -> sType => 'CHARACTER SET ' . $this -> m_odb -> Link_ID -> charset2mysql [ $this -> system_charset ]);
}
2004-08-13 21:01:03 +02:00
// creating the table
2005-11-04 19:35:09 +01:00
$aSql = $this -> dict -> CreateTableSQL ( $sTableName , $ado_cols = $this -> _egw2adodb_columndef ( $aTableDef ), $set_table_charset );
2004-08-13 21:01:03 +02:00
if ( ! ( $retVal = $this -> ExecuteSQLArray ( $aSql , 2 , 'CreateTableSQL(%1,%2) sql=%3' , False , $sTableName , $ado_cols , $aSql )))
{
return $retVal ;
}
// creating unique indices/constrains
foreach ( $aTableDef [ 'uc' ] as $name => $mFields )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
if ( is_numeric ( $name ))
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$name = $this -> _index_name ( $sTableName , $mFields );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
$aSql = $this -> dict -> CreateIndexSQL ( $name , $sTableName , $mFields , array ( 'UNIQUE' ));
if ( ! ( $retVal = $this -> ExecuteSQLArray ( $aSql , 2 , 'CreateIndexSql(%1,%2,%3,%4) sql=%5' , False , $name , $sTableName , $mFields , array ( 'UNIQUE' ), $aSql )))
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
return $retVal ;
2002-03-03 22:48:34 +01:00
}
}
2004-08-13 21:01:03 +02:00
// creation indices
foreach ( $aTableDef [ 'ix' ] as $name => $mFields )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$options = False ;
if ( is_array ( $mFields ))
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
if ( isset ( $mFields [ 'options' ])) // array sets additional options
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
if ( isset ( $mFields [ 'options' ][ $this -> sType ]))
{
$options = $mFields [ 'options' ][ $this -> sType ]; // db-specific options, eg. index-type
if ( ! $options ) continue ; // no index for our db-type
}
unset ( $mFields [ 'options' ]);
2002-03-03 22:48:34 +01:00
}
}
2004-10-14 22:55:52 +02:00
else
{
// only create indexes on text-columns, if (db-)specifiy options are given or FULLTEXT for mysql
// most DB's cant do them and give errors
if ( $aTableDef [ 'fd' ][ $mFields ][ 'type' ] == 'text' )
{
if ( $this -> sType == 'mysql' )
{
$options = 'FULLTEXT' ;
}
else
{
continue ; // ignore that index
}
}
}
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
if ( is_numeric ( $name ))
{
$name = $this -> _index_name ( $sTableName , $mFields );
}
$aSql = $this -> dict -> CreateIndexSQL ( $name , $sTableName , $mFields , array ( $options ));
if ( ! ( $retVal = $this -> ExecuteSQLArray ( $aSql , 2 , 'CreateIndexSql(%1,%2,%3,%4) sql=%5' , False , $name , $sTableName , $mFields , $options , $aSql )))
{
return $retVal ;
2002-03-03 22:48:34 +01:00
}
}
2006-01-06 17:21:51 +01:00
// preserve last value of an old sequence
if ( $this -> sType == 'pgsql' && $preserveSequence && $this -> pgsql_old_seq )
{
if ( $seq = $this -> _PostgresHasOldSequence ( $sTableName ))
{
$this -> pgsql_old_seq = $this -> pgsql_old_seq + 1 ;
$this -> m_odb -> query ( " ALTER SEQUENCE $seq RESTART WITH " . $this -> pgsql_old_seq , __LINE__ , __FILE__ );
}
$this -> pgsql_old_seq = 0 ;
}
2004-08-13 21:01:03 +02:00
return $retVal ;
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Drops all tables in $aTables
*
* @ param array $aTables array of eGW table - definitions
* @ param boolean $bOutputHTML should we give diagnostics , default False
* @ return boolean True if no error , else False
*/
2002-03-03 22:48:34 +01:00
function DropAllTables ( $aTables , $bOutputHTML = False )
{
if ( ! is_array ( $aTables ) || ! isset ( $this -> m_odb ))
{
return False ;
}
2004-08-13 21:01:03 +02:00
// set our debug-mode or $bOutputHTML is the other one is set
if ( $this -> debug ) $bOutputHTML = True ;
if ( $bOutputHTML && ! $this -> debug ) $this -> debug = 2 ;
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
foreach ( $aTables as $sTableName => $aTableDef )
2002-03-03 22:48:34 +01:00
{
if ( $this -> DropTable ( $sTableName ))
{
if ( $bOutputHTML )
{
echo '<br>Drop Table <b>' . $sTableSQL . '</b>' ;
}
}
else
{
return False ;
}
}
return True ;
}
2004-08-13 21:01:03 +02:00
/**
* Drops the table $sTableName
*
* @ param string $sTableName
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2002-03-03 22:48:34 +01:00
function DropTable ( $sTableName )
{
2004-08-13 21:01:03 +02:00
if ( $this -> sType == 'pgsql' ) $this -> _PostgresTestDropOldSequence ( $sTableName );
$aSql = $this -> dict -> DropTableSql ( $sTableName );
return $this -> ExecuteSQLArray ( $aSql , 2 , 'DropTable(%1) sql=%2' , False , $sTableName , $aSql );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Drops column $sColumnName from table $sTableName
*
* @ param string $sTableName table - name
* @ param array $aTableDef eGW table - defintion
* @ param string $sColumnName column - name
* @ param boolean $bCopyData ? ? ?
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2002-03-03 22:48:34 +01:00
function DropColumn ( $sTableName , $aTableDef , $sColumnName , $bCopyData = true )
{
2004-10-23 17:00:44 +02:00
$table_def = $this -> GetTableDefinition ( $sTableName );
unset ( $table_def [ 'fd' ][ $sColumnName ]);
$aSql = $this -> dict -> DropColumnSql ( $sTableName , $sColumnName , $ado_table = $this -> _egw2adodb_columndef ( $table_def ));
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
return $this -> ExecuteSQLArray ( $aSql , 2 , 'DropColumnSQL(%1,%2,%3) sql=%4' , False , $sTableName , $sColumnName , $ado_table , $aSql );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Renames table $sOldTableName to $sNewTableName
*
* @ param string $sOldTableName old ( existing ) table - name
* @ param string $sNewTableName new table - name
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2002-03-03 22:48:34 +01:00
function RenameTable ( $sOldTableName , $sNewTableName )
{
2005-02-10 16:15:29 +01:00
// if we have an old postgres sequence or index (the ones not linked to the table),
// we create a new table, copy the content and drop the old one
if ( $this -> sType == 'pgsql' )
{
$table_def = $this -> GetTableDefinition ( $sOldTableName );
2002-03-03 22:48:34 +01:00
2006-01-06 17:21:51 +01:00
if ( $this -> _PostgresHasOldSequence ( $sOldTableName , True ) || count ( $table_def [ 'pk' ]) ||
2005-02-10 16:15:29 +01:00
count ( $table_def [ 'ix' ]) || count ( $table_def [ 'uc' ]))
{
if ( $this -> adodb -> BeginTrans () &&
2006-01-06 17:21:51 +01:00
$this -> CreateTable ( $sNewTableName , $table_def , True ) &&
2005-02-10 16:15:29 +01:00
$this -> m_odb -> query ( " INSERT INTO $sNewTableName SELECT * FROM $sOldTableName " , __LINE__ , __FILE__ ) &&
$this -> DropTable ( $sOldTableName ))
{
$this -> adodb -> CommitTrans ();
return 2 ;
}
$this -> adodb -> RollbackTrans ();
return 0 ;
}
}
2004-08-13 21:01:03 +02:00
$aSql = $this -> dict -> RenameTableSQL ( $sOldTableName , $sNewTableName );
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
return $this -> ExecuteSQLArray ( $aSql , 2 , 'RenameTableSQL(%1,%2) sql=%3' , False , $sOldTableName , $sNewTableName , $aSql );
}
/**
2005-02-10 16:15:29 +01:00
* Check if we have an old , not automaticaly droped sequence
2004-08-13 21:01:03 +02:00
*
2005-02-10 16:15:29 +01:00
* @ param string $sTableName
2006-01-06 17:21:51 +01:00
* @ param bool $preserveValue
* @ return boolean / string sequence - name or false
2004-08-13 21:01:03 +02:00
*/
2006-01-06 17:21:51 +01:00
function _PostgresHasOldSequence ( $sTableName , $preserveValue = False )
2002-03-03 22:48:34 +01:00
{
2005-02-10 16:15:29 +01:00
if ( $this -> sType != 'pgsql' ) return false ;
2004-08-13 21:01:03 +02:00
2006-01-06 17:21:51 +01:00
$seq = $this -> adodb -> GetOne ( " SELECT d.adsrc FROM pg_attribute a, pg_class c, pg_attrdef d WHERE c.relname=' $sTableName ' AND c.oid=d.adrelid AND d.adsrc LIKE '%seq_ $sTableName\ '::text)' AND a.attrelid=c.oid AND d.adnum=a.attnum " );
$seq2 = $this -> adodb -> GetOne ( " SELECT d.adsrc FROM pg_attribute a, pg_class c, pg_attrdef d WHERE c.relname=' $sTableName ' AND c.oid=d.adrelid AND d.adsrc LIKE '% $sTableName %_seq \ '::text)' AND a.attrelid=c.oid AND d.adnum=a.attnum " );
2004-08-13 21:01:03 +02:00
2004-10-23 17:00:44 +02:00
if ( $seq && preg_match ( '/^nextval\(\'(.*)\'/' , $seq , $matches ))
2002-03-03 22:48:34 +01:00
{
2006-01-06 17:21:51 +01:00
if ( $preserveValue ) $this -> pgsql_old_seq = $this -> adodb -> GetOne ( " SELECT last_value FROM " . $matches [ 1 ]);
return $matches [ 1 ];
}
if ( $seq2 && preg_match ( '/^nextval\(\'public\.(.*)\'/' , $seq2 , $matches ))
{
if ( $preserveValue ) $this -> pgsql_old_seq = $this -> adodb -> GetOne ( " SELECT last_value FROM " . $matches [ 1 ]);
2005-02-10 16:15:29 +01:00
return $matches [ 1 ];
}
return false ;
}
/**
* Check if we have an old , not automaticaly droped sequence and drop it
*
* @ param $sTableName
2006-01-06 17:21:51 +01:00
* @ param bool $preserveValue
2005-02-10 16:15:29 +01:00
*/
2006-01-06 17:21:51 +01:00
function _PostgresTestDropOldSequence ( $sTableName , $preserveValue = False )
2005-02-10 16:15:29 +01:00
{
2006-01-06 17:21:51 +01:00
$this -> pgsql_old_seq = 0 ;
2005-02-10 16:15:29 +01:00
if ( $this -> sType == 'pgsql' && ( $seq = $this -> _PostgresHasOldSequence ( $sTableName )))
{
2006-01-06 17:21:51 +01:00
// only drop sequence, if there is no dependency on it
if ( ! $this -> adodb -> GetOne ( " SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname=' $seq ' AND relkind='S' AND deptype='i' " ))
{
2005-02-10 16:15:29 +01:00
$this -> query ( 'DROP SEQUENCE ' . $seq , __LINE__ , __FILE__ );
2002-03-03 22:48:34 +01:00
}
}
2006-01-06 17:21:51 +01:00
}
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
/**
* Changes one ( exiting ) column in a table
*
* @ param string $sTableName table - name
* @ param string $sColumnName column - name
* @ param array $aColumnDef new column - definition
* @ param boolean $bCopyData ? ? ?
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2002-03-03 22:48:34 +01:00
function AlterColumn ( $sTableName , $sColumnName , $aColumnDef , $bCopyData = True )
{
2004-10-23 17:00:44 +02:00
$table_def = $this -> GetTableDefinition ( $sTableName );
$table_def [ 'fd' ][ $sColumnName ] = $aColumnDef ;
2004-08-13 21:01:03 +02:00
$aSql = $this -> dict -> AlterColumnSQL ( $sTableName , $ado_col = $this -> _egw2adodb_columndef ( array (
'fd' => array ( $sColumnName => $aColumnDef ),
'pk' => array (),
2004-10-23 17:00:44 +02:00
)), $ado_table = $this -> _egw2adodb_columndef ( $table_def ));
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
return $this -> ExecuteSQLArray ( $aSql , 2 , 'AlterColumnSQL(%1,%2,%3) sql=%4' , False , $sTableName , $ado_col , $ado_table , $aSql );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Renames column $sOldColumnName to $sNewColumnName in table $sTableName
*
* @ param string $sTableName table - name
* @ param string $sOldColumnName old ( existing ) column - name
* @ param string $sNewColumnName new column - name
* @ param boolean $bCopyData ? ? ?
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
function RenameColumn ( $sTableName , $sOldColumnName , $sNewColumnName , $bCopyData = True )
{
2004-10-23 17:00:44 +02:00
$table_def = $this -> GetTableDefinition ( $sTableName );
2006-01-06 17:21:51 +01:00
$old_def = array ();
2005-02-27 20:51:24 +01:00
if ( isset ( $table_def [ 'fd' ][ $sOldColumnName ]))
{
$old_def = $table_def [ 'fd' ][ $sOldColumnName ];
}
else
{
foreach ( $table_def [ 'fd' ] as $col => $def )
{
2006-01-06 17:21:51 +01:00
if ( strtolower ( $col ) == strtolower ( $sOldColumnName ))
2005-02-27 20:51:24 +01:00
{
$old_def = $def ;
break ;
}
}
}
2004-08-13 21:01:03 +02:00
$col_def = $this -> _egw2adodb_columndef ( array (
2005-02-27 20:51:24 +01:00
'fd' => array ( $sNewColumnName => $old_def ),
2004-08-13 21:01:03 +02:00
'pk' => array (),
));
2004-10-23 17:00:44 +02:00
2004-08-13 21:01:03 +02:00
$aSql = $this -> dict -> RenameColumnSQL ( $sTableName , $sOldColumnName , $sNewColumnName , $col_def );
return $this -> ExecuteSQLArray ( $aSql , 2 , 'RenameColumnSQL(%1,%2,%3) sql=%4' , False , $sTableName , $sOldColumnName , $sNewColumnName , $aSql );
}
/**
* Add one ( new ) column to a table
*
* @ param string $sTableName table - name
* @ param string $sColumnName column - name
* @ param array $aColumnDef column - definition
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2002-03-03 22:48:34 +01:00
function AddColumn ( $sTableName , $sColumnName , $aColumnDef )
{
2004-08-13 21:01:03 +02:00
$aSql = $this -> dict -> AddColumnSQL ( $sTableName , $ado_cols = $this -> _egw2adodb_columndef ( array (
'fd' => array ( $sColumnName => $aColumnDef ),
'pk' => array (),
)));
return $this -> ExecuteSQLArray ( $aSql , 2 , 'AlterColumnSQL(%1,%2,%3) sql=%4' , False , $sTableName , $sColumnName , $aColumnDef , $aSql );
}
/**
* Create an ( unique ) Index over one or more columns
*
* @ param string $sTablename table - name
* @ param array $aColumnNames columns for the index
* @ param boolean $bUnique = false true for a unique index , default false
* @ param array / string $options = '' db - sepecific options , default '' = none
* @ param string $sIdxName = '' name of the index , if not given ( default ) its created automaticaly
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
2004-10-23 17:00:44 +02:00
function CreateIndex ( $sTableName , $aColumnNames , $bUnique = false , $options = '' , $sIdxName = '' )
2004-08-13 21:01:03 +02:00
{
if ( ! $sIdxName || is_numeric ( $sIdxName ))
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$sIdxName = $this -> _index_name ( $sTableName , $aColumnNames );
2002-03-03 22:48:34 +01:00
}
2004-10-23 17:00:44 +02:00
if ( ! is_array ( $options )) $options = $options ? array ( $options ) : array ();
if ( $bUnique ) $options [] = 'UNIQUE' ;
$aSql = $this -> dict -> CreateIndexSQL ( $name , $sTableName , $aColumnNames , $options );
2002-03-03 22:48:34 +01:00
2004-10-23 17:00:44 +02:00
return $this -> ExecuteSQLArray ( $aSql , 2 , 'CreateIndexSQL(%1,%2,%3,%4) sql=%5' , False , $name , $sTableName , $aColumnNames , $options , $aSql );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Drop an Index
*
* @ param string $sTablename table - name
* @ param array / string $aColumnNames columns of the index or the name of the index
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
function DropIndex ( $sTableName , $aColumnNames )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
if ( is_array ( $aColumnNames ))
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$indexes = $this -> dict -> MetaIndexes ( $sTableName );
if ( $indexes === False )
{
// if MetaIndexes is not availible for the DB, we try the name the index was created with
// this fails if one of the columns have been renamed
$sIdxName = $this -> _index_name ( $sTableName , $aColumnNames );
}
else
{
2005-02-10 16:15:29 +01:00
foreach ( $indexes as $idx => $idx_data )
2004-08-13 21:01:03 +02:00
{
if ( strtolower ( implode ( ':' , $idx_data [ 'columns' ])) == implode ( ':' , $aColumnNames ))
{
$sIdxName = $idx ;
break ;
}
}
}
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
else
{
$sIdxName = $aColumnNames ;
}
2004-10-23 17:00:44 +02:00
if ( ! $sIdxName )
2004-08-13 21:01:03 +02:00
{
return True ;
}
$aSql = $this -> dict -> DropIndexSQL ( $sIdxName , $sTableName );
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
return $this -> ExecuteSQLArray ( $aSql , 2 , 'DropIndexSQL(%1(%2),%3) sql=%4' , False , $sIdxName , $aColumnNames , $sTableName , $aSql );
}
/**
* Updating the sequence - value , after eg . copying data via RefreshTable
* @ param string $sTableName table - name
* @ param string $sColumnName column - name , which default is set to nextval ()
*/
2004-07-03 00:12:10 +02:00
function UpdateSequence ( $sTableName , $sColumnName )
{
2004-08-13 21:01:03 +02:00
switch ( $this -> sType )
2004-07-03 00:12:10 +02:00
{
2004-08-13 21:01:03 +02:00
case 'pgsql' :
// identify the sequence name, ADOdb uses a different name or it might be renamed
$columns = $this -> dict -> MetaColumns ( $sTableName );
$seq_name = 'seq_' . $sTableName ;
2004-10-14 22:55:52 +02:00
if ( preg_match ( " /nextval \ ('([^']+)'::text \ )/ " , $columns [ strtoupper ( $sColumnName )] -> default_value , $matches ))
2004-08-13 21:01:03 +02:00
{
$seq_name = $matches [ 1 ];
}
2004-10-14 22:55:52 +02:00
$sql = " SELECT setval(' $seq_name ',MAX( $sColumnName )) FROM $sTableName " ;
2004-10-23 17:00:44 +02:00
if ( $this -> debug ) { echo " <br>Updating sequence ' $seq_name using: $sql " ; }
2004-08-13 21:01:03 +02:00
return $this -> query ( $sql , __LINE__ , __FILE__ );
2004-07-03 00:12:10 +02:00
}
return True ;
}
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
/**
* This function manually re - created the table incl . primary key and all other indices
*
* It is meant to use if the primary key , existing indices or column - order changes or
* columns are not longer used or new columns need to be created ( with there default value or NULL )
* Beside the default - value in the schema , one can give extra defaults via $aDefaults to eg . use an
* other colum or function to set the value of a new or changed column
*
* @ param string $sTableName table - name
* @ param array $aTableDef eGW table - defintion
* @ param array / boolean $aDefaults array with default for the colums during copying , values are either ( old ) column - names or quoted string - literals
*/
2004-02-29 01:13:47 +01:00
function RefreshTable ( $sTableName , $aTableDef , $aDefaults = False )
2004-02-19 09:48:15 +01:00
{
2004-10-23 17:00:44 +02:00
if ( $this -> debug ) { echo " <p>schema_proc::RefreshTable(' $sTableName ', " . _debug_array ( $aTableDef , False ) . " )<p> $sTableName = " . _debug_array ( $old_table_def , False ) . " \n " ; }
$old_table_def = $this -> GetTableDefinition ( $sTableName );
2004-08-13 21:01:03 +02:00
2004-02-19 09:48:15 +01:00
$tmp_name = 'tmp_' . $sTableName ;
$this -> m_odb -> transaction_begin ();
$select = array ();
2004-08-13 21:01:03 +02:00
$blob_column_included = $auto_column_included = False ;
2004-02-19 09:48:15 +01:00
foreach ( $aTableDef [ 'fd' ] as $name => $data )
{
2004-02-29 01:13:47 +01:00
if ( $aDefaults && isset ( $aDefaults [ $name ])) // use given default
{
2004-06-27 11:53:58 +02:00
$value = $aDefaults [ $name ];
2004-02-29 01:13:47 +01:00
}
2004-10-23 17:00:44 +02:00
elseif ( isset ( $old_table_def [ 'fd' ][ $name ])) // existing column, use its value => column-name in query
2004-02-19 09:48:15 +01:00
{
2004-06-27 11:53:58 +02:00
$value = $name ;
2004-10-23 17:00:44 +02:00
// this is eg. necessary to change a varchar into an int column under postgres
if ( $this -> sType == 'pgsql' &&
in_array ( $old_table_def [ 'fd' ][ $name ][ 'type' ], array ( 'char' , 'varchar' , 'text' , 'blob' )) &&
in_array ( $data [ 'type' ], array ( 'int' , 'decimal' )))
{
2004-11-21 23:40:21 +01:00
$value = " to_number( $name ,'S9999999999999D99') " ;
2004-10-23 17:00:44 +02:00
}
2004-02-19 09:48:15 +01:00
}
else // new column => use default value or NULL
{
if ( ! isset ( $data [ 'default' ]) && ( ! isset ( $data [ 'nullable' ]) || $data [ 'nullable' ]))
{
2004-06-27 11:53:58 +02:00
$value = 'NULL' ;
2004-02-19 09:48:15 +01:00
}
else
{
2004-06-27 11:53:58 +02:00
$value = $this -> m_odb -> quote ( isset ( $data [ 'default' ]) ? $data [ 'default' ] : '' , $data [ 'type' ]);
if ( $this -> sType == 'pgsql' )
{
2004-10-23 17:00:44 +02:00
// fix for postgres error "no '<' operator for type 'unknown'"
if (( $type_translated = $this -> TranslateType ( $data [ 'type' ])))
{
$value = " CAST( $value AS $type_translated ) " ;
}
2004-06-27 11:53:58 +02:00
}
2004-02-19 09:48:15 +01:00
}
}
2004-08-13 21:01:03 +02:00
$blob_column_included = $blob_column_included || in_array ( $data [ 'type' ], array ( 'blob' , 'text' , 'longtext' ));
$auto_column_included = $auto_column_included || $data [ 'type' ] == 'auto' ;
2004-06-27 11:53:58 +02:00
$select [] = $value ;
2004-02-19 09:48:15 +01:00
}
$select = implode ( ',' , $select );
2004-07-03 00:12:10 +02:00
2004-08-13 21:01:03 +02:00
$extra = '' ;
$distinct = 'DISTINCT' ;
switch ( $this -> sType )
{
case 'mssql' :
if ( $auto_column_included ) $extra = " SET IDENTITY_INSERT $sTableName ON \n " ;
if ( $blob_column_included ) $distinct = '' ; // no distinct on blob-columns
break ;
}
// because of all the trouble with sequences and indexes in the global namespace,
2004-10-23 17:00:44 +02:00
// we use an additional temp. table for postgres and not rename the existing one, but drop it.
2004-08-13 21:01:03 +02:00
if ( $this -> sType == 'pgsql' )
{
2004-10-23 17:00:44 +02:00
$Ok = $this -> m_odb -> query ( " SELEcT * INTO TEMPORARY TABLE $tmp_name FROM $sTableName " , __LINE__ , __FILE__ ) &&
2004-08-13 21:01:03 +02:00
$this -> DropTable ( $sTableName );
}
else
{
$Ok = $this -> RenameTable ( $sTableName , $tmp_name );
}
$Ok = $Ok && $this -> CreateTable ( $sTableName , $aTableDef ) &&
$this -> m_odb -> query ( " $extra INSERT INTO $sTableName ( " .
implode ( ',' , array_keys ( $aTableDef [ 'fd' ])) .
2004-10-23 17:00:44 +02:00
" ) SELEcT $distinct $select FROM $tmp_name " , __LINE__ , __FILE__ ) &&
2004-08-13 21:01:03 +02:00
$this -> DropTable ( $tmp_name );
2004-02-19 09:48:15 +01:00
if ( ! $Ok )
{
2004-04-03 12:22:08 +02:00
$this -> m_odb -> transaction_abort ();
2004-02-19 09:48:15 +01:00
return False ;
}
2004-07-03 00:12:10 +02:00
// do we need to update the new sequences value ?
if ( count ( $aTableDef [ 'pk' ]) == 1 && $aTableDef [ 'fd' ][ $aTableDef [ 'pk' ][ 0 ]][ 'type' ] == 'auto' )
{
$this -> UpdateSequence ( $sTableName , $aTableDef [ 'pk' ][ 0 ]);
}
2004-02-19 09:48:15 +01:00
$this -> m_odb -> transaction_commit ();
return True ;
}
2004-08-13 21:01:03 +02:00
/**
* depricated Function does nothing any more
* @ depricated
*/
function GenerateScripts ( $aTables , $bOutputHTML = False )
{
return True ;
}
/**
* Creates all tables for one application
*
* @ param array $aTables array of eGW table - definitions
2005-11-04 19:35:09 +01:00
* @ param boolean $bOutputHTML = false should we give diagnostics , default False
2004-08-13 21:01:03 +02:00
* @ return boolean True on success , False if an ( fatal ) error occured
*/
function ExecuteScripts ( $aTables , $bOutputHTML = False )
{
if ( ! is_array ( $aTables ) || ! IsSet ( $this -> m_odb ))
{
return False ;
}
// set our debug-mode or $bOutputHTML is the other one is set
if ( $this -> debug ) $bOutputHTML = True ;
if ( $bOutputHTML && ! $this -> debug ) $this -> debug = 2 ;
foreach ( $aTables as $sTableName => $aTableDef )
{
if ( $this -> CreateTable ( $sTableName , $aTableDef ))
{
if ( $bOutputHTML )
{
echo '<br>Create Table <b>' . $sTableName . '</b>' ;
}
}
else
{
if ( $bOutputHTML )
{
echo '<br>Create Table Failed For <b>' . $sTableName . '</b>' ;
}
return False ;
}
}
return True ;
}
/**
* 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
*/
function f ( $value , $strip_slashes = False )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
return $this -> m_odb -> f ( $value , $strip_slashes );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Number of rows in current result set
*
* @ return int number of rows
*/
2002-03-03 22:48:34 +01:00
function num_rows ()
{
return $this -> m_odb -> num_rows ();
}
2004-08-13 21:01:03 +02:00
/**
* Move to the next row in the results set
*
* @ return bool was another row found ?
*/
2002-03-03 22:48:34 +01:00
function next_record ()
{
return $this -> m_odb -> next_record ();
}
2004-08-13 21:01:03 +02:00
/**
* Execute a query
*
* @ param string $Query_String the query to be executed
* @ param mixed $line the line method was called from - use __LINE__
* @ param string $file the file method was called from - use __FILE__
* @ param int $offset row to start from
2005-06-20 13:04:20 +02:00
* @ param int $num_rows number of rows to return ( optional ), if unset will use $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'maxmatchs' ]
2004-08-13 21:01:03 +02:00
* @ return ADORecordSet or false , if the query fails
*/
2002-03-03 22:48:34 +01:00
function query ( $sQuery , $line = '' , $file = '' )
{
return $this -> m_odb -> query ( $sQuery , $line , $file );
}
2004-08-13 21:01:03 +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
*
* @ 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
* if the row exists db :: update is called else a new row with $date merged with $where gets inserted ( data has precedence )
* @ param int $line line - number to pass to query
* @ param string $file file - name to pass to query
2005-11-04 19:35:09 +01:00
* @ param string $app = false string with name of app , this need to be set in setup anyway !!!
2004-08-13 21:01:03 +02:00
* @ return ADORecordSet or false , if the query fails
*/
2005-11-04 19:35:09 +01:00
function insert ( $table , $data , $where , $line , $file , $app = False , $use_prepared_statement = false )
2002-03-03 22:48:34 +01:00
{
2005-11-04 19:35:09 +01:00
return $this -> m_odb -> insert ( $table , $data , $where , $line , $file , $app , $use_prepared_statement );
2004-08-13 21:01:03 +02:00
}
/**
* Execute the Sql statements in an array and give diagnostics , if any error occures
*
* @ param $aSql array of SQL strings to execute
* @ param $debug_level int for which debug_level ( and higher ) should the diagnostics always been printed
* @ param $debug string variable number of arguments for the debug_message functions in case of an error
* @ return int 2 : no error , 1 : errors , but continued , 0 : errors aborted
*/
function ExecuteSqlArray ( $aSql , $debug_level , $debug )
{
$retval = $this -> dict -> ExecuteSQLArray ( $aSql );
if ( $retval < 2 || $this -> debug >= $debug_level || $this -> debug > 3 )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$debug_params = func_get_args ();
array_shift ( $debug_params );
array_shift ( $debug_params );
call_user_method_array ( 'debug_message' , $this , $debug_params );
if ( $retval < 2 && ! $this -> dict -> debug )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
echo '<p><b>' . $this -> adodb -> ErrorMsg () . " </b></p> \n " ;
2002-03-03 22:48:34 +01:00
}
}
2004-08-13 21:01:03 +02:00
return $retval ;
}
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
/**
* Created a ( unique ) name for an index
*
* As the length of the index name is limited on some databases , we use two algorithms :
* a ) we use just the first column - name with and added _2 , _3 , ... if more indexes uses that column
* b ) we use the table - names plus all column - names and remove dublicate parts
*
* @ internal
* @ param $sTableName string name of the table
* @ param $aColumnNames array of column - names or string with a single column - name
* @ return string the index - name
*/
function _index_name ( $sTableName , $aColumnNames )
{
// this code creates extrem short index-names, eg. for MaxDB
if ( isset ( $this -> max_index_length [ $this -> sType ]) && $this -> max_index_length [ $this -> sType ] <= 32 )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
static $existing_indexes = array ();
if ( ! isset ( $existing_indexes [ $sTableName ]) && method_exists ( $this -> adodb , 'MetaIndexes' ))
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$existing_indexes [ $sTableName ] = $this -> adodb -> MetaIndexes ( $sTableName );
}
$i = 0 ;
$firstCol = is_array ( $aColumnNames ) ? $aColumnNames [ 0 ] : $aColumnNames ;
do
2003-10-21 20:09:58 +02:00
{
2004-08-13 21:01:03 +02:00
++ $i ;
$name = $firstCol . ( $i > 1 ? '_' . $i : '' );
2003-10-21 20:09:58 +02:00
}
2004-08-13 21:01:03 +02:00
while ( isset ( $existing_indexes [ $sTableName ][ $name ]) || isset ( $existing_indexes [ strtoupper ( $sTableName )][ strtoupper ( $name )]));
$existing_indexes [ $sTableName ][ $name ] = True ; // mark it as existing now
return $name ;
}
// This code creates longer index-names incl. the table-names and the used columns
$table = str_replace ( array ( 'phpgw_' , 'egw_' ), '' , $sTableName );
// if the table-name or a part of it is repeated in the column-name, remove it there
$remove [] = $table . '_' ;
// also remove 3 or 4 letter shortcuts of the table- or app-name
$remove [] = substr ( $table , 0 , 3 ) . '_' ;
$remove [] = substr ( $table , 0 , 4 ) . '_' ;
// if the table-name consists of '_' limtied parts, remove occurences of these parts too
foreach ( explode ( '_' , $table ) as $part )
{
$remove [] = $part . '_' ;
}
$aColumnNames = str_replace ( $remove , '' , $aColumnNames );
$name = $sTableName . '_' . ( is_array ( $aColumnNames ) ? implode ( '_' , $aColumnNames ) : $aColumnNames );
return $name ;
}
/**
* Giving a non - fatal error - message
*/
function error ( $str )
{
echo " <p><b>Error:</b> $str </p> " ;
}
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
/**
* Giving a fatal error - message and exiting
*/
function fatal ( $str )
{
echo " <p><b>Fatal Error:</b> $str </p> " ;
exit ;
}
/**
* Gives out a debug - message with certain parameters
*
* All permanent debug - messages in the calendar should be done by this function !!!
* ( In future they may be logged or sent as xmlrpc - faults back . )
*
* Permanent debug - message need to make sure NOT to give secret information like passwords !!!
*
* This function do NOT honor the setting of the debug variable , you may use it like
* if ( $this -> debug > N ) $this -> debug_message ( 'Error ;-)' );
*
* The parameters get formated depending on their type .
*
* @ param $msg string message with parameters / variables like lang (), eg . '%1'
* @ param $backtrace include a function - backtrace , default True = On
* should only be set to False = Off , if your code ensures a call with backtrace = On was made before !!!
* @ param $param mixed a variable number of parameters , to be inserted in $msg
* arrays get serialized with print_r () !
*/
function debug_message ( $msg , $backtrace = True )
{
for ( $i = 2 ; $i < func_num_args (); ++ $i )
2003-10-21 20:09:58 +02:00
{
2004-08-13 21:01:03 +02:00
$param = func_get_arg ( $i );
if ( is_null ( $param ))
2003-12-17 14:58:02 +01:00
{
2004-08-13 21:01:03 +02:00
$param = 'NULL' ;
2003-12-17 14:58:02 +01:00
}
else
{
2004-08-13 21:01:03 +02:00
switch ( gettype ( $param ))
{
case 'string' :
$param = " ' $param ' " ;
break ;
case 'array' :
case 'object' :
list (, $content ) = @ each ( $param );
$do_pre = is_array ( $param ) ? count ( $param ) > 6 || is_array ( $content ) && count ( $content ) : True ;
$param = ( $do_pre ? '<pre>' : '' ) . print_r ( $param , True ) . ( $do_pre ? '</pre>' : '' );
break ;
case 'boolean' :
$param = $param ? 'True' : 'False' ;
break ;
}
2003-12-17 14:58:02 +01:00
}
2004-08-13 21:01:03 +02:00
$msg = str_replace ( '%' . ( $i - 1 ), $param , $msg );
2003-10-21 20:09:58 +02:00
}
2004-08-13 21:01:03 +02:00
echo '<p>' . $msg . " <br> \n " . ( $backtrace ? 'Backtrace: ' . function_backtrace ( 1 ) . " </p> \n " : '' );
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
/**
* Converts an eGW table - definition array into an ADOdb column - definition string
*
* @ internal
* @ param array $aTableDef eGW table - defintion
* @ return string ADOdb column - definition string ( comma separated )
*/
function _egw2adodb_columndef ( $aTableDef )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$ado_defs = array ();
foreach ( $aTableDef [ 'fd' ] as $col => $col_data )
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$ado_col = False ;
2002-03-03 22:48:34 +01:00
2004-08-13 21:01:03 +02:00
switch ( $col_data [ 'type' ])
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
case 'auto' :
$ado_col = 'I AUTOINCREMENT NOTNULL' ;
unset ( $col_data [ 'nullable' ]); // else we set it twice
2002-03-03 22:48:34 +01:00
break ;
2004-08-13 21:01:03 +02:00
case 'blob' :
$ado_col = 'B' ;
2002-03-03 22:48:34 +01:00
break ;
2004-08-13 21:01:03 +02:00
case 'bool' :
$ado_col = 'L' ;
2002-03-03 22:48:34 +01:00
break ;
2004-08-13 21:01:03 +02:00
case 'char' :
// ADOdb does not differ between char and varchar
2004-10-14 22:55:52 +02:00
case 'varchar' :
$ado_col = " C " ;
if ( 0 < $col_data [ 'precision' ] && $col_data [ 'precision' ] <= $this -> max_varchar_length )
2004-08-13 21:01:03 +02:00
{
2004-10-14 22:55:52 +02:00
$ado_col .= " ( $col_data[precision] ) " ;
2004-08-13 21:01:03 +02:00
}
2004-10-14 22:55:52 +02:00
if ( $col_data [ 'precision' ] > $this -> max_varchar_length )
2004-08-13 21:01:03 +02:00
{
$ado_col = 'X' ;
}
2002-03-03 22:48:34 +01:00
break ;
2004-08-13 21:01:03 +02:00
case 'date' :
$ado_col = 'D' ;
if ( $col_data [ 'default' ] == 'current_date' )
{
$ado_col .= ' DEFDATE' ;
unset ( $col_data [ 'default' ]);
}
break ;
case 'decimal' :
$ado_col = " N( $col_data[precision] . $col_data[scale] ) " ;
break ;
2004-08-15 17:43:52 +02:00
case 'double' :
2004-08-13 21:01:03 +02:00
case 'float' :
// ADOdb does not differ between float and double
$ado_col = 'F' ;
break ;
case 'int' :
$ado_col = 'I' ;
switch ( $col_data [ 'precision' ])
{
case 1 :
case 2 :
case 4 :
case 8 :
$ado_col .= $col_data [ 'precision' ];
break ;
}
break ;
case 'longtext' :
$ado_col = 'XL' ;
break ;
case 'text' :
$ado_col = 'X' ;
break ;
case 'timestamp' :
$ado_col = 'T' ;
if ( $col_data [ 'default' ] == 'current_timestamp' )
{
$ado_col .= ' DEFTIMESTAMP' ;
unset ( $col_data [ 'default' ]);
}
2003-09-25 03:32:08 +02:00
break ;
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
if ( ! $ado_col )
2002-03-03 22:48:34 +01:00
{
2004-10-23 17:00:44 +02:00
$this -> error ( " Ignoring unknown column-type ' $col_data[type] ( $col_data[precision] )' !!!<br> " . function_backtrace ());
2004-08-13 21:01:03 +02:00
continue ;
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
if ( isset ( $col_data [ 'nullable' ]) && ! $col_data [ 'nullable' ])
2002-03-03 22:48:34 +01:00
{
2004-08-13 21:01:03 +02:00
$ado_col .= ' NOTNULL' ;
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
if ( isset ( $col_data [ 'default' ]))
2002-03-03 22:48:34 +01:00
{
2005-11-29 08:52:18 +01:00
$ado_col .= ( in_array ( $col_data [ 'type' ], array ( 'bool' , 'int' , 'decimal' , 'float' , 'double' )) && $col_data [ 'default' ] != 'NULL' ? ' NOQUOTE' : '' ) .
' DEFAULT ' . $this -> m_odb -> quote ( $col_data [ 'default' ], $col_data [ 'type' ]);
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
if ( in_array ( $col , $aTableDef [ 'pk' ]))
{
$ado_col .= ' PRIMARY' ;
}
$ado_defs [] = $col . ' ' . $ado_col ;
2002-03-03 22:48:34 +01:00
}
2004-08-13 21:01:03 +02:00
//print_r($aTableDef); echo implode(",\n",$ado_defs)."\n";
return implode ( " , \n " , $ado_defs );
}
2004-10-23 17:00:44 +02:00
/**
* Translates an eGW type into the DB ' s native type
*
* @ param string $egw_type eGW name of type
* @ param string / boolean DB ' s name of the type or false if the type could not be identified ( should not happen )
*/
function TranslateType ( $egw_type )
{
$ado_col = $this -> _egw2adodb_columndef ( array (
'fd' => array ( 'test' => array ( 'type' => $egw_type )),
'pk' => array (),
));
return preg_match ( '/test ([A-Z0-9]+)/i' , $ado_col , $matches ) ? $this -> dict -> ActualType ( $matches [ 1 ]) : false ;
}
2004-08-13 21:01:03 +02:00
/**
2004-08-15 17:43:52 +02:00
* Read the table - definition direct from the database
*
* The definition might not be as accurate , depending on the DB !
*
* @ param string $sTableName table - name
* @ return array / boolean table - defition , like $phpgw_baseline [ $sTableName ] after including tables_current , or false on error
*/
function GetTableDefinition ( $sTableName )
{
2004-10-14 22:55:52 +02:00
// MetaType returns all varchar >= blobSize as blob, it's by default 100, which is wrong
if ( $this -> dict -> blobSize < 255 ) $this -> dict -> blobSize = 255 ;
2004-08-15 17:43:52 +02:00
if ( ! method_exists ( $this -> dict , 'MetaColumns' ) ||
! ( $columns = $this -> dict -> MetaColumns ( $sTableName )))
{
return False ;
}
$definition = array (
'fd' => array (),
'pk' => array (),
'fk' => array (),
'ix' => array (),
'uc' => array (),
);
2004-10-14 22:55:52 +02:00
//echo "$sTableName: <pre>".print_r($columns,true)."</pre>";
2004-08-15 17:43:52 +02:00
foreach ( $columns as $column )
{
2005-11-20 16:40:28 +01:00
$name = $this -> capabilities [ 'name_case' ] == 'upper' ? strtolower ( $column -> name ) : $column -> name ;
2004-08-15 17:43:52 +02:00
$type = method_exists ( $this -> dict , 'MetaType' ) ? $this -> dict -> MetaType ( $column ) : strtoupper ( $column -> type );
static $ado_type2egw = array (
'C' => 'varchar' ,
'C2' => 'varchar' ,
'X' => 'text' ,
'X2' => 'text' ,
'XL' => 'longtext' ,
'B' => 'blob' ,
'I' => 'int' ,
'T' => 'timestamp' ,
'D' => 'date' ,
'F' => 'float' ,
'N' => 'decimal' ,
2004-10-14 22:55:52 +02:00
'R' => 'auto' ,
2006-01-06 17:21:51 +01:00
'L' => 'bool' ,
2004-08-15 17:43:52 +02:00
);
$definition [ 'fd' ][ $name ][ 'type' ] = $ado_type2egw [ $type ];
switch ( $type )
{
2004-10-14 22:55:52 +02:00
case 'D' : case 'T' :
// detecting the automatic timestamps again
if ( $column -> has_default && preg_match ( '/(0000-00-00|timestamp)/i' , $column -> default_value ))
{
$column -> default_value = $type == 'D' ? 'current_date' : 'current_timestamp' ;
}
break ;
2004-08-15 17:43:52 +02:00
case 'C' : case 'C2' :
2004-10-14 22:55:52 +02:00
$definition [ 'fd' ][ $name ][ 'type' ] = 'varchar' ;
2004-08-15 17:43:52 +02:00
$definition [ 'fd' ][ $name ][ 'precision' ] = $column -> max_length ;
break ;
2004-10-14 22:55:52 +02:00
case 'B' :
case 'X' : case 'XL' : case 'X2' :
// text or blob's need to be nullable for most databases
$column -> not_null = false ;
break ;
2004-08-15 17:43:52 +02:00
case 'F' :
$definition [ 'fd' ][ $name ][ 'precision' ] = $column -> max_length ;
break ;
case 'N' :
$definition [ 'fd' ][ $name ][ 'precision' ] = $column -> max_length ;
$definition [ 'fd' ][ $name ][ 'scale' ] = $column -> scale ;
break ;
2004-10-14 22:55:52 +02:00
case 'R' :
$column -> auto_increment = true ;
// fall-through
2004-08-15 17:43:52 +02:00
case 'I' : case 'I1' : case 'I2' : case 'I4' : case 'I8' :
switch ( $type )
{
case 'I1' : case 'I2' : case 'I4' : case 'I8' :
$definition [ 'fd' ][ $name ][ 'precision' ] = ( int ) $type [ 1 ];
break ;
default :
if ( $column -> max_length > 11 )
{
$definition [ 'fd' ][ $name ][ 'precision' ] = 8 ;
}
elseif ( $column -> max_length > 6 || ! $column -> max_length )
{
$definition [ 'fd' ][ $name ][ 'precision' ] = 4 ;
}
elseif ( $column -> max_length > 2 )
{
$definition [ 'fd' ][ $name ][ 'precision' ] = 2 ;
}
else
{
$definition [ 'fd' ][ $name ][ 'precision' ] = 1 ;
}
break ;
}
2004-10-14 22:55:52 +02:00
if ( $column -> auto_increment )
{
// no precision for auto!
$definition [ 'fd' ][ $name ] = array (
'type' => 'auto' ,
'nullable' => False ,
);
$column -> has_default = False ;
$definition [ 'pk' ][] = $name ;
}
else
2004-08-15 17:43:52 +02:00
{
2004-10-14 22:55:52 +02:00
$definition [ 'fd' ][ $name ][ 'type' ] = 'int' ;
2005-02-10 16:15:29 +01:00
// detect postgres type-spec and remove it
if ( $this -> sType == 'pgsql' && $column -> has_default && preg_match ( '/\(([^)])\)::/' , $column -> default_value , $matches ))
{
$definition [ 'fd' ][ $name ][ 'default' ] = $matches [ 1 ];
$column -> has_default = False ;
}
2004-08-15 17:43:52 +02:00
}
break ;
}
if ( $column -> has_default )
{
$definition [ 'fd' ][ $name ][ 'default' ] = $column -> default_value ;
}
if ( $column -> not_null )
{
$definition [ 'fd' ][ $name ][ 'nullable' ] = False ;
}
if ( $column -> primary_key && ! in_array ( $name , $definition [ 'pk' ]))
{
$definition [ 'pk' ][] = $name ;
}
}
2004-08-15 18:20:39 +02:00
if ( $this -> debug > 2 ) $this -> debug_message ( " schema_proc::GetTableDefintion: MetaColumns(%1) = %2 " , False , $sTableName , $columns );
// not all DB's (odbc) return the primary keys via MetaColumns
if ( ! count ( $definition [ 'pk' ]) && method_exists ( $this -> dict , 'MetaPrimaryKeys' ) &&
2004-10-14 22:55:52 +02:00
is_array ( $primary = $this -> dict -> MetaPrimaryKeys ( $sTableName )) && count ( $primary ))
2004-08-15 18:20:39 +02:00
{
2005-11-20 16:40:28 +01:00
if ( $this -> capabilities [ 'name_case' ] == 'upper' )
2004-10-14 22:55:52 +02:00
{
2005-11-20 16:40:28 +01:00
array_walk ( $primary , create_function ( '&$s' , '$s = strtolower($s);' ));
2004-10-14 22:55:52 +02:00
}
2004-08-15 18:20:39 +02:00
$definition [ 'pk' ] = $primary ;
}
if ( $this -> debug > 1 ) $this -> debug_message ( " schema_proc::GetTableDefintion: MetaPrimaryKeys(%1) = %2 " , False , $sTableName , $primary );
2004-08-15 17:43:52 +02:00
if ( method_exists ( $this -> dict , 'MetaIndexes' ) &&
2004-10-14 22:55:52 +02:00
is_array ( $indexes = $this -> dict -> MetaIndexes ( $sTableName )) && count ( $indexes ))
2004-08-15 17:43:52 +02:00
{
foreach ( $indexes as $index )
{
2005-11-20 16:40:28 +01:00
if ( $this -> capabilities [ 'name_case' ] == 'upper' )
2004-10-14 22:55:52 +02:00
{
2005-11-20 16:40:28 +01:00
array_walk ( $index [ 'columns' ], create_function ( '&$s' , '$s = strtolower($s);' ));
2004-10-14 22:55:52 +02:00
}
2004-08-15 17:43:52 +02:00
if ( count ( $definition [ 'pk' ]) && ( implode ( ':' , $definition [ 'pk' ]) == implode ( ':' , $index [ 'columns' ]) ||
$index [ 'unique' ] && count ( array_intersect ( $definition [ 'pk' ], $index [ 'columns' ])) == count ( $definition [ 'pk' ])))
{
continue ; // is already the primary key => ignore it
}
$kind = $index [ 'unique' ] ? 'uc' : 'ix' ;
$definition [ $kind ][] = count ( $index [ 'columns' ]) > 1 ? $index [ 'columns' ] : $index [ 'columns' ][ 0 ];
}
}
2004-08-15 18:20:39 +02:00
if ( $this -> debug > 2 ) $this -> debug_message ( " schema_proc::GetTableDefintion: MetaIndexes(%1) = %2 " , False , $sTableName , $indexes );
if ( $this -> debug > 1 ) $this -> debug_message ( " schema_proc::GetTableDefintion(%1) = %2 " , False , $sTableName , $definition );
2004-08-15 17:43:52 +02:00
return $definition ;
}
/**
2004-10-23 17:00:44 +02:00
* Get actual columnnames as a comma - separated string in $sColumns and set indices as class - vars pk , fk , ix , uc
2004-08-15 17:43:52 +02:00
*
* old translator function , use GetTableDefition () instead
2004-08-13 21:01:03 +02:00
* @ depricated
*/
function _GetColumns ( $oProc , $sTableName , & $sColumns )
{
2004-08-15 17:43:52 +02:00
$this -> sCol = $this -> pk = $this -> fk = $this -> ix = $this -> uc = array ();
$tabledef = $this -> GetTableDefinition ( $sTableName );
$sColumns = implode ( ',' , array_keys ( $tabledef [ 'fd' ]));
foreach ( $tabledef [ 'fd' ] as $column => $data )
{
$col_def = " 'type' => ' $data[type] ' " ;
unset ( $data [ 'type' ]);
foreach ( $data as $key => $val )
{
$col_def .= " , ' $key ' => " . ( is_bool ( $val ) ? ( $val ? 'true' : 'false' ) :
( is_int ( $val ) ? $val : " ' $val ' " ));
}
$this -> sCol [] = " \t \t \t \t ' $column ' => array( $col_def ), \n " ;
}
foreach ( array ( 'pk' , 'fk' , 'ix' , 'uc' ) as $kind )
{
$this -> $kind = $tabledef [ $kind ];
}
2002-03-03 22:48:34 +01:00
}
}
?>