Add php files
This commit is contained in:
1357
include/database/DBHelper.php
Executable file
1357
include/database/DBHelper.php
Executable file
File diff suppressed because it is too large
Load Diff
1915
include/database/DBManager.php
Executable file
1915
include/database/DBManager.php
Executable file
File diff suppressed because it is too large
Load Diff
147
include/database/DBManagerFactory.php
Executable file
147
include/database/DBManagerFactory.php
Executable file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file generates the appropriate manager for the database
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
|
||||
require_once('include/database/DBManager.php');
|
||||
|
||||
class DBManagerFactory
|
||||
{
|
||||
/**
|
||||
* Returns a reference to the DB object for instance $instanceName, or the default
|
||||
* instance if one is not specified
|
||||
*
|
||||
* @param string $instanceName optional, name of the instance
|
||||
* @return object DBManager instance
|
||||
*/
|
||||
public static function getInstance(
|
||||
$instanceName = ''
|
||||
)
|
||||
{
|
||||
global $sugar_config, $dbinstances;
|
||||
static $count, $old_count;
|
||||
|
||||
$instanceName = 'db';
|
||||
$config = $sugar_config['dbconfig'];
|
||||
if(!isset($dbinstances)){
|
||||
$dbinstances = array();
|
||||
}
|
||||
//fall back to the default instance name
|
||||
if(empty($sugar_config['db'][$instanceName])){
|
||||
$instanceName = '';
|
||||
}
|
||||
if(!isset($dbinstances[$instanceName])){
|
||||
$my_db_manager = 'MysqlManager';
|
||||
if( $config['db_type'] == "mysql" ) {
|
||||
if (function_exists('mysqli_connect')) {
|
||||
$my_db_manager = 'MysqliManager';
|
||||
}
|
||||
}
|
||||
if( $config['db_type'] == "oci8" ){
|
||||
}
|
||||
elseif( $config['db_type'] == "mssql" ){
|
||||
if ( function_exists('sqlsrv_connect')
|
||||
&& (empty($config['db_mssql_force_driver']) || $config['db_mssql_force_driver'] == 'sqlsrv' ))
|
||||
$my_db_manager = 'SqlsrvManager';
|
||||
elseif (is_freetds()
|
||||
&& (empty($config['db_mssql_force_driver']) || $config['db_mssql_force_driver'] == 'freetds' ))
|
||||
$my_db_manager = 'FreeTDSManager';
|
||||
else
|
||||
$my_db_manager = 'MssqlManager';
|
||||
}
|
||||
$GLOBALS['log']->info("using $my_db_manager DBManager backend");
|
||||
if(!empty($config['db_manager'])){
|
||||
$my_db_manager = $config['db_manager'];
|
||||
}
|
||||
|
||||
require_once("include/database/{$my_db_manager}.php");
|
||||
|
||||
$dbinstances[$instanceName] = new $my_db_manager();
|
||||
$dbinstances[$instanceName]->getHelper();
|
||||
$dbinstances[$instanceName]->connect($config, true);
|
||||
$dbinstances[$instanceName]->count_id = $count;
|
||||
$dbinstances[$instanceName]->references = 0;
|
||||
$dbinstances[$instanceName]->getHelper()->db = $dbinstances[$instanceName];
|
||||
}
|
||||
else {
|
||||
$old_count++;
|
||||
$dbinstances[$instanceName]->references = $old_count;
|
||||
}
|
||||
return $dbinstances[$instanceName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the helper class
|
||||
*
|
||||
* @deprecated
|
||||
* @return object DBHelper instance
|
||||
*/
|
||||
public static function getHelperInstance()
|
||||
{
|
||||
$GLOBALS['log']->info('call to DBManagerFactory::getHelperInstance() is deprecated');
|
||||
return self::getInstance()->getHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the DBManager and DBHelper instance class files
|
||||
*
|
||||
* @deprecated
|
||||
* @param string $class_name
|
||||
*/
|
||||
public static function load_db_manager_class(
|
||||
$class_name
|
||||
)
|
||||
{
|
||||
$GLOBALS['log']->info('call to DBManagerFactory::load_db_manager_class() is deprecated');
|
||||
if( is_file("include/database/{$class_name}.php") && !class_exists($class_name))
|
||||
require_once("include/database/{$class_name}.php");
|
||||
|
||||
$class_name = str_ireplace('Manager','Helper',$class_name);
|
||||
|
||||
if( is_file("include/database/{$class_name}.php") && !class_exists($class_name))
|
||||
require_once("include/database/{$class_name}.php");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
179
include/database/FreeTDSHelper.php
Executable file
179
include/database/FreeTDSHelper.php
Executable file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
include_once('include/database/MssqlHelper.php');
|
||||
|
||||
class FreeTDSHelper extends MssqlHelper
|
||||
{
|
||||
/**
|
||||
* @see DBHelper::massageValue()
|
||||
*/
|
||||
public function massageValue(
|
||||
$val,
|
||||
$fieldDef
|
||||
)
|
||||
{
|
||||
if (!$val)
|
||||
return "''";
|
||||
|
||||
$type = $this->getFieldType($fieldDef);
|
||||
|
||||
switch ($type) {
|
||||
case 'int':
|
||||
case 'double':
|
||||
case 'float':
|
||||
case 'uint':
|
||||
case 'ulong':
|
||||
case 'long':
|
||||
case 'short':
|
||||
case 'tinyint':
|
||||
return $val;
|
||||
break;
|
||||
}
|
||||
|
||||
$qval = $this->quote($val);
|
||||
|
||||
switch ($type) {
|
||||
case 'varchar':
|
||||
case 'nvarchar':
|
||||
case 'char':
|
||||
case 'nchar':
|
||||
case 'longtext':
|
||||
case 'text':
|
||||
case 'ntext':
|
||||
case 'enum':
|
||||
case 'multienum':
|
||||
case 'blob':
|
||||
case 'longblob':
|
||||
case 'clob':
|
||||
case 'id':
|
||||
return $qval;
|
||||
break;
|
||||
case 'date':
|
||||
return "$qval";
|
||||
break;
|
||||
case 'datetime':
|
||||
return $qval;
|
||||
break;
|
||||
case 'time':
|
||||
return "$qval";
|
||||
break;
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the valid type for a column given the type in fieldDef
|
||||
*
|
||||
* @param string $type field type
|
||||
* @param string $name field name
|
||||
* @param string $table table name
|
||||
* @return string valid type for the given field
|
||||
*/
|
||||
public function getColumnType(
|
||||
$type,
|
||||
$name='',
|
||||
$table=''
|
||||
)
|
||||
{
|
||||
$map = array(
|
||||
'int' => 'int',
|
||||
'double' => 'float',
|
||||
'float' => 'float',
|
||||
'uint' => 'int',
|
||||
'ulong' => 'int',
|
||||
'long' => 'bigint',
|
||||
'short' => 'smallint',
|
||||
'varchar' => 'nvarchar',
|
||||
'nvarchar' => 'nvarchar',
|
||||
'longtext' => 'ntext',
|
||||
'text' => 'ntext',
|
||||
'ntext' => 'ntext',
|
||||
'date' => 'datetime',
|
||||
'enum' => 'nvarchar',
|
||||
'multienum'=> 'ntext',
|
||||
'datetime' => 'datetime',
|
||||
'datetimecombo' => 'datetime',
|
||||
'time' => 'datetime',
|
||||
'bool' => 'bit',
|
||||
'tinyint' => 'tinyint',
|
||||
'char' => 'char',
|
||||
'nchar' => 'nchar',
|
||||
'blob' => 'ntext',
|
||||
'longblob' => 'ntext',
|
||||
'decimal' => 'decimal',
|
||||
'decimal2' => 'decimal',
|
||||
'currency' => 'decimal(26,6)',
|
||||
'id' => 'nvarchar(36)',
|
||||
'url'=>'nvarchar',
|
||||
'encrypt'=>'nvarchar',
|
||||
);
|
||||
|
||||
return $map[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::oneColumnSQLRep()
|
||||
*/
|
||||
protected function oneColumnSQLRep(
|
||||
$fieldDef,
|
||||
$ignoreRequired = false,
|
||||
$table = '',
|
||||
$return_as_array = false
|
||||
)
|
||||
{
|
||||
$ref = parent::oneColumnSQLRep($fieldDef,$ignoreRequired,$table,true);
|
||||
|
||||
|
||||
if ( $ref['colType'] == 'nvarchar'
|
||||
|| $ref['colType'] == 'nchar' ) {
|
||||
if( !empty($fieldDef['len']))
|
||||
$ref['colType'] .= "(".$fieldDef['len'].")";
|
||||
else
|
||||
$ref['colType'] .= "(255)";
|
||||
}
|
||||
|
||||
if ( $return_as_array )
|
||||
return $ref;
|
||||
else
|
||||
return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
166
include/database/FreeTDSManager.php
Executable file
166
include/database/FreeTDSManager.php
Executable file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
include_once('include/database/MssqlManager.php');
|
||||
|
||||
class FreeTDSManager extends MssqlManager
|
||||
{
|
||||
|
||||
public $isFreeTDS = true;
|
||||
|
||||
/**
|
||||
* @see DBManager::query()
|
||||
*/
|
||||
public function query(
|
||||
$sql,
|
||||
$dieOnError = false,
|
||||
$msg = '',
|
||||
$suppress = false
|
||||
)
|
||||
{
|
||||
$sql = $this->appendN($sql);
|
||||
parent::countQuery($sql);
|
||||
$GLOBALS['log']->info('Query:' . $sql);
|
||||
$this->checkConnection();
|
||||
$this->query_time = microtime(true);
|
||||
|
||||
if ($suppress) {
|
||||
}
|
||||
else {
|
||||
$result = @mssql_query($sql,$this->database);
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
|
||||
// awu Bug 10657: ignoring mssql error message 'Changed database context to' - an intermittent
|
||||
// and difficult to reproduce error. The message is only a warning, and does
|
||||
// not affect the functionality of the query
|
||||
$sqlmsg = mssql_get_last_message();
|
||||
$sqlpos = strpos($sqlmsg, 'Changed database context to');
|
||||
|
||||
if($dieOnError)
|
||||
if ($sqlpos !== false)
|
||||
// if sqlmsg has 'Changed database context to', just log it
|
||||
$GLOBALS['log']->debug(mssql_get_last_message() . ": " . $sql );
|
||||
else
|
||||
sugar_die('SQL Error : ' . mssql_get_last_message());
|
||||
else
|
||||
echo 'SQL Error : ' . mssql_get_last_message();
|
||||
|
||||
$GLOBALS['log']->fatal(mssql_get_last_message() . ": " . $sql );
|
||||
}
|
||||
$this->lastmysqlrow = -1;
|
||||
|
||||
$this->query_time = microtime(true) - $this->query_time;
|
||||
$GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
|
||||
|
||||
|
||||
$this->checkError($msg.' Query Failed:' . $sql . '::', $dieOnError);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is a utility function to prepend the "N" character in front of SQL values that are
|
||||
* surrounded by single quotes.
|
||||
*
|
||||
* @param $sql string SQL statement
|
||||
* @return string SQL statement with single quote values prepended with "N" character for nvarchar columns
|
||||
*/
|
||||
public function appendN(
|
||||
$sql
|
||||
)
|
||||
{
|
||||
// If there are no single quotes, don't bother, will just assume there is no character data
|
||||
if (strpos($sql, '\'') === false)
|
||||
return $sql;
|
||||
|
||||
$sql = str_replace('\\\'', '<@#@#@ESCAPED_QUOTE@#@#@>', $sql);
|
||||
|
||||
//The only location of three subsequent ' will be at the begning or end of a value.
|
||||
$sql = preg_replace('/(?<!\')(\'{3})(?!\')/', "'<@#@#@PAIR@#@#@>", $sql);
|
||||
|
||||
// Flag if there are odd number of single quotes, just continue w/o trying to append N
|
||||
if ((substr_count($sql, '\'') & 1)) {
|
||||
$GLOBALS['log']->error('SQL statement[' . $sql . '] has odd number of single quotes.');
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// Remove any remaining '' and do not parse... replace later (hopefully we don't even have any)
|
||||
$pairs = array();
|
||||
$regexp = '/(\'{2})/';
|
||||
$pair_matches = array();
|
||||
preg_match_all($regexp, $sql, $pair_matches);
|
||||
if ($pair_matches) {
|
||||
foreach (array_unique($pair_matches[0]) as $key=>$value) {
|
||||
$pairs['<@PAIR-'.$key.'@>'] = $value;
|
||||
}
|
||||
if (!empty($pairs)) {
|
||||
$sql = str_replace($pairs, array_keys($pairs), $sql);
|
||||
}
|
||||
}
|
||||
|
||||
$regexp = "/(N?\'.+?\')/is";
|
||||
$matches = array();
|
||||
preg_match_all($regexp, $sql, $matches);
|
||||
$replace = array();
|
||||
if (!empty($matches)) {
|
||||
foreach ($matches[0] as $key=>$value) {
|
||||
// We are assuming that all nvarchar columns are no more than 200 characters in length
|
||||
// One problem we face is the image column type in reports which cannot accept nvarchar data
|
||||
if (!empty($value) && !is_numeric(trim(str_replace(array('\'', ','), '', $value))) && !preg_match('/^\'[\,]\'$/', $value)) {
|
||||
$replace[$value] = 'N' . trim($value, 'N');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($replace))
|
||||
$sql = str_replace(array_keys($replace), $replace, $sql);
|
||||
|
||||
if (!empty($pairs))
|
||||
$sql = str_replace(array_keys($pairs), $pairs, $sql);
|
||||
|
||||
if(strpos($sql, '<@#@#@PAIR@#@#@>'))
|
||||
$sql = str_replace(array('<@#@#@PAIR@#@#@>'), array('\'\''), $sql);
|
||||
|
||||
if(strpos($sql, '<@#@#@ESCAPED_QUOTE@#@#@>'))
|
||||
$sql = str_replace(array('<@#@#@ESCAPED_QUOTE@#@#@>'), array('\\\''), $sql);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
732
include/database/MssqlHelper.php
Executable file
732
include/database/MssqlHelper.php
Executable file
@@ -0,0 +1,732 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application specific
|
||||
* to Mssql database. It is called by the DBManager class to generate various sql statements.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* Please refer the DBManager documentation for the details.
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ___RPS___________________________________..
|
||||
********************************************************************************/
|
||||
|
||||
include_once('include/database/DBHelper.php');
|
||||
|
||||
class MssqlHelper extends DBHelper
|
||||
{
|
||||
/**
|
||||
* @see DBHelper::getColumnType()
|
||||
*/
|
||||
public function getColumnType(
|
||||
$type,
|
||||
$name = '',
|
||||
$table = ''
|
||||
)
|
||||
{
|
||||
$map = array(
|
||||
'int' => 'int',
|
||||
'double' => 'float',
|
||||
'float' => 'float',
|
||||
'uint' => 'int',
|
||||
'ulong' => 'int',
|
||||
'long' => 'bigint',
|
||||
'short' => 'smallint',
|
||||
'varchar' => 'varchar',
|
||||
'text' => 'text',
|
||||
'longtext' => 'text',
|
||||
'date' => 'datetime',
|
||||
'enum' => 'varchar',
|
||||
'relate' => 'varchar',
|
||||
'multienum'=> 'text',
|
||||
'html' => 'text',
|
||||
'datetime' => 'datetime',
|
||||
'datetimecombo' => 'datetime',
|
||||
'time' => 'datetime',
|
||||
'bool' => 'bit',
|
||||
'tinyint' => 'tinyint',
|
||||
'char' => 'char',
|
||||
'blob' => 'image',
|
||||
'longblob' => 'image',
|
||||
'currency' => 'decimal(26,6)',
|
||||
'decimal' => 'decimal',
|
||||
'decimal2' => 'decimal',
|
||||
'id' => 'varchar(36)',
|
||||
'url'=>'varchar',
|
||||
'encrypt'=>'varchar',
|
||||
);
|
||||
|
||||
return $map[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::dropTableNameSQL()
|
||||
*/
|
||||
public function dropTableNameSQL(
|
||||
$name
|
||||
)
|
||||
{
|
||||
return "DROP TABLE ".$name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SQL Alter table statment
|
||||
*
|
||||
* MSSQL has a quirky T-SQL alter table syntax. Pay special attention to the
|
||||
* modify operation
|
||||
* @param string $action
|
||||
* @param array $def
|
||||
* @param bool $ignorRequired
|
||||
* @param string $tablename
|
||||
*/
|
||||
private function alterSQLRep(
|
||||
$action,
|
||||
array $def,
|
||||
$ignoreRequired,
|
||||
$tablename = ''
|
||||
)
|
||||
{
|
||||
switch($action){
|
||||
case 'add':
|
||||
$f_def=$this->oneColumnSQLRep($def, $ignoreRequired,$tablename,false);
|
||||
return "ADD " . $f_def;
|
||||
break;
|
||||
case 'drop':
|
||||
return "DROP COLUMN " . $def['name'];
|
||||
break;
|
||||
case 'modify':
|
||||
//You cannot specify a default value for a column for MSSQL
|
||||
$f_def = $this->oneColumnSQLRep($def, $ignoreRequired,$tablename, true);
|
||||
$f_stmt = "ALTER COLUMN ".$f_def['name'].' '.$f_def['colType'].' '.
|
||||
$f_def['required'].' '.$f_def['auto_increment']."\n";
|
||||
if (!empty( $f_def['default']))
|
||||
$f_stmt .= " ALTER TABLE " . $tablename . " ADD ". $f_def['default'] . " FOR " . $def['name'];
|
||||
return $f_stmt;
|
||||
break;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::changeColumnSQL()
|
||||
*
|
||||
* MSSQL uses a different syntax than MySQL for table altering that is
|
||||
* not quite as simplistic to implement...
|
||||
*/
|
||||
protected function changeColumnSQL(
|
||||
$tablename,
|
||||
$fieldDefs,
|
||||
$action,
|
||||
$ignoreRequired = false
|
||||
)
|
||||
{
|
||||
$sql='';
|
||||
$constraints = $this->get_field_default_constraint_name($tablename);
|
||||
if ($this->isFieldArray($fieldDefs)) {
|
||||
foreach ($fieldDefs as $def)
|
||||
{
|
||||
//if the column is being modified drop the default value
|
||||
//constraint if it exists. alterSQLRep will add the constraint back
|
||||
if (!empty($constraints[$def['name']])) {
|
||||
$sql.=" ALTER TABLE " . $tablename . " DROP CONSTRAINT " . $constraints[$def['name']];
|
||||
}
|
||||
|
||||
$columns[] = $this->alterSQLRep($action, $def, $ignoreRequired,$tablename);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//if the column is being modified drop the default value
|
||||
//constraint if it exists. alterSQLRep will add the constraint back
|
||||
if (!empty($constraints[$fieldDefs['name']])) {
|
||||
$sql.=" ALTER TABLE " . $tablename . " DROP CONSTRAINT " . $constraints[$fieldDefs['name']];
|
||||
}
|
||||
|
||||
$columns[] = $this->alterSQLRep($action, $fieldDefs, $ignoreRequired,$tablename);
|
||||
}
|
||||
|
||||
$columns = implode(", ", $columns);
|
||||
$sql .= " ALTER TABLE $tablename $columns";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::deleteColumnSQL()
|
||||
*/
|
||||
public function deleteColumnSQL(
|
||||
SugarBean $bean,
|
||||
$fieldDefs
|
||||
)
|
||||
{
|
||||
if ($this->isFieldArray($fieldDefs))
|
||||
foreach ($fieldDefs as $fieldDef)
|
||||
$columns[] = $fieldDef['name'];
|
||||
else
|
||||
$columns[] = $fieldDefs['name'];
|
||||
|
||||
return "ALTER TABLE ".$bean->getTableName()." DROP COLUMN ".implode(", DROP COLUMN ", $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an alter table statement to build the list of indices
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param array $fieldDefs
|
||||
* @param array $indices
|
||||
* @return string SQL statement
|
||||
*/
|
||||
public function indexSQL(
|
||||
$tableName,
|
||||
$fieldDefs,
|
||||
$indices
|
||||
)
|
||||
{
|
||||
// check if the passed value is an array of fields.
|
||||
// if not, convert it into an array
|
||||
if (!$this->isFieldArray($indices))
|
||||
$indices[] = $indices;
|
||||
|
||||
$columns = array();
|
||||
foreach ($indices as $index) {
|
||||
if(!empty($index['db']) && $index['db'] != 'mssql')
|
||||
continue;
|
||||
|
||||
$type = $index['type'];
|
||||
$name = $index['name'];
|
||||
|
||||
if (is_array($index['fields']))
|
||||
$fields = implode(", ", $index['fields']);
|
||||
else
|
||||
$fields = $index['fields'];
|
||||
|
||||
switch ($type) {
|
||||
case 'primary':
|
||||
// SQL server requires primary key constraints to be created with
|
||||
// key word "PRIMARY KEY". Cannot default to index as synonym
|
||||
$columns[] = "ALTER TABLE $tableName ADD CONSTRAINT pk_$tableName PRIMARY KEY ($fields)";
|
||||
break;
|
||||
case 'unique':
|
||||
$columns[] = "ALTER TABLE $tableName ADD CONSTRAINT " . $index['name'] . " UNIQUE ($fields)";
|
||||
break;
|
||||
case 'index':
|
||||
case 'alternate_key':
|
||||
case 'foreign':
|
||||
$columns[] = "create index $name on $tableName ( $fields )";
|
||||
break;
|
||||
case 'fulltext':
|
||||
if ($this->full_text_indexing_enabled()) {
|
||||
$catalog_name="sugar_fts_catalog";
|
||||
if ( isset($index['catalog_name'])
|
||||
&& $index['catalog_name'] != 'default')
|
||||
$catalog_name = $index['catalog_name'];
|
||||
|
||||
$language = "Language 1033";
|
||||
if (isset($index['language']) && !empty($index['language']))
|
||||
$language = "Language " . $index['language'];
|
||||
|
||||
$key_index = $index['key_index'];;
|
||||
|
||||
$change_tracking = "auto";
|
||||
if (isset($index['change_tracking'])
|
||||
&& !empty($index['change_tracking']))
|
||||
$change_tracking = $index['change_tracking'];
|
||||
|
||||
$columns[] = " CREATE FULLTEXT INDEX ON $tableName($fields $language) KEY INDEX $key_index ON $catalog_name WITH CHANGE_TRACKING $change_tracking" ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$columns = implode(" ", $columns);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
protected function setAutoIncrement(
|
||||
$table,
|
||||
$field_name
|
||||
)
|
||||
{
|
||||
return "identity(1,1)";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::setAutoIncrementStart()
|
||||
*/
|
||||
public function setAutoIncrementStart(
|
||||
$table,
|
||||
$field_name,
|
||||
$start_value
|
||||
)
|
||||
{
|
||||
if($start_value > 1)
|
||||
$start_value -= 1;
|
||||
$this->db->query("DBCC CHECKIDENT ('$table', RESEED, $start_value)");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::getAutoIncrement()
|
||||
*/
|
||||
public function getAutoIncrement(
|
||||
$table,
|
||||
$field_name
|
||||
)
|
||||
{
|
||||
|
||||
|
||||
$result = $this->db->query("select IDENT_CURRENT('$table') + IDENT_INCR ( '$table' ) as 'Auto_increment'");
|
||||
$row = $this->db->fetchByAssoc($result);
|
||||
if (!empty($row['Auto_increment']))
|
||||
return $row['Auto_increment'];
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::createTableSQLParams()
|
||||
*/
|
||||
public function createTableSQLParams(
|
||||
$tablename,
|
||||
$fieldDefs,
|
||||
$indices,
|
||||
$engine = null
|
||||
)
|
||||
{
|
||||
if (empty($tablename) || empty($fieldDefs))
|
||||
return '';
|
||||
|
||||
$sql ='';
|
||||
$columns = $this->columnSQLRep($fieldDefs, false, $tablename);
|
||||
if (empty($columns))
|
||||
return false;
|
||||
|
||||
return "CREATE TABLE $tablename ($columns ) " .
|
||||
$this->indexSQL($tablename, $fieldDefs, $indices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::get_indices()
|
||||
*/
|
||||
public function get_indices(
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
//find all unique indexes and primary keys.
|
||||
$query = <<<EOSQL
|
||||
SELECT LEFT(so.[name], 30) TableName,
|
||||
LEFT(si.[name], 50) 'Key_name',
|
||||
LEFT(sik.[keyno], 30) Sequence,
|
||||
LEFT(sc.[name], 30) Column_name,
|
||||
isunique = CASE
|
||||
WHEN si.status & 2 = 2 AND so.xtype != 'PK' THEN 1
|
||||
ELSE 0
|
||||
END
|
||||
FROM sysindexes si
|
||||
INNER JOIN sysindexkeys sik
|
||||
ON (si.[id] = sik.[id] AND si.indid = sik.indid)
|
||||
INNER JOIN sysobjects so
|
||||
ON si.[id] = so.[id]
|
||||
INNER JOIN syscolumns sc
|
||||
ON (so.[id] = sc.[id] AND sik.colid = sc.colid)
|
||||
INNER JOIN sysfilegroups sfg
|
||||
ON si.groupid = sfg.groupid
|
||||
WHERE so.[name] = '$tablename'
|
||||
ORDER BY Key_name, Sequence, Column_name
|
||||
EOSQL;
|
||||
$result = $this->db->query($query);
|
||||
|
||||
$indices = array();
|
||||
while (($row=$this->db->fetchByAssoc($result)) != null) {
|
||||
$index_type = 'index';
|
||||
if ($row['Key_name'] == 'PRIMARY')
|
||||
$index_type = 'primary';
|
||||
elseif ($row['isunique'] == 1 )
|
||||
$index_type = 'unique';
|
||||
$name = strtolower($row['Key_name']);
|
||||
$indices[$name]['name'] = $name;
|
||||
$indices[$name]['type'] = $index_type;
|
||||
$indices[$name]['fields'][] = strtolower($row['Column_name']);
|
||||
}
|
||||
return $indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::get_columns()
|
||||
*/
|
||||
public function get_columns(
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
//find all unique indexes and primary keys.
|
||||
$result = $this->db->query("sp_columns $tablename");
|
||||
|
||||
$columns = array();
|
||||
while (($row=$this->db->fetchByAssoc($result)) !=null) {
|
||||
$column_name = strtolower($row['COLUMN_NAME']);
|
||||
$columns[$column_name]['name']=$column_name;
|
||||
$columns[$column_name]['type']=strtolower($row['TYPE_NAME']);
|
||||
if ( $row['TYPE_NAME'] == 'decimal' ) {
|
||||
$columns[$column_name]['len']=strtolower($row['PRECISION']);
|
||||
$columns[$column_name]['len'].=','.strtolower($row['SCALE']);
|
||||
}
|
||||
elseif ( in_array($row['TYPE_NAME'],array('nchar','nvarchar')) )
|
||||
$columns[$column_name]['len']=strtolower($row['PRECISION']);
|
||||
elseif ( !in_array($row['TYPE_NAME'],array('datetime','text')) )
|
||||
$columns[$column_name]['len']=strtolower($row['LENGTH']);
|
||||
if ( stristr($row['TYPE_NAME'],'identity') ) {
|
||||
$columns[$column_name]['auto_increment'] = '1';
|
||||
$columns[$column_name]['type']=str_replace(' identity','',strtolower($row['TYPE_NAME']));
|
||||
}
|
||||
|
||||
if (!empty($row['IS_NULLABLE']) && $row['IS_NULLABLE'] == 'NO' && (empty($row['KEY']) || !stristr($row['KEY'],'PRI')))
|
||||
$columns[strtolower($row['COLUMN_NAME'])]['required'] = 'true';
|
||||
|
||||
$column_def = 0;
|
||||
if ( strtolower($tablename) == 'relationships' ) {
|
||||
$column_def = $this->db->getOne("select cdefault from syscolumns where id = object_id('relationships') and name = '$column_name'");
|
||||
}
|
||||
if ( $column_def != 0 ) {
|
||||
$matches = array();
|
||||
$row['COLUMN_DEF'] = html_entity_decode($row['COLUMN_DEF'],ENT_QUOTES);
|
||||
if ( preg_match("/\([\(|'](.*)[\)|']\)/i",$row['COLUMN_DEF'],$matches) )
|
||||
$columns[$column_name]['default'] = $matches[1];
|
||||
elseif ( preg_match("/\(N'(.*)'\)/i",$row['COLUMN_DEF'],$matches) )
|
||||
$columns[$column_name]['default'] = $matches[1];
|
||||
else
|
||||
$columns[$column_name]['default'] = $row['COLUMN_DEF'];
|
||||
}
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::add_drop_constraint()
|
||||
*/
|
||||
public function add_drop_constraint(
|
||||
$table,
|
||||
$definition,
|
||||
$drop = false
|
||||
)
|
||||
{
|
||||
$type = $definition['type'];
|
||||
$fields = implode(',',$definition['fields']);
|
||||
$name = $definition['name'];
|
||||
$foreignTable = isset($definition['foreignTable']) ? $definition['foreignTable'] : array();
|
||||
$sql = '';
|
||||
|
||||
switch ($type){
|
||||
// generic indices
|
||||
case 'index':
|
||||
case 'alternate_key':
|
||||
if ($drop)
|
||||
$sql = "DROP INDEX {$name} ";
|
||||
else
|
||||
$sql = "CREATE INDEX {$name} ON {$table} ({$fields})";
|
||||
break;
|
||||
// constraints as indices
|
||||
case 'unique':
|
||||
if ($drop)
|
||||
$sql = "ALTER TABLE {$table} DROP INDEX $name";
|
||||
else
|
||||
$sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE ({$fields})";
|
||||
break;
|
||||
case 'primary':
|
||||
if ($drop)
|
||||
$sql = "ALTER TABLE {$table} DROP PRIMARY KEY";
|
||||
else
|
||||
$sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} PRIMARY KEY ({$fields})";
|
||||
break;
|
||||
case 'foreign':
|
||||
if ($drop)
|
||||
$sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})";
|
||||
else
|
||||
$sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} FOREIGN KEY ({$fields}) REFERENCES {$foreignTable}({$foreignfields})";
|
||||
break;
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::number_of_columns()
|
||||
*/
|
||||
public function number_of_columns(
|
||||
$table_name
|
||||
)
|
||||
{
|
||||
$def_query = <<<EOSQL
|
||||
SELECT count(*) as cols
|
||||
FROM sys.columns col join sys.types col_type
|
||||
on col.user_type_id=col_type.user_type_id
|
||||
where col.object_id = (
|
||||
select object_id(sys.schemas.name + '.' + sys.tables.name)
|
||||
from sys.tables join sys.schemas
|
||||
on sys.schemas.schema_id = sys.tables.schema_id
|
||||
where sys.tables.name='$table_name'
|
||||
)
|
||||
EOSQL;
|
||||
/**
|
||||
* @TODO test the similarities of the above the query against all system tables vs the query below against
|
||||
* the information_schema view in terms of results and efficiency. suspician is provided the two produce
|
||||
* the same information the latter will be slightly faster.
|
||||
* <code>
|
||||
* <?php
|
||||
* $def_query = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='$table_name'";
|
||||
* ?>
|
||||
* </code>
|
||||
*/
|
||||
|
||||
$result = $this->db->query($def_query);
|
||||
$row = $this->db->fetchByAssoc($result);
|
||||
if (!empty($row)) {
|
||||
return $row['cols'];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Full Text Search is installed
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function full_text_indexing_installed()
|
||||
{
|
||||
$ftsChckRes = $this->db->query(
|
||||
"SELECT FULLTEXTSERVICEPROPERTY('IsFulltextInstalled') as fts");
|
||||
$row = $this->db->fetchByAssoc($ftsChckRes);
|
||||
|
||||
return (isset($row) && isset($row['fts']) && ($row['fts'] == 1 || $row['fts'] == '1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::full_text_indexing_enabled()
|
||||
*/
|
||||
protected function full_text_indexing_enabled(
|
||||
$dbname = null
|
||||
)
|
||||
{
|
||||
// check to see if we already have install setting in session
|
||||
if(!isset($_SESSION['IsFulltextInstalled']))
|
||||
$_SESSION['IsFulltextInstalled'] = $this->full_text_indexing_installed();
|
||||
|
||||
// check to see if FTS Indexing service is installed
|
||||
if(empty($_SESSION['IsFulltextInstalled'])
|
||||
|| $_SESSION['IsFulltextInstalled'] === false)
|
||||
return false;
|
||||
|
||||
// grab the dbname if it was not passed through
|
||||
if (empty($dbname)) {
|
||||
global $sugar_config;
|
||||
$dbname = $sugar_config['dbconfig']['db_name'];
|
||||
}
|
||||
//we already know that Indexing service is installed, now check
|
||||
//to see if it is enabled
|
||||
$res = $this->db->query(
|
||||
"SELECT DATABASEPROPERTY('$dbname', 'IsFulltextEnabled') ftext");
|
||||
$row = $GLOBALS['db']->fetchByAssoc($res);
|
||||
|
||||
return (isset($row['ftext']) && $row['ftext'] == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates default full text catalog
|
||||
*/
|
||||
public function create_default_full_text_catalog()
|
||||
{
|
||||
if ($this->full_text_indexing_enabled()) {
|
||||
$GLOBALS['log']->debug('Creating the default catalog for full-text indexing, sugar_fts_catalog');
|
||||
|
||||
//drop catalog if exists.
|
||||
$ret = $this->db->query("
|
||||
if not exists(
|
||||
select *
|
||||
from sys.fulltext_catalogs
|
||||
where name ='sugar_fts_catalog'
|
||||
)
|
||||
CREATE FULLTEXT CATALOG sugar_fts_catalog");
|
||||
|
||||
if (empty($ret)) {
|
||||
$GLOBALS['log']->error('Error creating default full-text catalog, sugar_fts_catalog');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function returns name of the constraint automatically generated by sql-server.
|
||||
* We request this for default, primary key, required
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @return string
|
||||
*/
|
||||
private function get_field_default_constraint_name(
|
||||
$table,
|
||||
$column = null
|
||||
)
|
||||
{
|
||||
static $results = array();
|
||||
|
||||
if ( empty($column) && isset($results[$table]) )
|
||||
return $results[$table];
|
||||
|
||||
$query = <<<EOQ
|
||||
select s.name, o.name, c.name dtrt, d.name ctrt
|
||||
from sys.default_constraints as d
|
||||
join sys.objects as o
|
||||
on o.object_id = d.parent_object_id
|
||||
join sys.columns as c
|
||||
on c.object_id = o.object_id and c.column_id = d.parent_column_id
|
||||
join sys.schemas as s
|
||||
on s.schema_id = o.schema_id
|
||||
where o.name = '$table'
|
||||
EOQ;
|
||||
if ( !empty($column) )
|
||||
$query .= " and c.name = '$column'";
|
||||
$res = $this->db->query($query);
|
||||
if ( !empty($column) ) {
|
||||
$row = $this->db->fetchByAssoc($res);
|
||||
if (!empty($row))
|
||||
return $row['ctrt'];
|
||||
}
|
||||
else {
|
||||
$returnResult = array();
|
||||
while ( $row = $this->db->fetchByAssoc($res) )
|
||||
$returnResult[$row['dtrt']] = $row['ctrt'];
|
||||
$results[$table] = $returnResult;
|
||||
return $returnResult;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::massageFieldDef()
|
||||
*/
|
||||
public function massageFieldDef(
|
||||
&$fieldDef,
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
parent::massageFieldDef($fieldDef,$tablename);
|
||||
|
||||
if ($fieldDef['type'] == 'int')
|
||||
$fieldDef['len'] = '4';
|
||||
if ($fieldDef['type'] == 'bit' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '1';
|
||||
if ($fieldDef['type'] == 'bool' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '1';
|
||||
if ($fieldDef['type'] == 'float' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '8';
|
||||
if ($fieldDef['type'] == 'varchar' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '255';
|
||||
if ($fieldDef['type'] == 'nvarchar' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '255';
|
||||
if ($fieldDef['type'] == 'bit' && empty($fieldDef['default']) )
|
||||
$fieldDef['default'] = '0';
|
||||
if ($fieldDef['type'] == 'bool' && empty($fieldDef['default']) )
|
||||
$fieldDef['default'] = '0';
|
||||
if ($fieldDef['type'] == 'image' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '2147483647';
|
||||
if ($fieldDef['type'] == 'ntext' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '2147483646';
|
||||
if ($fieldDef['type'] == 'smallint' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '2';
|
||||
if (isset($fieldDef['required']) && $fieldDef['required'] && !isset($fieldDef['default']) )
|
||||
$fieldDef['default'] = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::oneColumnSQLRep()
|
||||
*/
|
||||
protected function oneColumnSQLRep(
|
||||
$fieldDef,
|
||||
$ignoreRequired = false,
|
||||
$table = '',
|
||||
$return_as_array = false
|
||||
)
|
||||
{
|
||||
//Bug 25814
|
||||
if(isset($fieldDef['name'])){
|
||||
$name = $fieldDef['name'];
|
||||
$type = $this->getFieldType($fieldDef);
|
||||
$colType = $this->getColumnType($type, $name, $table);
|
||||
if(stristr($colType, 'decimal')){
|
||||
$fieldDef['len'] = isset($fieldDef['len'])? min($fieldDef['len'],38) : 38;
|
||||
}
|
||||
//bug: 39690 float(8) is interpreted as real and this generates a diff when doing repair
|
||||
if(stristr($colType, 'float')){
|
||||
if(isset($fieldDef['len']) && $fieldDef['len'] == 8){
|
||||
unset($fieldDef['len']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true);
|
||||
|
||||
// Bug 24307 - Don't add precision for float fields.
|
||||
if ( stristr($ref['colType'],'float') )
|
||||
$ref['colType'] = preg_replace('/(,\d+)/','',$ref['colType']);
|
||||
|
||||
if ( $return_as_array )
|
||||
return $ref;
|
||||
else
|
||||
return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves changes to module's audit table
|
||||
*
|
||||
* @param object $bean Sugarbean instance
|
||||
* @param array $changes changes
|
||||
* @see DBHelper::getDataChanges()
|
||||
*/
|
||||
public function save_audit_records(
|
||||
SugarBean &$bean,
|
||||
&$changes
|
||||
)
|
||||
{
|
||||
//Bug 25078 fixed by Martin Hu: sqlserver haven't 'date' type, trim extra "00:00:00"
|
||||
if($changes['data_type'] == 'date'){
|
||||
$changes['before'] = str_replace(' 00:00:00','',$changes['before']);
|
||||
}
|
||||
parent::save_audit_records($bean,$changes);
|
||||
}
|
||||
}
|
||||
?>
|
||||
1279
include/database/MssqlManager.php
Executable file
1279
include/database/MssqlManager.php
Executable file
File diff suppressed because it is too large
Load Diff
519
include/database/MysqlHelper.php
Executable file
519
include/database/MysqlHelper.php
Executable file
@@ -0,0 +1,519 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application specific
|
||||
* to oracle database. It is called by the DBManager class to generate various sql statements.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* Please refer the DBManager documentation for the details.
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
require_once('include/database/DBHelper.php');
|
||||
|
||||
class MysqlHelper extends DBHelper
|
||||
{
|
||||
/**
|
||||
* @see DBHelper::createTableSQL()
|
||||
*/
|
||||
public function createTableSQL(
|
||||
SugarBean $bean
|
||||
)
|
||||
{
|
||||
$tablename = $bean->getTableName();
|
||||
$fieldDefs = $bean->getFieldDefinitions();
|
||||
$indices = $bean->getIndices();
|
||||
$engine = $this->getEngine($bean);
|
||||
return $this->createTableSQLParams($tablename, $fieldDefs, $indices, $engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates sql for create table statement for a bean.
|
||||
*
|
||||
* @param string $tablename
|
||||
* @param array $fieldDefs
|
||||
* @param array $indices
|
||||
* @param string $engine optional, MySQL engine to use
|
||||
* @return string SQL Create Table statement
|
||||
*/
|
||||
public function createTableSQLParams(
|
||||
$tablename,
|
||||
$fieldDefs,
|
||||
$indices,
|
||||
$engine = null
|
||||
)
|
||||
{
|
||||
if ( empty($engine) && isset($fieldDefs['engine']))
|
||||
$engine = $fieldDefs['engine'];
|
||||
if ( !$this->isEngineEnabled($engine) )
|
||||
$engine = '';
|
||||
|
||||
$sql = parent::createTableSQLParams($tablename,$fieldDefs,$indices);
|
||||
if (!empty($engine))
|
||||
$sql.= " ENGINE=$engine";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the engine to use or null if we are to use the default
|
||||
*
|
||||
* @param object $bean SugarBean instance
|
||||
* @return string
|
||||
*/
|
||||
private function getEngine(
|
||||
&$bean
|
||||
)
|
||||
{
|
||||
global $dictionary;
|
||||
$engine = null;
|
||||
if (isset($dictionary[$bean->getObjectName()]['engine'])) {
|
||||
$engine = $dictionary[$bean->getObjectName()]['engine'];
|
||||
}
|
||||
return $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the engine given is enabled in the backend
|
||||
*
|
||||
* @param string $engine
|
||||
* @return bool
|
||||
*/
|
||||
private function isEngineEnabled(
|
||||
$engine
|
||||
)
|
||||
{
|
||||
$engine = strtoupper($engine);
|
||||
|
||||
$r = $this->db->query("SHOW ENGINES");
|
||||
|
||||
while ( $row = $this->db->fetchByAssoc($r) )
|
||||
if ( strtoupper($row['Engine']) == $engine )
|
||||
return ($row['Support']=='YES' || $row['Support']=='DEFAULT');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::getColumnType()
|
||||
*/
|
||||
public function getColumnType(
|
||||
$type,
|
||||
$name = '',
|
||||
$table = ''
|
||||
)
|
||||
{
|
||||
$map = array(
|
||||
'int' => 'int',
|
||||
'double' => 'double',
|
||||
'float' => 'float',
|
||||
'uint' => 'int unsigned',
|
||||
'ulong' => 'bigint unsigned',
|
||||
'long' => 'bigint',
|
||||
'short' => 'smallint',
|
||||
'varchar' => 'varchar',
|
||||
'text' => 'text',
|
||||
'longtext' => 'longtext',
|
||||
'date' => 'date',
|
||||
'enum' => 'varchar',
|
||||
'relate' => 'varchar',
|
||||
'multienum'=> 'text',
|
||||
'html' => 'text',
|
||||
'datetime' => 'datetime',
|
||||
'datetimecombo' => 'datetime',
|
||||
'time' => 'time',
|
||||
'bool' => 'bool',
|
||||
'tinyint' => 'tinyint',
|
||||
'char' => 'char',
|
||||
'blob' => 'blob',
|
||||
'longblob' => 'longblob',
|
||||
'currency' => 'decimal(26,6)',
|
||||
'decimal' => 'decimal',
|
||||
'decimal2' => 'decimal',
|
||||
'id' => 'char(36)',
|
||||
'url'=>'varchar',
|
||||
'encrypt'=>'varchar',
|
||||
);
|
||||
|
||||
return $map[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::oneColumnSQLRep()
|
||||
*/
|
||||
protected function oneColumnSQLRep(
|
||||
$fieldDef,
|
||||
$ignoreRequired = false,
|
||||
$table = '',
|
||||
$return_as_array = false
|
||||
)
|
||||
{
|
||||
$ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true);
|
||||
|
||||
if ( $ref['colType'] == 'int'
|
||||
&& !empty($fieldDef['len']) )
|
||||
$ref['colType'] .= "(".$fieldDef['len'].")";
|
||||
|
||||
// bug 22338 - don't set a default value on text or blob fields
|
||||
if ( isset($ref['default']) &&
|
||||
($ref['colType'] == 'text' || $ref['colType'] == 'blob'
|
||||
|| $ref['colType'] == 'longtext' || $ref['colType'] == 'longblob' ))
|
||||
$ref['default'] = '';
|
||||
|
||||
if ( $return_as_array )
|
||||
return $ref;
|
||||
else
|
||||
return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::changeColumnSQL()
|
||||
*/
|
||||
protected function changeColumnSQL(
|
||||
$tablename,
|
||||
$fieldDefs,
|
||||
$action,
|
||||
$ignoreRequired = false
|
||||
)
|
||||
{
|
||||
if ($this->isFieldArray($fieldDefs)){
|
||||
foreach ($fieldDefs as $def){
|
||||
if ($action == 'drop')
|
||||
$columns[] = $def['name'];
|
||||
else
|
||||
$columns[] = $this->oneColumnSQLRep($def, $ignoreRequired);
|
||||
}
|
||||
}else{
|
||||
if ($action == 'drop')
|
||||
$columns[] = $fieldDefs['name'];
|
||||
else
|
||||
$columns[] = $this->oneColumnSQLRep($fieldDefs);
|
||||
}
|
||||
|
||||
return "alter table $tablename $action column ".implode(",$action column ", $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::deleteColumnSQL()
|
||||
*/
|
||||
public function deleteColumnSQL(
|
||||
SugarBean $bean,
|
||||
$fieldDefs
|
||||
)
|
||||
{
|
||||
if ($this->isFieldArray($fieldDefs))
|
||||
foreach ($fieldDefs as $fieldDef)
|
||||
$columns[] = $fieldDef['name'];
|
||||
else
|
||||
$columns[] = $fieldDefs['name'];
|
||||
|
||||
return "alter table ".$bean->getTableName()." drop column ".implode(", drop column ", $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::keysSQL
|
||||
*/
|
||||
public function keysSQL(
|
||||
$indices,
|
||||
$alter_table = false,
|
||||
$alter_action = ''
|
||||
)
|
||||
{
|
||||
// check if the passed value is an array of fields.
|
||||
// if not, convert it into an array
|
||||
if (!$this->isFieldArray($indices))
|
||||
$indices[] = $indices;
|
||||
|
||||
$columns = array();
|
||||
foreach ($indices as $index) {
|
||||
if(!empty($index['db']) && $index['db'] != 'mysql')
|
||||
continue;
|
||||
|
||||
$type = $index['type'];
|
||||
$name = $index['name'];
|
||||
|
||||
if (is_array($index['fields']))
|
||||
$fields = implode(", ", $index['fields']);
|
||||
else
|
||||
$fields = $index['fields'];
|
||||
|
||||
switch ($type) {
|
||||
case 'unique':
|
||||
$columns[] = " UNIQUE $name ($fields)";
|
||||
break;
|
||||
case 'primary':
|
||||
$columns[] = " PRIMARY KEY ($fields)";
|
||||
break;
|
||||
case 'index':
|
||||
case 'foreign':
|
||||
case 'alternate_key':
|
||||
/**
|
||||
* @todo here it is assumed that the primary key of the foreign
|
||||
* table will always be named 'id'. It must be noted though
|
||||
* that this can easily be fixed by referring to db dictionary
|
||||
* to find the correct primary field name
|
||||
*/
|
||||
if ( $alter_table )
|
||||
$columns[] = " INDEX $name ($fields)";
|
||||
else
|
||||
$columns[] = " KEY $name ($fields)";
|
||||
break;
|
||||
case 'fulltext':
|
||||
if ($this->full_text_indexing_enabled())
|
||||
$columns[] = " FULLTEXT ($fields)";
|
||||
else
|
||||
$GLOBALS['log']->debug('MYISAM engine is not available/enabled, full-text indexes will be skipped. Skipping:',$name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$columns = implode(", $alter_action ", $columns);
|
||||
if(!empty($alter_action)){
|
||||
$columns = $alter_action . ' '. $columns;
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::setAutoIncrement()
|
||||
*/
|
||||
protected function setAutoIncrement(
|
||||
$table,
|
||||
$field_name
|
||||
)
|
||||
{
|
||||
return "auto_increment";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the next auto-increment value of a column to a specific value.
|
||||
*
|
||||
* @param string $table tablename
|
||||
* @param string $field_name
|
||||
*/
|
||||
public function setAutoIncrementStart(
|
||||
$table,
|
||||
$field_name,
|
||||
$start_value
|
||||
)
|
||||
{
|
||||
$this->db->query( "ALTER TABLE $table AUTO_INCREMENT = $start_value;");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next value for an auto increment
|
||||
*
|
||||
* @param string $table tablename
|
||||
* @param string $field_name
|
||||
* @return string
|
||||
*/
|
||||
public function getAutoIncrement(
|
||||
$table,
|
||||
$field_name
|
||||
)
|
||||
{
|
||||
|
||||
$result = $this->db->query("SHOW TABLE STATUS LIKE '$table'");
|
||||
$row = $this->db->fetchByAssoc($result);
|
||||
if (!empty($row['Auto_increment']))
|
||||
return $row['Auto_increment'];
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::get_indices()
|
||||
*/
|
||||
public function get_indices(
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
//find all unique indexes and primary keys.
|
||||
$result = $this->db->query("SHOW INDEX FROM $tablename");
|
||||
|
||||
$indices = array();
|
||||
while (($row=$this->db->fetchByAssoc($result)) !=null) {
|
||||
$index_type='index';
|
||||
if ($row['Key_name'] =='PRIMARY') {
|
||||
$index_type='primary';
|
||||
}
|
||||
elseif ( $row['Non_unique'] == '0' ) {
|
||||
$index_type='unique';
|
||||
}
|
||||
$name = strtolower($row['Key_name']);
|
||||
$indices[$name]['name']=$name;
|
||||
$indices[$name]['type']=$index_type;
|
||||
$indices[$name]['fields'][]=strtolower($row['Column_name']);
|
||||
}
|
||||
return $indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::get_columns()
|
||||
*/
|
||||
public function get_columns(
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
//find all unique indexes and primary keys.
|
||||
$result = $this->db->query("DESCRIBE $tablename");
|
||||
|
||||
$columns = array();
|
||||
while (($row=$this->db->fetchByAssoc($result)) !=null) {
|
||||
$name = strtolower($row['Field']);
|
||||
$columns[$name]['name']=$name;
|
||||
$matches = array();
|
||||
preg_match_all("/(\w+)(?:\(([0-9]+,?[0-9]*)\)|)( unsigned)?/i", $row['Type'], $matches);
|
||||
$columns[$name]['type']=strtolower($matches[1][0]);
|
||||
if ( isset($matches[2][0]) && in_array(strtolower($matches[1][0]),array('varchar','char','varchar2','int','decimal','float')) )
|
||||
$columns[$name]['len']=strtolower($matches[2][0]);
|
||||
if ( stristr($row['Extra'],'auto_increment') )
|
||||
$columns[$name]['auto_increment'] = '1';
|
||||
if ($row['Null'] == 'NO' && !stristr($row['Key'],'PRI'))
|
||||
$columns[$name]['required'] = 'true';
|
||||
if ( !empty($row['Default']) )
|
||||
$columns[$name]['default'] = $row['Default'];
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::add_drop_constraint()
|
||||
*/
|
||||
public function add_drop_constraint(
|
||||
$table,
|
||||
$definition,
|
||||
$drop = false
|
||||
)
|
||||
{
|
||||
$type = $definition['type'];
|
||||
$fields = implode(',',$definition['fields']);
|
||||
$name = $definition['name'];
|
||||
$foreignTable = isset($definition['foreignTable']) ? $definition['foreignTable'] : array();
|
||||
$sql = '';
|
||||
|
||||
switch ($type){
|
||||
// generic indices
|
||||
case 'index':
|
||||
case 'alternate_key':
|
||||
if ($drop)
|
||||
$sql = "DROP INDEX {$name} ";
|
||||
else
|
||||
$sql = "CREATE INDEX {$name} ON {$table} ({$fields})";
|
||||
break;
|
||||
// constraints as indices
|
||||
case 'unique':
|
||||
if ($drop)
|
||||
$sql = "ALTER TABLE {$table} DROP INDEX $name";
|
||||
else
|
||||
$sql = "ALTER TABLE {$table} ADD CONSTRAINT UNIQUE {$name} ({$fields})";
|
||||
break;
|
||||
case 'primary':
|
||||
if ($drop)
|
||||
$sql = "ALTER TABLE {$table} DROP PRIMARY KEY";
|
||||
else
|
||||
$sql = "ALTER TABLE {$table} ADD CONSTRAINT PRIMARY KEY ({$fields})";
|
||||
break;
|
||||
case 'foreign':
|
||||
if ($drop)
|
||||
$sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})";
|
||||
else
|
||||
$sql = "ALTER TABLE {$table} ADD CONSTRAINT FOREIGN KEY {$name} ({$fields}) REFERENCES {$foreignTable}({$foreignfields})";
|
||||
break;
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::number_of_columns()
|
||||
*/
|
||||
public function number_of_columns(
|
||||
$table_name
|
||||
)
|
||||
{
|
||||
$result = $this->db->query("DESCRIBE $table_name");
|
||||
|
||||
return ($this->db->getRowCount($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::full_text_indexing_enabled()
|
||||
*/
|
||||
protected function full_text_indexing_enabled(
|
||||
$dbname = null
|
||||
)
|
||||
{
|
||||
return $this->isEngineEnabled('MyISAM');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::massageFieldDef()
|
||||
*/
|
||||
public function massageFieldDef(
|
||||
&$fieldDef,
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
DBHelper::massageFieldDef($fieldDef,$tablename);
|
||||
|
||||
if ( isset($fieldDef['default']) &&
|
||||
($fieldDef['dbType'] == 'text'
|
||||
|| $fieldDef['dbType'] == 'blob'
|
||||
|| $fieldDef['dbType'] == 'longtext'
|
||||
|| $fieldDef['dbType'] == 'longblob' ))
|
||||
unset($fieldDef['default']);
|
||||
if ($fieldDef['dbType'] == 'uint')
|
||||
$fieldDef['len'] = '10';
|
||||
if ($fieldDef['dbType'] == 'ulong')
|
||||
$fieldDef['len'] = '20';
|
||||
if ($fieldDef['dbType'] == 'bool')
|
||||
$fieldDef['type'] = 'tinyint';
|
||||
if ($fieldDef['dbType'] == 'bool' && empty($fieldDef['default']) )
|
||||
$fieldDef['default'] = '0';
|
||||
if (($fieldDef['dbType'] == 'varchar' || $fieldDef['dbType'] == 'enum') && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '255';
|
||||
if ($fieldDef['dbType'] == 'uint')
|
||||
$fieldDef['len'] = '10';
|
||||
if ($fieldDef['dbType'] == 'int' && empty($fieldDef['len']) )
|
||||
$fieldDef['len'] = '11';
|
||||
}
|
||||
}
|
||||
?>
|
||||
554
include/database/MysqlManager.php
Executable file
554
include/database/MysqlManager.php
Executable file
@@ -0,0 +1,554 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application.
|
||||
* It acts as the DB abstraction layer for the application. It depends on helper classes
|
||||
* which generate the necessary SQL. This sql is then passed to PEAR DB classes.
|
||||
* The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* The passed bean is passed to helper class which uses these functions to generate correct sql.
|
||||
*
|
||||
* The meta interface has the following functions:
|
||||
* getTableName() Returns table name of the object.
|
||||
* getFieldDefinitions() Returns a collection of field definitions in order.
|
||||
* getFieldDefintion(name) Return field definition for the field.
|
||||
* getFieldValue(name) Returns the value of the field identified by name.
|
||||
* If the field is not set, the function will return boolean FALSE.
|
||||
* getPrimaryFieldDefinition() Returns the field definition for primary key
|
||||
*
|
||||
* The field definition is an array with the following keys:
|
||||
*
|
||||
* name This represents name of the field. This is a required field.
|
||||
* type This represents type of the field. This is a required field and valid values are:
|
||||
* <20> int
|
||||
* <20> long
|
||||
* <20> varchar
|
||||
* <20> text
|
||||
* <20> date
|
||||
* <20> datetime
|
||||
* <20> double
|
||||
* <20> float
|
||||
* <20> uint
|
||||
* <20> ulong
|
||||
* <20> time
|
||||
* <20> short
|
||||
* <20> enum
|
||||
* length This is used only when the type is varchar and denotes the length of the string.
|
||||
* The max value is 255.
|
||||
* enumvals This is a list of valid values for an enum separated by "|".
|
||||
* It is used only if the type is <20>enum<75>;
|
||||
* required This field dictates whether it is a required value.
|
||||
* The default value is <20>FALSE<53>.
|
||||
* isPrimary This field identifies the primary key of the table.
|
||||
* If none of the fields have this flag set to <20>TRUE<55>,
|
||||
* the first field definition is assume to be the primary key.
|
||||
* Default value for this field is <20>FALSE<53>.
|
||||
* default This field sets the default value for the field definition.
|
||||
*
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
|
||||
//Technically we can port all the functions in the latest bean to this file
|
||||
// that is what PEAR is doing anyways.
|
||||
|
||||
class MysqlManager extends DBManager
|
||||
{
|
||||
/**
|
||||
* @see DBManager::$dbType
|
||||
*/
|
||||
public $dbType = 'mysql';
|
||||
|
||||
/**
|
||||
* @see DBManager::$backendFunctions
|
||||
*/
|
||||
protected $backendFunctions = array(
|
||||
'free_result' => 'mysql_free_result',
|
||||
'close' => 'mysql_close',
|
||||
'row_count' => 'mysql_num_rows',
|
||||
'affected_row_count' => 'mysql_affected_rows',
|
||||
);
|
||||
|
||||
/**
|
||||
* @see DBManager::checkError()
|
||||
*/
|
||||
public function checkError(
|
||||
$msg = '',
|
||||
$dieOnError = false
|
||||
)
|
||||
{
|
||||
if (parent::checkError($msg, $dieOnError))
|
||||
return true;
|
||||
|
||||
if (mysql_errno($this->getDatabase())) {
|
||||
if ($this->dieOnError || $dieOnError){
|
||||
$GLOBALS['log']->fatal("MySQL error ".mysql_errno($this->database).": ".mysql_error($this->database));
|
||||
sugar_die ($msg."MySQL error ".mysql_errno($this->database).": ".mysql_error($this->database));
|
||||
}
|
||||
else {
|
||||
$this->last_error = $msg."MySQL error ".mysql_errno($this->database).": ".mysql_error($this->database);
|
||||
$GLOBALS['log']->error("MySQL error ".mysql_errno($this->database).": ".mysql_error($this->database));
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and runs queries
|
||||
*
|
||||
* @param string $sql SQL Statement to execute
|
||||
* @param bool $dieOnError True if we want to call die if the query returns errors
|
||||
* @param string $msg Message to log if error occurs
|
||||
* @param bool $suppress Flag to suppress all error output unless in debug logging mode.
|
||||
* @param bool $autofree True if we want to push this result into the $lastResult array.
|
||||
* @return resource result set
|
||||
*/
|
||||
public function query(
|
||||
$sql,
|
||||
$dieOnError = false,
|
||||
$msg = '',
|
||||
$suppress = false,
|
||||
$autofree = false
|
||||
)
|
||||
{
|
||||
parent::countQuery($sql);
|
||||
$GLOBALS['log']->info('Query:' . $sql);
|
||||
$this->checkConnection();
|
||||
//$this->freeResult();
|
||||
$this->query_time = microtime(true);
|
||||
$this->lastsql = $sql;
|
||||
if ($suppress==true) {
|
||||
}
|
||||
else {
|
||||
$result = mysql_query($sql, $this->database);
|
||||
}
|
||||
|
||||
$this->lastmysqlrow = -1;
|
||||
$this->query_time = microtime(true) - $this->query_time;
|
||||
$GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
|
||||
|
||||
|
||||
$this->checkError($msg.' Query Failed:' . $sql . '::', $dieOnError);
|
||||
if($autofree)
|
||||
$this->lastResult[] =& $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::limitQuery()
|
||||
*/
|
||||
public function limitQuery(
|
||||
$sql,
|
||||
$start,
|
||||
$count,
|
||||
$dieOnError = false,
|
||||
$msg = '')
|
||||
{
|
||||
if ($start < 0)
|
||||
$start = 0;
|
||||
$GLOBALS['log']->debug('Limit Query:' . $sql. ' Start: ' .$start . ' count: ' . $count);
|
||||
|
||||
$sql = "$sql LIMIT $start,$count";
|
||||
$this->lastsql = $sql;
|
||||
|
||||
if(!empty($GLOBALS['sugar_config']['check_query'])){
|
||||
$this->checkQuery($sql);
|
||||
}
|
||||
|
||||
return $this->query($sql, $dieOnError, $msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see DBManager::checkQuery()
|
||||
*/
|
||||
protected function checkQuery(
|
||||
$sql
|
||||
)
|
||||
{
|
||||
$result = $this->query('EXPLAIN ' . $sql);
|
||||
$badQuery = array();
|
||||
while ($row = $this->fetchByAssoc($result)) {
|
||||
if (empty($row['table']))
|
||||
continue;
|
||||
$badQuery[$row['table']] = '';
|
||||
if (strtoupper($row['type']) == 'ALL')
|
||||
$badQuery[$row['table']] .= ' Full Table Scan;';
|
||||
if (empty($row['key']))
|
||||
$badQuery[$row['table']] .= ' No Index Key Used;';
|
||||
if (!empty($row['Extra']) && substr_count($row['Extra'], 'Using filesort') > 0)
|
||||
$badQuery[$row['table']] .= ' Using FileSort;';
|
||||
if (!empty($row['Extra']) && substr_count($row['Extra'], 'Using temporary') > 0)
|
||||
$badQuery[$row['table']] .= ' Using Temporary Table;';
|
||||
}
|
||||
|
||||
if ( empty($badQuery) )
|
||||
return true;
|
||||
|
||||
foreach($badQuery as $table=>$data ){
|
||||
if(!empty($data)){
|
||||
$warning = ' Table:' . $table . ' Data:' . $data;
|
||||
if(!empty($GLOBALS['sugar_config']['check_query_log'])){
|
||||
$GLOBALS['log']->fatal($sql);
|
||||
$GLOBALS['log']->fatal('CHECK QUERY:' .$warning);
|
||||
}
|
||||
else{
|
||||
$GLOBALS['log']->warn('CHECK QUERY:' .$warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::describeField()
|
||||
*/
|
||||
protected function describeField(
|
||||
$name,
|
||||
$tablename
|
||||
)
|
||||
{
|
||||
global $table_descriptions;
|
||||
if(isset($table_descriptions[$tablename])
|
||||
&& isset($table_descriptions[$tablename][$name]))
|
||||
return $table_descriptions[$tablename][$name];
|
||||
|
||||
$table_descriptions[$tablename] = array();
|
||||
$sql = "DESCRIBE $tablename";
|
||||
$result = $this->query($sql);
|
||||
while ($row = $this->fetchByAssoc($result) ){
|
||||
$table_descriptions[$tablename][$row['Field']] = $row;
|
||||
if(empty($table_descriptions[$tablename][$row['Field']]['Null']))
|
||||
$table_descriptions[$tablename][$row['Field']]['Null'] = 'NO';
|
||||
}
|
||||
if(isset($table_descriptions[$tablename][$name]))
|
||||
return $table_descriptions[$tablename][$name];
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::getFieldsArray()
|
||||
*/
|
||||
public function getFieldsArray(
|
||||
&$result,
|
||||
$make_lower_case=false)
|
||||
{
|
||||
$field_array = array();
|
||||
|
||||
if(! isset($result) || empty($result))
|
||||
return 0;
|
||||
|
||||
$i = 0;
|
||||
while ($i < mysql_num_fields($result)) {
|
||||
$meta = mysql_fetch_field($result, $i);
|
||||
if (!$meta)
|
||||
return 0;
|
||||
|
||||
if($make_lower_case == true)
|
||||
$meta->name = strtolower($meta->name);
|
||||
|
||||
$field_array[] = $meta->name;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $field_array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see DBManager::fetchByAssoc()
|
||||
*/
|
||||
public function fetchByAssoc(
|
||||
&$result,
|
||||
$rowNum = -1,
|
||||
$encode = true
|
||||
)
|
||||
{
|
||||
if (!$result)
|
||||
return false;
|
||||
|
||||
if ($result && $rowNum > -1){
|
||||
if ($this->getRowCount($result) > $rowNum)
|
||||
mysql_data_seek($result, $rowNum);
|
||||
$this->lastmysqlrow = $rowNum;
|
||||
}
|
||||
|
||||
$row = mysql_fetch_assoc($result);
|
||||
|
||||
if ($encode && $this->encode && is_array($row))
|
||||
return array_map('to_html', $row);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::getTablesArray()
|
||||
*/
|
||||
public function getTablesArray()
|
||||
{
|
||||
global $sugar_config;
|
||||
$GLOBALS['log']->debug('Fetching table list');
|
||||
|
||||
if ($this->getDatabase()) {
|
||||
$tables = array();
|
||||
$r = $this->query('SHOW TABLES');
|
||||
if (is_resource($r) || $r instanceOf mysqli_result ) {
|
||||
while ($a = $this->fetchByAssoc($r)) {
|
||||
$row = array_values($a);
|
||||
$tables[]=$row[0];
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // no database available
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::version()
|
||||
*/
|
||||
public function version()
|
||||
{
|
||||
return $this->getOne("SELECT version() version");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::tableExists()
|
||||
*/
|
||||
public function tableExists(
|
||||
$tableName
|
||||
)
|
||||
{
|
||||
$GLOBALS['log']->info("tableExists: $tableName");
|
||||
|
||||
if ($this->getDatabase()) {
|
||||
$result = $this->query("SHOW TABLES LIKE '".$tableName."'");
|
||||
return ($this->getRowCount($result) == 0) ? false : true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::quote()
|
||||
*/
|
||||
public function quote(
|
||||
$string,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
return mysql_real_escape_string(parent::quote($string), $this->getDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::quoteForEmail()
|
||||
*/
|
||||
public function quoteForEmail(
|
||||
$string,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
return mysql_real_escape_string($string, $this->getDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::connect()
|
||||
*/
|
||||
public function connect(
|
||||
array $configOptions = null,
|
||||
$dieOnError = false
|
||||
)
|
||||
{
|
||||
global $sugar_config;
|
||||
|
||||
if(is_null($configOptions))
|
||||
$configOptions = $sugar_config['dbconfig'];
|
||||
|
||||
if ($sugar_config['dbconfigoption']['persistent'] == true) {
|
||||
$this->database = @mysql_pconnect(
|
||||
$configOptions['db_host_name'],
|
||||
$configOptions['db_user_name'],
|
||||
$configOptions['db_password']
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->database) {
|
||||
$this->database = mysql_connect(
|
||||
$configOptions['db_host_name'],
|
||||
$configOptions['db_user_name'],
|
||||
$configOptions['db_password']
|
||||
)
|
||||
or sugar_die("Could not connect to server ".$configOptions['db_host_name']." as ".
|
||||
$configOptions['db_user_name'].".".mysql_error());
|
||||
// Do not pass connection information because we have not connected yet
|
||||
if($this->database && $sugar_config['dbconfigoption']['persistent'] == true){
|
||||
$_SESSION['administrator_error'] = "<b>Severe Performance Degradation: Persistent Database Connections "
|
||||
. "not working. Please set \$sugar_config['dbconfigoption']['persistent'] to false "
|
||||
. "in your config.php file</b>";
|
||||
}
|
||||
}
|
||||
@mysql_select_db($configOptions['db_name'])
|
||||
or sugar_die( "Unable to select database: " . mysql_error($this->database));
|
||||
|
||||
// cn: using direct calls to prevent this from spamming the Logs
|
||||
$charset = "SET CHARACTER SET utf8";
|
||||
if(isset($sugar_config['dbconfigoption']['collation']) && !empty($sugar_config['dbconfigoption']['collation']))
|
||||
$charset .= " COLLATE {$sugar_config['dbconfigoption']['collation']}";
|
||||
mysql_query($charset, $this->database); // no quotes around "[charset]"
|
||||
mysql_query("SET NAMES 'utf8'", $this->database);
|
||||
|
||||
if($this->checkError('Could Not Connect:', $dieOnError))
|
||||
$GLOBALS['log']->info("connected to db");
|
||||
|
||||
$GLOBALS['log']->info("Connect:".$this->database);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::repairTableParams()
|
||||
*
|
||||
* For MySQL, we can write the ALTER TABLE statement all in one line, which speeds things
|
||||
* up quite a bit. So here, we'll parse the returned SQL into a single ALTER TABLE command.
|
||||
*/
|
||||
public function repairTableParams(
|
||||
$tablename,
|
||||
$fielddefs,
|
||||
$indices,
|
||||
$execute = true,
|
||||
$engine = null
|
||||
)
|
||||
{
|
||||
$sql = parent::repairTableParams($tablename,$fielddefs,$indices,false,$engine);
|
||||
|
||||
if ( $sql == '' )
|
||||
return '';
|
||||
|
||||
if ( stristr($sql,'create table') )
|
||||
{
|
||||
if ($execute) {
|
||||
$msg = "Error creating table: ".$tablename. ":";
|
||||
$this->query($sql,true,$msg);
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// first, parse out all the comments
|
||||
$match = array();
|
||||
preg_match_all("!/\*.*?\*/!is", $sql, $match);
|
||||
$commentBlocks = $match[0];
|
||||
$sql = preg_replace("!/\*.*?\*/!is",'', $sql);
|
||||
|
||||
// now, we should only have alter table statements
|
||||
// let's replace the 'alter table name' part with a comma
|
||||
$sql = preg_replace("!alter table $tablename!is",', ', $sql);
|
||||
|
||||
// re-add it at the beginning
|
||||
$sql = substr_replace($sql,'',strpos($sql,','),1);
|
||||
$sql = str_replace(";","",$sql);
|
||||
$sql = str_replace("\n","",$sql);
|
||||
$sql = "ALTER TABLE $tablename $sql";
|
||||
|
||||
if ( $execute )
|
||||
$this->query($sql,'Error with MySQL repair table');
|
||||
|
||||
// and re-add the comments at the beginning
|
||||
$sql = implode("\n",$commentBlocks) . "\n". $sql . "\n";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::convert()
|
||||
*/
|
||||
public function convert(
|
||||
$string,
|
||||
$type,
|
||||
array $additional_parameters = array(),
|
||||
array $additional_parameters_oracle_only = array()
|
||||
)
|
||||
{
|
||||
// convert the parameters array into a comma delimited string
|
||||
$additional_parameters_string = '';
|
||||
if (!empty($additional_parameters))
|
||||
$additional_parameters_string = ','.implode(',',$additional_parameters);
|
||||
|
||||
switch ($type) {
|
||||
case 'today': return "CURDATE()";
|
||||
case 'left': return "LEFT($string".$additional_parameters_string.")";
|
||||
case 'date_format': return "DATE_FORMAT($string".$additional_parameters_string.")";
|
||||
case 'datetime': return "DATE_FORMAT($string, '%Y-%m-%d %H:%i:%s')";
|
||||
case 'IFNULL': return "IFNULL($string".$additional_parameters_string.")";
|
||||
case 'CONCAT': return "CONCAT($string,".implode(",",$additional_parameters).")";
|
||||
case 'text2char': return "$string";
|
||||
}
|
||||
|
||||
return "$string";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::concat()
|
||||
*/
|
||||
public function concat(
|
||||
$table,
|
||||
array $fields
|
||||
)
|
||||
{
|
||||
$ret = '';
|
||||
|
||||
foreach ( $fields as $index => $field )
|
||||
if (empty($ret))
|
||||
$ret = "CONCAT(". db_convert($table.".".$field,'IFNULL', array("''"));
|
||||
else
|
||||
$ret.= ",' ',".db_convert($table.".".$field,'IFNULL', array("''"));
|
||||
|
||||
if (!empty($ret))
|
||||
$ret .= ')';
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
54
include/database/MysqliHelper.php
Executable file
54
include/database/MysqliHelper.php
Executable file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application specific
|
||||
* to oracle database. It is called by the DBManager class to generate various sql statements.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* Please refer the DBManager documentation for the details.
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
require_once('include/database/MysqlHelper.php');
|
||||
|
||||
class MysqliHelper extends MysqlHelper
|
||||
{
|
||||
}
|
||||
?>
|
||||
326
include/database/MysqliManager.php
Executable file
326
include/database/MysqliManager.php
Executable file
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application.
|
||||
* It acts as the DB abstraction layer for the application. It depends on helper classes
|
||||
* which generate the necessary SQL. This sql is then passed to PEAR DB classes.
|
||||
* The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* The passed bean is passed to helper class which uses these functions to generate correct sql.
|
||||
*
|
||||
* The meta interface has the following functions:
|
||||
* getTableName() Returns table name of the object.
|
||||
* getFieldDefinitions() Returns a collection of field definitions in order.
|
||||
* getFieldDefintion(name) Return field definition for the field.
|
||||
* getFieldValue(name) Returns the value of the field identified by name.
|
||||
* If the field is not set, the function will return boolean FALSE.
|
||||
* getPrimaryFieldDefinition() Returns the field definition for primary key
|
||||
*
|
||||
* The field definition is an array with the following keys:
|
||||
*
|
||||
* name This represents name of the field. This is a required field.
|
||||
* type This represents type of the field. This is a required field and valid values are:
|
||||
* <20> int
|
||||
* <20> long
|
||||
* <20> varchar
|
||||
* <20> text
|
||||
* <20> date
|
||||
* <20> datetime
|
||||
* <20> double
|
||||
* <20> float
|
||||
* <20> uint
|
||||
* <20> ulong
|
||||
* <20> time
|
||||
* <20> short
|
||||
* <20> enum
|
||||
* length This is used only when the type is varchar and denotes the length of the string.
|
||||
* The max value is 255.
|
||||
* enumvals This is a list of valid values for an enum separated by "|".
|
||||
* It is used only if the type is <20>enum<75>;
|
||||
* required This field dictates whether it is a required value.
|
||||
* The default value is <20>FALSE<53>.
|
||||
* isPrimary This field identifies the primary key of the table.
|
||||
* If none of the fields have this flag set to <20>TRUE<55>,
|
||||
* the first field definition is assume to be the primary key.
|
||||
* Default value for this field is <20>FALSE<53>.
|
||||
* default This field sets the default value for the field definition.
|
||||
*
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
|
||||
//Technically we can port all the functions in the latest bean to this file
|
||||
// that is what PEAR is doing anyways.
|
||||
|
||||
require_once('include/database/MysqlManager.php');
|
||||
|
||||
class MysqliManager extends MysqlManager
|
||||
{
|
||||
/**
|
||||
* @see DBManager::$dbType
|
||||
*/
|
||||
public $dbType = 'mysql';
|
||||
|
||||
/**
|
||||
* @see DBManager::$backendFunctions
|
||||
*/
|
||||
protected $backendFunctions = array(
|
||||
'free_result' => 'mysqli_free_result',
|
||||
'close' => 'mysqli_close',
|
||||
'row_count' => 'mysqli_num_rows',
|
||||
'affected_row_count' => 'mysqli_affected_rows',
|
||||
);
|
||||
|
||||
protected $tmp_con;
|
||||
/**
|
||||
* @see DBManager::checkError()
|
||||
*/
|
||||
public function checkError(
|
||||
$msg = '',
|
||||
$dieOnError = false
|
||||
)
|
||||
{
|
||||
if (DBManager::checkError($msg, $dieOnError))
|
||||
return true;
|
||||
|
||||
if (mysqli_errno($this->getDatabase())){
|
||||
if($this->dieOnError || $dieOnError){
|
||||
$GLOBALS['log']->fatal("MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database));
|
||||
sugar_die ($msg."MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database));
|
||||
}
|
||||
else{
|
||||
$this->last_error = $msg."MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database);
|
||||
$GLOBALS['log']->error("MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database));
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MysqlManager::query()
|
||||
*/
|
||||
public function query(
|
||||
$sql,
|
||||
$dieOnError = false,
|
||||
$msg = '',
|
||||
$suppress = false,
|
||||
$autofree = false
|
||||
)
|
||||
{
|
||||
static $queryMD5 = array();
|
||||
parent::countQuery($sql);
|
||||
$GLOBALS['log']->info('Query:' . $sql);
|
||||
$this->checkConnection();
|
||||
//$this->freeResult();
|
||||
$this->query_time = microtime(true);
|
||||
$this->lastsql = $sql;
|
||||
if ($suppress==true){
|
||||
}
|
||||
else {
|
||||
$result = mysqli_query($this->database,$sql);
|
||||
}
|
||||
$md5 = md5($sql);
|
||||
|
||||
if (empty($queryMD5[$md5]))
|
||||
$queryMD5[$md5] = true;
|
||||
|
||||
$this->lastmysqlrow = -1;
|
||||
$this->query_time = microtime(true) - $this->query_time;
|
||||
$GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
|
||||
|
||||
|
||||
$this->checkError($msg.' Query Failed:' . $sql . '::', $dieOnError);
|
||||
if($autofree)
|
||||
$this->lastResult[] =& $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::getFieldsArray()
|
||||
*/
|
||||
public function getFieldsArray(
|
||||
&$result,
|
||||
$make_lower_case = false
|
||||
)
|
||||
{
|
||||
$field_array = array();
|
||||
|
||||
if (!isset($result) || empty($result))
|
||||
return 0;
|
||||
|
||||
$i = 0;
|
||||
while ($i < mysqli_num_fields($result)) {
|
||||
$meta = mysqli_fetch_field_direct($result, $i);
|
||||
if (!$meta)
|
||||
return 0;
|
||||
|
||||
if($make_lower_case == true)
|
||||
$meta->name = strtolower($meta->name);
|
||||
|
||||
$field_array[] = $meta->name;
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $field_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::fetchByAssoc()
|
||||
*/
|
||||
public function fetchByAssoc(
|
||||
&$result,
|
||||
$rowNum = -1,
|
||||
$encode = true
|
||||
)
|
||||
{
|
||||
if (!$result)
|
||||
return false;
|
||||
|
||||
if ($result && $rowNum > -1) {
|
||||
if ($this->getRowCount($result) > $rowNum)
|
||||
mysqli_data_seek($result, $rowNum);
|
||||
$this->lastmysqlrow = $rowNum;
|
||||
}
|
||||
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
|
||||
if ($encode && $this->encode && is_array($row))
|
||||
return array_map('to_html', $row);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::quote()
|
||||
*/
|
||||
public function quote(
|
||||
$string,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
return mysqli_escape_string($this->getDatabase(),DBManager::quote($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::quoteForEmail()
|
||||
*/
|
||||
public function quoteForEmail(
|
||||
$string,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
return mysqli_escape_string($this->getDatabase(),$string);
|
||||
}
|
||||
|
||||
function switchDataBase(){
|
||||
session_start();
|
||||
if($_SESSION['authenticated_user_id']!=''){
|
||||
global $sugar_config;
|
||||
|
||||
$link = mysql_connect($sugar_config['dbconfig']['db_host_name'],$sugar_config['dbconfig']['db_user_name'],$sugar_config['dbconfig']['db_password']);
|
||||
mysql_select_db($sugar_config['dbconfig']['db_name'],$link);
|
||||
$zap=mysql_query("select dbasename from users where id='".$_SESSION['authenticated_user_id']."'",$link);
|
||||
$row=mysql_fetch_array($zap);
|
||||
mysql_close($link);
|
||||
return $row['dbasename'];
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::connect()
|
||||
*/
|
||||
public function connect(
|
||||
array $configOptions = null,
|
||||
$dieOnError = false,
|
||||
$dbase = false
|
||||
)
|
||||
{
|
||||
global $sugar_config;
|
||||
|
||||
if (is_null($configOptions))
|
||||
$configOptions = $sugar_config['dbconfig'];
|
||||
|
||||
if(!isset($this->database)) {
|
||||
|
||||
//mysqli connector has a separate parameter for port.. We need to separate it out from the host name
|
||||
$dbhost=$configOptions['db_host_name'];
|
||||
$dbport=null;
|
||||
$pos=strpos($configOptions['db_host_name'],':');
|
||||
if ($pos !== false) {
|
||||
$dbhost=substr($configOptions['db_host_name'],0,$pos);
|
||||
$dbport=substr($configOptions['db_host_name'],$pos+1);
|
||||
}
|
||||
|
||||
$this->database = mysqli_connect($dbhost,$configOptions['db_user_name'],$configOptions['db_password'],$configOptions['db_name'],$dbport)
|
||||
or sugar_die("Could not connect to server ".$dbhost." as ".$configOptions['db_user_name'].". port " .$dbport . ". " . mysqli_connect_error());
|
||||
}
|
||||
|
||||
if($dbase!=false){
|
||||
@mysqli_select_db($this->database,$dbase)
|
||||
or sugar_die( "Unable to select database: " . mysqli_connect_error());
|
||||
} else {
|
||||
if($this->switchDataBase()!=false){
|
||||
|
||||
@mysqli_select_db($this->database,$this->switchDataBase())
|
||||
or sugar_die( "Unable to select database: " . mysqli_connect_error());
|
||||
} else {
|
||||
@mysqli_select_db($this->database,$configOptions['db_name'])
|
||||
or sugar_die( "Unable to select database: " . mysqli_connect_error());
|
||||
}
|
||||
}
|
||||
|
||||
// cn: using direct calls to prevent this from spamming the Logs
|
||||
mysqli_query($this->database,"SET CHARACTER SET utf8"); // no quotes around "[charset]"
|
||||
mysqli_query($this->database,"SET NAMES 'utf8'");
|
||||
|
||||
if($this->checkError('Could Not Connect:', $dieOnError))
|
||||
$GLOBALS['log']->info("connected to db");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
132
include/database/PearDatabase.php
Executable file
132
include/database/PearDatabase.php
Executable file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once('include/database/DBManager.php');
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class PearDatabase
|
||||
{
|
||||
/**
|
||||
* Returns DBManager instance
|
||||
*
|
||||
* @deprecated
|
||||
* @param string $instanceName optional, name of the instance
|
||||
* @return object DBManager instance
|
||||
*/
|
||||
public static function getInstance($instanceName='')
|
||||
{
|
||||
$GLOBALS['log']->info('call to PearDatabase::getInstance() is deprecated');
|
||||
return DBManagerFactory::getInstance($instanceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted string
|
||||
*
|
||||
* @deprecated
|
||||
* @param string $string
|
||||
* @param bool $isLike optional
|
||||
* @return string
|
||||
*/
|
||||
public static function quote(
|
||||
$string,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
$GLOBALS['log']->info('call to PearDatabase::quote() is deprecated');
|
||||
return $GLOBALS['db']->quote($string, $isLike);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a quoted string for email
|
||||
*
|
||||
* @deprecated
|
||||
* @param string $string
|
||||
* @param bool $isLike optional
|
||||
* @return string
|
||||
*/
|
||||
public static function quoteForEmail(
|
||||
$string,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
$GLOBALS['log']->info('call to PearDatabase::quoteForEmail() is deprecated');
|
||||
return $GLOBALS['db']->quoteForEmail($string, $isLike);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes each string in the given array
|
||||
*
|
||||
* @deprecated
|
||||
* @param array $array
|
||||
* @param bool $isLike optional
|
||||
* @return string
|
||||
*/
|
||||
public static function arrayQuote(
|
||||
array &$array,
|
||||
$isLike = true
|
||||
)
|
||||
{
|
||||
$GLOBALS['log']->info('call to PearDatabase::arrayQuote() is deprecated');
|
||||
return $GLOBALS['db']->arrayQuote($array, $isLike);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a string to a given length
|
||||
*
|
||||
* @deprecated
|
||||
* @param string $string
|
||||
* @param int $len length to trim to
|
||||
* @param string
|
||||
*/
|
||||
public static function truncate(
|
||||
$string,
|
||||
$len
|
||||
)
|
||||
{
|
||||
$GLOBALS['log']->info('call to PearDatabase::truncate() is deprecated');
|
||||
if ( is_numeric($len) && $len > 0 )
|
||||
$string=mb_substr($string,0,(int) $len);
|
||||
return $string;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
128
include/database/SqlsrvHelper.php
Executable file
128
include/database/SqlsrvHelper.php
Executable file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application specific
|
||||
* to SQL Server database using the php_sqlsrv extension. It is called by the DBManager class to generate various sql statements.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* Please refer the DBManager documentation for the details.
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
require_once('include/database/MssqlHelper.php');
|
||||
|
||||
class SqlsrvHelper extends MssqlHelper
|
||||
{
|
||||
/**
|
||||
* @see DBHelper::getColumnType()
|
||||
*/
|
||||
public function getColumnType(
|
||||
$type,
|
||||
$name = '',
|
||||
$table = ''
|
||||
)
|
||||
{
|
||||
$columnType = parent::getColumnType($type,$name,$table);
|
||||
|
||||
if ( in_array($columnType,array('char','varchar')) && !preg_match('/(_id$|^id$)/', $name))
|
||||
$columnType = 'n'.$columnType;
|
||||
|
||||
return $columnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBHelper::massageValue()
|
||||
*/
|
||||
public function massageValue(
|
||||
$val,
|
||||
$fieldDef
|
||||
)
|
||||
{
|
||||
$type = $this->getFieldType($fieldDef);
|
||||
|
||||
switch ($type) {
|
||||
case 'int':
|
||||
case 'double':
|
||||
case 'float':
|
||||
case 'uint':
|
||||
case 'ulong':
|
||||
case 'long':
|
||||
case 'short':
|
||||
case 'tinyint':
|
||||
return $val;
|
||||
break;
|
||||
}
|
||||
|
||||
$qval = $this->quote($val);
|
||||
|
||||
switch ($type) {
|
||||
case 'varchar':
|
||||
case 'nvarchar':
|
||||
case 'char':
|
||||
case 'nchar':
|
||||
case 'enum':
|
||||
case 'multienum':
|
||||
case 'id':
|
||||
return $qval;
|
||||
break;
|
||||
case 'date':
|
||||
return "$qval";
|
||||
break;
|
||||
case 'datetime':
|
||||
return $qval;
|
||||
break;
|
||||
case 'time':
|
||||
return "$qval";
|
||||
break;
|
||||
case 'text':
|
||||
case 'ntext':
|
||||
case 'blob':
|
||||
case 'longblob':
|
||||
case 'clob':
|
||||
case 'longtext':
|
||||
case 'image':
|
||||
return $qval;
|
||||
break;
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
?>
|
||||
495
include/database/SqlsrvManager.php
Executable file
495
include/database/SqlsrvManager.php
Executable file
@@ -0,0 +1,495 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
/*********************************************************************************
|
||||
|
||||
* Description: This file handles the Data base functionality for the application.
|
||||
* It acts as the DB abstraction layer for the application. It depends on helper classes
|
||||
* which generate the necessary SQL. This sql is then passed to PEAR DB classes.
|
||||
* The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php.
|
||||
*
|
||||
* All the functions in this class will work with any bean which implements the meta interface.
|
||||
* The passed bean is passed to helper class which uses these functions to generate correct sql.
|
||||
*
|
||||
* The meta interface has the following functions:
|
||||
* getTableName() Returns table name of the object.
|
||||
* getFieldDefinitions() Returns a collection of field definitions in order.
|
||||
* getFieldDefintion(name) Return field definition for the field.
|
||||
* getFieldValue(name) Returns the value of the field identified by name.
|
||||
* If the field is not set, the function will return boolean FALSE.
|
||||
* getPrimaryFieldDefinition() Returns the field definition for primary key
|
||||
*
|
||||
* The field definition is an array with the following keys:
|
||||
*
|
||||
* name This represents name of the field. This is a required field.
|
||||
* type This represents type of the field. This is a required field and valid values are:
|
||||
* int
|
||||
* long
|
||||
* varchar
|
||||
* text
|
||||
* date
|
||||
* datetime
|
||||
* double
|
||||
* float
|
||||
* uint
|
||||
* ulong
|
||||
* time
|
||||
* short
|
||||
* enum
|
||||
* length This is used only when the type is varchar and denotes the length of the string.
|
||||
* The max value is 255.
|
||||
* enumvals This is a list of valid values for an enum separated by "|".
|
||||
* It is used only if the type is ?enum?;
|
||||
* required This field dictates whether it is a required value.
|
||||
* The default value is ?FALSE?.
|
||||
* isPrimary This field identifies the primary key of the table.
|
||||
* If none of the fields have this flag set to ?TRUE?,
|
||||
* the first field definition is assume to be the primary key.
|
||||
* Default value for this field is ?FALSE?.
|
||||
* default This field sets the default value for the field definition.
|
||||
*
|
||||
*
|
||||
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________..
|
||||
********************************************************************************/
|
||||
|
||||
include_once('include/database/MssqlManager.php');
|
||||
|
||||
class SqlsrvManager extends MssqlManager
|
||||
{
|
||||
/**
|
||||
* @see DBManager::$backendFunctions
|
||||
*/
|
||||
protected $backendFunctions = array(
|
||||
'free_result' => 'sqlsrv_free_stmt',
|
||||
'close' => 'sqlsrv_close',
|
||||
);
|
||||
|
||||
/**
|
||||
* cache of the results sets as they are fetched
|
||||
*/
|
||||
protected $_resultsCache;
|
||||
|
||||
/**
|
||||
* cache of the results sets as they are fetched
|
||||
*/
|
||||
protected $_lastResultsCacheKey = 0;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->_resultsCache = new ArrayObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::connect()
|
||||
*/
|
||||
public function connect(
|
||||
array $configOptions = null,
|
||||
$dieOnError = false
|
||||
)
|
||||
{
|
||||
global $sugar_config;
|
||||
|
||||
if (is_null($configOptions))
|
||||
$configOptions = $sugar_config['dbconfig'];
|
||||
|
||||
//set the connections parameters
|
||||
$connect_param = '';
|
||||
$configOptions['db_host_instance'] = trim($configOptions['db_host_instance']);
|
||||
if (empty($configOptions['db_host_instance']))
|
||||
$connect_param = $configOptions['db_host_name'];
|
||||
else
|
||||
$connect_param = $configOptions['db_host_name']."\\".$configOptions['db_host_instance'];
|
||||
|
||||
/*
|
||||
* Don't try to specifically use a persistent connection
|
||||
* since the driver will handle that for us
|
||||
*/
|
||||
$this->database = sqlsrv_connect(
|
||||
$connect_param ,
|
||||
array(
|
||||
"UID" => $configOptions['db_user_name'],
|
||||
"PWD" => $configOptions['db_password'],
|
||||
"Database" => $configOptions['db_name'],
|
||||
"CharacterSet" => "UTF-8",
|
||||
"ReturnDatesAsStrings" => true,
|
||||
"MultipleActiveResultSets" => false,
|
||||
)
|
||||
)
|
||||
or sugar_die("Could not connect to server ".$configOptions['db_host_name'].
|
||||
" as ".$configOptions['db_user_name'].".");
|
||||
|
||||
//make sure connection exists
|
||||
if(!$this->database){
|
||||
sugar_die("Unable to establish connection");
|
||||
}
|
||||
|
||||
if($this->checkError('Could Not Connect:', $dieOnError))
|
||||
$GLOBALS['log']->info("connected to db");
|
||||
|
||||
$GLOBALS['log']->info("Connect:".$this->database);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::checkError()
|
||||
*/
|
||||
public function checkError(
|
||||
$msg = '',
|
||||
$dieOnError = false
|
||||
)
|
||||
{
|
||||
if (DBManager::checkError($msg, $dieOnError))
|
||||
return true;
|
||||
|
||||
$sqlmsg = $this->_getLastErrorMessages();
|
||||
$sqlpos = strpos($sqlmsg, 'Changed database context to');
|
||||
if ( $sqlpos !== false )
|
||||
$sqlmsg = ''; // empty out sqlmsg if its 'Changed database context to'
|
||||
else {
|
||||
global $app_strings;
|
||||
//ERR_MSSQL_DB_CONTEXT: localized version of 'Changed database context to' message
|
||||
if (empty($app_strings)
|
||||
or !isset($app_strings['ERR_MSSQL_DB_CONTEXT'])
|
||||
or !isset($app_strings['ERR_MSSQL_WARNING']) ) {
|
||||
//ignore the message from sql-server if $app_strings array is empty. This will happen
|
||||
//only if connection if made before languge is set.
|
||||
$GLOBALS['log']->debug("Ignoring this database message: " . $sqlmsg);
|
||||
$sqlmsg = '';
|
||||
}
|
||||
else {
|
||||
$sqlpos = strpos($sqlmsg, $app_strings['ERR_MSSQL_DB_CONTEXT']);
|
||||
$sqlpos2 = strpos($sqlmsg, $app_strings['ERR_MSSQL_WARNING']);
|
||||
if ( $sqlpos !== false || $sqlpos2 !== false)
|
||||
$sqlmsg = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ( strlen($sqlmsg) > 2 ) {
|
||||
$GLOBALS['log']->fatal("SQL Server error: " . $sqlmsg);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::query()
|
||||
*/
|
||||
public function query(
|
||||
$sql,
|
||||
$dieOnError = false,
|
||||
$msg = '',
|
||||
$suppress = false
|
||||
)
|
||||
{
|
||||
global $app_strings;
|
||||
|
||||
// Flag if there are odd number of single quotes
|
||||
if ((substr_count($sql, "'") & 1))
|
||||
$GLOBALS['log']->error("SQL statement[" . $sql . "] has odd number of single quotes.");
|
||||
|
||||
$sql = $this->_appendN($sql);
|
||||
|
||||
$this->countQuery($sql);
|
||||
$GLOBALS['log']->fatal('Query:' . $sql);
|
||||
$this->checkConnection();
|
||||
$this->query_time = microtime(true);
|
||||
|
||||
if ($suppress) {
|
||||
}
|
||||
else {
|
||||
$result = @sqlsrv_query($this->database, $sql);
|
||||
}
|
||||
// the sqlsrv driver will sometimes return false from sqlsrv_query()
|
||||
// on delete queries, so we'll also check to see if we get an error
|
||||
// message as well.
|
||||
// see this forum post for more info
|
||||
// http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3685918&SiteID=1
|
||||
if (!$result && ( $this->_getLastErrorMessages() != '' ) ) {
|
||||
// awu Bug 10657: ignoring mssql error message 'Changed database context to' - an intermittent
|
||||
// and difficult to reproduce error. The message is only a warning, and does
|
||||
// not affect the functionality of the query
|
||||
|
||||
$sqlmsg = $this->_getLastErrorMessages();
|
||||
$sqlpos = strpos($sqlmsg, 'Changed database context to');
|
||||
$sqlpos2 = strpos($sqlmsg, 'Warning:');
|
||||
|
||||
if ($sqlpos !== false || $sqlpos2 !== false) // if sqlmsg has 'Changed database context to', just log it
|
||||
$GLOBALS['log']->debug($sqlmsg . ": " . $sql );
|
||||
else {
|
||||
$GLOBALS['log']->fatal($sqlmsg . ": " . $sql );
|
||||
if($dieOnError)
|
||||
sugar_die('SQL Error : ' . $sqlmsg);
|
||||
else
|
||||
echo 'SQL Error : ' . $sqlmsg;
|
||||
}
|
||||
}
|
||||
$this->lastmysqlrow = -1;
|
||||
|
||||
$this->query_time = microtime(true) - $this->query_time;
|
||||
$GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
|
||||
|
||||
|
||||
$this->checkError($msg.' Query Failed:' . $sql . '::', $dieOnError);
|
||||
|
||||
// fetch all the returned rows into an the resultsCache
|
||||
if ( is_resource($result) ) {
|
||||
$i = 0;
|
||||
while ( $row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC) )
|
||||
$this->_resultsCache[$this->_lastResultsCacheKey][$i++] = $row;
|
||||
|
||||
sqlsrv_free_stmt($result);
|
||||
|
||||
return $this->_lastResultsCacheKey++;
|
||||
}
|
||||
else
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::getFieldsArray()
|
||||
*/
|
||||
public function getFieldsArray(
|
||||
&$result,
|
||||
$make_lower_case = false
|
||||
)
|
||||
{
|
||||
$field_array = array();
|
||||
|
||||
if ( !is_int($result) || !isset($this->_resultsCache[$result]) )
|
||||
return false;
|
||||
|
||||
foreach ( $this->_resultsCache[$result][0] as $key => $value ) {
|
||||
if($make_lower_case==true)
|
||||
$key = strtolower($key);
|
||||
|
||||
$field_array[] = $key;
|
||||
}
|
||||
|
||||
return $field_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::fetchByAssoc()
|
||||
*/
|
||||
public function fetchByAssoc(
|
||||
&$result,
|
||||
$rowNum = -1,
|
||||
$encode = true
|
||||
)
|
||||
{
|
||||
static $last_returned_result = array();
|
||||
|
||||
if ( !is_int($result) || !isset($this->_resultsCache[$result]) )
|
||||
return false;
|
||||
|
||||
if ( !isset($last_returned_result[$result]) )
|
||||
$last_returned_result[$result] = 0;
|
||||
|
||||
if ( !isset($this->_resultsCache[$result][$last_returned_result[$result]]) ) {
|
||||
$this->_resultsCache[$result] = null;
|
||||
unset($this->_resultsCache[$result]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = $this->_resultsCache[$result][$last_returned_result[$result]];
|
||||
if ( $last_returned_result[$result] >= count($this->_resultsCache[$result]) ) {
|
||||
$this->_resultsCache[$result] = null;
|
||||
unset($this->_resultsCache[$result]);
|
||||
}
|
||||
$last_returned_result[$result]++;
|
||||
//MSSQL returns a space " " when a varchar column is empty ("") and not null.
|
||||
//We need to iterate through the returned row array and strip empty spaces
|
||||
if(!empty($row)){
|
||||
foreach($row as $key => $column) {
|
||||
//notice we only strip if one space is returned. we do not want to strip
|
||||
//strings with intentional spaces (" foo ")
|
||||
if (!empty($column) && $column ==" ") {
|
||||
$row[$key] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($encode && $this->encode&& is_array($row))
|
||||
return array_map('to_html', $row);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::getRowCount()
|
||||
*/
|
||||
public function getRowCount(
|
||||
&$result
|
||||
)
|
||||
{
|
||||
return $this->getOne('SELECT @@ROWCOUNT');
|
||||
}
|
||||
|
||||
/**
|
||||
* Have this function always return true, since the result is already freed
|
||||
*
|
||||
* @see DBManager::freeResult()
|
||||
*/
|
||||
protected function freeResult(
|
||||
$result = false
|
||||
)
|
||||
{
|
||||
if ( is_int($result) && isset($this->_resultsCache[$result]) )
|
||||
unset($this->_resultsCache[$result]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulates old mssql_get_last_message() behavior, giving us any error messages from the previous
|
||||
* function call
|
||||
*
|
||||
* @return string error message(s)
|
||||
*/
|
||||
private function _getLastErrorMessages()
|
||||
{
|
||||
$message = '';
|
||||
|
||||
if ( ($errors = sqlsrv_errors()) != null)
|
||||
foreach ( $errors as $error )
|
||||
$message .= $error['message'] . '. ';
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DBManager::convert()
|
||||
*/
|
||||
public function convert(
|
||||
$string,
|
||||
$type,
|
||||
array $additional_parameters = array(),
|
||||
array $additional_parameters_oracle_only = array()
|
||||
)
|
||||
{
|
||||
if ( $type == 'datetime')
|
||||
return "CONVERT(varchar(25)," . $string . ",120)";
|
||||
else
|
||||
return parent::convert($string, $type, $additional_parameters, $additional_parameters_oracle_only);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a utility function to prepend the "N" character in front of SQL values that are
|
||||
* surrounded by single quotes.
|
||||
*
|
||||
* @param $sql string SQL statement
|
||||
* @return string SQL statement with single quote values prepended with "N" character for nvarchar columns
|
||||
*/
|
||||
private function _appendN(
|
||||
$sql
|
||||
)
|
||||
{
|
||||
// If there are no single quotes, don't bother, will just assume there is no character data
|
||||
if (strpos($sql, "'") === false)
|
||||
return $sql;
|
||||
|
||||
// Flag if there are odd number of single quotes, just continue w/o trying to append N
|
||||
if ((substr_count($sql, "'") & 1)) {
|
||||
$GLOBALS['log']->error("SQL statement[" . $sql . "] has odd number of single quotes.");
|
||||
return $sql;
|
||||
}
|
||||
|
||||
//The only location of three subsequent ' will be at the begning or end of a value.
|
||||
$sql = preg_replace('/(?<!\')(\'{3})(?!\')/', "'<@#@#@PAIR@#@#@>", $sql);
|
||||
|
||||
// Remove any remaining '' and do not parse... replace later (hopefully we don't even have any)
|
||||
$pairs = array();
|
||||
$regexp = '/(\'{2})/';
|
||||
$pair_matches = array();
|
||||
preg_match_all($regexp, $sql, $pair_matches);
|
||||
if ($pair_matches) {
|
||||
foreach (array_unique($pair_matches[0]) as $key=>$value) {
|
||||
$pairs['<@PAIR-'.$key.'@>'] = $value;
|
||||
}
|
||||
if (!empty($pairs)) {
|
||||
$sql = str_replace($pairs, array_keys($pairs), $sql);
|
||||
}
|
||||
}
|
||||
|
||||
$regexp = "/(N?\'.+?\')/is";
|
||||
$matches = array();
|
||||
preg_match_all($regexp, $sql, $matches);
|
||||
$replace = array();
|
||||
if (!empty($matches)) {
|
||||
foreach ($matches[0] as $key=>$value) {
|
||||
// We are assuming that all nvarchar columns are no more than 200 characters in length
|
||||
// One problem we face is the image column type in reports which cannot accept nvarchar data
|
||||
if (!empty($value) && !is_numeric(trim(str_replace(array("'", ","), "", $value))) && !preg_match('/^\'[\,]\'$/', $value)) {
|
||||
$replace[$value] = 'N' . trim($value, "N");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($replace))
|
||||
$sql = str_replace(array_keys($replace), $replace, $sql);
|
||||
|
||||
if (!empty($pairs))
|
||||
$sql = str_replace(array_keys($pairs), $pairs, $sql);
|
||||
|
||||
if(strpos($sql, "<@#@#@PAIR@#@#@>"))
|
||||
$sql = str_replace(array('<@#@#@PAIR@#@#@>'), array("''"), $sql);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two vardefs. Overriding 39098 due to bug: 39098 . IN 6.0 we changed the id columns to dbType = 'id'
|
||||
* for example emails_beans. In 554 the field email_id was nvarchar but in 6.0 since it id dbType = 'id' we would want to alter
|
||||
* it to varchar. This code will prevent it.
|
||||
*
|
||||
* @param array $fielddef1
|
||||
* @param array $fielddef2
|
||||
* @return bool true if they match, false if they don't
|
||||
*/
|
||||
public function compareVarDefs($fielddef1,$fielddef2)
|
||||
{
|
||||
if((isset($fielddef2['dbType']) && $fielddef2['dbType'] == 'id') || preg_match('/(_id$|^id$)/', $fielddef2['name'])){
|
||||
if(isset($fielddef1['type']) && isset($fielddef2['type'])){
|
||||
$fielddef2['type'] = $fielddef1['type'];
|
||||
}
|
||||
}
|
||||
return parent::compareVarDefs($fielddef1, $fielddef2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user