]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/database/MysqlHelper.php
Release 6.1.4
[Github/sugarcrm.git] / include / database / MysqlHelper.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 oracle 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): ______________________________________..
49 ********************************************************************************/
50 require_once('include/database/DBHelper.php');
51
52 class MysqlHelper extends DBHelper
53 {
54     /**
55      * @see DBHelper::createTableSQL()
56      */
57     public function createTableSQL(
58         SugarBean $bean
59         )
60     {
61         $tablename = $bean->getTableName();
62         $fieldDefs = $bean->getFieldDefinitions();
63         $indices   = $bean->getIndices();
64         $engine    = $this->getEngine($bean);
65         return $this->createTableSQLParams($tablename, $fieldDefs, $indices, $engine);
66         }
67     
68     /**
69      * Generates sql for create table statement for a bean.
70      *
71      * @param  string $tablename
72      * @param  array  $fieldDefs
73      * @param  array  $indices
74      * @param  string $engine optional, MySQL engine to use
75      * @return string SQL Create Table statement
76     */
77     public function createTableSQLParams(
78         $tablename, 
79         $fieldDefs, 
80         $indices, 
81         $engine = null
82         )
83     {           
84                 if ( empty($engine) && isset($fieldDefs['engine']))
85             $engine = $fieldDefs['engine'];
86         if ( !$this->isEngineEnabled($engine) )
87             $engine = '';
88
89         $sql = parent::createTableSQLParams($tablename,$fieldDefs,$indices);
90         if (!empty($engine))
91             $sql.= " ENGINE=$engine"; 
92
93         return $sql;
94         }
95     
96     /**
97      * Returns the name of the engine to use or null if we are to use the default
98      *
99      * @param  object $bean SugarBean instance
100      * @return string
101      */
102     private function getEngine(
103         &$bean
104         )
105     {
106         global $dictionary;
107         $engine = null;
108         if (isset($dictionary[$bean->getObjectName()]['engine'])) {
109                         $engine = $dictionary[$bean->getObjectName()]['engine'];
110                 }
111         return $engine;
112     }
113     
114     /**
115      * Returns true if the engine given is enabled in the backend
116      *
117      * @param  string $engine
118      * @return bool
119      */
120     private function isEngineEnabled(
121         $engine
122         )
123     {
124         $engine = strtoupper($engine);
125         
126         $r = $this->db->query("SHOW ENGINES");
127         
128         while ( $row = $this->db->fetchByAssoc($r) )
129             if ( strtoupper($row['Engine']) == $engine )
130                 return ($row['Support']=='YES' || $row['Support']=='DEFAULT');
131
132         return false;
133     }
134     
135     /**
136      * @see DBHelper::getColumnType()
137      */
138     public function getColumnType(
139         $type, 
140         $name = '', 
141         $table = ''
142         )
143     {
144         $map = array( 
145             'int'      => 'int',
146             'double'   => 'double',
147             'float'    => 'float',
148             'uint'     => 'int unsigned',
149             'ulong'    => 'bigint unsigned',
150             'long'     => 'bigint',
151             'short'    => 'smallint',
152             'varchar'  => 'varchar',
153             'text'     => 'text',
154             'longtext' => 'longtext',
155             'date'     => 'date',
156             'enum'     => 'varchar',
157             'relate'   => 'varchar',
158             'multienum'=> 'text',
159             'html'     => 'text',
160             'datetime' => 'datetime',
161             'datetimecombo' => 'datetime',
162             'time'     => 'time',
163             'bool'     => 'bool',
164             'tinyint'  => 'tinyint',
165             'char'     => 'char',
166             'blob'     => 'blob',
167             'longblob' => 'longblob',
168             'currency' => 'decimal(26,6)',
169             'decimal'  => 'decimal',
170             'decimal2' => 'decimal',
171             'id'       => 'char(36)',
172            'url'=>'varchar',
173            'encrypt'=>'varchar',
174             );
175         
176         return $map[$type];
177     }
178
179     /**
180      * @see DBHelper::oneColumnSQLRep()
181      */
182         protected function oneColumnSQLRep(
183         $fieldDef,  
184         $ignoreRequired = false, 
185         $table = '', 
186         $return_as_array = false
187         )
188     {
189         $ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true);
190         
191         if ( $ref['colType'] == 'int' 
192                 && !empty($fieldDef['len']) )
193             $ref['colType'] .= "(".$fieldDef['len'].")";
194         
195         // bug 22338 - don't set a default value on text or blob fields
196         if ( isset($ref['default']) && 
197             ($ref['colType'] == 'text' || $ref['colType'] == 'blob'
198                 || $ref['colType'] == 'longtext' || $ref['colType'] == 'longblob' ))
199             $ref['default'] = '';
200             
201         if ( $return_as_array )
202             return $ref;
203         else
204             return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}";
205     }
206
207     /**
208      * @see DBHelper::changeColumnSQL()
209      */
210     protected function changeColumnSQL(
211         $tablename, 
212         $fieldDefs, 
213         $action, 
214         $ignoreRequired = false
215         )
216     {
217         if ($this->isFieldArray($fieldDefs)){
218             foreach ($fieldDefs as $def){
219                 if ($action == 'drop')
220                     $columns[] = $def['name'];
221                 else
222                 $columns[] = $this->oneColumnSQLRep($def, $ignoreRequired);
223             }
224         }else{
225             if ($action == 'drop')
226                 $columns[] = $fieldDefs['name'];
227         else
228             $columns[] = $this->oneColumnSQLRep($fieldDefs);
229         }
230
231         return "alter table $tablename $action column ".implode(",$action column ", $columns);
232     }
233
234     /**
235      * @see DBHelper::deleteColumnSQL()
236      */
237     public function deleteColumnSQL(
238         SugarBean $bean, 
239         $fieldDefs
240         )
241     {
242         if ($this->isFieldArray($fieldDefs)) 
243             foreach ($fieldDefs as $fieldDef) 
244                 $columns[] = $fieldDef['name'];
245         else
246             $columns[] = $fieldDefs['name'];
247
248         return "alter table ".$bean->getTableName()." drop column ".implode(", drop column ", $columns);
249     }
250
251     /**
252      * @see DBHelper::keysSQL
253      */
254     public function keysSQL( 
255         $indices, 
256         $alter_table = false, 
257         $alter_action = '' 
258         )
259         {
260        // check if the passed value is an array of fields.
261        // if not, convert it into an array
262        if (!$this->isFieldArray($indices)) 
263            $indices[] = $indices;
264
265        $columns = array();
266        foreach ($indices as $index) {
267            if(!empty($index['db']) && $index['db'] != 'mysql')
268                continue;
269           
270            $type = $index['type'];
271            $name = $index['name'];
272
273            if (is_array($index['fields']))
274                $fields = implode(", ", $index['fields']);
275            else
276                $fields = $index['fields'];
277
278            switch ($type) {
279            case 'unique':
280                $columns[] = " UNIQUE $name ($fields)";
281                break;
282            case 'primary':
283                $columns[] = " PRIMARY KEY ($fields)";
284                break;
285            case 'index':
286            case 'foreign':
287            case 'clustered':
288            case 'alternate_key':
289                /** 
290                 * @todo here it is assumed that the primary key of the foreign
291                 * table will always be named 'id'. It must be noted though
292                 * that this can easily be fixed by referring to db dictionary
293                 * to find the correct primary field name
294                 */
295                if ( $alter_table )
296                    $columns[] = " INDEX $name ($fields)";
297                else
298                    $columns[] = " KEY $name ($fields)";
299                break;
300            case 'fulltext':
301                if ($this->full_text_indexing_enabled())
302                    $columns[] = " FULLTEXT ($fields)";
303                else
304                    $GLOBALS['log']->debug('MYISAM engine is not available/enabled, full-text indexes will be skipped. Skipping:',$name);
305                break;
306           }
307        }
308        $columns = implode(", $alter_action ", $columns);
309        if(!empty($alter_action)){
310            $columns = $alter_action . ' '. $columns;
311        }
312        return $columns;
313     }
314
315     /**
316      * @see DBHelper::setAutoIncrement()
317      */
318         protected function setAutoIncrement(
319         $table, 
320         $field_name
321         )
322     {
323                 return "auto_increment";
324         }
325
326         /**
327      * Sets the next auto-increment value of a column to a specific value.
328      *
329      * @param  string $table tablename
330      * @param  string $field_name
331      */
332     public function setAutoIncrementStart(
333         $table,
334         $field_name,
335         $start_value
336         )
337     {
338         $this->db->query( "ALTER TABLE $table AUTO_INCREMENT = $start_value;");
339         
340         return true;
341     }
342         
343     /**
344      * Returns the next value for an auto increment
345      *
346      * @param  string $table tablename
347      * @param  string $field_name
348      * @return string
349      */
350     public function getAutoIncrement(
351         $table,
352         $field_name
353         )
354     {
355         
356         $result = $this->db->query("SHOW TABLE STATUS LIKE '$table'");
357         $row = $this->db->fetchByAssoc($result);
358         if (!empty($row['Auto_increment']))
359             return $row['Auto_increment'];
360         
361         return "";
362     }
363
364         /**
365      * @see DBHelper::get_indices()
366      */
367     public function get_indices(
368         $tablename
369         ) 
370     {
371         //find all unique indexes and primary keys.
372         $result = $this->db->query("SHOW INDEX FROM $tablename");
373         
374         $indices = array();
375         while (($row=$this->db->fetchByAssoc($result)) !=null) {
376             $index_type='index';
377             if ($row['Key_name'] =='PRIMARY') {
378                 $index_type='primary';  
379             }
380             elseif ( $row['Non_unique'] == '0' ) {
381                 $index_type='unique';
382             }
383             $name = strtolower($row['Key_name']);
384             $indices[$name]['name']=$name;
385             $indices[$name]['type']=$index_type;
386             $indices[$name]['fields'][]=strtolower($row['Column_name']);
387         }
388         return $indices;
389     }
390
391         /**
392      * @see DBHelper::get_columns()
393      */
394     public function get_columns(
395         $tablename
396         ) 
397     {
398         //find all unique indexes and primary keys.
399         $result = $this->db->query("DESCRIBE $tablename");
400         
401         $columns = array();
402         while (($row=$this->db->fetchByAssoc($result)) !=null) {
403             $name = strtolower($row['Field']);
404             $columns[$name]['name']=$name;
405             $matches = array();
406             preg_match_all("/(\w+)(?:\(([0-9]+,?[0-9]*)\)|)( unsigned)?/i", $row['Type'], $matches);
407             $columns[$name]['type']=strtolower($matches[1][0]);
408             if ( isset($matches[2][0]) && in_array(strtolower($matches[1][0]),array('varchar','char','varchar2','int','decimal','float')) )
409                 $columns[$name]['len']=strtolower($matches[2][0]);
410             if ( stristr($row['Extra'],'auto_increment') )
411                 $columns[$name]['auto_increment'] = '1';
412             if ($row['Null'] == 'NO' && !stristr($row['Key'],'PRI'))
413                 $columns[$name]['required'] = 'true';
414             if ( !empty($row['Default']) )
415                 $columns[$name]['default'] = $row['Default'];
416         }
417         return $columns;
418     }
419     
420     /**
421      * @see DBHelper::add_drop_constraint()
422      */
423     public function add_drop_constraint(
424         $table,
425         $definition, 
426         $drop = false
427         ) 
428     {
429         $type         = $definition['type'];
430         $fields       = implode(',',$definition['fields']);
431         $name         = $definition['name'];
432         $foreignTable = isset($definition['foreignTable']) ? $definition['foreignTable'] : array();
433         $sql          = '';
434         
435         switch ($type){
436         // generic indices
437         case 'index':
438         case 'alternate_key':
439             if ($drop)
440                 $sql = "DROP INDEX {$name} ";
441             else
442                 $sql = "CREATE INDEX {$name} ON {$table} ({$fields})";
443             break;
444         // constraints as indices
445         case 'unique':
446             if ($drop)
447                 $sql = "ALTER TABLE {$table} DROP INDEX $name";
448             else
449                 $sql = "ALTER TABLE {$table} ADD CONSTRAINT UNIQUE {$name} ({$fields})";
450             break;
451         case 'primary':
452             if ($drop)
453                 $sql = "ALTER TABLE {$table} DROP PRIMARY KEY";
454             else
455                 $sql = "ALTER TABLE {$table} ADD CONSTRAINT PRIMARY KEY ({$fields})";
456             break;
457         case 'foreign':
458             if ($drop)
459                 $sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})";
460             else
461                 $sql = "ALTER TABLE {$table} ADD CONSTRAINT FOREIGN KEY {$name} ({$fields}) REFERENCES {$foreignTable}({$foreignfields})";
462             break;
463         }
464         return $sql;
465     }
466
467     /**
468      * @see DBHelper::number_of_columns()
469      */
470     public function number_of_columns(
471         $table_name
472         ) 
473     {
474         $result = $this->db->query("DESCRIBE $table_name");
475
476         return ($this->db->getRowCount($result));
477     }
478         
479         /**
480      * @see DBHelper::full_text_indexing_enabled()
481      */
482     protected function full_text_indexing_enabled(
483         $dbname = null
484         ) 
485     {
486                 return $this->isEngineEnabled('MyISAM');
487         }
488     
489     /**
490      * @see DBHelper::massageFieldDef()
491      */
492     public function massageFieldDef(
493         &$fieldDef,
494         $tablename
495         )
496     {
497         DBHelper::massageFieldDef($fieldDef,$tablename);
498         
499         if ( isset($fieldDef['default']) && 
500             ($fieldDef['dbType'] == 'text' 
501                 || $fieldDef['dbType'] == 'blob'
502                 || $fieldDef['dbType'] == 'longtext' 
503                 || $fieldDef['dbType'] == 'longblob' ))
504             unset($fieldDef['default']);
505         if ($fieldDef['dbType'] == 'uint')
506             $fieldDef['len'] = '10';
507         if ($fieldDef['dbType'] == 'ulong')
508             $fieldDef['len'] = '20';
509         if ($fieldDef['dbType'] == 'bool')
510             $fieldDef['type'] = 'tinyint';
511         if ($fieldDef['dbType'] == 'bool' && empty($fieldDef['default']) )
512             $fieldDef['default'] = '0';
513         if (($fieldDef['dbType'] == 'varchar' || $fieldDef['dbType'] == 'enum') && empty($fieldDef['len']) )
514             $fieldDef['len'] = '255';
515         if ($fieldDef['dbType'] == 'uint')
516             $fieldDef['len'] = '10';
517         if ($fieldDef['dbType'] == 'int' && empty($fieldDef['len']) )
518             $fieldDef['len'] = '11';
519     }
520 }
521 ?>