/** * Constructor * * @param Zend_Db_Statement $stmt * @return void * @access public * @since 4/4/08 */ public function __construct(Zend_Db_Statement $stmt, $adapter) { $this->stmt = $stmt; $this->adapter = $adapter; // It seems that PDO only supports buffered queries on MySQL and it is // not recommended to use them even there. buffering therefore must be done // here rather than in the adapter layer. $this->stmt->setFetchMode(Zend_Db::FETCH_ASSOC); $this->rows = $this->stmt->fetchAll(); $this->stmt->closeCursor(); }
/** * @param string $sql * @return void * @throws Zend_Db_Statement_Mysqli_Exception */ public function _prepSql($sql) { parent::_prepSql($sql); $mysqli = $this->_adapter->getConnection(); $this->_stmt = $mysqli->prepare($sql); if ($this->_stmt === false || $mysqli->errno) { /** * @see Zend_Db_Statement_Mysqli_Exception */ require_once 'Zend/Db/Statement/Mysqli/Exception.php'; throw new Zend_Db_Statement_Mysqli_Exception("Mysqli prepare error: " . $mysqli->error); } }
/** * Returns a specific record given it's offset/index * @param integer $offset Offset of record to fetch */ public function offsetGet($offset) { // PDO does not support scrollable cursor for MySQL, so we can't use the cursor // and offset parameters of _statement->fetch(). // Therefore, our only real option is to put a limit on the list temporarily and // then reset it. $previousLimitCount = $this->_select->getPart(Zend_Db_Select::LIMIT_COUNT); $previousLimitOffset = $this->_select->getPart(Zend_Db_Select::LIMIT_OFFSET); $this->limit(1, $offset); $this->_execute(); $item = $this->_statement->fetch(); $this->reset(Zend_Db_Select::LIMIT_COUNT); $this->reset(Zend_Db_Select::LIMIT_OFFSET); $this->limit($previousLimitCount, $previousLimitOffset); if ($item) { $class = $this->_class; return new $class($item, $this->tableName(), $this->_db); } return false; }
/** * Busca o próximo registro * * @param type $style * @param type $cursor * @param type $offset * @return boolean */ public function fetch($style = null, $cursor = null, $offset = null) { $this->_row = false; if ($this->_record instanceof Zend_Db_Statement) { $this->_row = $this->_record->fetch($style, $cursor, $offset); } else { if ($this->_index > -1 && $this->_index < count($this->_record)) { $this->_row = $this->_record[$this->_index]; $this->_index++; } } if ($this->_row) { if (count($this->_replaceAlias)) { foreach ($this->_replaceAlias as $oldAlias => $newAlias) { $this->_row[$newAlias] = $this->_row[$oldAlias]; unset($this->_row[$oldAlias]); } } if ($this->isRowFormated()) { $this->_formatRow($this->_row); } } return is_array($this->_row); }
/** * Returns an array containing all of the result set rows. * * @param int $style OPTIONAL Fetch mode. * @param int $col OPTIONAL Column number, if fetch mode is by column. * @return array Collection of rows, each in a format by the fetch mode. * * Behaves like parent, but if limit() * is used, the final result removes the extra column * 'zend_db_rownum' */ public function fetchAll($style = null, $col = null) { $data = parent::fetchAll($style, $col); $results = array(); $remove = $this->_adapter->foldCase('ZEND_DB_ROWNUM'); foreach ($data as $row) { if (is_array($row) && array_key_exists($remove, $row)) { unset($row[$remove]); } $results[] = $row; } return $results; }
/** * Prepare a statement handle. * * @param string $sql * @return void * @throws Zend_Db_Statement_Db2_Exception */ public function _prepSql($sql) { Zend_Db_Statement::_prepSql($sql); $connection = $this->_connection->getConnection(); $this->_stmt = db2_prepare($connection, $sql); if (!$this->_stmt) { require_once 'Zend/Db/Statement/Db2/Exception.php'; throw new Zend_Db_Statement_Db2_Exception(db2_stmt_errormsg($this->_stmt), db2_stmt_error($this->_stmt)); } }
/** * @param Zend_Db_Statement|PDOStatement $query * @param string|bool $fieldQueried * @param array $actionsTablesByType * @return int */ public static function updateActionsTableWithRowQuery($query, $fieldQueried, &$actionsTablesByType) { $rowsProcessed = 0; while ($row = $query->fetch()) { // var_dump($row); if (empty($row['idaction'])) { $row['type'] = $fieldQueried == 'idaction_url' ? Piwik_Tracker_Action::TYPE_ACTION_URL : Piwik_Tracker_Action::TYPE_ACTION_NAME; // This will be replaced with 'X not defined' later $row['name'] = ''; // Yes, this is kind of a hack, so we don't mix 'page url not defined' with 'page title not defined' etc. $row['idaction'] = -$row['type']; } if ($row['type'] != Piwik_Tracker_Action::TYPE_SITE_SEARCH) { unset($row[Piwik_Archive::INDEX_SITE_SEARCH_HAS_NO_RESULT]); } // This will appear as <url /> in the API, which is actually very important to keep // eg. When there's at least one row in a report that does not have a URL, not having this <url/> would break HTML/PDF reports. $url = ''; if ($row['type'] == Piwik_Tracker_Action::TYPE_SITE_SEARCH || $row['type'] == Piwik_Tracker_Action::TYPE_ACTION_NAME) { $url = null; } elseif (!empty($row['name']) && $row['name'] != Piwik_DataTable::LABEL_SUMMARY_ROW) { $url = Piwik_Tracker_Action::reconstructNormalizedUrl((string) $row['name'], $row['url_prefix']); } if (isset($row['name']) && isset($row['type'])) { $actionName = $row['name']; $actionType = $row['type']; $urlPrefix = $row['url_prefix']; $idaction = $row['idaction']; // in some unknown case, the type field is NULL, as reported in #1082 - we ignore this page view if (empty($actionType)) { if ($idaction != Piwik_DataTable::LABEL_SUMMARY_ROW) { self::setCachedActionRow($idaction, $actionType, false); } continue; } $actionRow = self::getActionRow($actionName, $actionType, $urlPrefix, $actionsTablesByType); self::setCachedActionRow($idaction, $actionType, $actionRow); } else { $actionRow = self::getCachedActionRow($row['idaction'], $row['type']); // Action processed as "to skip" for some reasons if ($actionRow === false) { continue; } } if (is_null($actionRow)) { continue; } // Here we do ensure that, the Metadata URL set for a given row, is the one from the Pageview with the most hits. // This is to ensure that when, different URLs are loaded with the same page name. // For example http://piwik.org and http://id.piwik.org are reported in Piwik > Actions > Pages with /index // But, we must make sure http://piwik.org is used to link & for transitions // Note: this code is partly duplicated from Piwik_DataTable_Row->sumRowMetadata() if (!is_null($url) && !$actionRow->isSummaryRow()) { if (($existingUrl = $actionRow->getMetadata('url')) !== false) { if (!empty($row[Piwik_Archive::INDEX_PAGE_NB_HITS]) && $row[Piwik_Archive::INDEX_PAGE_NB_HITS] > $actionRow->maxVisitsSummed) { $actionRow->setMetadata('url', $url); $actionRow->maxVisitsSummed = $row[Piwik_Archive::INDEX_PAGE_NB_HITS]; } } else { $actionRow->setMetadata('url', $url); $actionRow->maxVisitsSummed = !empty($row[Piwik_Archive::INDEX_PAGE_NB_HITS]) ? $row[Piwik_Archive::INDEX_PAGE_NB_HITS] : 0; } } unset($row['name']); unset($row['type']); unset($row['idaction']); unset($row['url_prefix']); foreach ($row as $name => $value) { // in some edge cases, we have twice the same action name with 2 different idaction // - this happens when 2 visitors visit the same new page at the same time, and 2 actions get recorded for the same name // - this could also happen when 2 URLs end up having the same label (eg. 2 subdomains get aggregated to the "/index" page name) if (($alreadyValue = $actionRow->getColumn($name)) !== false) { $actionRow->setColumn($name, $alreadyValue + $value); } else { $actionRow->addColumn($name, $value); } } // if the exit_action was not recorded properly in the log_link_visit_action // there would be an error message when getting the nb_hits column // we must fake the record and add the columns if ($actionRow->getColumn(Piwik_Archive::INDEX_PAGE_NB_HITS) === false) { // to test this code: delete the entries in log_link_action_visit for // a given exit_idaction_url foreach (self::getDefaultRow()->getColumns() as $name => $value) { $actionRow->addColumn($name, $value); } } $rowsProcessed++; } // just to make sure php copies the last $actionRow in the $parentTable array $actionRow =& $actionsTablesByType; return $rowsProcessed; }
/** * Create the new index records for the indexer entity * * @param Zend_Db_Statement $stmt * @return void */ protected function _insertIndexRecords(Zend_Db_Statement $stmt) { Varien_Profiler::start($this->_getProfilerName() . '::reindexEntity::insert'); $entityId = null; $data = $storesHandled = $entityDefaultGroupsWithoutMode = array(); while ($row = $stmt->fetch()) { $this->_prepareRow($row); // A new entity is being handled if ($entityId !== $row['entity_id']) { // Add missing store id records to the insert data array for the previous entity id // That is why we skip this condition on the first iteration. // We need to do this last because then $storesHandled is set completely for the $entityId if (null !== $entityId) { $this->_addMissingStoreRecords($data, $entityId, $entityDefaultGroupsWithoutMode, $storesHandled); // Insert INSERT_CHUNK_SIZE records at a time. // If INSERT_CHUNK_SIZE records exist in $data then it is reset to an empty array afterwards $this->_insertIndexRecordsIfMinChunkSizeReached($data, self::INSERT_CHUNK_SIZE); } // Set new entity as default $entityId = $row['entity_id']; // Set default groups for new entity (store id 0 is the first one for each entity in $result). // List of raw attribute value group ids without the store mode settings applied. $entityDefaultGroupsWithoutMode = $row['orig_group_ids']; // Reset stores handled for new entity to empty list $storesHandled = array(); // We don't need an index entry for store id 0, simply use it as the default continue; } // Don't include stores in the index where the module is disabled anyway if ($this->_isModuleDisabledInStore($row['store_id'])) { continue; } // Add index record for each group id foreach ($row['group_ids'] as $groupId) { $data[] = array('catalog_entity_id' => $row['entity_id'], 'group_id' => $groupId, 'store_id' => $row['store_id']); $storesHandled[] = $row['store_id']; } } // Check if at least one entity record was found. If not, $entityId will be null if ($entityId) { // The last iterations over $result will probably not have hit the >= INSERT_CHUNK_SIZE mark, // so we still need to insert these, too. // Add missing store id records to the insert data array for the last $entityId $this->_addMissingStoreRecords($data, $entityId, $entityDefaultGroupsWithoutMode, $storesHandled); // Insert missing index records $this->_insertIndexRecordsIfMinChunkSizeReached($data, 1); } Varien_Profiler::stop($this->_getProfilerName() . '::reindexEntity::insert'); }
/** * @param Zend_Db_Statement|PDOStatement $query * @param string|bool $fieldQueried * @return int */ protected function updateActionsTableWithRowQuery($query, $fieldQueried = false) { $rowsProcessed = 0; while ($row = $query->fetch()) { if (empty($row['idaction'])) { $row['type'] = $fieldQueried == 'idaction_url' ? Piwik_Tracker_Action::TYPE_ACTION_URL : Piwik_Tracker_Action::TYPE_ACTION_NAME; // This will be replaced with 'X not defined' later $row['name'] = ''; // Yes, this is kind of a hack, so we don't mix 'page url not defined' with 'page title not defined' etc. $row['idaction'] = -$row['type']; } // Only the first query will contain the name and type of actions, for performance reasons if (isset($row['name']) && isset($row['type'])) { $actionName = $row['name']; $actionType = $row['type']; $urlPrefix = $row['url_prefix']; // in some unknown case, the type field is NULL, as reported in #1082 - we ignore this page view if (empty($actionType)) { self::$cacheParsedAction[$row['idaction']] = false; continue; } $currentTable = $this->parseActionNameCategoriesInDataTable($actionName, $actionType, $urlPrefix); self::$cacheParsedAction[$row['idaction']] = $currentTable; } else { if (!isset(self::$cacheParsedAction[$row['idaction']])) { // This can happen when // - We select an entry page ID that was only seen yesterday, so wasn't selected in the first query // - We count time spent on a page, when this page was only seen yesterday continue; } $currentTable = self::$cacheParsedAction[$row['idaction']]; // Action processed as "to skip" for some reasons if ($currentTable === false) { continue; } } unset($row['name']); unset($row['type']); unset($row['idaction']); unset($row['url_prefix']); foreach ($row as $name => $value) { // in some edge cases, we have twice the same action name with 2 different idaction // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page, // and in between the two the other visitor comes. // here we handle the case where there is already a row for this action name, if this is the case we add the value if (($alreadyValue = $currentTable->getColumn($name)) !== false) { $currentTable->setColumn($name, $alreadyValue + $value); } else { $currentTable->addColumn($name, $value); } } // if the exit_action was not recorded properly in the log_link_visit_action // there would be an error message when getting the nb_hits column // we must fake the record and add the columns if ($currentTable->getColumn(Piwik_Archive::INDEX_PAGE_NB_HITS) === false) { // to test this code: delete the entries in log_link_action_visit for // a given exit_idaction_url foreach ($this->defaultRow->getColumns() as $name => $value) { $currentTable->addColumn($name, $value); } } $rowsProcessed++; } // just to make sure php copies the last $currentTable in the $parentTable array $currentTable =& $this->actionsTablesByType; return $rowsProcessed; }