]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/database/MssqlHelper.php
Release 6.1.4
[Github/sugarcrm.git] / include / database / MssqlHelper.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40 * Description: This file handles the Data base functionality for the application specific
41 * to Mssql database. It is called by the DBManager class to generate various sql statements.
42 *
43 * All the functions in this class will work with any bean which implements the meta interface.
44 * Please refer the DBManager documentation for the details.
45 *
46 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
47 * All Rights Reserved.
48 * Contributor(s): ___RPS___________________________________..
49 ********************************************************************************/
50
51 include_once('include/database/DBHelper.php');
52
53 class MssqlHelper extends DBHelper
54 {
55     /**
56      * @see DBHelper::getColumnType()
57      */
58     public function getColumnType(
59         $type, 
60         $name = '', 
61         $table = ''
62         )
63     {
64         $map = array( 
65             'int'      => 'int',
66             'double'   => 'float',
67             'float'    => 'float',
68             'uint'     => 'int',
69             'ulong'    => 'int',
70             'long'     => 'bigint',
71             'short'    => 'smallint',
72             'varchar'  => 'varchar',
73             'text'     => 'text',
74             'longtext' => 'text',
75             'date'     => 'datetime',
76             'enum'     => 'varchar',
77             'relate'   => 'varchar',
78             'multienum'=> 'text',
79             'html'     => 'text',
80             'datetime' => 'datetime',
81             'datetimecombo' => 'datetime',
82             'time'     => 'datetime',
83             'bool'     => 'bit',
84             'tinyint'  => 'tinyint',
85             'char'     => 'char',
86             'blob'     => 'image',
87             'longblob' => 'image',
88             'currency' => 'decimal(26,6)',
89             'decimal'  => 'decimal',
90             'decimal2' => 'decimal',
91             'id'       => 'varchar(36)',
92             'url'=>'varchar',
93             'encrypt'=>'varchar',
94             );
95         
96         return $map[$type];
97     }
98     
99     /**
100      * @see DBHelper::dropTableNameSQL()
101      */
102     public function dropTableNameSQL(
103         $name
104         )
105     {
106                 return "DROP TABLE ".$name;
107     }
108
109     /**
110      * Returns the SQL Alter table statment
111      *
112      * MSSQL has a quirky T-SQL alter table syntax. Pay special attention to the
113      * modify operation
114      * @param string $action
115      * @param array  $def
116      * @param bool   $ignorRequired
117      * @param string $tablename
118      */
119     private function alterSQLRep(
120         $action, 
121         array $def, 
122         $ignoreRequired, 
123         $tablename = ''
124         ) 
125     {
126         switch($action){
127         case 'add':
128              $f_def=$this->oneColumnSQLRep($def, $ignoreRequired,$tablename,false);
129             return "ADD " . $f_def;
130             break;
131         case 'drop':
132             return "DROP COLUMN " . $def['name'];
133             break;
134         case 'modify':
135             //You cannot specify a default value for a column for MSSQL
136             $f_def  = $this->oneColumnSQLRep($def, $ignoreRequired,$tablename, true);
137             $f_stmt = "ALTER COLUMN ".$f_def['name'].' '.$f_def['colType'].' '.
138                         $f_def['required'].' '.$f_def['auto_increment']."\n";
139             if (!empty( $f_def['default']))
140                 $f_stmt .= " ALTER TABLE " . $tablename .  " ADD  ". $f_def['default'] . " FOR " . $def['name'];
141             return $f_stmt;
142             break;
143         default:
144             return '';
145         }
146     }
147
148     /**
149      * @see DBHelper::changeColumnSQL()
150      *
151      * MSSQL uses a different syntax than MySQL for table altering that is
152      * not quite as simplistic to implement...
153      */
154     protected function changeColumnSQL(
155         $tablename, 
156         $fieldDefs, 
157         $action, 
158         $ignoreRequired = false
159         )
160     {
161         $sql='';
162         $constraints = $this->get_field_default_constraint_name($tablename);
163         if ($this->isFieldArray($fieldDefs)) {
164             foreach ($fieldDefs as $def)
165                 {
166                         //if the column is being modified drop the default value
167                         //constraint if it exists. alterSQLRep will add the constraint back
168                         if (!empty($constraints[$def['name']])) {
169                                 $sql.=" ALTER TABLE " . $tablename . " DROP CONSTRAINT " . $constraints[$def['name']];
170                         }
171
172                         $columns[] = $this->alterSQLRep($action, $def, $ignoreRequired,$tablename);
173                 }
174         }
175         else {
176             //if the column is being modified drop the default value
177                 //constraint if it exists. alterSQLRep will add the constraint back
178                 if (!empty($constraints[$fieldDefs['name']])) {
179                         $sql.=" ALTER TABLE " . $tablename . " DROP CONSTRAINT " . $constraints[$fieldDefs['name']];
180                 }
181
182                 $columns[] = $this->alterSQLRep($action, $fieldDefs, $ignoreRequired,$tablename);
183         }
184
185         $columns = implode(", ", $columns);
186         $sql .= " ALTER TABLE $tablename $columns";
187         
188         return $sql;
189     }
190
191     /**
192      * @see DBHelper::deleteColumnSQL()
193      */
194     public function deleteColumnSQL(
195         SugarBean $bean, 
196         $fieldDefs
197         )
198     {
199         if ($this->isFieldArray($fieldDefs)) 
200             foreach ($fieldDefs as $fieldDef) 
201                 $columns[] = $fieldDef['name'];
202         else 
203             $columns[] = $fieldDefs['name'];
204         
205         return "ALTER TABLE ".$bean->getTableName()." DROP COLUMN ".implode(", DROP COLUMN ", $columns);
206     }
207     
208     /**
209      * returns an alter table statement to build the list of indices
210      *
211      * @param  string $tableName
212      * @param  array  $fieldDefs
213      * @param  array  $indices
214      * @return string SQL statement
215      */
216     public function indexSQL( 
217         $tableName, 
218         $fieldDefs, 
219         $indices
220         ) 
221     {
222        // check if the passed value is an array of fields.
223        // if not, convert it into an array
224        if (!$this->isFieldArray($indices)) 
225            $indices[] = $indices;
226
227        $columns = array();
228        foreach ($indices as $index) {
229            if(!empty($index['db']) && $index['db'] != 'mssql')
230                continue;
231
232            $type = $index['type'];
233            $name = $index['name'];
234
235            if (is_array($index['fields']))
236                $fields = implode(", ", $index['fields']);
237            else
238                $fields = $index['fields'];
239
240            switch ($type) {
241            case 'primary':
242                // SQL server requires primary key constraints to be created with
243                // key word "PRIMARY KEY".  Cannot default to index as synonym
244                $columns[] = "ALTER TABLE $tableName ADD CONSTRAINT pk_$tableName PRIMARY KEY ($fields)";
245                break;
246            case 'unique':
247                $columns[] = "ALTER TABLE $tableName ADD CONSTRAINT " . $index['name'] . " UNIQUE ($fields)";
248                break;
249            case 'clustered':
250                $columns[] = "CREATE CLUSTERED INDEX $name ON $tableName ( $fields )";
251                break;
252            case 'index':
253            case 'alternate_key':
254            case 'foreign':
255                $columns[] = "CREATE INDEX $name ON $tableName ( $fields )";
256                break;
257            case 'fulltext':
258                if ($this->full_text_indexing_enabled()) {
259                    $catalog_name="sugar_fts_catalog";
260                    if ( isset($index['catalog_name']) 
261                             && $index['catalog_name'] != 'default')
262                                 $catalog_name = $index['catalog_name'];
263
264                         $language = "Language 1033";
265                         if (isset($index['language']) && !empty($index['language']))
266                                 $language = "Language " . $index['language'];
267                         
268                         $key_index = $index['key_index'];;
269
270                         $change_tracking = "auto";
271                         if (isset($index['change_tracking']) 
272                             && !empty($index['change_tracking']))
273                                 $change_tracking = $index['change_tracking'];
274                         
275                         $columns[] = " CREATE FULLTEXT INDEX ON $tableName($fields $language) KEY INDEX $key_index ON $catalog_name WITH CHANGE_TRACKING $change_tracking" ;
276                }
277                break;
278            }
279        }
280
281        $columns = implode(" ", $columns);
282        
283        return $columns;
284     }
285
286         protected function setAutoIncrement(
287         $table, 
288         $field_name
289         )
290     {
291                 return "identity(1,1)";
292         }
293
294     /**
295      * @see DBHelper::setAutoIncrementStart()
296      */
297     public function setAutoIncrementStart(
298         $table,
299         $field_name,
300         $start_value
301         )
302     {
303         if($start_value > 1)
304             $start_value -= 1;
305                 $this->db->query("DBCC CHECKIDENT ('$table', RESEED, $start_value)");
306         return true;
307     }
308         
309         /**
310      * @see DBHelper::getAutoIncrement()
311      */
312     public function getAutoIncrement(
313         $table,
314         $field_name
315         )
316     {
317         
318         
319                 $result = $this->db->query("select IDENT_CURRENT('$table') + IDENT_INCR ( '$table' ) as 'Auto_increment'");
320         $row = $this->db->fetchByAssoc($result);
321                 if (!empty($row['Auto_increment']))
322             return $row['Auto_increment'];
323         
324         return "";
325     }
326
327     /**
328      * @see DBHelper::createTableSQLParams()
329      */
330         public function createTableSQLParams(
331         $tablename, 
332         $fieldDefs, 
333         $indices,
334         $engine = null
335         )
336     {
337         if (empty($tablename) || empty($fieldDefs)) 
338             return '';
339
340         $sql ='';
341         $columns = $this->columnSQLRep($fieldDefs, false, $tablename);
342         if (empty($columns))
343             return false;
344         
345         return "CREATE TABLE $tablename ($columns ) " .
346             $this->indexSQL($tablename, $fieldDefs, $indices);
347     }
348
349         /**
350      * @see DBHelper::get_indices()
351      */
352     public function get_indices(
353         $tablename
354         ) 
355     {
356         //find all unique indexes and primary keys.
357         $query = <<<EOSQL
358 SELECT LEFT(so.[name], 30) TableName, 
359         LEFT(si.[name], 50) 'Key_name',
360         LEFT(sik.[keyno], 30) Sequence, 
361         LEFT(sc.[name], 30) Column_name,
362                 isunique = CASE
363             WHEN si.status & 2 = 2 AND so.xtype != 'PK' THEN 1
364             ELSE 0
365         END
366     FROM sysindexes si
367         INNER JOIN sysindexkeys sik 
368             ON (si.[id] = sik.[id] AND si.indid = sik.indid)
369         INNER JOIN sysobjects so 
370             ON si.[id] = so.[id]
371         INNER JOIN syscolumns sc 
372             ON (so.[id] = sc.[id] AND sik.colid = sc.colid)
373         INNER JOIN sysfilegroups sfg 
374             ON si.groupid = sfg.groupid
375     WHERE so.[name] = '$tablename'
376     ORDER BY Key_name, Sequence, Column_name
377 EOSQL;
378         $result = $this->db->query($query);
379         
380         $indices = array();
381         while (($row=$this->db->fetchByAssoc($result)) != null) {
382             $index_type = 'index';
383             if ($row['Key_name'] == 'PRIMARY')
384                 $index_type = 'primary';
385             elseif ($row['isunique'] == 1 )
386                 $index_type = 'unique';
387             $name = strtolower($row['Key_name']);
388             $indices[$name]['name']     = $name;
389             $indices[$name]['type']     = $index_type;
390             $indices[$name]['fields'][] = strtolower($row['Column_name']);
391         }
392         return $indices;
393     }
394
395     /**
396      * @see DBHelper::get_columns()
397      */
398     public function get_columns(
399         $tablename
400         ) 
401     {
402         //find all unique indexes and primary keys.
403         $result = $this->db->query("sp_columns $tablename");
404         
405         $columns = array();
406         while (($row=$this->db->fetchByAssoc($result)) !=null) {
407             $column_name = strtolower($row['COLUMN_NAME']);
408             $columns[$column_name]['name']=$column_name;
409             $columns[$column_name]['type']=strtolower($row['TYPE_NAME']);
410             if ( $row['TYPE_NAME'] == 'decimal' ) {
411                 $columns[$column_name]['len']=strtolower($row['PRECISION']);
412                 $columns[$column_name]['len'].=','.strtolower($row['SCALE']);
413             }
414                         elseif ( in_array($row['TYPE_NAME'],array('nchar','nvarchar')) )
415                                 $columns[$column_name]['len']=strtolower($row['PRECISION']);
416             elseif ( !in_array($row['TYPE_NAME'],array('datetime','text','bit')) )
417                 $columns[$column_name]['len']=strtolower($row['LENGTH']);
418             if ( stristr($row['TYPE_NAME'],'identity') ) {
419                 $columns[$column_name]['auto_increment'] = '1';
420                 $columns[$column_name]['type']=str_replace(' identity','',strtolower($row['TYPE_NAME']));
421             }
422             
423             if (!empty($row['IS_NULLABLE']) && $row['IS_NULLABLE'] == 'NO' && (empty($row['KEY']) || !stristr($row['KEY'],'PRI')))
424                 $columns[strtolower($row['COLUMN_NAME'])]['required'] = 'true';
425             
426             $column_def = 0;
427             if ( strtolower($tablename) == 'relationships' ) {
428                 $column_def = $this->db->getOne("select cdefault from syscolumns where id = object_id('relationships') and name = '$column_name'");
429             }
430             if ( $column_def != 0 ) {
431                 $matches = array();
432                 $row['COLUMN_DEF'] = html_entity_decode($row['COLUMN_DEF'],ENT_QUOTES);
433                 if ( preg_match("/\([\(|'](.*)[\)|']\)/i",$row['COLUMN_DEF'],$matches) )
434                     $columns[$column_name]['default'] = $matches[1];
435                 elseif ( preg_match("/\(N'(.*)'\)/i",$row['COLUMN_DEF'],$matches) )
436                     $columns[$column_name]['default'] = $matches[1];
437                 else
438                     $columns[$column_name]['default'] = $row['COLUMN_DEF'];
439             }
440         }
441         return $columns;
442     }
443     
444     /**
445      * @see DBHelper::add_drop_constraint()
446      */
447     public function add_drop_constraint(
448         $table,
449         $definition, 
450         $drop = false
451         ) 
452     {
453         $type         = $definition['type'];
454         $fields       = implode(',',$definition['fields']);
455         $name         = $definition['name'];
456         $foreignTable = isset($definition['foreignTable']) ? $definition['foreignTable'] : array();
457         $sql          = '';
458         
459         switch ($type){
460         // generic indices
461         case 'index':
462         case 'alternate_key':
463             if ($drop)
464                 $sql = "DROP INDEX {$name} ";
465             else
466                 $sql = "CREATE INDEX {$name} ON {$table} ({$fields})";
467             break;
468         // constraints as indices
469         case 'unique':
470             if ($drop)
471                 $sql = "ALTER TABLE {$table} DROP INDEX $name";
472             else
473                 $sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE ({$fields})";
474             break;
475         case 'primary':
476             if ($drop)
477                 $sql = "ALTER TABLE {$table} DROP PRIMARY KEY";
478             else
479                 $sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name} PRIMARY KEY ({$fields})";
480             break;
481         case 'foreign':
482             if ($drop)
483                 $sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})";
484             else
485                 $sql = "ALTER TABLE {$table} ADD CONSTRAINT {$name}  FOREIGN KEY ({$fields}) REFERENCES {$foreignTable}({$foreignfields})";
486             break;
487         case 'fulltext':
488             if ($this->full_text_indexing_enabled() && $drop)
489                 $sql = "DROP FULLTEXT INDEX ON {$table}";
490             elseif ($this->full_text_indexing_enabled()) {
491                 $catalog_name="sugar_fts_catalog";
492                 if ( isset($index['catalog_name']) && $index['catalog_name'] != 'default')
493                     $catalog_name = $index['catalog_name'];
494
495                 $language = "Language 1033";
496                 if (isset($index['language']) && !empty($index['language']))
497                     $language = "Language " . $index['language'];
498                 
499                 $key_index = $index['key_index'];
500
501                 $change_tracking = "auto";
502                 if (isset($index['change_tracking']) && !empty($index['change_tracking']))
503                     $change_tracking = $index['change_tracking'];
504                 
505                 $columns[] = " CREATE FULLTEXT INDEX ON $table ($fields $language) KEY INDEX $key_index ON $catalog_name WITH CHANGE_TRACKING $change_tracking" ;
506             }
507             break;
508         }
509         return $sql;
510     }
511
512     /**
513      * @see DBHelper::number_of_columns()
514      */
515     public function number_of_columns(
516         $table_name
517         ) 
518     {
519         $def_query = <<<EOSQL
520 SELECT count(*) as cols 
521     FROM sys.columns col join sys.types col_type 
522         on col.user_type_id=col_type.user_type_id 
523     where col.object_id = (
524         select object_id(sys.schemas.name + '.' + sys.tables.name)
525             from sys.tables join sys.schemas 
526                 on sys.schemas.schema_id = sys.tables.schema_id
527             where sys.tables.name='$table_name'
528         )
529 EOSQL;
530         /**
531          * @TODO test the similarities of the above the query against all system tables vs the query below against
532          * the information_schema view in terms of results and efficiency. suspician is provided the two produce
533          * the same information the latter will be slightly faster.
534          * <code>
535          * <?php
536          * $def_query = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='$table_name'";
537          * ?>
538          * </code>
539          */
540
541         $result = $this->db->query($def_query);
542         $row    = $this->db->fetchByAssoc($result);
543         if (!empty($row)) {
544             return $row['cols'];
545         }
546         return 0;
547     }
548
549     /**
550      * Returns true if Full Text Search is installed
551      *
552      * @return bool
553      */
554     protected function full_text_indexing_installed() 
555     {
556         $ftsChckRes = $this->db->query(
557             "SELECT FULLTEXTSERVICEPROPERTY('IsFulltextInstalled') as fts");
558         $row = $this->db->fetchByAssoc($ftsChckRes);
559
560         return (isset($row) && isset($row['fts']) && ($row['fts'] == 1 || $row['fts'] == '1'));
561     }
562
563     /**
564      * @see DBHelper::full_text_indexing_enabled()
565      */
566     protected function full_text_indexing_enabled(
567         $dbname = null
568         ) 
569     {
570         // check to see if we already have install setting in session
571         if(!isset($_SESSION['IsFulltextInstalled']))
572             $_SESSION['IsFulltextInstalled'] = $this->full_text_indexing_installed();
573         
574         // check to see if FTS Indexing service is installed
575         if(empty($_SESSION['IsFulltextInstalled']) 
576                 || $_SESSION['IsFulltextInstalled'] === false)
577             return false;
578
579         // grab the dbname if it was not passed through
580                 if (empty($dbname)) {
581                         global $sugar_config;
582                         $dbname = $sugar_config['dbconfig']['db_name'];
583                 }
584         //we already know that Indexing service is installed, now check
585         //to see if it is enabled
586                 $res = $this->db->query(
587             "SELECT DATABASEPROPERTY('$dbname', 'IsFulltextEnabled') ftext");
588                 $row = $GLOBALS['db']->fetchByAssoc($res);
589         
590         return (isset($row['ftext']) && $row['ftext'] == 1);
591         }
592
593     /**
594      * Creates default full text catalog
595      */
596         public function create_default_full_text_catalog() 
597     {
598                 if ($this->full_text_indexing_enabled()) {
599             $GLOBALS['log']->debug('Creating the default catalog for full-text indexing, sugar_fts_catalog');
600                         
601             //drop catalog if exists.
602                         $ret = $this->db->query("
603                 if not exists(
604                     select * 
605                         from sys.fulltext_catalogs 
606                         where name ='sugar_fts_catalog'
607                         ) 
608                 CREATE FULLTEXT CATALOG sugar_fts_catalog");
609
610                         if (empty($ret)) {
611                                 $GLOBALS['log']->error('Error creating default full-text catalog, sugar_fts_catalog');
612                         }
613                 }
614         }
615
616     /**
617      * Function returns name of the constraint automatically generated by sql-server.
618      * We request this for default, primary key, required
619      *
620      * @param  string $table
621      * @param  string $column
622      * @return string 
623      */
624         private function get_field_default_constraint_name(
625         $table, 
626         $column = null
627         ) 
628     {
629         static $results = array();
630         
631         if ( empty($column) && isset($results[$table]) )
632             return $results[$table];
633         
634         $query = <<<EOQ
635 select s.name, o.name, c.name dtrt, d.name ctrt
636     from sys.default_constraints as d
637         join sys.objects as o
638             on o.object_id = d.parent_object_id
639         join sys.columns as c
640             on c.object_id = o.object_id and c.column_id = d.parent_column_id
641         join sys.schemas as s
642             on s.schema_id = o.schema_id
643     where o.name = '$table'
644 EOQ;
645         if ( !empty($column) )
646             $query .= " and c.name = '$column'";
647         $res = $this->db->query($query);
648         if ( !empty($column) ) {
649             $row = $this->db->fetchByAssoc($res);
650             if (!empty($row)) 
651                 return $row['ctrt'];
652         }
653         else {
654             $returnResult = array();
655             while ( $row = $this->db->fetchByAssoc($res) )
656                 $returnResult[$row['dtrt']] = $row['ctrt'];
657             $results[$table] = $returnResult;
658             return $returnResult;
659         }
660                 
661         return null;
662         }
663     
664     /**
665      * @see DBHelper::massageFieldDef()
666      */
667     public function massageFieldDef(
668         &$fieldDef,
669         $tablename
670         )
671     {
672         parent::massageFieldDef($fieldDef,$tablename);
673         
674         if ($fieldDef['type'] == 'int')
675             $fieldDef['len'] = '4';
676         if ($fieldDef['type'] == 'bit' && empty($fieldDef['len']) )
677             $fieldDef['len'] = '1';
678                 if ($fieldDef['type'] == 'bool' && empty($fieldDef['len']) )
679             $fieldDef['len'] = '1';
680         if ($fieldDef['type'] == 'float' && empty($fieldDef['len']) )
681             $fieldDef['len'] = '8';
682         if ($fieldDef['type'] == 'varchar' && empty($fieldDef['len']) )
683             $fieldDef['len'] = '255';
684                 if ($fieldDef['type'] == 'nvarchar' && empty($fieldDef['len']) )
685             $fieldDef['len'] = '255';
686         if ($fieldDef['type'] == 'bit' && empty($fieldDef['default']) )
687             $fieldDef['default'] = '0';
688                 if ($fieldDef['type'] == 'bool' && empty($fieldDef['default']) )
689             $fieldDef['default'] = '0';
690         if ($fieldDef['type'] == 'image' && empty($fieldDef['len']) )
691             $fieldDef['len'] = '2147483647';
692         if ($fieldDef['type'] == 'ntext' && empty($fieldDef['len']) )
693             $fieldDef['len'] = '2147483646';
694         if ($fieldDef['type'] == 'smallint' && empty($fieldDef['len']) )
695             $fieldDef['len'] = '2';
696                 if (isset($fieldDef['required']) && $fieldDef['required'] && !isset($fieldDef['default']) )
697                         $fieldDef['default'] = '';
698     }
699     
700     /**
701      * @see DBHelper::oneColumnSQLRep()
702      */
703     protected function oneColumnSQLRep(
704         $fieldDef,
705         $ignoreRequired = false,
706         $table = '',
707         $return_as_array = false
708         )
709     {
710         //Bug 25814
711                 if(isset($fieldDef['name'])){
712                         $name = $fieldDef['name'];
713                 $type = $this->getFieldType($fieldDef);
714                 $colType = $this->getColumnType($type, $name, $table);
715                 if(stristr($colType, 'decimal')){
716                                 $fieldDef['len'] = isset($fieldDef['len'])? min($fieldDef['len'],38) : 38;
717                         }
718                         //bug: 39690 float(8) is interpreted as real and this generates a diff when doing repair
719                         if(stristr($colType, 'float')){
720                                 if(isset($fieldDef['len']) && $fieldDef['len'] == 8){
721                                         unset($fieldDef['len']);
722                                 }
723                         }
724                 }
725                 
726                 $ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true);
727         
728                 // Bug 24307 - Don't add precision for float fields.
729                 if ( stristr($ref['colType'],'float') )
730                         $ref['colType'] = preg_replace('/(,\d+)/','',$ref['colType']);
731             
732         if ( $return_as_array )
733             return $ref;
734         else
735             return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
736         }
737         
738     /**
739      * Saves changes to module's audit table
740      *
741      * @param object $bean    Sugarbean instance
742      * @param array  $changes changes
743      * @see DBHelper::getDataChanges()
744      */
745     public function save_audit_records(
746         SugarBean &$bean,
747         &$changes
748         )
749         {
750                 //Bug 25078 fixed by Martin Hu: sqlserver haven't 'date' type, trim extra "00:00:00"
751                 if($changes['data_type'] == 'date'){
752                         $changes['before'] = str_replace(' 00:00:00','',$changes['before']);
753                 }
754                 parent::save_audit_records($bean,$changes);
755         }
756 }
757 ?>