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