This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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-2013 SugarCRM Inc. |
||
6 | |||
7 | * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd. |
||
8 | * Copyright (C) 2011 - 2014 Salesagility Ltd. |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or modify it under |
||
11 | * the terms of the GNU Affero General Public License version 3 as published by the |
||
12 | * Free Software Foundation with the addition of the following permission added |
||
13 | * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK |
||
14 | * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY |
||
15 | * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. |
||
16 | * |
||
17 | * This program is distributed in the hope that it will be useful, but WITHOUT |
||
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||
19 | * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
||
20 | * details. |
||
21 | * |
||
22 | * You should have received a copy of the GNU Affero General Public License along with |
||
23 | * this program; if not, see http://www.gnu.org/licenses or write to the Free |
||
24 | * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
||
25 | * 02110-1301 USA. |
||
26 | * |
||
27 | * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, |
||
28 | * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected]. |
||
29 | * |
||
30 | * The interactive user interfaces in modified source and object code versions |
||
31 | * of this program must display Appropriate Legal Notices, as required under |
||
32 | * Section 5 of the GNU Affero General Public License version 3. |
||
33 | * |
||
34 | * In accordance with Section 7(b) of the GNU Affero General Public License version 3, |
||
35 | * these Appropriate Legal Notices must retain the display of the "Powered by |
||
36 | * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not |
||
37 | * reasonably feasible for technical reasons, the Appropriate Legal Notices must |
||
38 | * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". |
||
39 | ********************************************************************************/ |
||
40 | |||
41 | /********************************************************************************* |
||
42 | |||
43 | * Description: This file handles the Data base functionality for the application. |
||
44 | * It acts as the DB abstraction layer for the application. It depends on helper classes |
||
45 | * which generate the necessary SQL. This sql is then passed to PEAR DB classes. |
||
46 | * The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php. |
||
47 | * |
||
48 | * All the functions in this class will work with any bean which implements the meta interface. |
||
49 | * The passed bean is passed to helper class which uses these functions to generate correct sql. |
||
50 | * |
||
51 | * The meta interface has the following functions: |
||
52 | * getTableName() Returns table name of the object. |
||
53 | * getFieldDefinitions() Returns a collection of field definitions in order. |
||
54 | * getFieldDefintion(name) Return field definition for the field. |
||
55 | * getFieldValue(name) Returns the value of the field identified by name. |
||
56 | * If the field is not set, the function will return boolean FALSE. |
||
57 | * getPrimaryFieldDefinition() Returns the field definition for primary key |
||
58 | * |
||
59 | * The field definition is an array with the following keys: |
||
60 | * |
||
61 | * name This represents name of the field. This is a required field. |
||
62 | * type This represents type of the field. This is a required field and valid values are: |
||
63 | * � int |
||
64 | * � long |
||
65 | * � varchar |
||
66 | * � text |
||
67 | * � date |
||
68 | * � datetime |
||
69 | * � double |
||
70 | * � float |
||
71 | * � uint |
||
72 | * � ulong |
||
73 | * � time |
||
74 | * � short |
||
75 | * � enum |
||
76 | * length This is used only when the type is varchar and denotes the length of the string. |
||
77 | * The max value is 255. |
||
78 | * enumvals This is a list of valid values for an enum separated by "|". |
||
79 | * It is used only if the type is �enum�; |
||
80 | * required This field dictates whether it is a required value. |
||
81 | * The default value is �FALSE�. |
||
82 | * isPrimary This field identifies the primary key of the table. |
||
83 | * If none of the fields have this flag set to �TRUE�, |
||
84 | * the first field definition is assume to be the primary key. |
||
85 | * Default value for this field is �FALSE�. |
||
86 | * default This field sets the default value for the field definition. |
||
87 | * |
||
88 | * |
||
89 | * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. |
||
90 | * All Rights Reserved. |
||
91 | * Contributor(s): ______________________________________.. |
||
92 | ********************************************************************************/ |
||
93 | |||
94 | /** |
||
95 | * MySQL manager implementation for mysql extension |
||
96 | */ |
||
97 | class MysqlManager extends DBManager |
||
98 | { |
||
99 | /** |
||
100 | * @see DBManager::$dbType |
||
101 | */ |
||
102 | public $dbType = 'mysql'; |
||
103 | public $variant = 'mysql'; |
||
104 | public $dbName = 'MySQL'; |
||
105 | public $label = 'LBL_MYSQL'; |
||
106 | |||
107 | protected $maxNameLengths = array( |
||
108 | 'table' => 64, |
||
109 | 'column' => 64, |
||
110 | 'index' => 64, |
||
111 | 'alias' => 256 |
||
112 | ); |
||
113 | |||
114 | protected $type_map = array( |
||
115 | 'int' => 'int', |
||
116 | 'double' => 'double', |
||
117 | 'float' => 'float', |
||
118 | 'uint' => 'int unsigned', |
||
119 | 'ulong' => 'bigint unsigned', |
||
120 | 'long' => 'bigint', |
||
121 | 'short' => 'smallint', |
||
122 | 'varchar' => 'varchar', |
||
123 | 'text' => 'text', |
||
124 | 'longtext' => 'longtext', |
||
125 | 'date' => 'date', |
||
126 | 'enum' => 'varchar', |
||
127 | 'relate' => 'varchar', |
||
128 | 'multienum'=> 'text', |
||
129 | 'html' => 'text', |
||
130 | 'longhtml' => 'longtext', |
||
131 | 'datetime' => 'datetime', |
||
132 | 'datetimecombo' => 'datetime', |
||
133 | 'time' => 'time', |
||
134 | 'bool' => 'bool', |
||
135 | 'tinyint' => 'tinyint', |
||
136 | 'char' => 'char', |
||
137 | 'blob' => 'blob', |
||
138 | 'longblob' => 'longblob', |
||
139 | 'currency' => 'decimal(26,6)', |
||
140 | 'decimal' => 'decimal', |
||
141 | 'decimal2' => 'decimal', |
||
142 | 'id' => 'char(36)', |
||
143 | 'url' => 'varchar', |
||
144 | 'encrypt' => 'varchar', |
||
145 | 'file' => 'varchar', |
||
146 | 'decimal_tpl' => 'decimal(%d, %d)', |
||
147 | |||
148 | ); |
||
149 | |||
150 | protected $capabilities = array( |
||
151 | "affected_rows" => true, |
||
152 | "select_rows" => true, |
||
153 | "inline_keys" => true, |
||
154 | "create_user" => true, |
||
155 | "fulltext" => true, |
||
156 | "collation" => true, |
||
157 | "create_db" => true, |
||
158 | "disable_keys" => true, |
||
159 | ); |
||
160 | |||
161 | /** |
||
162 | * Parses and runs queries |
||
163 | * |
||
164 | * @param string $sql SQL Statement to execute |
||
165 | * @param bool $dieOnError True if we want to call die if the query returns errors |
||
166 | * @param string $msg Message to log if error occurs |
||
167 | * @param bool $suppress Flag to suppress all error output unless in debug logging mode. |
||
168 | * @param bool $keepResult True if we want to push this result into the $lastResult array. |
||
169 | * @return resource result set |
||
170 | */ |
||
171 | public function query($sql, $dieOnError = false, $msg = '', $suppress = false, $keepResult = false) |
||
172 | { |
||
173 | if(is_array($sql)) { |
||
174 | return $this->queryArray($sql, $dieOnError, $msg, $suppress); |
||
175 | } |
||
176 | |||
177 | parent::countQuery($sql); |
||
0 ignored issues
–
show
|
|||
178 | $GLOBALS['log']->info('Query:' . $sql); |
||
179 | $this->checkConnection(); |
||
180 | $this->query_time = microtime(true); |
||
0 ignored issues
–
show
The property
$query_time was declared of type integer , but microtime(true) is of type double . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
181 | $this->lastsql = $sql; |
||
182 | $result = $suppress?@mysql_query($sql, $this->database):mysql_query($sql, $this->database); |
||
183 | |||
184 | $this->query_time = microtime(true) - $this->query_time; |
||
0 ignored issues
–
show
The property
$query_time was declared of type integer , but microtime(true) - $this->query_time is of type double . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
185 | $GLOBALS['log']->info('Query Execution Time:'.$this->query_time); |
||
186 | |||
187 | |||
188 | if($keepResult) |
||
189 | $this->lastResult = $result; |
||
190 | |||
191 | $this->checkError($msg.' Query Failed:' . $sql . '::', $dieOnError); |
||
192 | return $result; |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Returns the number of rows affected by the last query |
||
197 | * @param $result |
||
198 | * @return int |
||
199 | */ |
||
200 | public function getAffectedRowCount($result) |
||
201 | { |
||
202 | return mysql_affected_rows($this->getDatabase()); |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * Returns the number of rows returned by the result |
||
207 | * |
||
208 | * This function can't be reliably implemented on most DB, do not use it. |
||
209 | * @abstract |
||
210 | * @deprecated |
||
211 | * @param resource $result |
||
212 | * @return int |
||
213 | */ |
||
214 | public function getRowCount($result) |
||
215 | { |
||
216 | return mysql_num_rows($result); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Disconnects from the database |
||
221 | * |
||
222 | * Also handles any cleanup needed |
||
223 | */ |
||
224 | public function disconnect() |
||
225 | { |
||
226 | $GLOBALS['log']->debug('Calling MySQL::disconnect()'); |
||
227 | if(!empty($this->database)){ |
||
228 | $this->freeResult(); |
||
229 | mysql_close($this->database); |
||
230 | $this->database = null; |
||
231 | } |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * @see DBManager::freeDbResult() |
||
236 | */ |
||
237 | protected function freeDbResult($dbResult) |
||
238 | { |
||
239 | if(!empty($dbResult)) |
||
240 | mysql_free_result($dbResult); |
||
241 | } |
||
242 | |||
243 | |||
244 | /** |
||
245 | * @abstract |
||
246 | * Check if query has LIMIT clause |
||
247 | * Relevant for now only for Mysql |
||
248 | * @param string $sql |
||
249 | * @return bool |
||
250 | */ |
||
251 | 9 | protected function hasLimit($sql) |
|
252 | { |
||
253 | 9 | return stripos($sql, " limit ") !== false; |
|
254 | } |
||
255 | |||
256 | /** |
||
257 | * @see DBManager::limitQuery() |
||
258 | */ |
||
259 | 172 | public function limitQuery($sql, $start, $count, $dieOnError = false, $msg = '', $execute = true) |
|
260 | { |
||
261 | 172 | $start = (int)$start; |
|
262 | 172 | $count = (int)$count; |
|
263 | 172 | if ($start < 0) |
|
264 | $start = 0; |
||
265 | 172 | $GLOBALS['log']->debug('Limit Query:' . $sql. ' Start: ' .$start . ' count: ' . $count); |
|
266 | |||
267 | 172 | $sql = "$sql LIMIT $start,$count"; |
|
268 | 172 | $this->lastsql = $sql; |
|
269 | |||
270 | 172 | if(!empty($GLOBALS['sugar_config']['check_query'])){ |
|
271 | $this->checkQuery($sql); |
||
272 | } |
||
273 | 172 | if(!$execute) { |
|
274 | return $sql; |
||
275 | } |
||
276 | |||
277 | 172 | return $this->query($sql, $dieOnError, $msg); |
|
278 | } |
||
279 | |||
280 | |||
281 | /** |
||
282 | * @see DBManager::checkQuery() |
||
283 | */ |
||
284 | protected function checkQuery($sql, $object_name = false) |
||
285 | { |
||
286 | $result = $this->query('EXPLAIN ' . $sql); |
||
287 | $badQuery = array(); |
||
288 | while ($row = $this->fetchByAssoc($result)) { |
||
289 | if (empty($row['table'])) |
||
290 | continue; |
||
291 | $badQuery[$row['table']] = ''; |
||
292 | if (strtoupper($row['type']) == 'ALL') |
||
293 | $badQuery[$row['table']] .= ' Full Table Scan;'; |
||
294 | if (empty($row['key'])) |
||
295 | $badQuery[$row['table']] .= ' No Index Key Used;'; |
||
296 | if (!empty($row['Extra']) && substr_count($row['Extra'], 'Using filesort') > 0) |
||
297 | $badQuery[$row['table']] .= ' Using FileSort;'; |
||
298 | if (!empty($row['Extra']) && substr_count($row['Extra'], 'Using temporary') > 0) |
||
299 | $badQuery[$row['table']] .= ' Using Temporary Table;'; |
||
300 | } |
||
301 | |||
302 | if ( empty($badQuery) ) |
||
303 | return true; |
||
304 | |||
305 | foreach($badQuery as $table=>$data ){ |
||
306 | if(!empty($data)){ |
||
307 | $warning = ' Table:' . $table . ' Data:' . $data; |
||
308 | if(!empty($GLOBALS['sugar_config']['check_query_log'])){ |
||
309 | $GLOBALS['log']->fatal($sql); |
||
310 | $GLOBALS['log']->fatal('CHECK QUERY:' .$warning); |
||
311 | } |
||
312 | else{ |
||
313 | $GLOBALS['log']->warn('CHECK QUERY:' .$warning); |
||
314 | } |
||
315 | } |
||
316 | } |
||
317 | |||
318 | return false; |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * @see DBManager::get_columns() |
||
323 | */ |
||
324 | public function get_columns($tablename) |
||
325 | { |
||
326 | //find all unique indexes and primary keys. |
||
327 | $result = $this->query("DESCRIBE $tablename"); |
||
328 | |||
329 | $columns = array(); |
||
330 | while (($row=$this->fetchByAssoc($result)) !=null) { |
||
331 | $name = strtolower($row['Field']); |
||
332 | $columns[$name]['name']=$name; |
||
333 | $matches = array(); |
||
334 | preg_match_all('/(\w+)(?:\(([0-9]+,?[0-9]*)\)|)( unsigned)?/i', $row['Type'], $matches); |
||
335 | $columns[$name]['type']=strtolower($matches[1][0]); |
||
336 | if ( isset($matches[2][0]) && in_array(strtolower($matches[1][0]),array('varchar','char','varchar2','int','decimal','float')) ) |
||
337 | $columns[$name]['len']=strtolower($matches[2][0]); |
||
338 | if ( stristr($row['Extra'],'auto_increment') ) |
||
339 | $columns[$name]['auto_increment'] = '1'; |
||
340 | if ($row['Null'] == 'NO' && !stristr($row['Key'],'PRI')) |
||
341 | $columns[$name]['required'] = 'true'; |
||
342 | if (!empty($row['Default']) ) |
||
343 | $columns[$name]['default'] = $row['Default']; |
||
344 | } |
||
345 | return $columns; |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * @see DBManager::getFieldsArray() |
||
350 | */ |
||
351 | public function getFieldsArray($result, $make_lower_case=false) |
||
352 | { |
||
353 | $field_array = array(); |
||
354 | |||
355 | if(empty($result)) |
||
356 | return 0; |
||
357 | |||
358 | $fields = mysql_num_fields($result); |
||
359 | for ($i=0; $i < $fields; $i++) { |
||
360 | $meta = mysql_fetch_field($result, $i); |
||
361 | if (!$meta) |
||
362 | return array(); |
||
363 | |||
364 | if($make_lower_case == true) |
||
0 ignored issues
–
show
|
|||
365 | $meta->name = strtolower($meta->name); |
||
366 | |||
367 | $field_array[] = $meta->name; |
||
368 | } |
||
369 | |||
370 | return $field_array; |
||
371 | } |
||
372 | |||
373 | /** |
||
374 | * @see DBManager::fetchRow() |
||
375 | */ |
||
376 | public function fetchRow($result) |
||
377 | { |
||
378 | if (empty($result)) return false; |
||
379 | |||
380 | return mysql_fetch_assoc($result); |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * @see DBManager::getTablesArray() |
||
385 | */ |
||
386 | public function getTablesArray() |
||
387 | { |
||
388 | $this->log->debug('Fetching table list'); |
||
389 | |||
390 | if ($this->getDatabase()) { |
||
391 | $tables = array(); |
||
392 | $r = $this->query('SHOW TABLES'); |
||
393 | if (!empty($r)) { |
||
394 | while ($a = $this->fetchByAssoc($r)) { |
||
395 | $row = array_values($a); |
||
396 | $tables[]=$row[0]; |
||
397 | } |
||
398 | return $tables; |
||
399 | } |
||
400 | } |
||
401 | |||
402 | return false; // no database available |
||
403 | } |
||
404 | |||
405 | /** |
||
406 | * @see DBManager::version() |
||
407 | */ |
||
408 | public function version() |
||
409 | { |
||
410 | return $this->getOne("SELECT version() version"); |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * @see DBManager::tableExists() |
||
415 | */ |
||
416 | public function tableExists($tableName) |
||
417 | { |
||
418 | $this->log->info("tableExists: $tableName"); |
||
419 | |||
420 | if ($this->getDatabase()) { |
||
421 | $result = $this->query("SHOW TABLES LIKE ".$this->quoted($tableName)); |
||
422 | if(empty($result)) return false; |
||
423 | $row = $this->fetchByAssoc($result); |
||
424 | return !empty($row); |
||
425 | } |
||
426 | |||
427 | return false; |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Get tables like expression |
||
432 | * @param $like string |
||
433 | * @return array |
||
434 | */ |
||
435 | public function tablesLike($like) |
||
436 | { |
||
437 | if ($this->getDatabase()) { |
||
438 | $tables = array(); |
||
439 | $r = $this->query('SHOW TABLES LIKE '.$this->quoted($like)); |
||
440 | if (!empty($r)) { |
||
441 | while ($a = $this->fetchByAssoc($r)) { |
||
442 | $row = array_values($a); |
||
443 | $tables[]=$row[0]; |
||
444 | } |
||
445 | return $tables; |
||
446 | } |
||
447 | } |
||
448 | return false; |
||
449 | } |
||
450 | |||
451 | /** |
||
452 | * @see DBManager::quote() |
||
453 | */ |
||
454 | public function quote($string) |
||
455 | { |
||
456 | if(is_array($string)) { |
||
457 | return $this->arrayQuote($string); |
||
458 | } |
||
459 | return mysql_real_escape_string($this->quoteInternal($string), $this->getDatabase()); |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * @see DBManager::quoteIdentifier() |
||
464 | */ |
||
465 | 25 | public function quoteIdentifier($string) |
|
466 | { |
||
467 | 25 | return '`'.$string.'`'; |
|
468 | } |
||
469 | |||
470 | /** |
||
471 | * @see DBManager::connect() |
||
472 | */ |
||
473 | public function connect(array $configOptions = null, $dieOnError = false) |
||
474 | { |
||
475 | global $sugar_config; |
||
476 | |||
477 | if(is_null($configOptions)) |
||
478 | $configOptions = $sugar_config['dbconfig']; |
||
479 | |||
480 | if ($this->getOption('persistent')) { |
||
481 | $this->database = @mysql_pconnect( |
||
482 | $configOptions['db_host_name'], |
||
483 | $configOptions['db_user_name'], |
||
484 | $configOptions['db_password'] |
||
485 | ); |
||
486 | } |
||
487 | |||
488 | if (!$this->database) { |
||
489 | $this->database = mysql_connect( |
||
490 | $configOptions['db_host_name'], |
||
491 | $configOptions['db_user_name'], |
||
492 | $configOptions['db_password'] |
||
493 | ); |
||
494 | if(empty($this->database)) { |
||
495 | $GLOBALS['log']->fatal("Could not connect to server ".$configOptions['db_host_name']." as ".$configOptions['db_user_name'].":".mysql_error()); |
||
496 | if($dieOnError) { |
||
497 | if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) { |
||
498 | sugar_die($GLOBALS['app_strings']['ERR_NO_DB']); |
||
499 | } else { |
||
500 | sugar_die("Could not connect to the database. Please refer to suitecrm.log for details."); |
||
501 | } |
||
502 | } else { |
||
503 | return false; |
||
504 | } |
||
505 | } |
||
506 | // Do not pass connection information because we have not connected yet |
||
507 | if($this->database && $this->getOption('persistent')){ |
||
508 | $_SESSION['administrator_error'] = "<b>Severe Performance Degradation: Persistent Database Connections " |
||
509 | . "not working. Please set \$sugar_config['dbconfigoption']['persistent'] to false " |
||
510 | . "in your config.php file</b>"; |
||
511 | } |
||
512 | } |
||
513 | if(!empty($configOptions['db_name']) && !@mysql_select_db($configOptions['db_name'])) { |
||
514 | $GLOBALS['log']->fatal( "Unable to select database {$configOptions['db_name']}: " . mysql_error($this->database)); |
||
515 | if($dieOnError) { |
||
516 | sugar_die($GLOBALS['app_strings']['ERR_NO_DB']); |
||
517 | } else { |
||
518 | return false; |
||
519 | } |
||
520 | } |
||
521 | |||
522 | // cn: using direct calls to prevent this from spamming the Logs |
||
523 | mysql_query("SET CHARACTER SET utf8", $this->database); |
||
524 | $names = "SET NAMES 'utf8'"; |
||
525 | $collation = $this->getOption('collation'); |
||
526 | if(!empty($collation)) { |
||
527 | $names .= " COLLATE '$collation'"; |
||
528 | } |
||
529 | mysql_query($names, $this->database); |
||
530 | |||
531 | if(!$this->checkError('Could Not Connect:', $dieOnError)) |
||
532 | $GLOBALS['log']->info("connected to db"); |
||
533 | $this->connectOptions = $configOptions; |
||
534 | |||
535 | $GLOBALS['log']->info("Connect:".$this->database); |
||
536 | return true; |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * @see DBManager::repairTableParams() |
||
541 | * |
||
542 | * For MySQL, we can write the ALTER TABLE statement all in one line, which speeds things |
||
543 | * up quite a bit. So here, we'll parse the returned SQL into a single ALTER TABLE command. |
||
544 | */ |
||
545 | public function repairTableParams($tablename, $fielddefs, $indices, $execute = true, $engine = null) |
||
546 | { |
||
547 | $sql = parent::repairTableParams($tablename,$fielddefs,$indices,false,$engine); |
||
548 | |||
549 | if ( $sql == '' ) |
||
550 | return ''; |
||
551 | |||
552 | if ( stristr($sql,'create table') ) |
||
553 | { |
||
554 | if ($execute) { |
||
555 | $msg = "Error creating table: ".$tablename. ":"; |
||
556 | $this->query($sql,true,$msg); |
||
557 | } |
||
558 | return $sql; |
||
559 | } |
||
560 | |||
561 | // first, parse out all the comments |
||
562 | $match = array(); |
||
563 | preg_match_all('!/\*.*?\*/!is', $sql, $match); |
||
564 | $commentBlocks = $match[0]; |
||
565 | $sql = preg_replace('!/\*.*?\*/!is','', $sql); |
||
566 | |||
567 | // now, we should only have alter table statements |
||
568 | // let's replace the 'alter table name' part with a comma |
||
569 | $sql = preg_replace("!alter table $tablename!is",', ', $sql); |
||
570 | |||
571 | // re-add it at the beginning |
||
572 | $sql = substr_replace($sql,'',strpos($sql,','),1); |
||
573 | $sql = str_replace(";","",$sql); |
||
574 | $sql = str_replace("\n","",$sql); |
||
575 | $sql = "ALTER TABLE $tablename $sql"; |
||
576 | |||
577 | if ( $execute ) |
||
578 | $this->query($sql,'Error with MySQL repair table'); |
||
579 | |||
580 | // and re-add the comments at the beginning |
||
581 | $sql = implode("\n",$commentBlocks) . "\n". $sql . "\n"; |
||
582 | |||
583 | return $sql; |
||
584 | } |
||
585 | |||
586 | /** |
||
587 | * @see DBManager::convert() |
||
588 | */ |
||
589 | 111 | public function convert($string, $type, array $additional_parameters = array()) |
|
590 | { |
||
591 | 111 | $all_parameters = $additional_parameters; |
|
592 | 111 | if(is_array($string)) { |
|
593 | $all_parameters = array_merge($string, $all_parameters); |
||
594 | 111 | } elseif (!is_null($string)) { |
|
595 | 110 | array_unshift($all_parameters, $string); |
|
596 | } |
||
597 | 111 | $all_strings = implode(',', $all_parameters); |
|
598 | |||
599 | 111 | switch (strtolower($type)) { |
|
600 | 111 | case 'today': |
|
601 | 32 | return "CURDATE()"; |
|
602 | 104 | case 'left': |
|
603 | 1 | return "LEFT($all_strings)"; |
|
604 | 103 | case 'date_format': |
|
0 ignored issues
–
show
|
|||
605 | 1 | if(empty($additional_parameters)) { |
|
606 | 1 | return "DATE_FORMAT($string,'%Y-%m-%d')"; |
|
607 | } else { |
||
608 | $format = $additional_parameters[0]; |
||
609 | if($format[0] != "'") { |
||
610 | $format = $this->quoted($format); |
||
611 | } |
||
612 | return "DATE_FORMAT($string,$format)"; |
||
613 | } |
||
614 | 102 | case 'ifnull': |
|
615 | 15 | if(empty($additional_parameters) && !strstr($all_strings, ",")) { |
|
616 | $all_strings .= ",''"; |
||
617 | } |
||
618 | 15 | return "IFNULL($all_strings)"; |
|
619 | 101 | case 'concat': |
|
620 | 15 | return "CONCAT($all_strings)"; |
|
621 | 89 | case 'quarter': |
|
622 | 1 | return "QUARTER($string)"; |
|
623 | 88 | case "length": |
|
624 | 5 | return "LENGTH($string)"; |
|
625 | 86 | case 'month': |
|
626 | 1 | return "MONTH($string)"; |
|
627 | 85 | case 'add_date': |
|
628 | 1 | return "DATE_ADD($string, INTERVAL {$additional_parameters[0]} {$additional_parameters[1]})"; |
|
629 | 84 | case 'add_time': |
|
630 | 1 | return "DATE_ADD($string, INTERVAL + CONCAT({$additional_parameters[0]}, ':', {$additional_parameters[1]}) HOUR_MINUTE)"; |
|
631 | 83 | case 'add_tz_offset' : |
|
0 ignored issues
–
show
There must be no space before the colon in a CASE statement
As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements. switch ($selector) {
case "A": //right
doSomething();
break;
case "B" : //wrong
doSomethingElse();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
632 | 1 | $getUserUTCOffset = $GLOBALS['timedate']->getUserUTCOffset(); |
|
633 | 1 | $operation = $getUserUTCOffset < 0 ? '-' : '+'; |
|
634 | 1 | return $string . ' ' . $operation . ' INTERVAL ' . abs($getUserUTCOffset) . ' MINUTE'; |
|
635 | 82 | case 'avg': |
|
636 | 1 | return "avg($string)"; |
|
637 | } |
||
638 | |||
639 | 81 | return $string; |
|
640 | } |
||
641 | |||
642 | /** |
||
643 | * (non-PHPdoc) |
||
644 | * @see DBManager::fromConvert() |
||
645 | */ |
||
646 | 92 | public function fromConvert($string, $type) |
|
647 | { |
||
648 | 92 | return $string; |
|
649 | } |
||
650 | |||
651 | /** |
||
652 | * Returns the name of the engine to use or null if we are to use the default |
||
653 | * |
||
654 | * @param object $bean SugarBean instance |
||
655 | * @return string |
||
656 | */ |
||
657 | protected function getEngine($bean) |
||
658 | { |
||
659 | global $dictionary; |
||
660 | $engine = null; |
||
661 | if (isset($dictionary[$bean->getObjectName()]['engine'])) { |
||
662 | $engine = $dictionary[$bean->getObjectName()]['engine']; |
||
663 | } |
||
664 | return $engine; |
||
665 | } |
||
666 | |||
667 | /** |
||
668 | * Returns true if the engine given is enabled in the backend |
||
669 | * |
||
670 | * @param string $engine |
||
671 | * @return bool |
||
672 | */ |
||
673 | protected function isEngineEnabled($engine) |
||
674 | { |
||
675 | if(!is_string($engine)) return false; |
||
676 | |||
677 | $engine = strtoupper($engine); |
||
678 | |||
679 | $r = $this->query("SHOW ENGINES"); |
||
680 | |||
681 | while ( $row = $this->fetchByAssoc($r) ) |
||
682 | if ( strtoupper($row['Engine']) == $engine ) |
||
683 | return ($row['Support']=='YES' || $row['Support']=='DEFAULT'); |
||
684 | |||
685 | return false; |
||
686 | } |
||
687 | |||
688 | /** |
||
689 | * @see DBManager::createTableSQL() |
||
690 | */ |
||
691 | public function createTableSQL(SugarBean $bean) |
||
692 | { |
||
693 | $tablename = $bean->getTableName(); |
||
694 | $fieldDefs = $bean->getFieldDefinitions(); |
||
695 | $indices = $bean->getIndices(); |
||
696 | $engine = $this->getEngine($bean); |
||
697 | return $this->createTableSQLParams($tablename, $fieldDefs, $indices, $engine); |
||
698 | } |
||
699 | |||
700 | /** |
||
701 | * Generates sql for create table statement for a bean. |
||
702 | * |
||
703 | * @param string $tablename |
||
704 | * @param array $fieldDefs |
||
705 | * @param array $indices |
||
706 | * @param string $engine optional, MySQL engine to use |
||
707 | * @return string SQL Create Table statement |
||
708 | */ |
||
709 | public function createTableSQLParams($tablename, $fieldDefs, $indices, $engine = null) |
||
710 | { |
||
711 | if ( empty($engine) && isset($fieldDefs['engine'])) |
||
712 | $engine = $fieldDefs['engine']; |
||
713 | if ( !$this->isEngineEnabled($engine) ) |
||
714 | $engine = ''; |
||
715 | |||
716 | $columns = $this->columnSQLRep($fieldDefs, false, $tablename); |
||
717 | if (empty($columns)) |
||
718 | return false; |
||
719 | |||
720 | $keys = $this->keysSQL($indices); |
||
721 | if (!empty($keys)) |
||
722 | $keys = ",$keys"; |
||
723 | |||
724 | // cn: bug 9873 - module tables do not get created in utf8 with assoc collation |
||
725 | $collation = $this->getOption('collation'); |
||
726 | if(empty($collation)) { |
||
727 | $collation = 'utf8_general_ci'; |
||
728 | } |
||
729 | $sql = "CREATE TABLE $tablename ($columns $keys) CHARACTER SET utf8 COLLATE $collation"; |
||
730 | |||
731 | if (!empty($engine)) |
||
732 | $sql.= " ENGINE=$engine"; |
||
733 | |||
734 | return $sql; |
||
735 | } |
||
736 | |||
737 | /** |
||
738 | * Does this type represent text (i.e., non-varchar) value? |
||
739 | * @param string $type |
||
740 | */ |
||
741 | 13 | public function isTextType($type) |
|
742 | { |
||
743 | 13 | $type = $this->getColumnType(strtolower($type)); |
|
744 | 13 | return in_array($type, array('blob','text','longblob', 'longtext')); |
|
745 | } |
||
746 | |||
747 | /** |
||
748 | * @see DBManager::oneColumnSQLRep() |
||
749 | */ |
||
750 | protected function oneColumnSQLRep($fieldDef, $ignoreRequired = false, $table = '', $return_as_array = false) |
||
751 | { |
||
752 | // always return as array for post-processing |
||
753 | $ref = parent::oneColumnSQLRep($fieldDef, $ignoreRequired, $table, true); |
||
754 | |||
755 | if ( $ref['colType'] == 'int' && !empty($fieldDef['len']) ) { |
||
756 | $ref['colType'] .= "(".$fieldDef['len'].")"; |
||
757 | } |
||
758 | |||
759 | // bug 22338 - don't set a default value on text or blob fields |
||
760 | if ( isset($ref['default']) && |
||
761 | in_array($ref['colBaseType'], array('text', 'blob', 'longtext', 'longblob'))) |
||
762 | $ref['default'] = ''; |
||
763 | |||
764 | if ( $return_as_array ) |
||
765 | return $ref; |
||
766 | else |
||
767 | return "{$ref['name']} {$ref['colType']} {$ref['default']} {$ref['required']} {$ref['auto_increment']}"; |
||
768 | } |
||
769 | |||
770 | /** |
||
771 | * @see DBManager::changeColumnSQL() |
||
772 | */ |
||
773 | protected function changeColumnSQL($tablename, $fieldDefs, $action, $ignoreRequired = false) |
||
774 | { |
||
775 | $columns = array(); |
||
776 | if ($this->isFieldArray($fieldDefs)){ |
||
777 | foreach ($fieldDefs as $def){ |
||
778 | if ($action == 'drop') |
||
779 | $columns[] = $def['name']; |
||
780 | else |
||
781 | $columns[] = $this->oneColumnSQLRep($def, $ignoreRequired); |
||
782 | } |
||
783 | } else { |
||
784 | if ($action == 'drop') |
||
785 | $columns[] = $fieldDefs['name']; |
||
786 | else |
||
787 | $columns[] = $this->oneColumnSQLRep($fieldDefs); |
||
788 | } |
||
789 | |||
790 | return "ALTER TABLE $tablename $action COLUMN ".implode(",$action column ", $columns); |
||
791 | } |
||
792 | |||
793 | /** |
||
794 | * Generates SQL for key specification inside CREATE TABLE statement |
||
795 | * |
||
796 | * The passes array is an array of field definitions or a field definition |
||
797 | * itself. The keys generated will be either primary, foreign, unique, index |
||
798 | * or none at all depending on the setting of the "key" parameter of a field definition |
||
799 | * |
||
800 | * @param array $indices |
||
801 | * @param bool $alter_table |
||
802 | * @param string $alter_action |
||
803 | * @return string SQL Statement |
||
804 | */ |
||
805 | protected function keysSQL($indices, $alter_table = false, $alter_action = '') |
||
806 | { |
||
807 | // check if the passed value is an array of fields. |
||
808 | // if not, convert it into an array |
||
809 | if (!$this->isFieldArray($indices)) |
||
810 | $indices[] = $indices; |
||
811 | |||
812 | $columns = array(); |
||
813 | foreach ($indices as $index) { |
||
814 | if(!empty($index['db']) && $index['db'] != $this->dbType) |
||
815 | continue; |
||
816 | if (isset($index['source']) && $index['source'] != 'db') |
||
817 | continue; |
||
818 | |||
819 | $type = $index['type']; |
||
820 | $name = $index['name']; |
||
821 | |||
822 | if (is_array($index['fields'])) |
||
823 | $fields = implode(", ", $index['fields']); |
||
824 | else |
||
825 | $fields = $index['fields']; |
||
826 | |||
827 | switch ($type) { |
||
828 | case 'unique': |
||
829 | $columns[] = " UNIQUE $name ($fields)"; |
||
830 | break; |
||
831 | case 'primary': |
||
832 | $columns[] = " PRIMARY KEY ($fields)"; |
||
833 | break; |
||
834 | case 'index': |
||
835 | case 'foreign': |
||
836 | case 'clustered': |
||
837 | case 'alternate_key': |
||
838 | /** |
||
839 | * @todo here it is assumed that the primary key of the foreign |
||
840 | * table will always be named 'id'. It must be noted though |
||
841 | * that this can easily be fixed by referring to db dictionary |
||
842 | * to find the correct primary field name |
||
843 | */ |
||
844 | if ( $alter_table ) |
||
845 | $columns[] = " INDEX $name ($fields)"; |
||
846 | else |
||
847 | $columns[] = " KEY $name ($fields)"; |
||
848 | break; |
||
849 | case 'fulltext': |
||
850 | if ($this->full_text_indexing_installed()) |
||
851 | $columns[] = " FULLTEXT ($fields)"; |
||
852 | else |
||
853 | $GLOBALS['log']->debug('MYISAM engine is not available/enabled, full-text indexes will be skipped. Skipping:',$name); |
||
854 | break; |
||
855 | } |
||
856 | } |
||
857 | $columns = implode(", $alter_action ", $columns); |
||
858 | if(!empty($alter_action)){ |
||
859 | $columns = $alter_action . ' '. $columns; |
||
860 | } |
||
861 | return $columns; |
||
862 | } |
||
863 | |||
864 | /** |
||
865 | * @see DBManager::setAutoIncrement() |
||
866 | */ |
||
867 | protected function setAutoIncrement($table, $field_name) |
||
868 | { |
||
869 | return "auto_increment"; |
||
870 | } |
||
871 | |||
872 | /** |
||
873 | * Sets the next auto-increment value of a column to a specific value. |
||
874 | * |
||
875 | * @param string $table tablename |
||
876 | * @param string $field_name |
||
877 | */ |
||
878 | public function setAutoIncrementStart($table, $field_name, $start_value) |
||
879 | { |
||
880 | $start_value = (int)$start_value; |
||
881 | return $this->query( "ALTER TABLE $table AUTO_INCREMENT = $start_value;"); |
||
882 | } |
||
883 | |||
884 | /** |
||
885 | * Returns the next value for an auto increment |
||
886 | * |
||
887 | * @param string $table tablename |
||
888 | * @param string $field_name |
||
889 | * @return string |
||
890 | */ |
||
891 | public function getAutoIncrement($table, $field_name) |
||
892 | { |
||
893 | $result = $this->query("SHOW TABLE STATUS LIKE '$table'"); |
||
894 | $row = $this->fetchByAssoc($result); |
||
895 | if (!empty($row['Auto_increment'])) |
||
896 | return $row['Auto_increment']; |
||
897 | |||
898 | return ""; |
||
899 | } |
||
900 | |||
901 | /** |
||
902 | * @see DBManager::get_indices() |
||
903 | */ |
||
904 | public function get_indices($tablename) |
||
905 | { |
||
906 | //find all unique indexes and primary keys. |
||
907 | $result = $this->query("SHOW INDEX FROM $tablename"); |
||
908 | |||
909 | $indices = array(); |
||
910 | while (($row=$this->fetchByAssoc($result)) !=null) { |
||
911 | $index_type='index'; |
||
912 | if ($row['Key_name'] =='PRIMARY') { |
||
913 | $index_type='primary'; |
||
914 | } |
||
915 | elseif ( $row['Non_unique'] == '0' ) { |
||
916 | $index_type='unique'; |
||
917 | } |
||
918 | $name = strtolower($row['Key_name']); |
||
919 | $indices[$name]['name']=$name; |
||
920 | $indices[$name]['type']=$index_type; |
||
921 | $indices[$name]['fields'][]=strtolower($row['Column_name']); |
||
922 | } |
||
923 | return $indices; |
||
924 | } |
||
925 | |||
926 | /** |
||
927 | * @see DBManager::add_drop_constraint() |
||
928 | */ |
||
929 | public function add_drop_constraint($table, $definition, $drop = false) |
||
930 | { |
||
931 | $type = $definition['type']; |
||
932 | $fields = implode(',',$definition['fields']); |
||
933 | $name = $definition['name']; |
||
934 | $sql = ''; |
||
935 | |||
936 | switch ($type){ |
||
937 | // generic indices |
||
938 | case 'index': |
||
939 | case 'alternate_key': |
||
940 | case 'clustered': |
||
941 | if ($drop) |
||
942 | $sql = "ALTER TABLE {$table} DROP INDEX {$name} "; |
||
943 | else |
||
944 | $sql = "ALTER TABLE {$table} ADD INDEX {$name} ({$fields})"; |
||
945 | break; |
||
946 | // constraints as indices |
||
947 | case 'unique': |
||
948 | if ($drop) |
||
949 | $sql = "ALTER TABLE {$table} DROP INDEX $name"; |
||
950 | else |
||
951 | $sql = "ALTER TABLE {$table} ADD CONSTRAINT UNIQUE {$name} ({$fields})"; |
||
952 | break; |
||
953 | case 'primary': |
||
954 | if ($drop) |
||
955 | $sql = "ALTER TABLE {$table} DROP PRIMARY KEY"; |
||
956 | else |
||
957 | $sql = "ALTER TABLE {$table} ADD CONSTRAINT PRIMARY KEY ({$fields})"; |
||
958 | break; |
||
959 | case 'foreign': |
||
960 | if ($drop) |
||
961 | $sql = "ALTER TABLE {$table} DROP FOREIGN KEY ({$fields})"; |
||
962 | else |
||
963 | $sql = "ALTER TABLE {$table} ADD CONSTRAINT FOREIGN KEY {$name} ({$fields}) REFERENCES {$definition['foreignTable']}({$definition['foreignField']})"; |
||
964 | break; |
||
965 | } |
||
966 | return $sql; |
||
967 | } |
||
968 | |||
969 | /** |
||
970 | * Runs a query and returns a single row |
||
971 | * |
||
972 | * @param string $sql SQL Statement to execute |
||
973 | * @param bool $dieOnError True if we want to call die if the query returns errors |
||
974 | * @param string $msg Message to log if error occurs |
||
975 | * @param bool $suppress Message to log if error occurs |
||
976 | * @return array single row from the query |
||
977 | */ |
||
978 | 3 | public function fetchOne($sql, $dieOnError = false, $msg = '', $suppress = false) |
|
979 | { |
||
980 | 3 | if(stripos($sql, ' LIMIT ') === false) { |
|
981 | // little optimization to just fetch one row |
||
982 | 3 | $sql .= " LIMIT 0,1"; |
|
983 | } |
||
984 | 3 | return parent::fetchOne($sql, $dieOnError, $msg, $suppress); |
|
985 | } |
||
986 | |||
987 | /** |
||
988 | * @see DBManager::full_text_indexing_installed() |
||
989 | */ |
||
990 | public function full_text_indexing_installed($dbname = null) |
||
991 | { |
||
992 | return $this->isEngineEnabled('MyISAM'); |
||
993 | } |
||
994 | |||
995 | /** |
||
996 | * @see DBManager::massageFieldDef() |
||
997 | */ |
||
998 | public function massageFieldDef(&$fieldDef, $tablename) |
||
999 | { |
||
1000 | parent::massageFieldDef($fieldDef,$tablename); |
||
1001 | |||
1002 | if ( isset($fieldDef['default']) && |
||
1003 | ($fieldDef['dbType'] == 'text' |
||
1004 | || $fieldDef['dbType'] == 'blob' |
||
1005 | || $fieldDef['dbType'] == 'longtext' |
||
1006 | || $fieldDef['dbType'] == 'longblob' )) |
||
1007 | unset($fieldDef['default']); |
||
1008 | if ($fieldDef['dbType'] == 'uint') |
||
1009 | $fieldDef['len'] = '10'; |
||
1010 | if ($fieldDef['dbType'] == 'ulong') |
||
1011 | $fieldDef['len'] = '20'; |
||
1012 | if ($fieldDef['dbType'] == 'bool') |
||
1013 | $fieldDef['type'] = 'tinyint'; |
||
1014 | if ($fieldDef['dbType'] == 'bool' && empty($fieldDef['default']) ) |
||
1015 | $fieldDef['default'] = '0'; |
||
1016 | if (($fieldDef['dbType'] == 'varchar' || $fieldDef['dbType'] == 'enum') && empty($fieldDef['len']) ) |
||
1017 | $fieldDef['len'] = '255'; |
||
1018 | if ($fieldDef['dbType'] == 'uint') |
||
1019 | $fieldDef['len'] = '10'; |
||
1020 | if ($fieldDef['dbType'] == 'int' && empty($fieldDef['len']) ) |
||
1021 | $fieldDef['len'] = '11'; |
||
1022 | |||
1023 | if($fieldDef['dbType'] == 'decimal') { |
||
1024 | if(isset($fieldDef['len'])) { |
||
1025 | if(strstr($fieldDef['len'], ",") === false) { |
||
1026 | $fieldDef['len'] .= ",0"; |
||
1027 | } |
||
1028 | } else { |
||
1029 | $fieldDef['len'] = '10,0'; |
||
1030 | } |
||
1031 | } |
||
1032 | } |
||
1033 | |||
1034 | /** |
||
1035 | * Generates SQL for dropping a table. |
||
1036 | * |
||
1037 | * @param string $name table name |
||
1038 | * @return string SQL statement |
||
1039 | */ |
||
1040 | public function dropTableNameSQL($name) |
||
1041 | { |
||
1042 | return "DROP TABLE IF EXISTS ".$name; |
||
1043 | } |
||
1044 | |||
1045 | public function dropIndexes($tablename, $indexes, $execute = true) |
||
1046 | { |
||
1047 | $sql = array(); |
||
1048 | foreach ($indexes as $index) { |
||
1049 | $name =$index['name']; |
||
1050 | if($execute) { |
||
1051 | unset(self::$index_descriptions[$tablename][$name]); |
||
1052 | } |
||
1053 | if ($index['type'] == 'primary') { |
||
1054 | $sql[] = 'DROP PRIMARY KEY'; |
||
1055 | } else { |
||
1056 | $sql[] = "DROP INDEX $name"; |
||
1057 | } |
||
1058 | } |
||
1059 | if (!empty($sql)) { |
||
1060 | $sql = "ALTER TABLE $tablename " . join(",", $sql) . ";"; |
||
1061 | if($execute) |
||
1062 | $this->query($sql); |
||
1063 | } else { |
||
1064 | $sql = ''; |
||
1065 | } |
||
1066 | return $sql; |
||
1067 | } |
||
1068 | |||
1069 | /** |
||
1070 | * List of available collation settings |
||
1071 | * @return string |
||
1072 | */ |
||
1073 | public function getDefaultCollation() |
||
1074 | { |
||
1075 | return "utf8_general_ci"; |
||
1076 | } |
||
1077 | |||
1078 | /** |
||
1079 | * List of available collation settings |
||
1080 | * @return array |
||
1081 | */ |
||
1082 | public function getCollationList() |
||
1083 | { |
||
1084 | $q = "SHOW COLLATION LIKE 'utf8%'"; |
||
1085 | $r = $this->query($q); |
||
1086 | $res = array(); |
||
1087 | while($a = $this->fetchByAssoc($r)) { |
||
1088 | $res[] = $a['Collation']; |
||
1089 | } |
||
1090 | return $res; |
||
1091 | } |
||
1092 | |||
1093 | /** |
||
1094 | * (non-PHPdoc) |
||
1095 | * @see DBManager::renameColumnSQL() |
||
1096 | */ |
||
1097 | public function renameColumnSQL($tablename, $column, $newname) |
||
1098 | { |
||
1099 | $field = $this->describeField($column, $tablename); |
||
1100 | $field['name'] = $newname; |
||
1101 | return "ALTER TABLE $tablename CHANGE COLUMN $column ".$this->oneColumnSQLRep($field); |
||
1102 | } |
||
1103 | |||
1104 | 25 | public function emptyValue($type) |
|
1105 | { |
||
1106 | 25 | $ctype = $this->getColumnType($type); |
|
1107 | 25 | if($ctype == "datetime") { |
|
1108 | 7 | return $this->convert($this->quoted("0000-00-00 00:00:00"), "datetime"); |
|
1109 | } |
||
1110 | 24 | if($ctype == "date") { |
|
1111 | 2 | return $this->convert($this->quoted("0000-00-00"), "date"); |
|
1112 | } |
||
1113 | 23 | if($ctype == "time") { |
|
1114 | return $this->convert($this->quoted("00:00:00"), "time"); |
||
1115 | } |
||
1116 | 23 | return parent::emptyValue($type); |
|
1117 | } |
||
1118 | |||
1119 | /** |
||
1120 | * (non-PHPdoc) |
||
1121 | * @see DBManager::lastDbError() |
||
1122 | */ |
||
1123 | public function lastDbError() |
||
1124 | { |
||
1125 | if($this->database) { |
||
1126 | if(mysql_errno($this->database)) { |
||
1127 | return "MySQL error ".mysql_errno($this->database).": ".mysql_error($this->database); |
||
1128 | } |
||
1129 | } else { |
||
1130 | $err = mysql_error(); |
||
1131 | if($err) { |
||
1132 | return $err; |
||
1133 | } |
||
1134 | } |
||
1135 | return false; |
||
1136 | } |
||
1137 | |||
1138 | /** |
||
1139 | * Quote MySQL search term |
||
1140 | * @param unknown_type $term |
||
1141 | */ |
||
1142 | protected function quoteTerm($term) |
||
1143 | { |
||
1144 | if(strpos($term, ' ') !== false) { |
||
1145 | return '"'.$term.'"'; |
||
1146 | } |
||
1147 | return $term; |
||
1148 | } |
||
1149 | |||
1150 | /** |
||
1151 | * Generate fulltext query from set of terms |
||
1152 | * @param string $fields Field to search against |
||
0 ignored issues
–
show
There is no parameter named
$fields . Did you maybe mean $field ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not. ![]() |
|||
1153 | * @param array $terms Search terms that may be or not be in the result |
||
1154 | * @param array $must_terms Search terms that have to be in the result |
||
1155 | * @param array $exclude_terms Search terms that have to be not in the result |
||
1156 | */ |
||
1157 | public function getFulltextQuery($field, $terms, $must_terms = array(), $exclude_terms = array()) |
||
1158 | { |
||
1159 | $condition = array(); |
||
1160 | foreach($terms as $term) { |
||
1161 | $condition[] = $this->quoteTerm($term); |
||
1162 | } |
||
1163 | foreach($must_terms as $term) { |
||
1164 | $condition[] = "+".$this->quoteTerm($term); |
||
1165 | } |
||
1166 | foreach($exclude_terms as $term) { |
||
1167 | $condition[] = "-".$this->quoteTerm($term); |
||
1168 | } |
||
1169 | $condition = $this->quoted(join(" ",$condition)); |
||
1170 | return "MATCH($field) AGAINST($condition IN BOOLEAN MODE)"; |
||
1171 | } |
||
1172 | |||
1173 | /** |
||
1174 | * Get list of all defined charsets |
||
1175 | * @return array |
||
1176 | */ |
||
1177 | protected function getCharsetInfo() |
||
1178 | { |
||
1179 | $charsets = array(); |
||
1180 | $res = $this->query("show variables like 'character\\_set\\_%'"); |
||
1181 | while($row = $this->fetchByAssoc($res)) { |
||
1182 | $charsets[$row['Variable_name']] = $row['Value']; |
||
1183 | } |
||
1184 | return $charsets; |
||
1185 | } |
||
1186 | |||
1187 | public function getDbInfo() |
||
1188 | { |
||
1189 | $charsets = $this->getCharsetInfo(); |
||
1190 | $charset_str = array(); |
||
1191 | foreach($charsets as $name => $value) { |
||
1192 | $charset_str[] = "$name = $value"; |
||
1193 | } |
||
1194 | return array( |
||
1195 | "MySQL Version" => @mysql_get_client_info(), |
||
1196 | "MySQL Host Info" => @mysql_get_host_info($this->database), |
||
1197 | "MySQL Server Info" => @mysql_get_server_info($this->database), |
||
1198 | "MySQL Client Encoding" => @mysql_client_encoding($this->database), |
||
1199 | "MySQL Character Set Settings" => join(", ", $charset_str), |
||
1200 | ); |
||
1201 | } |
||
1202 | |||
1203 | public function validateQuery($query) |
||
1204 | { |
||
1205 | $res = $this->query("EXPLAIN $query"); |
||
1206 | return !empty($res); |
||
1207 | } |
||
1208 | |||
1209 | protected function makeTempTableCopy($table) |
||
1210 | { |
||
1211 | $this->log->debug("creating temp table for [$table]..."); |
||
1212 | $result = $this->query("SHOW CREATE TABLE {$table}"); |
||
1213 | if(empty($result)) { |
||
1214 | return false; |
||
1215 | } |
||
1216 | $row = $this->fetchByAssoc($result); |
||
1217 | if(empty($row) || empty($row['Create Table'])) { |
||
1218 | return false; |
||
1219 | } |
||
1220 | $create = $row['Create Table']; |
||
1221 | // rewrite DDL with _temp name |
||
1222 | $tempTableQuery = str_replace("CREATE TABLE `{$table}`", "CREATE TABLE `{$table}__uw_temp`", $create); |
||
1223 | $r2 = $this->query($tempTableQuery); |
||
1224 | if(empty($r2)) { |
||
1225 | return false; |
||
1226 | } |
||
1227 | |||
1228 | // get sample data into the temp table to test for data/constraint conflicts |
||
1229 | $this->log->debug('inserting temp dataset...'); |
||
1230 | $q3 = "INSERT INTO `{$table}__uw_temp` SELECT * FROM `{$table}` LIMIT 10"; |
||
1231 | $this->query($q3, false, "Preflight Failed for: {$q3}"); |
||
1232 | return true; |
||
1233 | } |
||
1234 | |||
1235 | /** |
||
1236 | * Tests an ALTER TABLE query |
||
1237 | * @param string table The table name to get DDL |
||
1238 | * @param string query The query to test. |
||
1239 | * @return string Non-empty if error found |
||
1240 | */ |
||
1241 | protected function verifyAlterTable($table, $query) |
||
1242 | { |
||
1243 | $this->log->debug("verifying ALTER TABLE"); |
||
1244 | // Skipping ALTER TABLE [table] DROP PRIMARY KEY because primary keys are not being copied |
||
1245 | // over to the temp tables |
||
1246 | if(strpos(strtoupper($query), 'DROP PRIMARY KEY') !== false) { |
||
1247 | $this->log->debug("Skipping DROP PRIMARY KEY"); |
||
1248 | return ''; |
||
1249 | } |
||
1250 | if(!$this->makeTempTableCopy($table)) { |
||
1251 | return 'Could not create temp table copy'; |
||
1252 | } |
||
1253 | |||
1254 | // test the query on the test table |
||
1255 | $this->log->debug('testing query: ['.$query.']'); |
||
1256 | $tempTableTestQuery = str_replace("ALTER TABLE `{$table}`", "ALTER TABLE `{$table}__uw_temp`", $query); |
||
1257 | if (strpos($tempTableTestQuery, 'idx') === false) { |
||
1258 | if(strpos($tempTableTestQuery, '__uw_temp') === false) { |
||
1259 | return 'Could not use a temp table to test query!'; |
||
1260 | } |
||
1261 | |||
1262 | $this->log->debug('testing query on temp table: ['.$tempTableTestQuery.']'); |
||
1263 | $this->query($tempTableTestQuery, false, "Preflight Failed for: {$query}"); |
||
1264 | } else { |
||
1265 | // test insertion of an index on a table |
||
1266 | $tempTableTestQuery_idx = str_replace("ADD INDEX `idx_", "ADD INDEX `temp_idx_", $tempTableTestQuery); |
||
1267 | $this->log->debug('testing query on temp table: ['.$tempTableTestQuery_idx.']'); |
||
1268 | $this->query($tempTableTestQuery_idx, false, "Preflight Failed for: {$query}"); |
||
1269 | } |
||
1270 | $mysqlError = $this->getL(); |
||
0 ignored issues
–
show
The method
getL() does not seem to exist on object<MysqlManager> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
1271 | if(!empty($mysqlError)) { |
||
1272 | return $mysqlError; |
||
1273 | } |
||
1274 | $this->dropTableName("{$table}__uw_temp"); |
||
1275 | |||
1276 | return ''; |
||
1277 | } |
||
1278 | |||
1279 | protected function verifyGenericReplaceQuery($querytype, $table, $query) |
||
1280 | { |
||
1281 | $this->log->debug("verifying $querytype statement"); |
||
1282 | |||
1283 | if(!$this->makeTempTableCopy($table)) { |
||
1284 | return 'Could not create temp table copy'; |
||
1285 | } |
||
1286 | // test the query on the test table |
||
1287 | $this->log->debug('testing query: ['.$query.']'); |
||
1288 | $tempTableTestQuery = str_replace("$querytype `{$table}`", "$querytype `{$table}__uw_temp`", $query); |
||
1289 | if(strpos($tempTableTestQuery, '__uw_temp') === false) { |
||
1290 | return 'Could not use a temp table to test query!'; |
||
1291 | } |
||
1292 | |||
1293 | $this->query($tempTableTestQuery, false, "Preflight Failed for: {$query}"); |
||
1294 | $error = $this->lastError(); // empty on no-errors |
||
1295 | $this->dropTableName("{$table}__uw_temp"); // just in case |
||
1296 | return $error; |
||
1297 | } |
||
1298 | |||
1299 | /** |
||
1300 | * Tests a DROP TABLE query |
||
1301 | * @param string table The table name to get DDL |
||
1302 | * @param string query The query to test. |
||
1303 | * @return string Non-empty if error found |
||
1304 | */ |
||
1305 | public function verifyDropTable($table, $query) |
||
1306 | { |
||
1307 | return $this->verifyGenericReplaceQuery("DROP TABLE", $table, $query); |
||
1308 | } |
||
1309 | |||
1310 | /** |
||
1311 | * Tests an INSERT INTO query |
||
1312 | * @param string table The table name to get DDL |
||
1313 | * @param string query The query to test. |
||
1314 | * @return string Non-empty if error found |
||
1315 | */ |
||
1316 | public function verifyInsertInto($table, $query) |
||
1317 | { |
||
1318 | return $this->verifyGenericReplaceQuery("INSERT INTO", $table, $query); |
||
1319 | } |
||
1320 | |||
1321 | /** |
||
1322 | * Tests an UPDATE query |
||
1323 | * @param string table The table name to get DDL |
||
1324 | * @param string query The query to test. |
||
1325 | * @return string Non-empty if error found |
||
1326 | */ |
||
1327 | public function verifyUpdate($table, $query) |
||
1328 | { |
||
1329 | return $this->verifyGenericReplaceQuery("UPDATE", $table, $query); |
||
1330 | } |
||
1331 | |||
1332 | /** |
||
1333 | * Tests an DELETE FROM query |
||
1334 | * @param string table The table name to get DDL |
||
1335 | * @param string query The query to test. |
||
1336 | * @return string Non-empty if error found |
||
1337 | */ |
||
1338 | public function verifyDeleteFrom($table, $query) |
||
1339 | { |
||
1340 | return $this->verifyGenericReplaceQuery("DELETE FROM", $table, $query); |
||
1341 | } |
||
1342 | |||
1343 | /** |
||
1344 | * Check if certain database exists |
||
1345 | * @param string $dbname |
||
1346 | */ |
||
1347 | public function dbExists($dbname) |
||
1348 | { |
||
1349 | $db = $this->getOne("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ".$this->quoted($dbname)); |
||
1350 | return !empty($db); |
||
1351 | } |
||
1352 | |||
1353 | /** |
||
1354 | * Select database |
||
1355 | * @param string $dbname |
||
1356 | */ |
||
1357 | protected function selectDb($dbname) |
||
1358 | { |
||
1359 | return mysql_select_db($dbname); |
||
1360 | } |
||
1361 | |||
1362 | /** |
||
1363 | * Check if certain DB user exists |
||
1364 | * @param string $username |
||
1365 | */ |
||
1366 | public function userExists($username) |
||
1367 | { |
||
1368 | $db = $this->getOne("SELECT DATABASE()"); |
||
1369 | if(!$this->selectDb("mysql")) { |
||
1370 | return false; |
||
1371 | } |
||
1372 | $user = $this->getOne("select count(*) from user where user = ".$this->quoted($username)); |
||
1373 | if(!$this->selectDb($db)) { |
||
1374 | $this->checkError("Cannot select database $db", true); |
||
1375 | } |
||
1376 | return !empty($user); |
||
1377 | } |
||
1378 | |||
1379 | /** |
||
1380 | * Create DB user |
||
1381 | * @param string $database_name |
||
1382 | * @param string $host_name |
||
1383 | * @param string $user |
||
1384 | * @param string $password |
||
1385 | */ |
||
1386 | public function createDbUser($database_name, $host_name, $user, $password) |
||
1387 | { |
||
1388 | $qpassword = $this->quote($password); |
||
1389 | $this->query("GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, INDEX |
||
1390 | ON `$database_name`.* |
||
1391 | TO \"$user\"@\"$host_name\" |
||
1392 | IDENTIFIED BY '{$qpassword}';", true); |
||
1393 | |||
1394 | $this->query("SET PASSWORD FOR \"{$user}\"@\"{$host_name}\" = password('{$qpassword}');", true); |
||
1395 | if($host_name != 'localhost') { |
||
1396 | $this->createDbUser($database_name, "localhost", $user, $password); |
||
1397 | } |
||
1398 | } |
||
1399 | |||
1400 | /** |
||
1401 | * Create a database |
||
1402 | * @param string $dbname |
||
1403 | */ |
||
1404 | public function createDatabase($dbname) |
||
1405 | { |
||
1406 | $this->query("CREATE DATABASE `$dbname` CHARACTER SET utf8 COLLATE utf8_general_ci", true); |
||
1407 | } |
||
1408 | |||
1409 | public function preInstall() |
||
1410 | { |
||
1411 | $db->query("ALTER DATABASE `{$setup_db_database_name}` DEFAULT CHARACTER SET utf8", true); |
||
1412 | $db->query("ALTER DATABASE `{$setup_db_database_name}` DEFAULT COLLATE utf8_general_ci", true); |
||
1413 | |||
1414 | } |
||
1415 | |||
1416 | /** |
||
1417 | * Drop a database |
||
1418 | * @param string $dbname |
||
1419 | */ |
||
1420 | public function dropDatabase($dbname) |
||
1421 | { |
||
1422 | return $this->query("DROP DATABASE IF EXISTS `$dbname`", true); |
||
1423 | } |
||
1424 | |||
1425 | /** |
||
1426 | * Check if this driver can be used |
||
1427 | * @return bool |
||
1428 | */ |
||
1429 | public function valid() |
||
1430 | { |
||
1431 | return function_exists("mysql_connect"); |
||
1432 | } |
||
1433 | |||
1434 | /** |
||
1435 | * Check DB version |
||
1436 | * @see DBManager::canInstall() |
||
1437 | */ |
||
1438 | public function canInstall() |
||
1439 | { |
||
1440 | $db_version = $this->version(); |
||
1441 | if(empty($db_version)) { |
||
1442 | return array('ERR_DB_VERSION_FAILURE'); |
||
1443 | } |
||
1444 | if(version_compare($db_version, '4.1.2') < 0) { |
||
1445 | return array('ERR_DB_MYSQL_VERSION', $db_version); |
||
1446 | } |
||
1447 | return true; |
||
1448 | } |
||
1449 | |||
1450 | public function installConfig() |
||
1451 | { |
||
1452 | return array( |
||
1453 | 'LBL_DBCONFIG_MSG3' => array( |
||
1454 | "setup_db_database_name" => array("label" => 'LBL_DBCONF_DB_NAME', "required" => true), |
||
1455 | ), |
||
1456 | 'LBL_DBCONFIG_MSG2' => array( |
||
1457 | "setup_db_host_name" => array("label" => 'LBL_DBCONF_HOST_NAME', "required" => true), |
||
1458 | ), |
||
1459 | 'LBL_DBCONF_TITLE_USER_INFO' => array(), |
||
1460 | 'LBL_DBCONFIG_B_MSG1' => array( |
||
1461 | "setup_db_admin_user_name" => array("label" => 'LBL_DBCONF_DB_ADMIN_USER', "required" => true), |
||
1462 | "setup_db_admin_password" => array("label" => 'LBL_DBCONF_DB_ADMIN_PASSWORD', "type" => "password"), |
||
1463 | ) |
||
1464 | ); |
||
1465 | } |
||
1466 | |||
1467 | /** |
||
1468 | * Disable keys on the table |
||
1469 | * @abstract |
||
1470 | * @param string $tableName |
||
1471 | */ |
||
1472 | public function disableKeys($tableName) |
||
1473 | { |
||
1474 | return $this->query('ALTER TABLE '.$tableName.' DISABLE KEYS'); |
||
1475 | } |
||
1476 | |||
1477 | /** |
||
1478 | * Re-enable keys on the table |
||
1479 | * @abstract |
||
1480 | * @param string $tableName |
||
1481 | */ |
||
1482 | public function enableKeys($tableName) |
||
1483 | { |
||
1484 | return $this->query('ALTER TABLE '.$tableName.' ENABLE KEYS'); |
||
1485 | } |
||
1486 | |||
1487 | /** |
||
1488 | * Returns a DB specific FROM clause which can be used to select against functions. |
||
1489 | * Note that depending on the database that this may also be an empty string. |
||
1490 | * @return string |
||
1491 | */ |
||
1492 | public function getFromDummyTable() |
||
1493 | { |
||
1494 | return ''; |
||
1495 | } |
||
1496 | |||
1497 | /** |
||
1498 | * Returns a DB specific piece of SQL which will generate GUID (UUID) |
||
1499 | * This string can be used in dynamic SQL to do multiple inserts with a single query. |
||
1500 | * I.e. generate a unique Sugar id in a sub select of an insert statement. |
||
1501 | * @return string |
||
1502 | */ |
||
1503 | |||
1504 | public function getGuidSQL() |
||
1505 | { |
||
1506 | return 'UUID()'; |
||
1507 | } |
||
1508 | } |
||
1509 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.