From 4d1368d89adf2ac49a8478f96c8d35c58ec86e79 Mon Sep 17 00:00:00 2001 From: "deb.monish" Date: Thu, 29 Jun 2017 17:34:49 +0530 Subject: [PATCH] CRM-17748: Expose options to CRM_Core_DAO --- CRM/Core/DAO.php | 90 ++++++++++++++++++------------ tests/phpunit/CRM/Core/DAOTest.php | 38 +++++++++++++ 2 files changed, 91 insertions(+), 37 deletions(-) diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php index b1bf5ba765..d83070dcc7 100644 --- a/CRM/Core/DAO.php +++ b/CRM/Core/DAO.php @@ -1233,43 +1233,17 @@ FROM civicrm_domain $i18nRewrite = TRUE, $trapException = FALSE ) { - $queryStr = self::composeQuery($query, $params, $abort); - //CRM_Core_Error::debug( 'q', $queryStr ); - if (!$daoName) { - $dao = new CRM_Core_DAO(); - } - else { - $dao = new $daoName(); - } - - if ($trapException) { - CRM_Core_Error::ignoreException(); - } - - // set the DAO object to use an unbuffered query - $dao->setOptions(array('result_buffering' => 0)); - - $result = $dao->query($queryStr, $i18nRewrite); - if ($trapException) { - CRM_Core_Error::setCallback(); - } - - if (is_a($result, 'DB_Error')) { - return $result; - } - - // since it is unbuffered, ($dao->N==0) is true. This blocks the standard fetch() mechanism. - $dao->N = TRUE; - - if ($freeDAO || - preg_match('/^(insert|update|delete|create|drop|replace)/i', $queryStr) - ) { - // we typically do this for insert/update/delete stataments OR if explicitly asked to - // free the dao - $dao->free(); - } - return $dao; + return self::executeQuery( + $query, + $params, + $abort, + $daoName, + $freeDAO, + $i18nRewrite, + $trapException, + array('result_buffering' => 0) + ); } /** @@ -1284,6 +1258,7 @@ FROM civicrm_domain * @param bool $freeDAO * @param bool $i18nRewrite * @param bool $trapException + * @param array $options * * @return CRM_Core_DAO|object * object that holds the results of the query @@ -1297,7 +1272,8 @@ FROM civicrm_domain $daoName = NULL, $freeDAO = FALSE, $i18nRewrite = TRUE, - $trapException = FALSE + $trapException = FALSE, + $options = array() ) { $queryStr = self::composeQuery($query, $params, $abort); @@ -1312,8 +1288,17 @@ FROM civicrm_domain $errorScope = CRM_Core_TemporaryErrorScope::ignoreException(); } + if ($dao->isValidOption($options)) { + $dao->setOptions($options); + } + $result = $dao->query($queryStr, $i18nRewrite); + // since it is unbuffered, ($dao->N==0) is true. This blocks the standard fetch() mechanism. + if (CRM_Utils_Array::value('result_buffering', $options) === 0) { + $dao->N = TRUE; + } + if (is_a($result, 'DB_Error')) { return $result; } @@ -1328,6 +1313,37 @@ FROM civicrm_domain return $dao; } + /** + * Wrapper to validate internal DAO options before passing to DB_mysql/DB_Common level + * + * @param array $options + * + * @return bool + * Provided options are valid + */ + public function isValidOption($options) { + $isValid = FALSE; + $validOptions = array( + 'result_buffering', + 'persistent', + 'ssl', + 'portability', + ); + + if (empty($options)) { + return $isValid; + } + + foreach (array_keys($options) as $option) { + if (!in_array($option, $validOptions)) { + return FALSE; + } + $isValid = TRUE; + } + + return $isValid; + } + /** * Execute a query and get the single result. * diff --git a/tests/phpunit/CRM/Core/DAOTest.php b/tests/phpunit/CRM/Core/DAOTest.php index 21b62eb44d..1a9077a34a 100644 --- a/tests/phpunit/CRM/Core/DAOTest.php +++ b/tests/phpunit/CRM/Core/DAOTest.php @@ -308,4 +308,42 @@ class CRM_Core_DAOTest extends CiviUnitTestCase { } } + /** + * CRM-17748: Test internal DAO options + */ + public function testDBOptions() { + $contactIDs = array(); + for ($i = 0; $i < 10; $i++) { + $contactIDs[] = $this->individualCreate(array( + 'first_name' => 'Alan' . substr(sha1(rand()), 0, 7), + 'last_name' => 'Smith' . substr(sha1(rand()), 0, 4), + )); + } + + // Test option 'result_buffering' + $this->_testMemoryUsageForUnbufferedQuery(); + + // cleanup + foreach ($contactIDs as $contactID) { + $this->callAPISuccess('Contact', 'delete', array('id' => $contactID)); + } + } + + /** + * Helper function to test result of buffered and unbuffered query + */ + public function _testMemoryUsageForUnbufferedQuery() { + $sql = "SELECT * FROM civicrm_contact WHERE first_name LIKE 'Alan%' AND last_name LIKE 'Smith%' "; + + $dao = CRM_Core_DAO::executeQuery($sql); + $contactsFetchedFromBufferedQuery = $dao->fetchAll(); + $dao->free(); + + $dao = CRM_Core_DAO::executeUnbufferedQuery($sql); + $contactsFetchedFromUnbufferedQuery = $dao->fetchAll(); + $dao->free(); + + $this->checkArrayEquals($contactsFetchedFromBufferedQuery, $contactsFetchedFromUnbufferedQuery); + } + } -- 2.25.1