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 | include_once('include/database/MssqlManager.php'); |
||
95 | |||
96 | /** |
||
97 | * SQL Server (sqlsrv) manager |
||
98 | */ |
||
99 | class SqlsrvManager extends MssqlManager |
||
100 | { |
||
101 | public $dbName = 'SQL Server'; |
||
102 | public $variant = 'sqlsrv'; |
||
103 | public $priority = 10; |
||
104 | public $label = 'LBL_MSSQL_SQLSRV'; |
||
105 | |||
106 | protected $capabilities = array( |
||
107 | "affected_rows" => true, |
||
108 | 'fulltext' => true, |
||
109 | 'limit_subquery' => true, |
||
110 | 'create_user' => true, |
||
111 | "create_db" => true, |
||
112 | ); |
||
113 | |||
114 | protected $type_map = array( |
||
115 | 'int' => 'int', |
||
116 | 'double' => 'float', |
||
117 | 'float' => 'float', |
||
118 | 'uint' => 'int', |
||
119 | 'ulong' => 'int', |
||
120 | 'long' => 'bigint', |
||
121 | 'short' => 'smallint', |
||
122 | 'varchar' => 'nvarchar', |
||
123 | 'text' => 'nvarchar(max)', |
||
124 | 'longtext' => 'nvarchar(max)', |
||
125 | 'date' => 'datetime', |
||
126 | 'enum' => 'nvarchar', |
||
127 | 'relate' => 'nvarchar', |
||
128 | 'multienum'=> 'nvarchar(max)', |
||
129 | 'html' => 'nvarchar(max)', |
||
130 | 'longhtml' => 'nvarchar(max)', |
||
131 | 'datetime' => 'datetime', |
||
132 | 'datetimecombo' => 'datetime', |
||
133 | 'time' => 'datetime', |
||
134 | 'bool' => 'bit', |
||
135 | 'tinyint' => 'tinyint', |
||
136 | 'char' => 'char', |
||
137 | 'blob' => 'nvarchar(max)', |
||
138 | 'longblob' => 'nvarchar(max)', |
||
139 | 'currency' => 'decimal(26,6)', |
||
140 | 'decimal' => 'decimal', |
||
141 | 'decimal2' => 'decimal', |
||
142 | 'id' => 'varchar(36)', |
||
143 | 'url' => 'nvarchar', |
||
144 | 'encrypt' => 'nvarchar', |
||
145 | 'file' => 'nvarchar', |
||
146 | 'decimal_tpl' => 'decimal(%d, %d)', |
||
147 | ); |
||
148 | |||
149 | /** |
||
150 | * @see DBManager::connect() |
||
151 | */ |
||
152 | public function connect(array $configOptions = null, $dieOnError = false) |
||
153 | { |
||
154 | global $sugar_config; |
||
155 | |||
156 | if (is_null($configOptions)) |
||
157 | $configOptions = $sugar_config['dbconfig']; |
||
158 | |||
159 | //set the connections parameters |
||
160 | $connect_param = ''; |
||
161 | $configOptions['db_host_instance'] = trim($configOptions['db_host_instance']); |
||
162 | if (empty($configOptions['db_host_instance'])) |
||
163 | $connect_param = $configOptions['db_host_name']; |
||
164 | else |
||
165 | $connect_param = $configOptions['db_host_name']."\\".$configOptions['db_host_instance']; |
||
166 | |||
167 | /* |
||
168 | * Don't try to specifically use a persistent connection |
||
169 | * since the driver will handle that for us |
||
170 | */ |
||
171 | $options = array( |
||
172 | "UID" => $configOptions['db_user_name'], |
||
173 | "PWD" => $configOptions['db_password'], |
||
174 | "CharacterSet" => "UTF-8", |
||
175 | "ReturnDatesAsStrings" => true, |
||
176 | "MultipleActiveResultSets" => true, |
||
177 | ); |
||
178 | if(!empty($configOptions['db_name'])) { |
||
179 | $options["Database"] = $configOptions['db_name']; |
||
180 | } |
||
181 | $this->database = sqlsrv_connect($connect_param, $options); |
||
182 | if(empty($this->database)) { |
||
183 | $GLOBALS['log']->fatal("Could not connect to server ".$configOptions['db_host_name']." as ".$configOptions['db_user_name']."."); |
||
184 | if($dieOnError) { |
||
185 | if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) { |
||
186 | sugar_die($GLOBALS['app_strings']['ERR_NO_DB']); |
||
187 | } else { |
||
188 | sugar_die("Could not connect to the database. Please refer to suitecrm.log for details."); |
||
189 | } |
||
190 | } else { |
||
191 | return false; |
||
192 | } |
||
193 | } |
||
194 | |||
195 | if($this->checkError('Could Not Connect:', $dieOnError)) |
||
196 | $GLOBALS['log']->info("connected to db"); |
||
197 | |||
198 | sqlsrv_query($this->database, 'SET DATEFORMAT mdy'); |
||
199 | |||
200 | $this->connectOptions = $configOptions; |
||
201 | |||
202 | $GLOBALS['log']->info("Connect:".$this->database); |
||
203 | return true; |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * @see DBManager::query() |
||
208 | */ |
||
209 | public function query($sql, $dieOnError = false, $msg = '', $suppress = false, $keepResult = false) |
||
210 | { |
||
211 | if(is_array($sql)) { |
||
212 | return $this->queryArray($sql, $dieOnError, $msg, $suppress); |
||
213 | } |
||
214 | $sql = $this->_appendN($sql); |
||
215 | |||
216 | $this->countQuery($sql); |
||
0 ignored issues
–
show
|
|||
217 | $GLOBALS['log']->info('Query:' . $sql); |
||
218 | $this->checkConnection(); |
||
219 | $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;
![]() |
|||
220 | |||
221 | $result = $suppress?@sqlsrv_query($this->database, $sql):sqlsrv_query($this->database, $sql); |
||
222 | |||
223 | $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;
![]() |
|||
224 | $GLOBALS['log']->info('Query Execution Time:'.$this->query_time); |
||
225 | |||
226 | |||
227 | $this->checkError($msg.' Query Failed:' . $sql . '::', $dieOnError); |
||
228 | |||
229 | //suppress non error messages |
||
230 | sqlsrv_configure('WarningsReturnAsErrors',false); |
||
231 | |||
232 | return $result; |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * @see DBManager::getFieldsArray() |
||
237 | */ |
||
238 | public function getFieldsArray($result, $make_lower_case = false) |
||
239 | { |
||
240 | $field_array = array(); |
||
241 | |||
242 | if ( !$result ) { |
||
243 | return false; |
||
244 | } |
||
245 | |||
246 | foreach ( sqlsrv_field_metadata($result) as $fieldMetadata ) { |
||
247 | $key = $fieldMetadata['Name']; |
||
248 | if($make_lower_case==true) |
||
0 ignored issues
–
show
|
|||
249 | $key = strtolower($key); |
||
250 | |||
251 | $field_array[] = $key; |
||
252 | } |
||
253 | |||
254 | return $field_array; |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * @see DBManager::fetchRow() |
||
259 | */ |
||
260 | public function fetchRow($result) |
||
261 | { |
||
262 | if (empty($result)) return false; |
||
263 | |||
264 | $row = sqlsrv_fetch_array($result,SQLSRV_FETCH_ASSOC); |
||
265 | if (empty($row)) { |
||
266 | return false; |
||
267 | } |
||
268 | |||
269 | foreach($row as $key => $column) { |
||
270 | // MSSQL returns a space " " when a varchar column is empty ("") and not null. |
||
271 | // We need to strip empty spaces |
||
272 | // notice we only strip if one space is returned. we do not want to strip |
||
273 | // strings with intentional spaces (" foo ") |
||
274 | if (!empty($column) && $column == " ") { |
||
275 | $row[$key] = ''; |
||
276 | } |
||
277 | } |
||
278 | |||
279 | return $row; |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * @see DBManager::convert() |
||
284 | */ |
||
285 | public function convert($string, $type, array $additional_parameters = array()) |
||
286 | { |
||
287 | if ( $type == 'datetime') |
||
288 | // see http://msdn.microsoft.com/en-us/library/ms187928.aspx for details |
||
289 | return "CONVERT(datetime,$string,120)"; |
||
290 | else |
||
291 | return parent::convert($string, $type, $additional_parameters); |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * Compares two vardefs. Overriding 39098 due to bug: 39098 . IN 6.0 we changed the id columns to dbType = 'id' |
||
296 | * for example emails_beans. In 554 the field email_id was nvarchar but in 6.0 since it id dbType = 'id' we would want to alter |
||
297 | * it to varchar. This code will prevent it. |
||
298 | * |
||
299 | * @param array $fielddef1 |
||
300 | * @param array $fielddef2 |
||
301 | * @return bool true if they match, false if they don't |
||
302 | */ |
||
303 | public function compareVarDefs($fielddef1,$fielddef2, $ignoreName = false) |
||
304 | { |
||
305 | if((isset($fielddef2['dbType']) && $fielddef2['dbType'] == 'id') || preg_match('/(_id$|^id$)/', $fielddef2['name'])){ |
||
306 | if(isset($fielddef1['type']) && isset($fielddef2['type'])){ |
||
307 | $fielddef2['type'] = $fielddef1['type']; |
||
308 | } |
||
309 | } |
||
310 | return parent::compareVarDefs($fielddef1, $fielddef2); |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * Disconnects from the database |
||
315 | * |
||
316 | * Also handles any cleanup needed |
||
317 | */ |
||
318 | public function disconnect() |
||
319 | { |
||
320 | $GLOBALS['log']->debug('Calling Mssql::disconnect()'); |
||
321 | if(!empty($this->database)){ |
||
322 | $this->freeResult(); |
||
323 | sqlsrv_close($this->database); |
||
324 | $this->database = null; |
||
325 | } |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * @see DBManager::freeDbResult() |
||
330 | */ |
||
331 | protected function freeDbResult($dbResult) |
||
332 | { |
||
333 | if(!empty($dbResult)) |
||
334 | sqlsrv_free_stmt($dbResult); |
||
335 | } |
||
336 | |||
337 | |||
338 | /** |
||
339 | * Detect if no clustered index has been created for a table; if none created then just pick the first index and make it that |
||
340 | * |
||
341 | * @see MssqlHelper::indexSQL() |
||
342 | */ |
||
343 | public function getConstraintSql($indices, $table) |
||
344 | { |
||
345 | if ( $this->doesTableHaveAClusteredIndexDefined($table) ) { |
||
346 | return parent::getConstraintSql($indices, $table); |
||
347 | } |
||
348 | |||
349 | // check to see if one of the passed in indices is a primary one; if so we can bail as well |
||
350 | foreach ( $indices as $index ) { |
||
351 | if ( $index['type'] == 'primary' ) { |
||
352 | return parent::getConstraintSql($indices, $table); |
||
353 | } |
||
354 | } |
||
355 | |||
356 | // Change the first index listed to be a clustered one instead ( so we have at least one for the table ) |
||
357 | if ( isset($indices[0]) ) { |
||
358 | $indices[0]['type'] = 'clustered'; |
||
359 | } |
||
360 | |||
361 | return parent::getConstraintSql($indices, $table); |
||
362 | } |
||
363 | |||
364 | /** |
||
365 | * @see DBManager::get_columns() |
||
366 | */ |
||
367 | public function get_columns($tablename) |
||
368 | { |
||
369 | //find all unique indexes and primary keys. |
||
370 | $result = $this->query("sp_columns_90 $tablename"); |
||
371 | |||
372 | $columns = array(); |
||
373 | while (($row=$this->fetchByAssoc($result)) !=null) { |
||
374 | $column_name = strtolower($row['COLUMN_NAME']); |
||
375 | $columns[$column_name]['name']=$column_name; |
||
376 | $columns[$column_name]['type']=strtolower($row['TYPE_NAME']); |
||
377 | if ( $row['TYPE_NAME'] == 'decimal' ) { |
||
378 | $columns[$column_name]['len']=strtolower($row['PRECISION']); |
||
379 | $columns[$column_name]['len'].=','.strtolower($row['SCALE']); |
||
380 | } |
||
381 | elseif ( in_array($row['TYPE_NAME'],array('nchar','nvarchar')) ) { |
||
382 | $columns[$column_name]['len']=strtolower($row['PRECISION']); |
||
383 | if ( $row['TYPE_NAME'] == 'nvarchar' && $row['PRECISION'] == '0' ) { |
||
384 | $columns[$column_name]['len']='max'; |
||
385 | } |
||
386 | } |
||
387 | elseif ( !in_array($row['TYPE_NAME'],array('datetime','text')) ) { |
||
388 | $columns[$column_name]['len']=strtolower($row['LENGTH']); |
||
389 | } |
||
390 | if ( stristr($row['TYPE_NAME'],'identity') ) { |
||
391 | $columns[$column_name]['auto_increment'] = '1'; |
||
392 | $columns[$column_name]['type']=str_replace(' identity','',strtolower($row['TYPE_NAME'])); |
||
393 | } |
||
394 | |||
395 | if (!empty($row['IS_NULLABLE']) && $row['IS_NULLABLE'] == 'NO' && (empty($row['KEY']) || !stristr($row['KEY'],'PRI'))) |
||
396 | $columns[strtolower($row['COLUMN_NAME'])]['required'] = 'true'; |
||
397 | |||
398 | $column_def = 1; |
||
399 | if ( strtolower($tablename) == 'relationships' ) { |
||
400 | $column_def = $this->getOne("select cdefault from syscolumns where id = object_id('relationships') and name = '$column_name'"); |
||
401 | } |
||
402 | if ( $column_def != 0 && ($row['COLUMN_DEF'] != null)) { // NOTE Not using !empty as an empty string may be a viable default value. |
||
403 | $matches = array(); |
||
404 | $row['COLUMN_DEF'] = html_entity_decode($row['COLUMN_DEF'],ENT_QUOTES); |
||
405 | if ( preg_match('/\([\(|\'](.*)[\)|\']\)/i',$row['COLUMN_DEF'],$matches) ) |
||
406 | $columns[$column_name]['default'] = $matches[1]; |
||
407 | elseif ( preg_match('/\(N\'(.*)\'\)/i',$row['COLUMN_DEF'],$matches) ) |
||
408 | $columns[$column_name]['default'] = $matches[1]; |
||
409 | else |
||
410 | $columns[$column_name]['default'] = $row['COLUMN_DEF']; |
||
411 | } |
||
412 | } |
||
413 | return $columns; |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * protected function to return true if the given tablename has any clustered indexes defined. |
||
418 | * |
||
419 | * @param string $tableName |
||
420 | * @return bool |
||
421 | */ |
||
422 | protected function doesTableHaveAClusteredIndexDefined($tableName) |
||
423 | { |
||
424 | $query = <<<EOSQL |
||
425 | SELECT IST.TABLE_NAME |
||
426 | FROM INFORMATION_SCHEMA.TABLES IST |
||
427 | WHERE objectProperty(object_id(IST.TABLE_NAME), 'IsUserTable') = 1 |
||
428 | AND objectProperty(object_id(IST.TABLE_NAME), 'TableHasClustIndex') = 1 |
||
429 | AND IST.TABLE_NAME = '{$tableName}' |
||
430 | EOSQL; |
||
431 | |||
432 | $result = $this->getOne($query); |
||
433 | if ( !$result ) { |
||
0 ignored issues
–
show
The expression
$result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
434 | return false; |
||
435 | } |
||
436 | |||
437 | return true; |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * protected function to return true if the given tablename has any fulltext indexes defined. |
||
442 | * |
||
443 | * @param string $tableName |
||
444 | * @return bool |
||
445 | */ |
||
446 | protected function doesTableHaveAFulltextIndexDefined($tableName) |
||
447 | { |
||
448 | $query = <<<EOSQL |
||
449 | SELECT 1 |
||
450 | FROM sys.fulltext_indexes i |
||
451 | JOIN sys.objects o ON i.object_id = o.object_id |
||
452 | WHERE o.name = '{$tableName}' |
||
453 | EOSQL; |
||
454 | |||
455 | $result = $this->getOne($query); |
||
456 | if ( !$result ) { |
||
0 ignored issues
–
show
The expression
$result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
457 | return false; |
||
458 | } |
||
459 | |||
460 | return true; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * Override method to add support for detecting and dropping fulltext indices. |
||
465 | * |
||
466 | * @see DBManager::changeColumnSQL() |
||
467 | * @see MssqlHelper::changeColumnSQL() |
||
468 | */ |
||
469 | protected function changeColumnSQL($tablename,$fieldDefs, $action, $ignoreRequired = false) |
||
470 | { |
||
471 | $sql = ''; |
||
472 | if ( $action == 'drop' && $this->doesTableHaveAFulltextIndexDefined($tablename) ) { |
||
473 | $sql .= "DROP FULLTEXT INDEX ON {$tablename}"; |
||
474 | } |
||
475 | |||
476 | $sql .= parent::changeColumnSQL($tablename, $fieldDefs, $action, $ignoreRequired); |
||
477 | |||
478 | return $sql; |
||
479 | } |
||
480 | |||
481 | /** |
||
482 | * Truncate table |
||
483 | * @param $name |
||
484 | * @return string |
||
485 | */ |
||
486 | public function truncateTableSQL($name) |
||
487 | { |
||
488 | return "TRUNCATE TABLE $name"; |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * (non-PHPdoc) |
||
493 | * @see DBManager::lastDbError() |
||
494 | */ |
||
495 | public function lastDbError() |
||
496 | { |
||
497 | $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); |
||
498 | if(empty($errors)) return false; |
||
499 | global $app_strings; |
||
500 | if (empty($app_strings) |
||
501 | or !isset($app_strings['ERR_MSSQL_DB_CONTEXT']) |
||
502 | or !isset($app_strings['ERR_MSSQL_WARNING']) ) { |
||
503 | //ignore the message from sql-server if $app_strings array is empty. This will happen |
||
504 | //only if connection if made before languge is set. |
||
505 | return false; |
||
506 | } |
||
507 | $messages = array(); |
||
508 | foreach($errors as $error) { |
||
509 | $sqlmsg = $error['message']; |
||
510 | $sqlpos = strpos($sqlmsg, 'Changed database context to'); |
||
511 | $sqlpos2 = strpos($sqlmsg, 'Warning:'); |
||
512 | $sqlpos3 = strpos($sqlmsg, 'Checking identity information:'); |
||
513 | if ( $sqlpos !== false || $sqlpos2 !== false || $sqlpos3 !== false ) { |
||
514 | continue; |
||
515 | } |
||
516 | $sqlpos = strpos($sqlmsg, $app_strings['ERR_MSSQL_DB_CONTEXT']); |
||
517 | $sqlpos2 = strpos($sqlmsg, $app_strings['ERR_MSSQL_WARNING']); |
||
518 | if ( $sqlpos !== false || $sqlpos2 !== false) { |
||
519 | continue; |
||
520 | } |
||
521 | $messages[] = $sqlmsg; |
||
522 | } |
||
523 | |||
524 | if(!empty($messages)) { |
||
525 | return join("\n", $messages); |
||
526 | } |
||
527 | return false; |
||
528 | } |
||
529 | |||
530 | /** |
||
531 | * (non-PHPdoc) |
||
532 | * @see DBManager::getDbInfo() |
||
533 | * @return array |
||
534 | */ |
||
535 | public function getDbInfo() |
||
536 | { |
||
537 | $info = array_merge(sqlsrv_client_info(), sqlsrv_server_info()); |
||
538 | return $info; |
||
539 | } |
||
540 | |||
541 | /** |
||
542 | * Execute data manipulation statement, then roll it back |
||
543 | * @param $type |
||
544 | * @param $table |
||
545 | * @param $query |
||
546 | * @return string |
||
547 | */ |
||
548 | protected function verifyGenericQueryRollback($type, $table, $query) |
||
549 | { |
||
550 | $this->log->debug("verifying $type statement"); |
||
551 | if(!sqlsrv_begin_transaction($this->database)) { |
||
552 | return "Failed to create transaction"; |
||
553 | } |
||
554 | $this->query($query, false); |
||
555 | $error = $this->lastError(); |
||
556 | sqlsrv_rollback($this->database); |
||
557 | return $error; |
||
558 | } |
||
559 | |||
560 | /** |
||
561 | * Tests an INSERT INTO query |
||
562 | * @param string table The table name to get DDL |
||
563 | * @param string query The query to test. |
||
564 | * @return string Non-empty if error found |
||
565 | */ |
||
566 | public function verifyInsertInto($table, $query) |
||
567 | { |
||
568 | return $this->verifyGenericQueryRollback("INSERT", $table, $query); |
||
569 | } |
||
570 | |||
571 | /** |
||
572 | * Tests an UPDATE query |
||
573 | * @param string table The table name to get DDL |
||
574 | * @param string query The query to test. |
||
575 | * @return string Non-empty if error found |
||
576 | */ |
||
577 | public function verifyUpdate($table, $query) |
||
578 | { |
||
579 | return $this->verifyGenericQueryRollback("UPDATE", $table, $query); |
||
580 | } |
||
581 | |||
582 | /** |
||
583 | * Tests an DELETE FROM query |
||
584 | * @param string table The table name to get DDL |
||
585 | * @param string query The query to test. |
||
586 | * @return string Non-empty if error found |
||
587 | */ |
||
588 | public function verifyDeleteFrom($table, $query) |
||
589 | { |
||
590 | return $this->verifyGenericQueryRollback("DELETE", $table, $query); |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * Select database |
||
595 | * @param string $dbname |
||
596 | */ |
||
597 | protected function selectDb($dbname) |
||
598 | { |
||
599 | return $this->query("USE ".$this->quoted($dbname)); |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * Check if this driver can be used |
||
604 | * @return bool |
||
605 | */ |
||
606 | public function valid() |
||
607 | { |
||
608 | return function_exists("sqlsrv_connect"); |
||
609 | } |
||
610 | } |
||
611 |
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.