diff -bruaN phpgroupware-0.9.14rc2/setup/inc/class.schema_proc.inc.php phpgroupware/setup/inc/class.schema_proc.inc.php --- phpgroupware-0.9.14rc2/setup/inc/class.schema_proc.inc.php Wed Sep 12 15:44:35 2001 +++ phpgroupware/setup/inc/class.schema_proc.inc.php Thu Mar 28 14:57:29 2002 @@ -73,7 +73,7 @@ return true; } - function ExecuteScripts($aTables, $bOutputHTML = false) + function ExecuteScripts($aTables, $bOutputHTML = False) { if (!is_array($aTables) || !IsSet($this->m_odb)) { @@ -382,6 +382,10 @@ if ($bNullable == false) { $sFieldSQL .= ' NOT NULL'; + } + else + { + $sFieldSQL .= ' NULL'; } if ($sDefault != '') diff -bruaN phpgroupware-0.9.14rc2/setup/inc/class.schema_proc_sybase.inc.php phpgroupware/setup/inc/class.schema_proc_sybase.inc.php --- phpgroupware-0.9.14rc2/setup/inc/class.schema_proc_sybase.inc.php Thu Jan 1 01:00:00 1970 +++ phpgroupware/setup/inc/class.schema_proc_sybase.inc.php Wed Apr 3 11:07:55 2002 @@ -0,0 +1,347 @@ +<?php + /**************************************************************************\ + * phpGroupWare - Setup * + * http://www.phpgroupware.org * + * -------------------------------------------- * + * mixed db_mysql and db_mssql to have sybase support more up to date by * + * Yves Mettier <ymettier@libertysurf.fr> * + * -------------------------------------------- * + * 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: class.schema_proc_sybase.inc.php,v 1.6 2002/01/11 03:40:59 milosch Exp $ */ + + class schema_proc_sybase + { + var $m_sStatementTerminator; + /* Following added to convert sql to array */ + var $sCol = array(); + var $pk = array(); + var $fk = array(); + var $ix = array(); + var $uc = array(); + + function schema_proc_sybase() + { + $this->m_sStatementTerminator = ''; + } + + /* Return a type suitable for DDL */ + function TranslateType($sType, $iPrecision = 0, $iScale = 0, &$sTranslated) + { + $sTranslated = ''; + switch($sType) + { + case 'auto': + $sTranslated = 'numeric(11) identity'; + break; + case 'blob': + $sTranslated = 'image'; /* wonder how well PHP will support this??? */ + break; + case 'char': + if ($iPrecision > 0 && $iPrecision < 256) + { + $sTranslated = sprintf("char(0)", $iPrecision); + } + if ($iPrecision > 255) + { + $sTranslated = 'text'; + } + break; + case 'date': + $sTranslated = 'smalldatetime'; + break; + case 'decimal': + $sTranslated = sprintf("decimal(0,0)", $iPrecision, $iScale); + break; + case 'float': + switch ($iPrecision) + { + case 4: + $sTranslated = 'float'; + break; + case 8: + $sTranslated = 'real'; + break; + } + break; + case 'int': + switch ($iPrecision) + { + case 2: + $sTranslated = 'smallint'; + break; + case 4: + case 8: + $sTranslated = 'int'; + break; + } + break; + case 'longtext': + case 'text': + $sTranslated = 'text'; + break; + case 'timestamp': + $sTranslated = 'datetime'; + break; + case 'varchar': + if ($iPrecision > 0 && $iPrecision < 256) + { + $sTranslated = sprintf("varchar(0)", $iPrecision); + } + if ($iPrecision > 255) + { + $sTranslated = 'text'; + } + break; + } + + return (strlen($sTranslated) > 0); + } + + function TranslateDefault($sDefault) + { + switch ($sDefault) + { + case 'current_date': + case 'current_timestamp': + return 'now'; + } + + return $sDefault; + } + + /* Inverse of above, convert sql column types to array info */ + function rTranslateType($sType, $iPrecision = 0, $iScale = 0, &$sTranslated) + { + $sTranslated = ''; + if ($sType == 'int' || $sType == 'tinyint' || $sType == 'smallint') + { + if ($iPrecision > 8) + { + $iPrecision = 8; + } + elseif($iPrecision > 4) + { + $iPrecision = 4; + } + else + { + $iPrecision = 2; + } + } + switch($sType) + { + case 'tinyint': + case 'smallint': + $sTranslated = "'type' => 'int', 'precision' => 2"; + break; + case 'int': + $sTranslated = "'type' => 'int', 'precision' => 4"; + break; + case 'char': + if ($iPrecision > 0 && $iPrecision < 256) + { + $sTranslated = "'type' => 'char', 'precision' => $iPrecision"; + } + if ($iPrecision > 255) + { + $sTranslated = "'type' => 'text'"; + } + break; + case 'decimal': + $sTranslated = "'type' => 'decimal', 'precision' => $iPrecision, 'scale' => $iScale"; + break; + case 'float': + case 'double': + $sTranslated = "'type' => 'float', 'precision' => $iPrecision"; + break; + case 'smalldatetime': + $sTranslated = "'type' => 'date'"; + break; + case 'datetime': + $sTranslated = "'type' => 'timestamp'"; + break; + case 'varchar': + if ($iPrecision > 0 && $iPrecision < 256) + { + $sTranslated = "'type' => 'varchar', 'precision' => $iPrecision"; + } + if ($iPrecision > 255) + { + $sTranslated = "'type' => 'text'"; + } + break; + case 'image': + $sTranslated = "'type' => 'blob'"; + break; + case 'text': + $sTranslated = "'type' => '$sType'"; + break; + } + + return (strlen($sTranslated) > 0); + } + + function GetPKSQL($sFields) + { + return "PRIMARY KEY($sFields)"; + } + + function GetUCSQL($sFields) + { + return "UNIQUE($sFields)"; + } + + function _GetColumns($oProc, $sTableName, &$sColumns, $sDropColumn = '') + { + $sColumns = ''; + $this->pk = array(); + $this->fk = array(); + $this->ix = array(); + $this->uc = array(); + + // Field, Type, Null, Key, Default, Extra + $oProc->m_odb->query("exec sp_columns '$sTableName'"); + while ($oProc->m_odb->next_record()) + { + $type = $default = $null = $nullcomma = $prec = $scale = $ret = $colinfo = $scales = ''; + if ($sColumns != '') + { + $sColumns .= ','; + } + $sColumns .= $oProc->m_odb->f(0); + + // The rest of this is used only for SQL->array + $colinfo = explode('(',$oProc->m_odb->f(1)); + $prec = ereg_replace(')','',$colinfo[1]); + $scales = explode(',',$prec); + if ($scales[1]) + { + $prec = $scales[0]; + $scale = $scales[1]; + } + $this->rTranslateType($colinfo[0], $prec, $scale, &$type); + + if ($oProc->m_odb->f(2) == 'YES') + { + $null = "'nullable' => True"; + } + else + { + $null = "'nullable' => False"; + } + if ($oProc->m_odb->f(4)) + { + $default = "'default' => '".$oProc->m_odb->f(4)."'"; + $nullcomma = ','; + } + else + { + $default = ''; + $nullcomma = ''; + } + if ($oProc->m_odb->f(5)) + { + $type = "'type' => 'auto'"; + } + $this->sCol[] = "\t\t\t\t'" . $oProc->m_odb->f(0)."' => array(" . $type . ',' . $null . $nullcomma . $default . '),' . "\n"; + if ($oProc->m_odb->f(3) == 'PRI') + { + $this->pk[] = $oProc->m_odb->f(0); + } + if ($oProc->m_odb->f(3) == 'UNI') + { + $this->uc[] = $oProc->m_odb->f(0); + } + /* Hmmm, MUL could also mean unique, or not... */ + if ($oProc->m_odb->f(3) == 'MUL') + { + $this->ix[] = $oProc->m_odb->f(0); + } + } + /* ugly as heck, but is here to chop the trailing comma on the last element (for php3) */ + $this->sCol[count($this->sCol) - 1] = substr($this->sCol[count($this->sCol) - 1],0,-2) . "\n"; + + return false; + } + + function DropTable($oProc, &$aTables, $sTableName) + { + return !!($oProc->m_odb->query("DROP TABLE " . $sTableName)); + } + + function DropColumn($oProc, &$aTables, $sTableName, $aNewTableDef, $sColumnName, $bCopyData = true) + { + return !!($oProc->m_odb->query("ALTER TABLE $sTableName DROP COLUMN $sColumnName")); + } + + function RenameTable($oProc, &$aTables, $sOldTableName, $sNewTableName) + { + return !!($oProc->m_odb->query("EXEC sp_rename '$sOldTableName', '$sNewTableName'")); + } + + function RenameColumn($oProc, &$aTables, $sTableName, $sOldColumnName, $sNewColumnName, $bCopyData = true) + { + // This really needs testing - it can affect primary keys, and other table-related objects + // like sequences and such + global $DEBUG; + if ($DEBUG) { echo '<br>RenameColumn: calling _GetFieldSQL for ' . $sNewColumnName; } + if ($oProc->_GetFieldSQL($aTables[$sTableName]["fd"][$sNewColumnName], $sNewColumnSQL)) + { + return !!($oProc->m_odb->query("EXEC sp_rename '$sTableName.$sOldColumnName', '$sNewColumnName'")); + } + return false; + } + + function AlterColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef, $bCopyData = true) + { + global $DEBUG; + if ($DEBUG) { echo '<br>AlterColumn: calling _GetFieldSQL for ' . $sNewColumnName; } + if ($oProc->_GetFieldSQL($aTables[$sTableName]["fd"][$sColumnName], $sNewColumnSQL)) + { + return !!($oProc->m_odb->query("ALTER TABLE $sTableName ALTER COLUMN $sColumnName " . $sNewColumnSQL)); + } + + return false; + } + + function AddColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef) + { + $oProc->_GetFieldSQL($aColumnDef, $sFieldSQL); + $query = "ALTER TABLE $sTableName ADD $sColumnName $sFieldSQL"; + + return !!($oProc->m_odb->query($query)); + } + + function GetSequenceSQL($sTableName, &$sSequenceSQL) + { + $sSequenceSQL = ''; + return true; + } + + function CreateTable($oProc, &$aTables, $sTableName, $aTableDef) + { + if ($oProc->_GetTableSQL($sTableName, $aTableDef, $sTableSQL, $sSequenceSQL)) + { + /* create sequence first since it will be needed for default */ + if ($sSequenceSQL != '') + { + $oProc->m_odb->query($sSequenceSQL); + } + + $query = "CREATE TABLE $sTableName ($sTableSQL)"; + $query = preg_replace("/not +null +default +('[^,)]+')/im","DEFAULT \\1 NOT NULL",$query); + $query = preg_replace("'not +null +default +([^,)]+)'im","DEFAULT \\1 NOT NULL",$query); + $query = preg_replace("/null +default +('[^,)]+')/im","DEFAULT \\1 NULL",$query); + $query = preg_replace("'null +default +([^,)]+)'im","DEFAULT \\1 NULL",$query); + return !!($oProc->m_odb->query($query)); + } + + return false; + } + } +?> diff -bruaN phpgroupware-0.9.14rc2/phpgwapi/inc/class.db_sybase.inc.php phpgroupware/phpgwapi/inc/class.db_sybase.inc.php --- phpgroupware-0.9.14rc2/phpgwapi/inc/class.db_sybase.inc.php Sat Sep 29 02:25:58 2001 +++ phpgroupware/phpgwapi/inc/class.db_sybase.inc.php Wed Apr 3 11:08:01 2002 @@ -5,6 +5,8 @@ * Kristian Koehntopp * * Adapted from db_mysql.inc by Sascha Schumann <sascha@schumann.cx> * * metadata() contributed by Adelino Monteiro <adelino@infologia.pt> * + * mixed db_mysql and db_mssql to have sybase support more up to date by * + * Yves Mettier <ymettier@libertysurf.fr> * * ------------------------------------------------------------------------ * * This is not part of phpGroupWare, but is used by phpGroupWare. * * http://www.phpgroupware.org/ * @@ -27,26 +29,92 @@ var $Link_ID = 0; var $Query_ID = 0; var $Record = array(); - var $Row; + var $Row = 0; + var $VEOF = -1; + /* public: configuration parameters */ + var $auto_stripslashes = False; var $Auto_Free = 0; ## Set this to 1 for automatic sybase_free_result() + var $Debug = 0; ## Set to 1 for debugging messages. + var $Halt_On_Error = 'yes'; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning) + var $Seq_Table = 'db_sequence'; + var $Transaction = false; + + /* public: result array and current row number */ + var $Record = array(); + var $Row; + + /* public: current error number and error text */ + var $Errno = 0; + var $Error = ''; + + // For our error handling + var $xmlrpc = False; + var $soap = False; + + // For sybase types + var $sybase_types = array(); + + /* public: constructor */ + function db($query = '') + { + $this->query($query); + + if (ereg('xmlrpc.php',$GLOBALS['PHP_SELF'])) + { + $this->xmlrpc = True; + } + + if (ereg('soap.php',$GLOBALS['PHP_SELF'])) + { + $this->soap = True; + } + } + + /* public: some trivial reporting */ + function link_id() + { + return $this->Link_ID; + } + + function query_id() + { + return $this->Query_ID; + } - function connect() + function connect($Database = '', $Host = '', $User = '', $Password = '') { + /* Handle defaults */ + if ('' == $Database) + { + $Database = $this->Database; + } + if ('' == $Host) + { + $Host = $this->Host; + } + if ('' == $User) + { + $User = $this->User; + } + if ('' == $Password) + { + $Password = $this->Password; + } if ( 0 == $this->Link_ID ) { if ($GLOBALS['phpgw_info']['server']['db_persistent']) { - $this->Link_ID=sybase_pconnect($this->Host,$this->User,$this->Password); + $this->Link_ID=sybase_pconnect($Host, $User, $Password); } else { - $this->Link_ID=sybase_connect($this->Host,$this->User,$this->Password); + $this->Link_ID=sybase_connect($Host, $User, $Password); } } if (!$this->Link_ID) { - $this->halt('Link-ID == false, '.($GLOBALS['phpgw_info']['server']['db_persistent']?'p':'')..'connect failed'); + $this->halt('Link-ID == false, '.($GLOBALS['phpgw_info']['server']['db_persistent']?'p':'').'connect failed'); } if(!sybase_select_db($this->Database, $this->Link_ID)) { @@ -54,24 +122,206 @@ } } - function query($Query_String) + function query($Query_String, $line = '', $file = '') + { + /* No empty queries, please, since PHP4 chokes on them. */ + /* The empty query string is passed on from the constructor, + * when calling the class without a query, e.g. in situations + * like these: '$db = new db_Subclass;' + */ + if ($Query_String == '') + { + return 0; + } + $this->connect(); + + if(preg_match("/^(.*);[ \t]*$/m",$Query_String,$matches)) { + $Query_String = $matches[1]; + } + if(preg_match("/^[\t \n]*insert[\t \n]+into[\t \n]+([^\t \n]+)[\t \n]+\((.+)\)[\t \n]+values[\t \n]+\((.+)\)[\t\n ]*$/im",$Query_String,$matches)) + { + $tablename = $matches[1]; + $names = explode(",",$matches[2]); + + $values = explode(",",$matches[3]); + for($i=0; $i<strlen($matches[3]); $i++) + { + + } + + + $Query_String = "INSERT INTO $tablename ("; + + + reset($names); + while(list($k,$v) = each($names)) + { + $subquery = "select syscolumns.type from sysobjects,syscolumns "; + $subquery .= "where sysobjects.name='$tablename' "; + $subquery .= "and sysobjects.id=syscolumns.id "; + $v = preg_replace("/^[\t ]*([^\t ]+)[\t ]*$/","\\1",$v); + $subquery .= "and syscolumns.name = '$v' "; + $Query_ID = sybase_query($subquery,$this->Link_ID); + if (! $Query_ID) + { + $this->halt("Invalid SQL: ".$subquery, $line, $file); + } + $r = sybase_fetch_row($Query_ID); + $type = $r[0]; + sybase_free_result($Query_ID); + $this->disconnect(); + $this->connect(); + + if(!$this->sybase_types[$type]) { + $subquery = "select name from systypes "; + $subquery .= "where type = $type "; + $Query_ID = sybase_query($subquery,$this->Link_ID); + if (! $Query_ID) + { + $this->halt("Invalid SQL: ".$subquery, $line, $file); + } + $r = sybase_fetch_row($Query_ID); + $this->sybase_types[$type] = preg_replace("/^[\t ]*([^\t ]+)[\t ]*$/","\\1",$r[0]);; + sybase_free_result($Query_ID); + $this->disconnect(); $this->connect(); + } + if($this->sybase_types[$type] == "varchar") + { + $values[$k] = "CONVERT(varchar,".$values[$k].")"; + } else if($this->sybase_types[$type] == "nvarchar") + { + $values[$k] = "CONVERT(varchar,".$values[$k].")"; + } else if($this->sybase_types[$type] == "sysname") + { + $values[$k] = "CONVERT(varchar,".$values[$k].")"; + } else if($this->sybase_types[$type] == "int") + { + $values[$k] = preg_replace("/^[\t '\"]*([^\t '\"]+)[\t '\"]*$/","\\1",$values[$k]); + } else if($this->sybase_types[$type] == "intn") + { + $values[$k] = preg_replace("/^[\t '\"]*([^\t '\"]+)[\t '\"]*$/","\\1",$values[$k]); + } + $Query_String .= "$v, "; + } + $Query_String = substr($Query_String,0,strlen($Query_String)-2); + $Query_String .= ") VALUES ("; + + reset($values); + while(list(,$v) = each($values)) + { + $Query_String .= "$v, "; + } + $Query_String = substr($Query_String,0,strlen($Query_String)-2); + $Query_String .= ")"; + } - # printf("Debug: query = <br>\n", $Query_String); + + # New query, discard previous result. + if ($this->Query_ID) + { + $this->free(); + } + + if ($this->Debug) + { + printf("<pre>Debug: query = </pre>\n", $Query_String); + } $this->Query_ID = sybase_query($Query_String,$this->Link_ID); $this->Row = 0; - if (!$this->Query_ID) + if (! $this->Query_ID) { - $this->halt('Invalid SQL: '.$Query_String); + $this->halt("Invalid SQL: ".$Query_String, $line, $file); } + # Will return nada if it fails. That's fine. return $this->Query_ID; } + /* This only affects systems not using persistant connections */ + function disconnect() + { + if ($GLOBALS['phpgw_info']['server']['db_persistent']) + { + return(1); + } + else + { + return @sybase_close($this->Link_ID); + } + } + + function db_addslashes($str) + { + if (!isset($str) || $str == '') + { + return ''; + } + + return addslashes($str); + } + + function to_timestamp($epoch) + { + return date('Y-m-d H:i:s',$epoch); + } + + function from_timestamp($timestamp) + { + ereg('([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})',$timestamp,$parts); + + return mktime($parts[4],$parts[5],$parts[6],$parts[2],$parts[3],$parts[1]); + } + + // public: perform a query with limited result set + function limit_query($Query_String, $offset, $line = '', $file = '', $num_rows = '') + { + if (! $num_rows) + { + $num_rows = $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs']; + } + + if ($this->Debug) + { + printf("Debug: limit_query = <br>offset=0, num_rows=0<br>\n", $Query_String, $offset, $num_rows); + } + + $this->query($Query_String, $line, $file); + if ($this->Query_ID) + { + $this->Row = $offset; + // Push cursor to appropriate row in case next_record() is used + if ($offset > 0) + { + @sybase_data_seek($this->Query_ID, $offset); + } + $this->VEOF = $offset + $num_rows - 1; + } + + return $this->Query_ID; + } + + + // public: discard the query result + function free() + { + if($this->Query_ID) + { +# sybase_free_result($this->Query_ID); + } + $this->Query_ID = 0; + } + function next_record() { + if (!$this->Query_ID) + { +# $this->halt('next_record called with no query pending.'); + return 0; + } + $this->Record = sybase_fetch_array($this->Query_ID); $this->Row += 1; @@ -94,6 +344,47 @@ return; } + function transaction_begin() + { + $this->Transaction = !!sybase_query('BEGIN TRAN', $this->Link_ID); + return $this->Transaction; + } + + function transaction_commit() + { + if (!$this->Errno && $this->Transaction) + { + $this->Transaction = false; + return !!sybase_query('COMMIT TRAN', $this->Link_ID); + } + + return False; + } + + function transaction_abort() + { + if ($this->Transaction) + { + $this->Transaction = false; + return !!sybase_query('ROLLBACK TRAN', $this->Link_ID); + } + + return false; + } + + function lock($table, $mode = 'write') + { + $result = $this->transaction_begin(); + + return $result; + } + + function unlock() + { + return $this->transaction_commit(); + } + + function metadata($table) { $count = 0; @@ -129,8 +420,12 @@ function num_rows() { + if($this->Query_ID) + { return sybase_num_rows($this->Query_ID); } + return 0; + } function num_fields() { @@ -147,21 +442,94 @@ print $this->num_rows(); } - function f($Name) + function f($Name, $strip_slashes = "") + { + if ($strip_slashes || ($this->auto_stripslashes && ! $strip_slashes)) + { + return stripslashes($this->Record[$Name]); + } + else { return $this->Record[$Name]; } + } + function p($Name) { print $this->Record[$Name]; } + /* public: table locking */ + function get_last_insert_id($table, $field) + { + /* This will get the last insert ID created on the current connection. Should only be called + * after an insert query is run on a table that has an auto incrementing field. Of note, table + * and field are required for pgsql compatiblity. SYBASE uses a query to retrieve the last + * identity on the connection, so table and field are ignored here as well. + */ + if (!isset($table) || $table == '' || !isset($field) || $field == '') + { + return -1; + } + + $result = @sybase_query("select @@identity", $this->Link_ID); + if (!$result) + { + return -1; + } + return sybase_result($result, 0, 0); + } function halt($msg) { + $this->unlock(); /* Just in case there is a table currently locked */ + + $this->Error = @sybase_get_last_message(); + if ($this->Halt_On_Error == "no") + { + return; + } + $this->haltmsg($msg); + + if ($file) + { + printf("<br><b>File:</b> ",$file); + } + if ($line) + { + printf("<br><b>Line:</b> ",$line); + } + + if ($this->Halt_On_Error != "report") + { + echo "<p><b>Session halted.</b>"; + $GLOBALS['phpgw']->common->phpgw_exit(True); + } + } + + function haltmsg($msg) + { printf("<b>Database error:</b> <br>\n", $msg); - printf("<b>Sybase Error</b><br>\n"); - die("Session halted."); + if ($this->Errno != "0" && $this->Error != "()") + { + printf("<b>Sybase Error</b>: ()<br>\n",$this->Errno,$this->Error); + } } + + function table_names() + { + $this->query("SELECT name FROM sysobjects WHERE type != 'S'"); + if (!$this->Query_ID) return(NULL); + $i=0; + while ($this->next_record()) + { + $return[$i]['table_name']= $this->f(0); + $return[$i]['tablespace_name']=$this->Database; + $return[$i]['database']=$this->Database; + $i++; + } + return $return; + } + } ?> diff -bruaN phpgroupware-0.9.14rc2/setup/manageheader.php phpgroupware/setup/manageheader.php --- phpgroupware-0.9.14rc2/setup/manageheader.php Fri Feb 15 17:56:19 2002 +++ phpgroupware/setup/manageheader.php Thu Mar 28 14:57:29 2002 @@ -189,6 +189,15 @@ { echo 'No Microsoft SQL Server support found. Disabling<br>' . "\n"; } + if (extension_loaded('sybase') || function_exists('sybase_connect')) + { + echo 'You appear to have Sybase support enabled<br>' . "\n"; + $supported_db[] = 'sybase'; + } + else + { + echo 'No Sybase support found. Disabling<br>' . "\n"; + } if (extension_loaded('oci8')) { echo 'You appear to have Oracle V8 (OCI) support enabled<br>' . "\n";