PageRenderTime 59ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/include/database/DBManager.php

https://github.com/mikmagic/sugarcrm_dev
PHP | 1932 lines | 1082 code | 169 blank | 681 comment | 249 complexity | a7e65da839eb59f20b505eca1da80959 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  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. * Description: This file handles the Data base functionality for the application.
  39. * It acts as the DB abstraction layer for the application. It depends on helper classes
  40. * which generate the necessary SQL. This sql is then passed to PEAR DB classes.
  41. * The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php.
  42. *
  43. * All the functions in this class will work with any bean which implements the meta interface.
  44. * The passed bean is passed to helper class which uses these functions to generate correct sql.
  45. *
  46. * The meta interface has the following functions:
  47. * getTableName() Returns table name of the object.
  48. * getFieldDefinitions() Returns a collection of field definitions in order.
  49. * getFieldDefintion(name) Return field definition for the field.
  50. * getFieldValue(name) Returns the value of the field identified by name.
  51. * If the field is not set, the function will return boolean FALSE.
  52. * getPrimaryFieldDefinition() Returns the field definition for primary key
  53. *
  54. * The field definition is an array with the following keys:
  55. *
  56. * name This represents name of the field. This is a required field.
  57. * type This represents type of the field. This is a required field and valid values are:
  58. * � int
  59. * � long
  60. * � varchar
  61. * � text
  62. * � date
  63. * � datetime
  64. * � double
  65. * � float
  66. * � uint
  67. * � ulong
  68. * � time
  69. * � short
  70. * � enum
  71. * length This is used only when the type is varchar and denotes the length of the string.
  72. * The max value is 255.
  73. * enumvals This is a list of valid values for an enum separated by "|".
  74. * It is used only if the type is �enum�;
  75. * required This field dictates whether it is a required value.
  76. * The default value is �FALSE�.
  77. * isPrimary This field identifies the primary key of the table.
  78. * If none of the fields have this flag set to �TRUE�,
  79. * the first field definition is assume to be the primary key.
  80. * Default value for this field is �FALSE�.
  81. * default This field sets the default value for the field definition.
  82. *
  83. *
  84. * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
  85. * All Rights Reserved.
  86. * Contributor(s): ______________________________________..
  87. ********************************************************************************/
  88. abstract class DBManager
  89. {
  90. /**
  91. * DBHelper object instance for this class
  92. */
  93. public $helper;
  94. /**
  95. * Name of database table we are dealing with
  96. */
  97. protected $tableName;
  98. /**
  99. * Name of database
  100. */
  101. public $database = null;
  102. /**
  103. * Indicates whether we should die when we get an error from the DB
  104. */
  105. protected $dieOnError = false;
  106. /**
  107. * Indicates whether we should html encode the results from a query by default
  108. */
  109. protected $encode = true;
  110. /**
  111. * Records the execution time of the last query
  112. */
  113. protected $query_time = 0;
  114. /**
  115. * Number of the last row fetched from the query result set
  116. */
  117. protected $lastmysqlrow = -1;
  118. /**
  119. * Last error message from the DB backend
  120. */
  121. protected $last_error = '';
  122. /**
  123. * Registry of available result sets
  124. */
  125. protected $lastResult = array();
  126. /**
  127. * Current query count
  128. */
  129. private static $queryCount = 0;
  130. /**
  131. * Query threshold limit
  132. */
  133. private static $queryLimit = 0;
  134. /**
  135. * Array of common backend functions and what the PHP they map to is
  136. */
  137. protected $backendFunctions = array();
  138. /**
  139. * Array of prepared statements and their correspoding parsed tokens
  140. */
  141. protected $preparedTokens = array();
  142. /**
  143. * Wrapper for those trying to access the private and protected class members directly
  144. */
  145. public function __get($p)
  146. {
  147. $GLOBALS['log']->info('call to DBManagerFactory::$'.$p.' is deprecated');
  148. return $this->$p;
  149. }
  150. public function __construct()
  151. {
  152. }
  153. /**
  154. * Returns the current tablename
  155. *
  156. * @return string
  157. */
  158. public function getTableName()
  159. {
  160. return $this->tableName;
  161. }
  162. /**
  163. * Returns the current database handle
  164. *
  165. * @return resource
  166. */
  167. public function getDatabase()
  168. {
  169. $this->checkConnection();
  170. return $this->database;
  171. }
  172. /**
  173. * Returns this instance's DBHelper
  174. *
  175. * @return object DBHelper instance
  176. */
  177. public function getHelper()
  178. {
  179. if ( !($this->helper instanceof DBHelper) ) {
  180. global $sugar_config;
  181. switch ( $sugar_config['dbconfig']['db_type'] ) {
  182. case "mysql":
  183. $my_db_helper = 'MysqlHelper';
  184. if ( (!isset($sugar_config['mysqli_disabled'])
  185. || $sugar_config['mysqli_disabled'] == false)
  186. && function_exists('mysqli_connect') )
  187. $my_db_helper = 'MysqliHelper';
  188. break;
  189. case "mssql":
  190. if ( function_exists('sqlsrv_connect')
  191. && (empty($config['db_mssql_force_driver']) || $config['db_mssql_force_driver'] == 'sqlsrv' ))
  192. $my_db_helper = 'SqlsrvHelper';
  193. elseif (is_freetds()
  194. && (empty($config['db_mssql_force_driver']) || $config['db_mssql_force_driver'] == 'freetds' ))
  195. $my_db_helper = 'FreeTDSHelper';
  196. else
  197. $my_db_helper = 'MssqlHelper';
  198. break;
  199. default:
  200. $my_db_helper = 'MysqlHelper';
  201. }
  202. $GLOBALS['log']->info("using $my_db_helper DBHelper backend");
  203. require_once("include/database/{$my_db_helper}.php");
  204. $this->helper = new $my_db_helper();
  205. $this->helper->db = $this;
  206. }
  207. return $this->helper;
  208. }
  209. /**
  210. * Checks for database not being connected
  211. *
  212. * @param string $msg message to prepend to the error message
  213. * @param bool $dieOnError true if we want to die immediately on error
  214. * @return bool
  215. */
  216. public function checkError(
  217. $msg = '',
  218. $dieOnError = false)
  219. {
  220. $userMsg = inDeveloperMode()?"$msg: ":"";
  221. if (!isset($this->database)) {
  222. $GLOBALS['log']->error("Database Is Not Connected");
  223. if($this->dieOnError || $dieOnError)
  224. sugar_die ($userMsg."Database Is Not Connected");
  225. else
  226. $this->last_error = $userMsg."Database Is Not Connected";
  227. return true;
  228. }
  229. return false;
  230. }
  231. /**
  232. * This method is called by every method that runs a query.
  233. * If slow query dumping is turned on and the query time is beyond
  234. * the time limit, we will log the query. This function may do
  235. * additional reporting or log in a different area in the future.
  236. *
  237. * @param string $query query to log
  238. * @return boolean true if the query was logged, false otherwise
  239. */
  240. protected function dump_slow_queries(
  241. $query
  242. )
  243. {
  244. global $sugar_config;
  245. $do_the_dump = isset($sugar_config['dump_slow_queries'])
  246. ? $sugar_config['dump_slow_queries'] : false;
  247. $slow_query_time_msec = isset($sugar_config['slow_query_time_msec'])
  248. ? $sugar_config['slow_query_time_msec'] : 5000;
  249. if($do_the_dump) {
  250. if($slow_query_time_msec < ($this->query_time * 1000)) {
  251. // Then log both the query and the query time
  252. $GLOBALS['log']->fatal('Slow Query (time:'.$this->query_time."\n".$query);
  253. return true;
  254. }
  255. }
  256. return false;
  257. }
  258. /**
  259. * Scans order by to ensure that any field being ordered by is.
  260. *
  261. * It will throw a warning error to the log file - fatal if slow query logging is enabled
  262. *
  263. * @param string $sql query to be run
  264. * @param bool $object_name optional, object to look up indices in
  265. * @return bool true if an index is found false otherwise
  266. */
  267. protected function checkQuery(
  268. $sql,
  269. $object_name = false
  270. )
  271. {
  272. $match = array();
  273. preg_match_all("'.* FROM ([^ ]*).* ORDER BY (.*)'is", $sql, $match);
  274. $indices = false;
  275. if (!empty($match[1][0]))
  276. $table = $match[1][0];
  277. else
  278. return false;
  279. if (!empty($object_name) && !empty($GLOBALS['dictionary'][$object_name]))
  280. $indices = $GLOBALS['dictionary'][$object_name]['indices'];
  281. if (empty($indices)) {
  282. foreach ( $GLOBALS['dictionary'] as $current ) {
  283. if ($current['table'] == $table){
  284. $indices = $current['indices'];
  285. break;
  286. }
  287. }
  288. }
  289. if (empty($indices)) {
  290. $GLOBALS['log']->warn('CHECK QUERY: Could not find index definitions for table ' . $table);
  291. return false;
  292. }
  293. if (!empty($match[2][0])) {
  294. $orderBys = explode(' ', $match[2][0]);
  295. foreach ($orderBys as $orderBy){
  296. $orderBy = trim($orderBy);
  297. if (empty($orderBy))
  298. continue;
  299. $orderBy = strtolower($orderBy);
  300. if ($orderBy == 'asc' || $orderBy == 'desc')
  301. continue;
  302. $orderBy = str_replace(array($table . '.', ','), '', $orderBy);
  303. foreach ($indices as $index)
  304. if (empty($index['db']) || $index['db'] == $this->dbType)
  305. foreach ($index['fields'] as $field)
  306. if ($field == $orderBy)
  307. return true;
  308. $warning = 'Missing Index For Order By Table: ' . $table . ' Order By:' . $orderBy ;
  309. if (!empty($GLOBALS['sugar_config']['dump_slow_queries']))
  310. $GLOBALS['log']->fatal('CHECK QUERY:' .$warning);
  311. else
  312. $GLOBALS['log']->warn('CHECK QUERY:' .$warning);
  313. }
  314. }
  315. return false;
  316. }
  317. /**
  318. * Returns the time the last query took to execute
  319. *
  320. * @return int
  321. */
  322. public function getQueryTime()
  323. {
  324. return $this->query_time;
  325. }
  326. /**
  327. * Checks the current connection; if it is not connected then reconnect
  328. */
  329. public function checkConnection()
  330. {
  331. $this->last_error = '';
  332. if (!isset($this->database))
  333. $this->connect();
  334. }
  335. /**
  336. * Sets the dieOnError value
  337. *
  338. * @param bool $value
  339. */
  340. public function setDieOnError(
  341. $value
  342. )
  343. {
  344. $this->dieOnError = $value;
  345. }
  346. /**
  347. * Implements a generic insert for any bean.
  348. *
  349. * @param object $bean SugarBean instance
  350. */
  351. public function insert(
  352. SugarBean $bean
  353. )
  354. {
  355. $sql = $this->getHelper()->insertSQL($bean);
  356. $this->tableName = $bean->getTableName();
  357. $msg = "Error inserting into table: ".$this->tableName;
  358. $this->query($sql,true,$msg);
  359. }
  360. /**
  361. * Implements a generic update for any bean
  362. *
  363. * @param object $bean Sugarbean instance
  364. * @param array $where values with the keys as names of fields.
  365. * If we want to pass multiple values for a name, pass it as an array
  366. * If where is not passed, it defaults to id of table
  367. */
  368. public function update(
  369. SugarBean $bean,
  370. array $where = array()
  371. )
  372. {
  373. $sql = $this->getHelper()->updateSQL($bean, $where);
  374. $this->tableName = $bean->getTableName();
  375. $msg = "Error updating table: ".$this->tableName. ":";
  376. $this->query($sql,true,$msg);
  377. }
  378. /**
  379. * Implements a generic delete for any bean identified by id
  380. *
  381. * @param object $bean Sugarbean instance
  382. * @param array $where values with the keys as names of fields.
  383. * If we want to pass multiple values for a name, pass it as an array
  384. * If where is not passed, it defaults to id of table
  385. */
  386. public function delete(
  387. SugarBean $bean,
  388. array $where = array()
  389. )
  390. {
  391. $sql = $this->getHelper()->deleteSQL($bean, $where);
  392. $this->tableName = $bean->getTableName();
  393. $msg = "Error deleting from table: ".$this->tableName. ":";
  394. $this->query($sql,true,$msg);
  395. }
  396. /**
  397. * Implements a generic retrieve for any bean identified by id
  398. *
  399. * If we want to pass multiple values for a name, pass it as an array
  400. * If where is not passed, it defaults to id of table
  401. *
  402. * @param object $bean Sugarbean instance
  403. * @param array $where values with the keys as names of fields.
  404. * @return resource result from the query
  405. */
  406. public function retrieve(
  407. SugarBean $bean,
  408. array $where = array()
  409. )
  410. {
  411. $sql = $this->getHelper()->retrieveSQL($bean, $where);
  412. $this->tableName = $bean->getTableName();
  413. $msg = "Error retriving values from table:".$this->tableName. ":";
  414. return $this->query($sql,true,$msg);
  415. }
  416. /**
  417. * Implements a generic retrieve for a collection of beans.
  418. *
  419. * These beans will be joined in the sql by the key attribute of field defs.
  420. * Currently, this function does support outer joins.
  421. *
  422. * @param array $beans Sugarbean instance(s)
  423. * @param array $cols columns to be returned with the keys as names of bean as identified by
  424. * get_class of bean. Values of this array is the array of fieldDefs to be returned for a bean.
  425. * If an empty array is passed, all columns are selected.
  426. * @param array $where values with the keys as names of bean as identified by get_class of bean
  427. * Each value at the first level is an array of values for that bean identified by name of fields.
  428. * If we want to pass multiple values for a name, pass it as an array
  429. * If where is not passed, all the rows will be returned.
  430. * @return resource
  431. */
  432. public function retrieveView(
  433. array $beans,
  434. array $cols = array(),
  435. array $where = array()
  436. )
  437. {
  438. $sql = $this->getHelper()->retrieveViewSQL($beans, $cols, $where);
  439. $this->tableName = "View Collection"; // just use this string for msg
  440. $msg = "Error retriving values from table:".$this->tableName. ":";
  441. $this->query($sql,true,$msg);
  442. }
  443. /**
  444. * Implements creation of a db table for a bean.
  445. *
  446. * @param object $bean Sugarbean instance
  447. */
  448. public function createTable(
  449. SugarBean $bean
  450. )
  451. {
  452. $sql = $this->getHelper()->createTableSQL($bean);
  453. $this->tableName = $bean->getTableName();
  454. $msg = "Error creating table: ".$this->tableName. ":";
  455. $this->query($sql,true,$msg);
  456. }
  457. /**
  458. * Implements creation of a db table
  459. *
  460. * @param string $tablename
  461. * @param array $fieldDefs
  462. * @param array $indices
  463. * @param string $engine MySQL engine to use
  464. */
  465. public function createTableParams(
  466. $tablename,
  467. $fieldDefs,
  468. $indices,
  469. $engine = null
  470. )
  471. {
  472. if (!empty($fieldDefs)) {
  473. $sql = $this->getHelper()
  474. ->createTableSQLParams($tablename, $fieldDefs, $indices,$engine);
  475. $this->tableName = $tablename;
  476. if ($sql) {
  477. $msg = "Error creating table: ".$this->tableName. ":";
  478. $this->query($sql,true,$msg);
  479. }
  480. }
  481. }
  482. /**
  483. * Implements repair of a db table for a bean.
  484. *
  485. * @param object $bean SugarBean instance
  486. * @param bool $execute true if we want the action to take place, false if we just want the sql returned
  487. * @return string SQL statement or empty string, depending upon $execute
  488. */
  489. public function repairTable(SugarBean $bean, $execute = true)
  490. {
  491. $indices = $bean->getIndices();
  492. $fielddefs = $bean->getFieldDefinitions();
  493. $tablename = $bean->getTableName();
  494. //Clean the indicies to prevent duplicate definitions
  495. $new_Indecies = array();
  496. foreach($indices as $ind_def){
  497. $new_Indecies[$ind_def['name']] = $ind_def;
  498. }
  499. //jc: added this for beans that do not actually have a table, namely
  500. //ForecastOpportunities
  501. if($tablename == 'does_not_exist' || $tablename == '')
  502. return '';
  503. global $dictionary;
  504. $engine=null;
  505. if (isset($dictionary[$bean->getObjectName()]['engine']) && !empty($dictionary[$bean->getObjectName()]['engine']) )
  506. $engine = $dictionary[$bean->getObjectName()]['engine'];
  507. return $this->repairTableParams($tablename, $fielddefs,$new_Indecies,$execute,$engine);
  508. }
  509. /**
  510. * Builds the SQL commands that repair a table structure
  511. *
  512. * @param string $tablename
  513. * @param array $fielddefs
  514. * @param array $indices
  515. * @param bool $execute optional, true if we want the queries executed instead of returned
  516. * @param string $engine optional, MySQL engine
  517. */
  518. public function repairTableParams(
  519. $tablename,
  520. $fielddefs,
  521. $indices,
  522. $execute = true,
  523. $engine = null
  524. )
  525. {
  526. global $table_descriptions;
  527. //jc: had a bug when running the repair if the tablename is blank the repair will
  528. //fail when it tries to create a repair table
  529. if ($tablename == '')
  530. return '';
  531. if (empty($fielddefs))
  532. return '';
  533. //if the table does not exist create it and we are done
  534. $sql = "/* Table : $tablename */\n";
  535. if (!$this->tableExists($tablename)){
  536. $createtablesql = $this->getHelper()
  537. ->createTableSQLParams($tablename,$fielddefs,$indices,$engine);
  538. if($execute && $createtablesql){
  539. $this->createTableParams($tablename,$fielddefs,$indices,$engine);
  540. }
  541. $sql .= "/* MISSING TABLE: {$tablename} */\n";
  542. $sql .= $createtablesql . "\n";
  543. return $sql;
  544. }
  545. $compareFieldDefs = $this->getHelper()->get_columns($tablename);
  546. $compareIndices = $this->getHelper()->get_indices($tablename);
  547. $take_action = false;
  548. // do column comparisions
  549. $sql .= "/*COLUMNS*/\n";
  550. foreach ($fielddefs as $value) {
  551. if (isset($value['source']) && $value['source'] != 'db')
  552. continue;
  553. $name = $value['name'];
  554. // add or fix the field defs per what the DB is expected to give us back
  555. $this->getHelper()->massageFieldDef($value,$tablename);
  556. $ignorerequired=false;
  557. //Do not track requiredness in the DB, auto_increment, ID, and deleted fields are always required in the DB, so don't force those
  558. if (empty($value['auto_increment']) && (empty($value['type']) || $value['type'] != 'id')
  559. && (empty($value['dbType']) || $value['dbType'] != 'id')
  560. && (empty($value['name']) || ($value['name'] != 'id' && $value['name'] != 'deleted'))
  561. ){
  562. $value['required'] = false;
  563. }
  564. //Should match the conditions in DBHelper::oneColumnSQLRep for DB required fields, type='id' fields will sometimes
  565. //come into this function as 'type' = 'char', 'dbType' = 'id' without required set in $value. Assume they are correct and leave them alone.
  566. else if (($name == 'id' || $value['type'] == 'id' || (isset($value['dbType']) && $value['dbType'] == 'id'))
  567. && (!isset($value['required']) && isset($compareFieldDefs[$name]['required'])))
  568. {
  569. $value['required'] = $compareFieldDefs[$name]['required'];
  570. }
  571. if ( !isset($compareFieldDefs[$name]) ) {
  572. // ok we need this field lets create it
  573. $sql .= "/*MISSING IN DATABASE - $name - ROW*/\n";
  574. $sql .= $this->getHelper()->addColumnSQL($tablename, $value) . "\n";
  575. if ($execute)
  576. $this->addColumn($tablename, $value);
  577. $take_action = true;
  578. }
  579. elseif ( !$this->compareVarDefs($compareFieldDefs[$name],$value)) {
  580. //fields are different lets alter it
  581. $sql .= "/*MISMATCH WITH DATABASE - $name - ROW ";
  582. foreach($compareFieldDefs[$name] as $rKey => $rValue)
  583. $sql .= "[$rKey] => '$rValue' ";
  584. $sql .= "*/\n";
  585. $sql .= "/* VARDEF - $name - ROW";
  586. foreach($value as $rKey => $rValue)
  587. $sql .= "[$rKey] => '$rValue' ";
  588. $sql .= "*/\n";
  589. //jc: oracle will complain if you try to execute a statement that sets a column to (not) null
  590. //when it is already (not) null
  591. if ( isset($value['isnull']) && isset($compareFieldDefs[$name]['isnull']) ) {
  592. if ($value['isnull'] === $compareFieldDefs[$name]['isnull']) {
  593. unset($value['required']);
  594. $ignorerequired=true;
  595. }
  596. }
  597. //dwheeler: Once a column has been defined as null, we cannot try to force it back to !null
  598. if ((isset($value['required']) && ($value['required'] === true || $value['required'] == 'true' || $value['required'] === 1))
  599. && (empty($compareFieldDefs[$name]['required']) || $compareFieldDefs[$name]['required'] != 'true'))
  600. {
  601. $ignorerequired = true;
  602. }
  603. $sql .= $this->getHelper()->alterColumnSQL($tablename, $value,$ignorerequired) . "\n";
  604. if($execute){
  605. $this->alterColumn($tablename, $value,$ignorerequired);
  606. }
  607. $take_action = true;
  608. }
  609. }
  610. // do index comparisions
  611. $sql .= "/* INDEXES */\n";
  612. $correctedIndexs = array();
  613. // do indicies comparisons case-insensitive
  614. foreach($compareIndices as $k => $value){
  615. $value['name'] = strtolower($value['name']);
  616. $compareIndices_case_insensitive[strtolower($k)] = $value;
  617. }
  618. $compareIndices = $compareIndices_case_insensitive;
  619. unset($compareIndices_case_insensitive);
  620. foreach ($indices as $value) {
  621. if (isset($value['source']) && $value['source'] != 'db')
  622. continue;
  623. $name = strtolower($value['name']);
  624. //Don't attempt to fix the same index twice in one pass;
  625. if (isset($correctedIndexs[$name]))
  626. continue;
  627. //don't bother checking primary nothing we can do about them
  628. if (isset($value['type']) && $value['type'] == 'primary')
  629. continue;
  630. //database helpers do not know how to handle full text indices
  631. if ($value['type']=='fulltext')
  632. continue;
  633. if ( in_array($value['type'],array('alternate_key','foreign')) )
  634. $value['type'] = 'index';
  635. if ( !isset($compareIndices[$name]) ) {
  636. // ok we need this field lets create it
  637. $sql .= "/*MISSING INDEX IN DATABASE - $name -{$value['type']} ROW */\n";
  638. $sql .= $this->addIndexes($tablename,array($value), $execute) . "\n";
  639. $take_action = true;
  640. $correctedIndexs[$name] = true;
  641. }
  642. elseif ( !$this->compareVarDefs($compareIndices[$name],$value) ) {
  643. // fields are different lets alter it
  644. $sql .= "/*INDEX MISMATCH WITH DATABASE - $name - ROW ";
  645. foreach ($compareIndices[$name] as $n1 => $t1) {
  646. $sql .= "<$n1>";
  647. if ( $n1 == 'fields' )
  648. foreach($t1 as $rKey => $rValue)
  649. $sql .= "[$rKey] => '$rValue' ";
  650. else
  651. $sql .= " $t1 ";
  652. }
  653. $sql .= "*/\n";
  654. $sql .= "/* VARDEF - $name - ROW";
  655. foreach ($value as $n1 => $t1) {
  656. $sql .= "<$n1>";
  657. if ( $n1 == 'fields' )
  658. foreach ($t1 as $rKey => $rValue)
  659. $sql .= "[$rKey] => '$rValue' ";
  660. else
  661. $sql .= " $t1 ";
  662. }
  663. $sql .= "*/\n";
  664. $sql .= $this->modifyIndexes($tablename,array($value), $execute) . "\n";
  665. $take_action = true;
  666. $correctedIndexs[$name] = true;
  667. }
  668. }
  669. return ($take_action === true) ? $sql : "";
  670. }
  671. /**
  672. * Compares two vardefs
  673. *
  674. * @param array $fielddef1 This is from the database
  675. * @param array $fielddef2 This is from the vardef
  676. * @return bool true if they match, false if they don't
  677. */
  678. public function compareVarDefs(
  679. $fielddef1,
  680. $fielddef2
  681. )
  682. {
  683. foreach ( $fielddef1 as $key => $value ) {
  684. if ( $key == 'name' && ( strtolower($fielddef1[$key]) == strtolower($fielddef2[$key]) ) )
  685. continue;
  686. if ( isset($fielddef2[$key]) && $fielddef1[$key] == $fielddef2[$key] )
  687. continue;
  688. return false;
  689. }
  690. return true;
  691. }
  692. /**
  693. * Compare a field in two tables
  694. *
  695. * @param string $name field name
  696. * @param string $table1
  697. * @param string $table2
  698. * @return array array with keys 'msg','table1','table2'
  699. */
  700. public function compareFieldInTables(
  701. $name,
  702. $table1,
  703. $table2
  704. )
  705. {
  706. $row1 = $this->describeField($name, $table1);
  707. $row2 = $this->describeField($name, $table2);
  708. $returnArray = array(
  709. 'table1' => $row1,
  710. 'table2' => $row2,
  711. 'msg' => 'error',
  712. );
  713. $ignore_filter = array('Key'=>1);
  714. if ($row1) {
  715. if (!$row2) {
  716. // Exists on table1 but not table2
  717. $returnArray['msg'] = 'not_exists_table2';
  718. }
  719. else {
  720. if (sizeof($row1) != sizeof($row2)) {
  721. $returnArray['msg'] = 'no_match';
  722. }
  723. else {
  724. $returnArray['msg'] = 'match';
  725. foreach($row1 as $key => $value){
  726. //ignore keys when checking we will check them when we do the index check
  727. if( !isset($ignore_filter[$key]) && $row1[$key] !== $row2[$key]){
  728. $returnArray['msg'] = 'no_match';
  729. }
  730. }
  731. }
  732. }
  733. }
  734. else {
  735. $returnArray['msg'] = 'not_exists_table1';
  736. }
  737. return $returnArray;
  738. }
  739. /**
  740. * Compare an index in two different tables
  741. *
  742. * @param string $name index name
  743. * @param string $table1
  744. * @param string $table2
  745. * @return array array with keys 'msg','table1','table2'
  746. */
  747. public function compareIndexInTables(
  748. $name,
  749. $table1,
  750. $table2
  751. )
  752. {
  753. $row1 = $this->describeIndex($name, $table1);
  754. $row2 = $this->describeIndex($name, $table2);
  755. $returnArray = array(
  756. 'table1' => $row1,
  757. 'table2' => $row2,
  758. 'msg' => 'error',
  759. );
  760. $ignore_filter = array('Table'=>1, 'Seq_in_index'=>1,'Cardinality'=>1, 'Sub_part'=>1, 'Packed'=>1, 'Comment'=>1);
  761. if ($row1) {
  762. if (!$row2) {
  763. //Exists on table1 but not table2
  764. $returnArray['msg'] = 'not_exists_table2';
  765. }
  766. else {
  767. if (sizeof($row1) != sizeof($row2)) {
  768. $returnArray['msg'] = 'no_match';
  769. }
  770. else {
  771. $returnArray['msg'] = 'match';
  772. foreach ($row1 as $fname => $fvalue) {
  773. if (!isset($row2[$fname])) {
  774. $returnArray['msg'] = 'no_match';
  775. }
  776. foreach($fvalue as $key => $value) {
  777. //ignore keys when checking we will check them when we do the index check
  778. if(!isset($ignore_filter[$key]) && $row1[$fname][$key] != $row2[$fname][$key]){
  779. $returnArray['msg'] = 'no_match';
  780. }
  781. }
  782. }
  783. }
  784. }
  785. }
  786. else {
  787. $returnArray['msg'] = 'not_exists_table1';
  788. }
  789. return $returnArray;
  790. }
  791. /**
  792. * Creates an index identified by name on the given fields.
  793. *
  794. * @param object $bean SugarBean instance
  795. * @param array $fieldDefs
  796. * @param string $name index name
  797. * @param bool $unique optional, true if we want to create an unique index
  798. */
  799. public function createIndex(
  800. SugarBean $bean,
  801. $fieldDefs,
  802. $name,
  803. $unique = true
  804. )
  805. {
  806. $sql = $this->getHelper()->createIndexSQL($bean, $fieldDefs, $name, $unique);
  807. $this->tableName = $bean->getTableName();
  808. $msg = "Error creating index $name on table: ".$this->tableName. ":";
  809. $this->query($sql,true,$msg);
  810. }
  811. /**
  812. * Adds a new indexes
  813. *
  814. * @param string $tablename
  815. * @param array $indexes indexes to add
  816. * @param bool $execute true if we want to execute the returned sql statement
  817. * @return string SQL statement
  818. */
  819. public function addIndexes(
  820. $tablename,
  821. $indexes,
  822. $execute = true
  823. )
  824. {
  825. $alters = $this->getHelper()->keysSQL($indexes,true,'ADD');
  826. $sql = "ALTER TABLE $tablename $alters";
  827. if ($execute)
  828. $this->query($sql);
  829. return $sql;
  830. }
  831. /**
  832. * Drops indexes
  833. *
  834. * @param string $tablename
  835. * @param array $indexes indexes to drop
  836. * @param bool $execute true if we want to execute the returned sql statement
  837. * @return string SQL statement
  838. */
  839. public function dropIndexes(
  840. $tablename,
  841. $indexes,
  842. $execute = true
  843. )
  844. {
  845. $sql = '';
  846. foreach ($indexes as $index) {
  847. $name =$index['name'];
  848. if($execute)
  849. unset($GLOBALS['table_descriptions'][$tablename]['indexes'][$name]);
  850. if ($index['type'] == 'primary')
  851. $name = 'PRIMARY KEY';
  852. else
  853. $name = "INDEX $name";
  854. if (empty($sql))
  855. $sql .= " DROP $name ";
  856. else
  857. $sql .= ", DROP $name ";
  858. }
  859. if (!empty($sql)) {
  860. $sql = "ALTER TABLE $tablename $sql";
  861. if($execute)
  862. $this->query($sql);
  863. }
  864. return $sql;
  865. }
  866. /**
  867. * Modifies indexes
  868. *
  869. * @param string $tablename
  870. * @param array $indexes indexes to modify
  871. * @param bool $execute true if we want to execute the returned sql statement
  872. * @return string SQL statement
  873. */
  874. public function modifyIndexes(
  875. $tablename,
  876. $indexes,
  877. $execute = true
  878. )
  879. {
  880. return $this->dropIndexes($tablename, $indexes, $execute)."\n".
  881. $this->addIndexes($tablename, $indexes, $execute);
  882. }
  883. /**
  884. * Adds a column to table identified by field def.
  885. *
  886. * @param string $tablename
  887. * @param array $fieldDefs
  888. */
  889. public function addColumn(
  890. $tablename,
  891. $fieldDefs
  892. )
  893. {
  894. $this->tableName = $tablename;
  895. $sql = $this->getHelper()->addColumnSQL($this->tableName, $fieldDefs);
  896. if ($this->getHelper()->isFieldArray($fieldDefs)){
  897. foreach ($fieldDefs as $fieldDef) $columns[] = $fieldDef['name'];
  898. $columns = implode(",", $columns);
  899. }
  900. else
  901. $columns = $fieldDefs['name'];
  902. $msg = "Error adding column(s) ".$columns." on table: ".$this->tableName. ":";
  903. $this->query($sql,true,$msg);
  904. }
  905. /**
  906. * Alters old column identified by oldFieldDef to new fieldDef.
  907. *
  908. * @param string $tablename
  909. * @param array $newFieldDef
  910. * @param bool $ignoreRequired optional, true if we are ignoring this being a required field
  911. */
  912. public function alterColumn(
  913. $tablename,
  914. $newFieldDef,
  915. $ignoreRequired = false
  916. )
  917. {
  918. $this->tableName = $tablename;
  919. $sql = $this->getHelper()->alterColumnSQL($this->tableName, $newFieldDef,$ignoreRequired);
  920. if ($this->getHelper()->isFieldArray($newFieldDef)){
  921. foreach ($newFieldDef as $fieldDef) {
  922. unset($GLOBALS['table_descriptions'][$tablename][$fieldDef['name']]);
  923. $columns[] = $fieldDef['name'];
  924. }
  925. $columns = implode(",", $columns);
  926. }
  927. else {
  928. unset($GLOBALS['table_descriptions'][$tablename][$newFieldDef['name']]);
  929. $columns = $newFieldDef['name'];
  930. }
  931. $msg = "Error altering column(s) ".$columns." on table: ".$this->tableName. ":";
  932. $this->query($sql,true,$msg);
  933. }
  934. /**
  935. * Drops the table associated with a bean
  936. *
  937. * @param object $bean SugarBean instance
  938. */
  939. public function dropTable(
  940. SugarBean $bean
  941. )
  942. {
  943. $this->tableName = $bean->getTableName();
  944. $this->dropTableName( $this->tableName);
  945. }
  946. /**
  947. * Drops the table by name
  948. *
  949. * @param string $name SugarBean instance
  950. */
  951. public function dropTableName(
  952. $name
  953. )
  954. {
  955. $sql = $this->getHelper()->dropTableNameSQL($name);
  956. $msg = "Error dropping table ".$this->tableName. ":";
  957. $this->query($sql,true,$msg);
  958. }
  959. /**
  960. * Deletes a column identified by fieldDef.
  961. *
  962. * @param string $name SugarBean instance
  963. * @param array $fieldDefs
  964. */
  965. public function deleteColumn(
  966. SugarBean $bean,
  967. $fieldDefs
  968. )
  969. {
  970. $sql = $this->getHelper()->deleteColumnSQL($bean, $fieldDefs);
  971. $this->tableName = $bean->getTableName();
  972. $msg = "Error deleting column(s) ".$columns." on table: ".$this->tableName. ":";
  973. $this->query($sql,true,$msg);
  974. }
  975. /**
  976. * Fetches all the rows for a select query. Returns FALSE if query failed and
  977. * DB_OK for all other queries
  978. *
  979. * @deprecated
  980. *
  981. * @param resource $result
  982. * @return array All rows in result set
  983. */
  984. private function setResult(
  985. $result
  986. )
  987. {
  988. $GLOBALS['log']->info('call to DBManager::setResult() is deprecated');
  989. if (PEAR::isError($result) === true) {
  990. $GLOBALS['log']->error($msg);
  991. $result = FALSE;
  992. }
  993. elseif ($result != DB_OK) {
  994. // must be a result
  995. $GLOBALS['log']->fatal("setResult:".print_r($result,true));
  996. $row = array();
  997. $rows = array();
  998. while (ocifetchinto($result, $row, OCI_ASSOC|OCI_RETURN_NULLS|OCI_RETURN_LOBS)){
  999. $err = ocierror($result);
  1000. if ($err == false) $rows[] = $row;
  1001. else print_r($err);
  1002. }
  1003. $result = $rows;
  1004. }
  1005. $GLOBALS['log']->fatal("setResult: returning rows from setResult");
  1006. return $result;
  1007. }
  1008. /**
  1009. * Private function to handle most of the sql statements which go as queries
  1010. *
  1011. * @deprecated
  1012. *
  1013. * @param string $sql
  1014. * @param int $start
  1015. * @param int $count
  1016. * @param boolean $dieOnError
  1017. * @param string $msg
  1018. * @return array All rows in result set
  1019. */
  1020. public function executeLimitQuery(
  1021. $query,
  1022. $start,
  1023. $count,
  1024. $dieOnError = false,
  1025. $msg = '')
  1026. {
  1027. $GLOBALS['log']->info('call to DBManager::executeLimitQuery() is deprecated');
  1028. $result = $this->limitQuery($query,$start,$count, $dieOnError, $msg);
  1029. return $this->setResult($result);
  1030. }
  1031. /**
  1032. * Private function to handle most of the sql statements which go as queries
  1033. *
  1034. * @deprecated
  1035. *
  1036. * @param string $query
  1037. * @param string $msg
  1038. * @param bool $getRows
  1039. * @return array All rows in result set
  1040. */
  1041. public function executeQuery(
  1042. $query,
  1043. $msg,
  1044. $getRows = false
  1045. )
  1046. {
  1047. $GLOBALS['log']->info('call to DBManager::executeQuery() is deprecated');
  1048. $result = $this->query($query,true,$msg);
  1049. if ($getRows)
  1050. return $this->setResult($result);
  1051. // dd not get rows. Simply go on.
  1052. }
  1053. /**
  1054. * Given a db_type return the correct DBHelper
  1055. *
  1056. * @deprecated
  1057. *
  1058. * @param string $db_type the type of database being used
  1059. * @return object DBHelper instance corresponding to the db_type
  1060. */
  1061. private function configureHelper(
  1062. $db_type
  1063. )
  1064. {
  1065. $GLOBALS['log']->info('call to DBManager::configureHelper() is deprecated');
  1066. global $sugar_config;
  1067. $my_db_helper = 'MysqlHelper';
  1068. if( $sugar_config['dbconfig']['db_type'] == "mysql" ) {
  1069. if (!isset($sugar_config['mysqli_disabled']) or $sugar_config['mysqli_disabled']==false) {
  1070. if (function_exists('mysqli_connect')) {
  1071. $my_db_helper = 'MysqliHelper';
  1072. }
  1073. }
  1074. }
  1075. if($db_type == "oci8" ){
  1076. }else if($db_type == "mssql"){
  1077. require_once('include/database/MssqlHelper.php');
  1078. $my_db_helper = 'MssqlHelper';
  1079. }
  1080. if($my_db_helper == 'MysqlHelper'){
  1081. require_once('include/database/MysqlHelper.php');
  1082. }
  1083. return new $my_db_helper();
  1084. }
  1085. /**
  1086. * Generate a set of Insert statements based on the bean given
  1087. *
  1088. * @deprecated
  1089. *
  1090. * @param object $bean the bean from which table we will generate insert stmts
  1091. * @param string $select_query the query which will give us the set of objects we want to place into our insert statement
  1092. * @param int $start the first row to query
  1093. * @param int $count the number of rows to query
  1094. * @param string $table the table to query from
  1095. * @param string $db_type the client db type
  1096. * @return string SQL insert statement
  1097. */
  1098. public function generateInsertSQL(
  1099. SugarBean $bean,
  1100. $select_query,
  1101. $start,
  1102. $count = -1,
  1103. $table,
  1104. $db_type,
  1105. $is_related_query = false
  1106. )
  1107. {
  1108. $GLOBALS['log']->info('call to DBManager::generateInsertSQL() is deprecated');
  1109. global $sugar_config;
  1110. $count_query = $bean->create_list_count_query($select_query);
  1111. if(!empty($count_query))
  1112. {
  1113. // We have a count query. Run it and get the results.
  1114. $result = $this->query($count_query, true, "Error running count query for $this->object_name List: ");
  1115. $assoc = $this->fetchByAssoc($result);
  1116. if(!empty($assoc['c']))
  1117. {
  1118. $rows_found = $assoc['c'];
  1119. }
  1120. }
  1121. if($count == -1){
  1122. $count = $sugar_config['list_max_entries_per_page'];
  1123. }
  1124. $next_offset = $start + $count;
  1125. $result = $this->limitQuery($select_query, $start, $count);
  1126. $row_count = $this->getRowCount($result);
  1127. // get basic insert
  1128. $sql = "INSERT INTO ".$table;
  1129. $custom_sql = "INSERT INTO ".$table."_cstm";
  1130. // get field definitions
  1131. $fields = $bean->getFieldDefinitions();
  1132. $custom_fields = array();
  1133. if($bean->hasCustomFields()){
  1134. foreach ($fields as $fieldDef){
  1135. if($fieldDef['source'] == 'custom_fields'){
  1136. $custom_fields[$fieldDef['name']] = $fieldDef['name'];
  1137. }
  1138. }
  1139. if(!empty($custom_fields)){
  1140. $custom_fields['id_c'] = 'id_c';
  1141. $id_field = array('name' => 'id_c', custom_type => 'id',);
  1142. $fields[] = $id_field;
  1143. }
  1144. }
  1145. // get column names and values
  1146. $row_array = array();
  1147. $columns = array();
  1148. $cstm_row_array = array();
  1149. $cstm_columns = array();
  1150. $built_columns = false;
  1151. //configure client helper
  1152. $dbHelper = $this->configureHelper($db_type);
  1153. while(($row = $this->fetchByAssoc($result)) != null)
  1154. {
  1155. $values = array();
  1156. $cstm_values = array();
  1157. if(!$is_related_query){
  1158. foreach ($fields as $fieldDef)
  1159. {
  1160. if(isset($fieldDef['source']) && $fieldDef['source'] != 'db' && $fieldDef['source'] != 'custom_fields') continue;
  1161. $val = $row[$fieldDef['name']];
  1162. //handle auto increment values here only need to do this on insert not create
  1163. if ($fieldDef['name'] == 'deleted'){
  1164. $values['deleted'] = $val;
  1165. if(!$built_columns){
  1166. $columns[] = 'deleted';
  1167. }
  1168. }
  1169. else
  1170. {
  1171. $type = $fieldDef['type'];
  1172. if(!empty($fieldDef['custom_type'])){
  1173. $type = $fieldDef['custom_type'];
  1174. }
  1175. // need to do some thing about types of values
  1176. if($db_type == 'mysql' && $val == '' && ($type == 'datetime' || $type == 'date' || $type == 'int' || $type == 'currency' || $type == 'decimal')){
  1177. if(!empty($custom_fields[$fieldDef['name']]))
  1178. $cstm_values[$fieldDef['name']] = 'null';
  1179. else
  1180. $values[$fieldDef['name']] = 'null';
  1181. }else{
  1182. if(isset($type) && $type=='int') {
  1183. if(!empty($custom_fields[$fieldDef['name']]))
  1184. $cstm_values[$fieldDef['name']] = $GLOBALS['db']->quote(from_html($val));
  1185. else
  1186. $values[$fieldDef['name']] = $GLOBALS['db']->quote(from_html($val));
  1187. } else {
  1188. if(!empty($custom_fields[$fieldDef['name']]))
  1189. $cstm_values[$fieldDef['name']] = "'".$GLOBALS['db']->quote(from_html($val))."'";
  1190. else
  1191. $values[$fieldDef['name']] = "'".$GLOBALS['db']->quote(from_html($val))."'";
  1192. }
  1193. }
  1194. if(!$built_columns){
  1195. if(!empty($custom_fields[$fieldDef['name']]))
  1196. $cstm_columns[] = $fieldDef['name'];
  1197. else
  1198. $columns[] = $fieldDef['name'];
  1199. }
  1200. }
  1201. }
  1202. }else{
  1203. foreach ($row as $key=>$val)
  1204. {
  1205. if($key != 'orc_row'){
  1206. $values[$key] = "'$val'";
  1207. if(!$built_columns){
  1208. $columns[] = $key;
  1209. }
  1210. }
  1211. }
  1212. }
  1213. $built_columns = true;
  1214. if(!empty($values)){
  1215. $row_array[] = $values;
  1216. }
  1217. if(!empty($cstm_values) && !empty($cstm_values['id_c']) && (strlen($cstm_values['id_c']) > 7)){
  1218. $cstm_row_array[] = $cstm_values;
  1219. }
  1220. }
  1221. //if (sizeof ($values) == 0) return ""; // no columns set
  1222. // get the entire sql
  1223. $sql .= "(".implode(",", $columns).") ";
  1224. $sql .= "VALUES";
  1225. for($i = 0; $i < count($row_array); $i++){
  1226. $sql .= " (".implode(",", $row_array[$i]).")";
  1227. if($i < (count($row_array) - 1)){
  1228. $sql .= ", ";
  1229. }
  1230. }
  1231. //custom
  1232. // get the entire sql
  1233. $custom_sql .= "(".implode(",", $cstm_columns).") ";
  1234. $custom_sql .= "VALUES";
  1235. for($i = 0; $i < count($cstm_row_array); $i++){
  1236. $custom_sql .= " (".implode(",", $cstm_row_array[$i]).")";
  1237. if($i < (count($cstm_row_array) - 1)){
  1238. $custom_sql .= ", ";
  1239. }
  1240. }
  1241. return array('data' => $sql, 'cstm_sql' => $custom_sql, 'result_count' => $row_count, 'total_count' => $rows_found, 'next_offset' => $next_offset);
  1242. }
  1243. /**
  1244. * Disconnects all instances
  1245. */
  1246. public function disconnectAll()
  1247. {
  1248. global $dbinstances;
  1249. if (!empty($dbinstances)) {
  1250. $cur = current($dbinstances);
  1251. while ($cur) {
  1252. $cur->disconnect();
  1253. $cur = next($dbinstances);
  1254. }
  1255. }
  1256. }
  1257. /**
  1258. * This function sets the query threshold limit
  1259. *
  1260. * @param int $limit value of query threshold limit
  1261. */
  1262. public static function setQueryLimit($limit){
  1263. //reset the queryCount
  1264. self::$queryCount = 0;
  1265. self::$queryLimit = $limit;
  1266. }
  1267. /**
  1268. * Returns the static queryCount value
  1269. *
  1270. * @return int value of the queryCount static variable
  1271. */
  1272. public static function getQueryCount()
  1273. {
  1274. return self::$queryCount;
  1275. }
  1276. /**
  1277. * Resets the queryCount value to 0
  1278. *
  1279. */
  1280. public static function resetQueryCount() {
  1281. self::$queryCount = 0;
  1282. }
  1283. /**
  1284. * This function increments the global $sql_queries variable
  1285. *
  1286. * @param $sql The SQL statement being counted
  1287. */
  1288. public function countQuery(
  1289. $sql
  1290. )
  1291. {
  1292. if (self::$queryLimit != 0 && ++self::$queryCount > self::$queryLimit
  1293. &&(empty($GLOBALS['current_user']) || !is_admin($GLOBALS['current_user']))) {
  1294. require_once('include/resource/ResourceManager.php');
  1295. $resourceManager = ResourceManager::getInstance();
  1296. $resourceManager->notifyObservers('ERR_QUERY_LIMIT');
  1297. }
  1298. }
  1299. /**
  1300. * Returns a string properly quoted for this database
  1301. *
  1302. * @param string $string
  1303. * @param bool $isLike
  1304. */
  1305. public function quote(
  1306. $string,
  1307. $isLike = true
  1308. )
  1309. {
  1310. return from_html($string);
  1311. }
  1312. /**
  1313. * Returns a string properly quoted for this database that is an email
  1314. *
  1315. * @param string $string
  1316. * @param bool $isLike
  1317. */
  1318. abstract public function quoteforEmail(
  1319. $string,
  1320. $isLike = true
  1321. );
  1322. /**
  1323. * Quote the strings of the passed in array
  1324. *
  1325. * The array must only contain strings
  1326. *
  1327. * @param array $array
  1328. * @param bool $isLike
  1329. */
  1330. public function arrayQuote(
  1331. array &$array,
  1332. $isLike = true
  1333. )
  1334. {
  1335. for($i = 0; $i < count($array); $i++){
  1336. $array[$i] = $this->quote($array[$i], $isLike);
  1337. }
  1338. }
  1339. /**
  1340. * Parses and runs queries
  1341. *
  1342. * @param string $sql SQL Statement to execute
  1343. * @param bool $dieOnError True if we want to call die if the query returns errors
  1344. * @param string $msg Message to log if error occurs
  1345. * @param bool $suppress Flag to suppress all error output unless in debug logging mode.
  1346. * @return resource result set
  1347. */
  1348. abstract public function query(
  1349. $sql,
  1350. $dieOnError = false,
  1351. $msg = '',
  1352. $suppress = false
  1353. );
  1354. /**
  1355. * Runs a limit query: one where we specify where to start getting records and how many to get
  1356. *
  1357. * @param string $sql
  1358. * @param int $start
  1359. * @param int $count
  1360. * @param boolean $dieOnError
  1361. * @param string $msg
  1362. * @return resource query result
  1363. */
  1364. abstract function limitQuery(
  1365. $sql,
  1366. $start,
  1367. $count,
  1368. $dieOnError = false,
  1369. $msg = '');
  1370. /**
  1371. * Frees out previous results
  1372. *
  1373. * @param resource $result optional, pass if you want to free a single result instead of all results
  1374. */
  1375. protected function freeResult(
  1376. $result = false
  1377. )
  1378. {
  1379. $free_result = $this->backendFunctions['free_result'];
  1380. if(!$result && $this->lastResult){

Large files files are truncated, but you can click here to view the full file