getTableName();
$fieldDefs = $bean->getFieldDefinitions();
$indices = $bean->getIndices();
return $this->createTableSQLParams($tablename, $fieldDefs, $indices);
}
/**
* Generates sql for create table statement for a bean.
*
* @param string $tablename
* @param array $fieldDefs
* @param array $indices
* @param string $engine
* @return string SQL Create Table statement
*/
public function createTableSQLParams(
$tablename,
$fieldDefs,
$indices,
$engine = null
)
{
$columns = $this->columnSQLRep($fieldDefs, false, $tablename);
if (empty($columns))
return false;
$keys = $this->keysSQL($indices);
if (!empty($keys))
$keys = ",$keys";
// cn: bug 9873 - module tables do not get created in utf8 with assoc collation
return "CREATE TABLE $tablename ($columns $keys) CHARACTER SET utf8 COLLATE utf8_general_ci";
}
/**
* Generates SQL for insert statement.
*
* @param object $bean SugarBean instance
* @return string SQL Create Table statement
*/
public function insertSQL(
SugarBean $bean
)
{
// get column names and values
$values = array();
foreach ($bean->getFieldDefinitions() as $fieldDef)
{
if (isset($fieldDef['source']) && $fieldDef['source'] != 'db')
continue;
$val = $bean->getFieldValue($fieldDef['name']);
// clean the incoming value..
$val = from_html($val);
if (strlen($val) <= 0) {
if(isset($fieldDef['default']) && (strlen($fieldDef['default']) > 0))
$val = $fieldDef['default'];
else
$val = null;
}
//handle auto increment values here only need to do this on insert not create
if (isset($fieldDef['auto_increment']) && $fieldDef['auto_increment']) {
$values[$fieldDef['name']] =
$this->getAutoIncrementSQL($bean->getTableName(), $fieldDef['name']);
}
elseif (isset($bean->$fieldDef['name'])) {
// need to do some thing about types of values
$values[$fieldDef['name']] = $this->massageValue($val, $fieldDef);
}
elseif ($fieldDef['name'] == 'deleted'){
$values['deleted'] = $val;
}
}
if ( sizeof($values) == 0 )
return ""; // no columns set
// get the entire sql
return "INSERT INTO ".$bean->getTableName()."
(".implode(",", array_keys($values)).")
VALUES (".implode(",", $values).")";
}
/**
* Generates SQL for update statement.
*
* @param object $bean SugarBean instance
* @param array $where Optional, where conditions in an array
* @return string SQL Create Table statement
*/
public function updateSQL(
SugarBean $bean,
array $where = array()
)
{
$primaryField = $bean->getPrimaryFieldDefinition();
$columns = array();
// get column names and values
foreach ($bean->getFieldDefinitions() as $field => $fieldDef) {
// Do not write out the id field on the update statement.
// We are not allowed to change ids.
if ($fieldDef['name'] == $primaryField['name'])
continue;
// If the field is an auto_increment field, then we shouldn't be setting it. This was added
// specially for Bugs and Cases which have a number associated with them.
if (isset($bean->field_name_map[$field]['auto_increment']) &&
$bean->field_name_map[$field]['auto_increment'] == true)
continue;
//custom fields handle their save seperatley
if(isset($bean->field_name_map) && !empty($bean->field_name_map[$field]['custom_type']))
continue;
if (isset($bean->$fieldDef['name'])
&& (!isset($fieldDef['source']) || $fieldDef['source'] == 'db')) {
$val = $bean->getFieldValue($fieldDef['name']);
// clean the incoming value..
$val = from_html($val);
// need to do some thing about types of values
if (strlen($val) <= 0)
$columns[] = "{$fieldDef['name']}=null";
else
$columns[] = "{$fieldDef['name']}=".$this->massageValue($val, $fieldDef);
}
}
if ( sizeof($columns) == 0 )
return ""; // no columns set
// build where clause
$where = $this->updateWhereArray($bean, $where);
$where = $this->getWhereClause($bean, $where);
return "update ".$bean->getTableName()."
set ".implode(",", $columns)."
$where and deleted=0";
}
/**
* This method returns a where array so that it has id entry if
* where is not an array or is empty
*
* @param object $bean SugarBean instance
* @param array $where Optional, where conditions in an array
* @return array
*/
protected function updateWhereArray(
SugarBean $bean,
array $where = array()
)
{
if (sizeof($where) == 0) {
$fieldDef = $bean->getPrimaryFieldDefinition();
$primaryColumn = $fieldDef['name'];
$val = $bean->getFieldValue($fieldDef['name']);
if ($val != FALSE){
$where[$primaryColumn] = $val;
}
}
return $where;
}
/**
* Returns a where clause without the 'where' key word
*
* The clause returned does not have an 'and' at the beginning and the columns
* are joined by 'and'.
*
* @param string $table table name
* @param array $whereArray Optional, where conditions in an array
* @return string
*/
protected function getColumnWhereClause(
$table,
array $whereArray = array()
)
{
foreach ($whereArray as $name => $val) {
$op = "=";
if (is_array($val)) {
$op = "IN";
$temp = array();
foreach ($val as $tval){
$temp[] = "'$tval'";
}
$val = implode(",", $temp);
$val = "($val)";
}
else
$val = "'$val'";
$where[] = " $table.$name $op $val";
}
if (is_array($where))
$where = implode(" and ", $where);
return $where;
}
/**
* This method returns a complete where clause built from the
* where values specified.
*
* @param string $table table name
* @param array $whereArray Optional, where conditions in an array
* @return string
*/
protected function getWhereClause(
SugarBean $bean,
array $whereArray
)
{
return " where " . $this->getColumnWhereClause($bean->getTableName(), $whereArray);
}
/**
* Designed to take an SQL statement and produce a list of fields used in that select
* @param String $selectStatement
*/
public function getSelectFieldsFromQuery($selectStatement)
{
$selectStatement = trim($selectStatement);
if (strtoupper(substr($selectStatement, 0, 6)) == "SELECT")
$selectStatement = trim(substr($selectStatement, 6));
//Due to sql functions existing in many selects, we can't use php explode
$fields = array();
$level = 0;
$selectField = "";
$strLen = strlen($selectStatement);
for($i = 0; $i < $strLen; $i++)
{
$char = $selectStatement[$i];
if ($char == "," && $level == 0)
{
$field = $this->getFieldNameFromSelect(trim($selectField));
$fields[$field] = $selectField;
$selectField = "";
}
else if ($char == "("){
$level++;
$selectField .= $char;
}
else if($char == ")"){
$level--;
$selectField .= $char;
}else{
$selectField .= $char;
}
}
$fields[$this->getFieldNameFromSelect($selectField)] = $selectField;
return $fields;
}
/**
* returns the field name used in a select
* @param String $string
*/
protected function getFieldNameFromSelect($string)
{
if(strncasecmp($string, "DISTINCT ", 9) == 0) {
$string = substr($string, 9);
}
if (stripos($string, " as ") !== false)
//"as" used for an alias
return trim(substr($string, strripos($string, " as ") + 4));
else if (strrpos($string, " ") != 0)
//Space used as a delimeter for an alias
return trim(substr($string, strrpos($string, " ")));
else if (strpos($string, ".") !== false)
//No alias, but a table.field format was used
return substr($string, strpos($string, ".") + 1);
else
//Give up and assume the whole thing is the field name
return $string;
}
/**
* Generates SQL for delete statement identified by id.
*
* @param object $bean SugarBean instance
* @param array $where where conditions in an array
* @return string SQL Update Statement
*/
public function deleteSQL(
SugarBean $bean,
array $where
)
{
$where = $this->updateWhereArray($bean, $where);
$where = $this->getWhereClause($bean, $where);
return "update ".$bean->getTableName()." set deleted=1 $where";
}
/**
* Generates SQL for select statement for any bean identified by id.
*
* @param object $bean SugarBean instance
* @param array $where where conditions in an array
* @return string SQL Select Statement
*/
public function retrieveSQL(
SugarBean $bean,
array $where
)
{
$where = $this->updateWhereArray($bean, $where);
$where = $this->getWhereClause($bean, $where);
return "select * from ".$bean->getTableName()." $where and deleted=0";
}
/**
* This method implements a generic sql for a collection of beans.
*
* Currently, this function does not support outer joins.
*
* @param array $bean value returned by get_class method as the keys and a bean as
* the value for that key. These beans will be joined in the sql by the key
* attribute of field defs.
* @param array $cols Optional, columns to be returned with the keys as names of bean
* as identified by get_class of bean. Values of this array is the array of fieldDefs
* to be returned for a bean. If an empty array is passed, all columns are selected.
* @param array $whereClause Optional, values with the keys as names of bean as identified
* by get_class of bean. Each value at the first level is an array of values for that
* bean identified by name of fields. If we want to pass multiple values for a name,
* pass it as an array. If where is not passed, all the rows will be returned.
* @return string SQL Select Statement
*/
public function retrieveViewSQL(
array $beans,
array $cols = array(),
array $whereClause = array()
)
{
$relations = array(); // stores relations between tables as they are discovered
foreach ($beans as $beanID => $bean) {
$tableName = $bean->getTableName();
$beanTables[$beanID] = $tableName;
$table = "$beanID";
$tables[$table] = $tableName;
$aliases[$tableName][] = $table;
// build part of select for this table
if (is_array($cols[$beanID]))
foreach ($cols[$beanID] as $def) $select[] = $table.".".$def['name'];
// build part of where clause
if (is_array($whereClause[$beanID])){
$where[] = $this->getColumnWhereClause($table, $whereClause[$beanID]);
}
// initialize so that it can be used properly in form clause generation
$table_used_in_from[$table] = false;
$indices = $bean->getIndices();
foreach ($indices as $index){
if ($index['type'] == 'foreign') {
$relationship[$table][] = array('foreignTable'=> $index['foreignTable']
,'foreignColumn'=>$index['foreignField']
,'localColumn'=> $index['fields']
);
}
}
$where[] = " $table.deleted = 0";
}
// join these clauses
$select = (sizeof($select) > 0) ? implode(",", $select) : "*";
$where = implode(" and ", $where);
// generate the from clause. Use relations array to generate outer joins
// all the rest of the tables will be used as a simple from
// relations table define relations between table1 and table2 through column on table 1
// table2 is assumed to joing through primaty key called id
$separator = "";
foreach ($relations as $table1 => $rightsidearray){
if ($table_used_in_from[$table1]) continue; // table has been joined
$from .= $separator." ".$table1;
$table_used_in_from[$table1] = true;
foreach ($rightsidearray as $tablearray){
$table2 = $tablearray['foreignTable']; // get foreign table
$tableAlias = $aliases[$table2]; // get a list of aliases fo thtis table
foreach ($tableAlias as $table2) {
//choose first alias that does not match
// we are doing this because of self joins.
// in case of self joins, the same table will bave many aliases.
if ($table2 != $table1) break;
}
$col = $tablearray['foreingColumn'];
$name = $tablearray['localColumn'];
$from .= " LEFT JOIN $table on ($table1.$name = $table2.$col)";
$table_used_in_from[$table2] = true;
}
$separator = ",";
}
return "select $select from $from where $where";
}
/**
* Generates SQL for create index statement for a bean.
*
* @param object $bean SugarBean instance
* @param array $fields fields used in the index
* @param string $name index name
* @param bool $unique Optional, set to true if this is an unique index
* @return string SQL Select Statement
*/
public function createIndexSQL(
SugarBean $bean,
array $fields,
$name,
$unique = TRUE
)
{
$unique = ($unique) ? "unique" : "";
$tablename = $bean->getTableName();
// get column names
foreach ($fields as $fieldDef)
$columns[] = $fieldDef['name'];
if (sizeof($columns) == 0)
return "";
$columns = implode(",", $columns);
return "create $unique index $name on $tablename ($columns)";
}
/**
* Returns the type of the variable in the field
*
* @param array $fieldDef
* @return string
*/
public function getFieldType(
$fieldDef
)
{
// get the type for db type. if that is not set,
// get it from type. This is done so that
// we do not have change a lot of existing code
// and add dbtype where type is being used for some special
// purposes like referring to foreign table etc.
if(!empty($fieldDef['dbType']))
return $fieldDef['dbType'];
if(!empty($fieldDef['dbtype']))
return $fieldDef['dbtype'];
if (!empty($fieldDef['type']))
return $fieldDef['type'];
if (!empty($fieldDef['Type']))
return $fieldDef['Type'];
if (!empty($fieldDef['data_type']))
return $fieldDef['data_type'];
return null;
}
/**
* Returns the defintion for a single column
*
* @param array $fieldDef
* @param bool $ignoreRequired Optional, true if we should ignor this being a required field
* @param string $table Optional, table name
* @param bool $return_as_array Optional, true if we should return the result as an array instead of sql
* @return string or array if $return_as_array is true
*/
protected function oneColumnSQLRep(
$fieldDef,
$ignoreRequired = false,
$table = '',
$return_as_array = false
)
{
$name = $fieldDef['name'];
$type = $this->getFieldType($fieldDef);
$colType = $this->getColumnType($type, $name, $table);
if (( $colType == 'nvarchar'
or $colType == 'nchar'
or $colType == 'varchar'
or $colType == 'char'
or $colType == 'varchar2') ) {
if( !empty($fieldDef['len']))
$colType .= "(".$fieldDef['len'].")";
else
$colType .= "(255)";
}
if($colType == 'decimal' || $colType == 'float'){
if(!empty($fieldDef ['len'])){
if(!empty($fieldDef['precision']) && is_numeric($fieldDef['precision']))
if(strpos($fieldDef ['len'],',') === false){
$colType .= "(".$fieldDef['len'].",".$fieldDef['precision'].")";
}else{
$colType .= "(".$fieldDef['len'].")";
}
else
$colType .= "(".$fieldDef['len'].")";
}
}
if (isset($fieldDef['default']) && strlen($fieldDef['default']) > 0)
$default = " DEFAULT '".$fieldDef['default']."'";
elseif (!isset($default) && $type == 'bool')
$default = " DEFAULT 0 ";
elseif (!isset($default))
$default = '';
$auto_increment = '';
if(!empty($fieldDef['auto_increment']) && $fieldDef['auto_increment'])
$auto_increment = $this->setAutoIncrement($table , $fieldDef['name']);
$required = 'NULL'; // MySQL defaults to NULL, SQL Server defaults to NOT NULL -- must specify
//Starting in 6.0, only ID and auto_increment fields will be NOT NULL in the DB.
if ((empty($fieldDef['isnull']) || strtolower($fieldDef['isnull']) == 'false') &&
(!empty($auto_increment) || $name == 'id' || ($fieldDef['type'] == 'id' && isset($fieldDef['required']) && $fieldDef['required'])))
{
$required = "NOT NULL";
}
if ($ignoreRequired)
$required = "";
if ( $return_as_array )
return array(
'name' => $name,
'colType' => $colType,
'default' => $default,
'required' => $required,
'auto_increment' => $auto_increment,
'full' => "$name $colType $default $required $auto_increment",
);
else
return "$name $colType $default $required $auto_increment";
}
/**
* Returns SQL defintions for all columns in a table
*
* @param array $fieldDefs
* @param bool $ignoreRequired Optional, true if we should ignor this being a required field
* @param string $tablename Optional, table name
* @return string SQL column definitions
*/
protected function columnSQLRep(
$fieldDefs,
$ignoreRequired = false,
$tablename
)
{
$columns = array();
if ($this->isFieldArray($fieldDefs)) {
foreach ($fieldDefs as $fieldDef) {
if(!isset($fieldDef['source']) || $fieldDef['source'] == 'db') {
$columns[] = $this->oneColumnSQLRep($fieldDef,false, $tablename);
}
}
$columns = implode(",", $columns);
}
else {
$columns = $this->oneColumnSQLRep($fieldDefs,$ignoreRequired, $tablename);
}
return $columns;
}
/**
* Returns the next value for an auto increment
*
* @param string $table tablename
* @param string $field_name
* @return string
*/
public function getAutoIncrement(
$table,
$field_name
)
{
return "";
}
/**
* Returns the sql for the next value in a sequence
*
* @param string $table tablename
* @param string $field_name
* @return string
*/
public function getAutoIncrementSQL(
$table,
$field_name
)
{
return "";
}
/**
* Either creates an auto increment through queries or returns sql for auto increment
* that can be appended to the end of column defination (mysql)
*
* @param string $table tablename
* @param string $field_name
* @return string
*/
protected function setAutoIncrement(
$table,
$field_name
)
{
$this->deleteAutoIncrement($table, $field_name);
return "";
}
/**
* 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
)
{
return "";
}
/**
* Deletes an auto increment (for oracle not mysql)
*
* @param string $table tablename
* @param string $field_name
*/
public function deleteAutoIncrement(
$table,
$field_name
)
{
return;
}
/**
* Generates the SQL for changing columns
*
* @param string $tablename
* @param array $fieldDefs
* @param string $action
* @param bool $ignoreRequired Optional, true if we should ignor this being a required field
*/
abstract protected function changeColumnSQL(
$tablename,
$fieldDefs,
$action,
$ignoreRequired = false);
/**
* This method generates sql for adding a column to table identified by field def.
*
* @param string $tablename
* @param array $fieldDefs
* @return string SQL statement
*/
public function addColumnSQL(
$tablename,
$fieldDefs
)
{
return $this->changeColumnSQL($tablename, $fieldDefs, 'add');
}
/**
* This method genrates sql for altering old column identified by oldFieldDef to new fieldDef.
*
* @param string $tablename
* @param array $newFieldDefs
* @param bool $ignoreRequired Optional, true if we should ignor this being a required field
* @return string SQL statement
*/
public function alterColumnSQL(
$tablename,
$newFieldDefs,
$ignorerequired = false
)
{
return $this->changeColumnSQL($tablename, $newFieldDefs, 'modify', $ignorerequired);
}
/**
* Generates SQL for dropping a table.
*
* @param object $bean Sugarbean instance
* @return string SQL statement
*/
public function dropTableSQL(
SugarBean $bean
)
{
return $this->dropTableNameSQL($bean->getTableName());
}
/**
* Generates SQL for dropping a table.
*
* @param string $name table name
* @return string SQL statement
*/
public function dropTableNameSQL(
$name
)
{
return "drop table if exists ".$name;
}
/**
* This method generates sql that deletes a column identified by fieldDef.
*
* @param object $bean Sugarbean instance
* @param array $fieldDefs
* @return string SQL statement
*/
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 (".implode(", ", $columns).")";
}
/**
* This method generates sql that drops a column identified by fieldDef.
* Designed to work like the other addColumnSQL() and alterColumnSQL() functions
*
* @param string $tablename
* @param array $fieldDefs
* @return string SQL statement
*/
public function dropColumnSQL(
$tablename,
$fieldDefs
)
{
$sql = $this->changeColumnSQL(
$tablename,
$fieldDefs,
'drop'
);
return $sql;
}
/**
* Generates SQL for key statement for any bean identified by id.
*
* The passes array is an array of field definitions or a field definition
* itself. The keys generated will be either primary, foreign, unique, index
* or none at all depending on the setting of the "key" parameter of a field definition
*
* @param array $indices
* @param bool $alter_table
* @param string $alter_action
* @return string SQL Statement
*/
protected function keysSQL(
$indices,
$alter_table = false,
$alter_action = ''
)
{
return '';
}
/**
* Outputs a correct string for the sql statement according to value
*
* @param mixed $val
* @param array $fieldDef field definition
* @return mixed
*/
public function massageValue(
$val,
$fieldDef
)
{
if ( strlen($val) <= 0 )
return "''";
$type = $this->getFieldType($fieldDef);
switch ($type) {
case 'int':
case 'double':
case 'float':
case 'uint':
case 'ulong':
case 'long':
case 'short':
case 'tinyint':
case 'bool':
return $val;
break;
}
$qval = $this->quote($val);
switch ($type) {
case 'varchar':
case 'char':
case 'longtext':
case 'text':
case 'enum':
case 'multienum':
case 'html':
case 'blob':
case 'longblob':
case 'clob':
case 'id':
case 'datetime':
return $qval;
break;
case 'date':
case 'time':
return "$qval";
break;
}
return $val;
}
/**
* Massages the field defintions to fill in anything else the DB backend may add
*
* @param array $fieldDef
* @param string $tablename
* @return array
*/
public function massageFieldDef(
&$fieldDef,
$tablename
)
{
if ( !isset($fieldDef['dbType']) ) {
if ( isset($fieldDef['dbtype']) )
$fieldDef['dbType'] = $fieldDef['dbtype'];
else
$fieldDef['dbType'] = $fieldDef['type'];
}
$type = $this->getColumnType($fieldDef['dbType'],$fieldDef['name'],$tablename);
$matches = array();
preg_match_all("/(\w+)(?:\(([0-9]+,?[0-9]*)\)|)/i", $type, $matches);
if ( isset($matches[1][0]) )
$fieldDef['type'] = $matches[1][0];
if ( isset($matches[2][0]) && empty($fieldDef['len']) )
$fieldDef['len'] = $matches[2][0];
if ( !empty($fieldDef['precision']) && is_numeric($fieldDef['precision']) && !strstr($fieldDef['len'],',') )
$fieldDef['len'] .= ",{$fieldDef['precision']}";
if (isset($fieldDef['required']) && ($fieldDef['required'] == true
|| $fieldDef['required'] == '1'
|| $fieldDef['required'] == 1)
|| ($fieldDef['name'] == 'id' && !isset($fieldDef['required'])) )
$fieldDef['required'] = 'true';
}
/**
* Returns the valid type for a column given the type in fieldDef
*
* @param string $type field type
* @return string valid type for the given field
*/
abstract public function getColumnType(
$type,
$name = '',
$table = ''
);
/**
* Checks to see if passed array is truely an array of defitions
*
* Such an array may have type as a key but it will point to an array
* for a true array of definitions an to a col type for a definition only
*
* @param mixed $defArray
* @return bool
*/
public function isFieldArray(
$defArray
)
{
if ( !is_array($defArray) )
return false;
if ( isset($defArray['type']) ){
// type key exists. May be an array of defs or a simple definition
$type = $defArray['type'];
return is_array($type); // type is not an array => definition else array
}
// type does not exist. Must be array of definitions
return true;
}
/**
* returns true if the type can be mapped to a valid column type
*
* @param string $type
* @return bool
*/
protected function validColumnType(
$type
)
{
$coltype = $this->getColumnType($type);
return ($coltype) ? true : false;
}
/**
* 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
)
{
global $current_user;
$sql = "INSERT INTO ".$bean->get_audit_table_name();
//get field defs for the audit table.
require('metadata/audit_templateMetaData.php');
$fieldDefs = $dictionary['audit']['fields'];
$values=array();
$values['id']=$this->massageValue(create_guid(), $fieldDefs['id']);
$values['parent_id']=$bean->dbManager->getHelper()->massageValue($bean->id, $fieldDefs['parent_id']);
$values['field_name']=$bean->dbManager->getHelper()->massageValue($changes['field_name'], $fieldDefs['field_name']);
$values['data_type']=$bean->dbManager->getHelper()->massageValue($changes['data_type'], $fieldDefs['data_type']);
if ($changes['data_type']=='text') {
$bean->fetched_row[$changes['field_name']]=$changes['after'];;
$values['before_value_text']=$bean->dbManager->getHelper()->massageValue($changes['before'], $fieldDefs['before_value_text']);
$values['after_value_text']=$bean->dbManager->getHelper()->massageValue($changes['after'], $fieldDefs['after_value_text']);
} else {
$bean->fetched_row[$changes['field_name']]=$changes['after'];;
$values['before_value_string']=$bean->dbManager->getHelper()->massageValue($changes['before'], $fieldDefs['before_value_string']);
$values['after_value_string']=$bean->dbManager->getHelper()->massageValue($changes['after'], $fieldDefs['after_value_string']);
}
$values['date_created']=$bean->dbManager->getHelper()->massageValue(gmdate($GLOBALS['timedate']->get_db_date_time_format()), $fieldDefs['date_created']);
$values['created_by']=$bean->dbManager->getHelper()->massageValue($current_user->id, $fieldDefs['created_by']);
$sql .= "(".implode(",", array_keys($values)).") ";
$sql .= "VALUES(".implode(",", $values).")";
if ( $this->db->dbType == 'oci8' && $changes['data_type'] == 'text' ) {
$sql .= " RETURNING before_value_text, after_value_text INTO :before_value_text, :after_value_text";
$stmt = oci_parse($this->db->getDatabase(), $sql);
$err = oci_error($this->db->getDatabase());
if ($err != false){
$GLOBALS['log']->fatal($sql.">>".$err['code'].":".$err['message']);
return false;
}
$before_value_text_LOB = oci_new_descriptor($this->db->getDatabase(), OCI_D_LOB);
oci_bind_by_name($stmt, ":before_value_text", $before_value_text_LOB, -1, OCI_B_CLOB);
$after_value_text_LOB = oci_new_descriptor($this->db->getDatabase(), OCI_D_LOB);
oci_bind_by_name($stmt, ":after_value_text", $after_value_text_LOB, -1, OCI_B_CLOB);
oci_execute($stmt, OCI_DEFAULT);
$err = oci_error($this->db->getDatabase());
if ($err != false){
$GLOBALS['log']->fatal($sql.">>".$err['code'].":".$err['message']);
return false;
}
$before_value_text_LOB->save($changes['before']);
$after_value_text_LOB->save($changes['after']);
oci_commit($this->db->getDatabase());
$before_value_text_LOB->free();
$after_value_text_LOB->free();
oci_free_statement($stmt);
}
else {
$bean->db->query($sql);
}
}
/**
* Uses the audit enabled fields array to find fields whose value has changed.
* The before and after values are stored in the bean.
*
* @param object $bean Sugarbean instance
* @return array
*/
public function getDataChanges(
SugarBean &$bean
)
{
$changed_values=array();
$audit_fields=$bean->getAuditEnabledFieldDefinitions();
if (is_array($audit_fields) and count($audit_fields) > 0) {
foreach ($audit_fields as $field=>$properties) {
if (!empty($bean->fetched_row) && array_key_exists($field, $bean->fetched_row)) {
$before_value=$bean->fetched_row[$field];
$after_value=$bean->$field;
if (isset($properties['type']))
$field_type=$properties['type'];
else {
if (isset($properties['dbType']))
$field_type=$properties['dbType'];
else if(isset($properties['data_type']))
$field_type=$properties['data_type'];
else
$field_type=$properties['dbtype'];
}
//Because of bug #25078(sqlserver haven't 'date' type, trim extra "00:00:00" when insert into *_cstm table). so when we read the audit datetime field from sqlserver, we have to replace the extra "00:00:00" again.
if(!empty($field_type) && $field_type == 'date'){
$before_value = from_db_convert($before_value , $field_type);
}
//if the type and values match, do nothing.
if (!($this->_emptyValue($before_value,$field_type) && $this->_emptyValue($after_value,$field_type))) {
if (trim($before_value) !== trim($after_value)) {
if (!($this->_isTypeNumber($field_type) && (trim($before_value)+0) == (trim($after_value)+0))) {
if (!($this->_isTypeBoolean($field_type) && ($this->_getBooleanValue($before_value)== $this->_getBooleanValue($after_value)))) {
$changed_values[$field]=array('field_name'=>$field,
'data_type'=>$field_type,
'before'=>$before_value,
'after'=>$after_value);
}
}
}
}
}
}
}
return $changed_values;
}
/**
* Function returns true is full-text indexing is available in the connected database.
*
* Default value is false.
*
* @param string $dbname
* @return bool
*/
abstract protected function full_text_indexing_enabled(
$dbname = null
);
/**
* Quotes a string for storing in the database
*
* Return value will be surrounded by quotes
*
* @param string $string
* @return string
*/
public function quote(
$string
)
{
return "'".$this->db->quote($string)."'";
}
/**
* Quotes a string for storing in the database
*
* Return value will be not surrounded by quotes
*
* @param string $string
* @return string
*/
public function escape_quote(
$string
)
{
return $this->db->quote($string);
}
/**
* Returns definitions of all indies for passed table.
*
* return will is a multi-dimensional array that
* categorizes the index definition by types, unique, primary and index.
*
* array (
* 'name' => 'index1',
* 'type' => 'primary',
* 'fields' => array('field1','field2')
* )
* )
* ?>
*
* This format is similar to how indicies are defined in vardef file.
*
* @param string $tablename
* @return array
*/
abstract public function get_indices(
$tablename
);
/**
* Returns definitions of all indies for passed table.
*
* return will is a multi-dimensional array that
* categorizes the index definition by types, unique, primary and index.
*
* array (
* 'name' => 'field1',
* 'type' => 'varchar',
* 'len' => '200'
* )
* )
* ?>
*
* This format is similar to how indicies are defined in vardef file.
*
* @param string $tablename
* @return array
*/
abstract public function get_columns(
$tablename
);
/**
* Generates alter constraint statement given a table name and vardef definition.
*
* Supports both adding and droping a constraint.
*
* @param string $table tablename
* @param array $defintion field definition
* @param bool $drop true if we are dropping the constraint, false if we are adding it
* @return string SQL statement
*/
abstract public function add_drop_constraint(
$table,
$definition,
$drop = false);
/**
* Renames an index definition
*
* @param array $old_definition
* @param array $new_definition
* @param string $tablename
* @return string SQL statement
*/
public function rename_index(
$old_definition,
$new_definition,
$table_name
)
{
$ret_commands = array();
$ret_commands[] = $this->add_drop_constraint($table_name,$old_definition,true);
$ret_commands[] = $this->add_drop_constraint($table_name,$new_definition);
return $ret_commands;
}
/**
* Returns the number of columns in a table
*
* @param string $table_name
* @return int
*/
abstract public function number_of_columns(
$table_name
);
protected function _isTypeBoolean(
$type
)
{
switch ($type) {
case 'bool':
return true;
}
return false;
}
protected function _getBooleanValue(
$val
)
{
//need to put the === sign here otherwise true == 'non empty string'
if (empty($val) or $val==='off')
return false;
return true;
}
protected function _isTypeNumber(
$type
)
{
switch ($type) {
case 'decimal':
case 'int':
case 'double':
case 'float':
case 'uint':
case 'ulong':
case 'long':
case 'short':
return true;
}
return false;
}
/**
* return true if the value if empty
*/
protected function _emptyValue(
$val,
$type
)
{
if (empty($val))
return true;
switch ($type) {
case 'decimal':
case 'int':
case 'double':
case 'float':
case 'uint':
case 'ulong':
case 'long':
case 'short':
if ($val == 0)
return true;
return false;
case 'date':
if ($val == '0000-00-00')
return true;
if ($val == 'NULL')
return true;
return false;
}
return false;
}
}
?>