protected function prepareSelectedCubeQueryStatement(AbstractSQLDataSourceQueryHandler $datasourceHandler, DataControllerCallContext $callcontext, AbstractCubeQueryRequest $request) { $metamodel = data_controller_get_metamodel(); // loading cube configuration $cubeName = $request->getCubeName(); $cube = $metamodel->getCube($cubeName); $factsDataset = $metamodel->getDataset($cube->factsDatasetName); $generationContext = $this->prepareStatementGenerationContext($request, $cube); $TABLE_ALIAS__SOURCE = 's'; // to store configuration for each accessed table $datasetConfigs = NULL; // preparing facts dataset configuration $this->registerDatasetConfig($datasetConfigs, 0, $factsDataset, NULL, NULL); $columnReferenceFactory = new CompositeColumnReferenceFactory(array( $cube->factsDataset, new FormulaReferenceFactory($request->getFormulas()))); $expressionAssembler = new FormulaExpressionAssembler($columnReferenceFactory); // statement for aggregation portion of final sql $aggrStatement = new Statement(); // adding support for facts dataset column queries $factsDatasetColumnQueries = $request->findFactsDatasetColumnQueries(); if (isset($factsDatasetColumnQueries)) { foreach ($factsDatasetColumnQueries as $queryColumn) { foreach ($queryColumn->values as $value) { $this->registerDatasetConfig($datasetConfigs, 0, NULL, $queryColumn->name, NULL); $aggrStatement->conditions[] = new WhereConditionSection( $TABLE_ALIAS__SOURCE . '0', $queryColumn->name, new ExactConditionSectionValue( $datasourceHandler->formatOperatorValue($callcontext, $request, $factsDataset->name, $queryColumn->name, $value))); } } } $possibleDimensions = NULL; // adding dimensions from a cube if (isset($cube->dimensions)) { foreach ($cube->dimensions as $dimension) { $possibleDimensions[$dimension->name] = $dimension; } } // creating 'virtual' dimensions from formulas if (isset($request->dimensions)) { foreach ($request->dimensions as $selectedDimension) { // it is predefined dimension if (isset($possibleDimensions[$selectedDimension->name])) { continue; } // it could be a 'virtual' dimension defined by a formula $formula = $request->findFormula($selectedDimension->name); if (!isset($formula)) { continue; } // defining 'virtual dimension' $formulaDimension = new DimensionMetaData(); $formulaDimension->name = $selectedDimension->name; $formulaDimension->attributeColumnName = $selectedDimension->name; $possibleDimensions[$formulaDimension->name] = $formulaDimension; } } // FIXME why do we start with 1? $tableIndex = 1 + count($possibleDimensions); // preparing list of columns which are required to group data for the aggregation $aggrSelectColumns = NULL; // preparing list of measures which are calculated in the aggregation, preparing support for measure conditions $aggrSelectMeasureColumns = NULL; if (isset($possibleDimensions)) { foreach ($possibleDimensions as $dimension) { $dimensionName = $dimension->name; $selectedDimension = $request->findDimension($dimensionName); $queriedDimension = $request->findDimensionQuery($dimensionName); if (!isset($selectedDimension) && !isset($queriedDimension)) { continue; } $factsColumn = $factsDataset->findColumn($dimension->attributeColumnName); $selectedColumnNames = isset($selectedDimension) ? $selectedDimension->getColumnNames() : NULL; list($selectedFactsColumnNames, $selectedDimensionColumnNames) = isset($selectedColumnNames) && isset($factsColumn) ? $this->detectColumnNameOwner($factsColumn, $selectedColumnNames) : array(NULL, $selectedColumnNames); $queriedColumnNames = isset($queriedDimension) ? $queriedDimension->getColumnNames() : NULL; list($queriedFactsColumnNames, $queriedDimensionColumnNames) = isset($queriedColumnNames) && isset($factsColumn) ? $this->detectColumnNameOwner($factsColumn, $queriedColumnNames) : array(NULL, $queriedColumnNames); $isJoinWithDimensionDatasetRequired = (isset($queriedDimension) && isset($queriedColumnNames) && (isset($dimension->datasetName) || isset($queriedDimensionColumnNames))) || ( isset($generationContext->dimensionJoinPhase[__DefaultQueryEngine_StatementGenerationContext::DIMENSION_JOIN_PHASE__GROUPING_INITIAL][$dimensionName]) && $generationContext->dimensionJoinPhase[__DefaultQueryEngine_StatementGenerationContext::DIMENSION_JOIN_PHASE__GROUPING_INITIAL][$dimensionName]); $dimensionDataset = NULL; if (isset($dimension->datasetName)) { $dimensionDataset = $metamodel->getDataset($dimension->datasetName); } elseif ($isJoinWithDimensionDatasetRequired) { // 02/26/2014 there could be a case when dimension dataset does not exist but we try to connect with extension table using PK-to-PK connection $dimensionDataset = $factsDataset; } $keyColumnName = isset($dimensionDataset) ? $dimensionDataset->getKeyColumn()->name : (isset($dimension->key) ? $dimension->key : NULL); // joining with dimension dataset ... if necessary if ($isJoinWithDimensionDatasetRequired) { // registering the dimension dataset $tableIndex--; $this->registerDatasetConfig($datasetConfigs, $tableIndex, $dimensionDataset, NULL, NULL); if (isset($queriedDimensionColumnNames)) { foreach ($queriedDimension->columns as $queryColumn) { if (!isset($queryColumn->name)) { continue; } if (!in_array($queryColumn->name, $queriedDimensionColumnNames)) { continue; } $this->registerDatasetConfig($datasetConfigs, $tableIndex, NULL, $queryColumn->name, NULL); foreach ($queryColumn->values as $value) { $aggrStatement->conditions[] = new WhereConditionSection( $TABLE_ALIAS__SOURCE . $tableIndex, $queryColumn->name, new ExactConditionSectionValue( $datasourceHandler->formatOperatorValue($callcontext, $request, $dimensionDataset->name, $queryColumn->name, $value))); } } } // selected columns are part of the dimension dataset if (isset($selectedDimensionColumnNames)) { foreach ($selectedDimensionColumnNames as $columnName) { $responseColumnName = ParameterNameHelper::assemble($dimensionName, $columnName); $databaseColumnName = DataSourceColumnNameHelper::generateFromParameterElements( $datasourceHandler->getMaximumEntityNameLength(), ($request->referenced ? ReferencePathHelper::assembleReference($factsDataset->name, $dimensionName) : $dimensionName), $columnName); $callcontext->columnMapping[$databaseColumnName] = $responseColumnName; $this->registerDatasetConfig($datasetConfigs, $tableIndex, $dimensionDataset, $columnName, NULL); $aggrSelectColumns[$tableIndex][] = new ColumnSection($columnName, $databaseColumnName); } } } if (isset($selectedFactsColumnNames) || isset($selectedDimension->requestColumnIndex)) { $responseColumnName = ParameterNameHelper::assemble($dimensionName); $databaseColumnName = DataSourceColumnNameHelper::generateFromParameterElements( $datasourceHandler->getMaximumEntityNameLength(), ($request->referenced ? ReferencePathHelper::assembleReference($factsDataset->name, $dimensionName) : $dimensionName)); $callcontext->columnMapping[$databaseColumnName] = $responseColumnName; // selected columns are part of facts table if (isset($selectedFactsColumnNames)) { foreach ($selectedFactsColumnNames as $columnName) { $responseSelectedColumnName = ParameterNameHelper::assemble($dimensionName, $columnName); $databaseSelectedColumnName = DataSourceColumnNameHelper::generateFromParameterElements( $datasourceHandler->getMaximumEntityNameLength(), ($request->referenced ? ReferencePathHelper::assembleReference($factsDataset->name, $dimensionName) : $dimensionName), $columnName); $callcontext->columnMapping[$databaseSelectedColumnName] = $responseSelectedColumnName; $this->registerDatasetConfig($datasetConfigs, 0, NULL, $columnName, NULL); $aggrSelectColumns[0][] = new ColumnSection($columnName, $databaseSelectedColumnName); } } elseif (isset($selectedDimension->requestColumnIndex)) { $formula = $request->findFormula($dimension->name); if (isset($formula)) { $expression = $expressionAssembler->assemble($formula); $column = new CompositeColumnSection($expression, $databaseColumnName); if (isset($formula->isMeasure) && !$formula->isMeasure) { $aggrSelectColumns[0][] = $column; } else { $aggrSelectMeasureColumns[] = $column; } } else { $column = new ColumnSection( DataSourceColumnNameHelper::generateFromParameterElements($datasourceHandler->getMaximumEntityNameLength(), $dimension->attributeColumnName), $databaseColumnName); $aggrSelectColumns[0][] = $column; } $this->registerDatasetConfig($datasetConfigs, 0, NULL, $dimension->attributeColumnName, NULL); } } // adding facts table conditions if (isset($queriedDimension)) { foreach ($queriedDimension->columns as $queryColumn) { if (isset($queryColumn->name)) { if (!isset($queriedFactsColumnNames) || !in_array($queryColumn->name, $queriedFactsColumnNames)) { continue; } } $queryColumnName = isset($queryColumn->name) ? $queryColumn->name : $dimension->attributeColumnName; $this->registerDatasetConfig($datasetConfigs, 0, NULL, $queryColumnName, NULL); foreach ($queryColumn->values as $value) { $aggrStatement->conditions[] = new WhereConditionSection( $TABLE_ALIAS__SOURCE . 0, $queryColumnName, new ExactConditionSectionValue( $datasourceHandler->formatOperatorValue($callcontext, $request, $factsDataset->name, $queryColumnName, $value))); } } } // linking the dimension dataset with master source if ($isJoinWithDimensionDatasetRequired) { $this->registerDatasetConfig($datasetConfigs, 0, NULL, $dimension->attributeColumnName, NULL); $this->registerDatasetConfig( $datasetConfigs, $tableIndex, NULL, $keyColumnName, new JoinConditionSection( $keyColumnName, new TableColumnConditionSectionValue($TABLE_ALIAS__SOURCE . '0', $dimension->attributeColumnName))); } } } // preparing a list of required measures $selectedMeasureNames = NULL; if (isset($request->measures)) { foreach ($request->measures as $measure) { $selectedMeasureNames[$measure->name] = TRUE; } } $measureQueries = $request->findMeasureQueries(); if (isset($measureQueries)) { foreach ($measureQueries as $query) { $selectedMeasureNames[$query->name] = TRUE; } } // adding measures to the statement if (isset($selectedMeasureNames)) { foreach ($selectedMeasureNames as $measureName => $flag) { $measureExpression = NULL; // checking cube first $cubeMeasure = $cube->findMeasure($measureName); if (isset($cubeMeasure)) { $measureExpression = $cubeMeasure->getFunction(); } else { $formula = $request->findFormula($measureName); $measureExpression = $expressionAssembler->assemble($formula); } $selectedMeasure = $request->findMeasure($measureName); $queriedMeasure = $request->findMeasureQuery($measureName); if ($request->referenced) { $measureName = ReferencePathHelper::assembleReference($factsDataset->name, $measureName); } $databaseColumnName = DataSourceColumnNameHelper::generateFromParameterElements( $datasourceHandler->getMaximumEntityNameLength(), $measureName); $columnSection = new CompositeColumnSection($measureExpression, $databaseColumnName); if (isset($selectedMeasure)) { $callcontext->columnMapping[$databaseColumnName] = $measureName; $aggrSelectMeasureColumns[] = $columnSection; } if (isset($queriedMeasure)) { foreach ($queriedMeasure->values as $value) { $aggrStatement->havingConditions[] = new HavingConditionSection( $columnSection, new ExactConditionSectionValue( $datasourceHandler->formatOperatorValue($callcontext, $request, $factsDataset->name, NULL, $value))); } } // looking for possible columns in the measure function. We need to retrieve those from the database $columnNames = $columnSection->parseColumns(); if (isset($columnNames)) { foreach ($columnNames as $columnName) { $this->registerDatasetConfig($datasetConfigs, 0, NULL, $columnName, NULL); } } } } // sorting configuration to support joins in correct order ksort($datasetConfigs, SORT_NUMERIC); // preparing dataset source statements foreach ($datasetConfigs as $orderIndex => $datasetConfig) { $tableStatement = $datasourceHandler->prepareDatasetSourceStatement($callcontext, $request, $datasetConfig->dataset, $datasetConfig->usedColumnNames); // adding join conditions if (isset($datasetConfig->conditions)) { foreach ($datasetConfig->conditions as $condition) { $tableStatement->getColumnTable($condition->subjectColumnName)->conditions[] = $condition; } } // BLOCK 1: finding tables to which we want to attach columns which participate in aggregation // the code would be simpler if we supported several aliases per column // if we move the logic to BLOCK 3 getColumnTable(, TRUE) will not work $selectedAggregationTables = NULL; if (isset($aggrSelectColumns[$orderIndex])) { $tableSelectColumns = $aggrSelectColumns[$orderIndex]; foreach ($tableSelectColumns as $aggrColumnIndex => $tableSelectColumn) { // FIXME check other places to understand why I need to use parameter with TRUE value // looking for a table in the statement which provides the column for SELECT section if ($tableSelectColumn instanceof CompositeColumnSection) { $tableSection = $tableStatement->tables[0]; } else { $tableSection = $tableStatement->getColumnTable($tableSelectColumn->name, TRUE); } $selectedAggregationTables[$orderIndex][$aggrColumnIndex] = $tableSection; } } // BLOCK 2: we do not need to return any columns from the table by default foreach ($tableStatement->tables as $table) { if (isset($table->columns)) { foreach ($table->columns as $column) { $column->visible = FALSE; } } else { $table->columns = array(); // We do not need any columns } } // preparing measures which we want to return. Adding those measures to facts table if (($orderIndex == 0) && isset($aggrSelectMeasureColumns)) { foreach ($aggrSelectMeasureColumns as $tableSelectMeasureColumn) { $columnNames = $tableSelectMeasureColumn->parseColumns(); // searching which table contains the column $tableSection = NULL; if (isset($columnNames)) { foreach ($columnNames as $columnName) { $formattedColumnAlias = DataSourceColumnNameHelper::generateFromParameterElements( $datasourceHandler->getMaximumEntityNameLength(), $columnName); foreach ($tableStatement->tables as $table) { if ($table->findColumnByAlias($formattedColumnAlias) != NULL) { if (isset($tableSection)) { if ($tableSection->alias !== $table->alias) { // FIXME we should not have such functionality // checking if the same column is used for several times in a table under different aliases $tableSectionColumns = $tableSection->findColumns($formattedColumnAlias); $tableColumns = $table->findColumns($formattedColumnAlias); $isTableSelected = FALSE; if (($tableSectionColumns > 0) && ($tableColumns > 0)) { if ($tableSectionColumns > $tableColumns) { $tableSection = $table; $isTableSelected = TRUE; } elseif ($tableColumns > $tableSectionColumns) { $isTableSelected = TRUE; } } if (!$isTableSelected) { throw new UnsupportedOperationException(t('Aggregation function bases on several tables')); } } } else { $tableSection = $table; } } } } } if (!isset($tableSection)) { $tableSection = $tableStatement->tables[0]; } $tableSelectMeasureColumn->attachTo($tableSection); } } // updating join statement table aliases $sourceTableAlias = $TABLE_ALIAS__SOURCE . $orderIndex; foreach ($tableStatement->tables as $table) { $oldTableAlias = $table->alias; $newTableAlias = $sourceTableAlias . (isset($oldTableAlias) ? '_' . $oldTableAlias : ''); $tableStatement->updateTableAlias($oldTableAlias, $newTableAlias); // TODO Review. Probably is not needed anymore. Updating statement conditions which are used to join levels foreach ($datasetConfigs as $nextOrderIndex => $nextDatasetConfig) { if (($nextOrderIndex <= $orderIndex) || !isset($nextDatasetConfig->conditions)) { continue; } foreach ($nextDatasetConfig->conditions as $condition) { if (($condition instanceof JoinConditionSection) && ($condition->joinValue instanceof TableColumnConditionSectionValue) && ($condition->joinValue->tableAlias === $sourceTableAlias) && (($table->findColumn($condition->joinValue->columnName) != NULL) || (count($tableStatement->tables) === 1))) { $condition->joinValue->tableAlias = $newTableAlias; } } } // updating aggregation statement conditions if (isset($aggrStatement->conditions)) { foreach ($aggrStatement->conditions as $condition) { if ($condition->subjectTableAlias != $sourceTableAlias) { continue; } $tableColumn = $table->findColumn($condition->subjectColumnName); if (!isset($tableColumn)) { continue; } // checking if any other table in the statement support the column as an alias $otherColumnFound = FALSE; foreach ($tableStatement->tables as $subjectColumnTable) { $subjectColumn = $subjectColumnTable->findColumnByAlias($condition->subjectColumnName); if (isset($subjectColumn) && ($subjectColumn instanceof ColumnSection)) { if ($subjectColumnTable->alias != $table->alias) { $condition->subjectTableAlias = $sourceTableAlias . (isset($subjectColumnTable->alias) ? '_' . $subjectColumnTable->alias : ''); $condition->subjectColumnName = $subjectColumn->name; $otherColumnFound = TRUE; } } } if (!$otherColumnFound) { $condition->subjectTableAlias = $newTableAlias; if ($tableColumn instanceof ColumnSection) { // $condition->subjectColumnName = $tableColumn->name; } } } } } // BLOCK 3: preparing the table columns which we want to return if (isset($aggrSelectColumns[$orderIndex])) { $tableSelectColumns = $aggrSelectColumns[$orderIndex]; foreach ($tableSelectColumns as $aggrColumnIndex => $tableSelectColumn) { $tableSection = $selectedAggregationTables[$orderIndex][$aggrColumnIndex]; $relatedConditions = NULL; if (isset($aggrStatement->conditions)) { foreach ($aggrStatement->conditions as $condition) { if (($tableSelectColumn instanceof ColumnSection) && ($condition->subjectColumnName == $tableSelectColumn->name) && ($condition->subjectTableAlias == $tableSection->alias)) { $relatedConditions[] = $condition; } } } $attachedColumn = $tableSelectColumn->attachTo($tableSection); if (isset($relatedConditions)) { foreach ($relatedConditions as $relatedCondition) { $relatedCondition->subjectColumnName = $attachedColumn->alias; } } $aggrStatement->groupByColumns[] = new GroupByColumnSection($attachedColumn); } } $aggrStatement->merge($tableStatement); } return $aggrStatement; }
protected function prepareSelectedCubeQueryStatement(AbstractSQLDataSourceQueryHandler $datasourceHandler, DataControllerCallContext $callcontext, CubeQueryRequest $request) { $metamodel = data_controller_get_metamodel(); // loading cube configuration $cubeName = $request->getCubeName(); $cube = $metamodel->getCube($cubeName); // loading cube source configuration $cubeDatasetName = $cube->sourceDatasetName; $cubeDataset = $metamodel->getDataset($cubeDatasetName); // table alias prefix for level datasets $TABLE_ALIAS__SOURCE = 's'; $tableIndex = 1; if (isset($cube->dimensions)) { foreach ($cube->dimensions as $dimension) { $tableIndex += $dimension->getLevelCount(); } } // to store configuration for each accessed table $datasetConfigs = NULL; // preparing cube source dataset configuration $this->registerDatasetConfig($datasetConfigs, 0, $cubeDataset, NULL, NULL); // statement for aggregation portion of final sql $aggrStatement = new Statement(); // adding support for source dataset property queries $sourceDatasetPropertyQueries = $request->findSourceDatasetPropertyQueries(); if (isset($sourceDatasetPropertyQueries)) { foreach ($sourceDatasetPropertyQueries as $sourceDatasetPropertyQuery) { $propertyName = $sourceDatasetPropertyQuery->propertyName; foreach ($sourceDatasetPropertyQuery->values as $propertyValue) { $this->registerDatasetConfig($datasetConfigs, 0, NULL, $propertyName, NULL); $aggrStatement->conditions[] = new WhereConditionSection($TABLE_ALIAS__SOURCE . '0', $propertyName, new ExactConditionSectionValue($datasourceHandler->formatOperatorValue($callcontext, $request, $cubeDataset->name, $propertyName, $propertyValue))); } } } // preparing list of columns which are required to group data for the aggregation $aggrSelectColumns = NULL; if (isset($cube->dimensions)) { foreach ($cube->dimensions as $dimension) { $dimensionName = $dimension->name; $queryDimension = $request->findDimensionQuery($dimensionName); $outputDimension = $request->findDimension($dimensionName); // processing ONLY dimensions which are part of request query or output if (!isset($queryDimension) && !isset($outputDimension)) { continue; } $isDimensionLevelUsed = FALSE; // We navigate starting from the highest level because it is possible to have several references to source // From efficiency prospective we need to use reference to source from the highest level possible // because we would not need to join with lower level datasets // Example (year_id and date_id columns are in source): // * efficient way: year->SOURCE // * inefficient way: year->quarter->month->date->SOURCE $levels = $dimension->levels; for ($i = count($levels) - 1; $i >= 0; $i--) { $level = $levels[$i]; $levelName = $level->name; $isQueryDimensionLevel = isset($queryDimension) && $queryDimension->levelName === $levelName; $isOutputDimensionLevel = isset($outputDimension) && $outputDimension->levelName === $levelName; if (!$isQueryDimensionLevel && !$isOutputDimensionLevel && !$isDimensionLevelUsed) { continue; } $lowerLevelKeyColumnName = isset($level->sourceColumnName) ? NULL : (isset($level->parentKey) ? $level->parentKey : $level->key); // joining with current level dataset ... if necessary $queryPropertyNames = isset($queryDimension) ? $queryDimension->getPropertyNames() : NULL; if ($isDimensionLevelUsed || $isQueryDimensionLevel && isset($queryPropertyNames)) { $levelDataset = $metamodel->getDataset($level->datasetName); // registering the level dataset $tableIndex--; $this->registerDatasetConfig($datasetConfigs, $tableIndex, $levelDataset, NULL, NULL); if ($isQueryDimensionLevel && isset($queryPropertyNames)) { foreach ($queryDimension->values as $propertyValue) { if (isset($propertyValue->name)) { $this->registerDatasetConfig($datasetConfigs, $tableIndex, NULL, $propertyValue->name, NULL); } $conditionPropertyName = isset($propertyValue->name) ? $propertyValue->name : $levelDataset->getKeyColumn()->name; foreach ($propertyValue->values as $value) { $aggrStatement->conditions[] = new WhereConditionSection($TABLE_ALIAS__SOURCE . $tableIndex, $conditionPropertyName, new ExactConditionSectionValue($datasourceHandler->formatOperatorValue($callcontext, $request, $levelDataset->name, $conditionPropertyName, $value))); } } } } // adding returning columns if ($isOutputDimensionLevel) { $responseColumnName = ParameterHelper::assembleParameterName($outputDimension->dimensionName, $outputDimension->levelName); $databaseColumnName = ParameterHelper::assembleDatabaseColumnName($datasourceHandler->getMaximumEntityNameLength(), $request->referenced ? ReferencePathHelper::assembleReference($cubeDataset->name, $outputDimension->dimensionName) : $outputDimension->dimensionName, $outputDimension->levelName); $callcontext->columnMapping[$databaseColumnName] = $responseColumnName; if (isset($level->sourceColumnName)) { $aggrSelectColumns[0][] = new ColumnSection(ReferencePathHelper::assembleDatabaseColumnName($datasourceHandler->getMaximumEntityNameLength(), $level->sourceColumnName), $databaseColumnName); $this->registerDatasetConfig($datasetConfigs, 0, NULL, $level->sourceColumnName, NULL); } else { $lowerLevelTableIndex = $tableIndex - 1; $aggrSelectColumns[$lowerLevelTableIndex][] = new ColumnSection($lowerLevelKeyColumnName, $databaseColumnName); $this->registerDatasetConfig($datasetConfigs, $lowerLevelTableIndex, NULL, $lowerLevelKeyColumnName, NULL); } } if (isset($level->sourceColumnName)) { // joining with source if ($isDimensionLevelUsed || $isQueryDimensionLevel) { $this->registerDatasetConfig($datasetConfigs, 0, NULL, $level->sourceColumnName, NULL); if ($isQueryDimensionLevel && !isset($queryPropertyNames)) { // applying conditions to master source foreach ($queryDimension->values as $propertyValue) { foreach ($propertyValue->values as $value) { $aggrStatement->conditions[] = new WhereConditionSection($TABLE_ALIAS__SOURCE . '0', $level->sourceColumnName, new ExactConditionSectionValue($datasourceHandler->formatOperatorValue($callcontext, $request, $cubeDataset->name, $level->sourceColumnName, $value))); } } } else { // linking the level dataset with master source $this->registerDatasetConfig($datasetConfigs, $tableIndex, NULL, $level->key, new JoinConditionSection($level->key, new TableColumnConditionSectionValue($TABLE_ALIAS__SOURCE . '0', $level->sourceColumnName))); } } // we do not need to go through rest of the levels break; } else { if ($isQueryDimensionLevel && !isset($queryPropertyNames)) { $lowerLevelTableIndex = $tableIndex - 1; $this->registerDatasetConfig($datasetConfigs, $lowerLevelTableIndex, NULL, $lowerLevelKeyColumnName, NULL); $lowerlevelDatasetName = $levels[$i - 1]->datasetName; foreach ($queryDimension->values as $propertyValue) { foreach ($propertyValue->value as $value) { $aggrStatement->conditions[] = new WhereConditionSection($TABLE_ALIAS__SOURCE . $lowerLevelTableIndex, $lowerLevelKeyColumnName, new ExactConditionSectionValue($datasourceHandler->formatOperatorValue($callcontext, $request, $lowerlevelDatasetName, $lowerLevelKeyColumnName, $value))); } } } // FIXME simplify this condition. We just need to check if current level dataset is used if ($isDimensionLevelUsed || $isQueryDimensionLevel && isset($queryPropertyNames)) { // joining with lower level $lowerLevelTableIndex = $tableIndex - 1; $this->registerDatasetConfig($datasetConfigs, $lowerLevelTableIndex, NULL, $lowerLevelKeyColumnName, NULL); $this->registerDatasetConfig($datasetConfigs, $tableIndex, NULL, $level->key, new JoinConditionSection($level->key, new TableColumnConditionSectionValue($TABLE_ALIAS__SOURCE . $lowerLevelTableIndex, $lowerLevelKeyColumnName))); } } $isDimensionLevelUsed = TRUE; } } } // preparing list of measures which are calculated in the aggregation, preparing support for measure conditions $aggrSelectMeasureColumns = NULL; foreach ($cube->measures as $cubeMeasure) { $measureName = $cubeMeasure->name; $selectedMeasure = $request->findMeasure($measureName); $queriedMeasure = $request->findMeasureQuery($measureName); if (!isset($selectedMeasure) && !isset($queriedMeasure)) { continue; } if ($request->referenced) { $measureName = ReferencePathHelper::assembleReference($cubeDataset->name, $measureName); } $databaseColumnName = ParameterHelper::assembleDatabaseColumnName($datasourceHandler->getMaximumEntityNameLength(), $measureName); $columnSection = new CompositeColumnSection($cubeMeasure->function, $databaseColumnName); if (isset($selectedMeasure)) { $callcontext->columnMapping[$databaseColumnName] = $measureName; $aggrSelectMeasureColumns[] = $columnSection; } if (isset($queriedMeasure)) { foreach ($queriedMeasure->values as $measureValue) { $aggrStatement->havingConditions[] = new HavingConditionSection($columnSection, new ExactConditionSectionValue($datasourceHandler->formatOperatorValue($callcontext, $request, $cubeDataset->name, NULL, $measureValue))); } } // looking for possible columns in the measure function. We need to retrieve those from the database $columnNames = $columnSection->parseColumns(); if (isset($columnNames)) { foreach ($columnNames as $columnName) { $this->registerDatasetConfig($datasetConfigs, 0, NULL, $columnName, NULL); } } } // sorting configuration to support joins in correct order ksort($datasetConfigs, SORT_NUMERIC); // preparing dataset source statements foreach ($datasetConfigs as $orderIndex => $datasetConfig) { $tableStatement = $datasourceHandler->prepareDatasetSourceStatement($callcontext, $datasetConfig->dataset, $datasetConfig->usedColumnNames); // adding join conditions if (isset($datasetConfig->conditions)) { foreach ($datasetConfig->conditions as $condition) { $tableStatement->getColumnTable($condition->subjectColumnName)->conditions[] = $condition; } } // we do not need to return any columns from the table by default foreach ($tableStatement->tables as $table) { if (isset($table->columns)) { foreach ($table->columns as $column) { $column->visible = FALSE; } } else { $table->columns = array(); // We do not need any columns } } // preparing the table columns which we want to return if (isset($aggrSelectColumns[$orderIndex])) { $tableSelectColumns = $aggrSelectColumns[$orderIndex]; foreach ($tableSelectColumns as $tableSelectColumn) { // looking for a table in the statement which provides the column for SELECT section $tableSection = $tableStatement->getColumnTable($tableSelectColumn->name); $attachedColumn = $tableSelectColumn->attachTo($tableSection); $aggrStatement->groupByColumns[] = new GroupByColumnSection($attachedColumn); } } // preparing measures which we want to return. Adding those measures to facts table if ($orderIndex == 0 && isset($aggrSelectMeasureColumns)) { foreach ($aggrSelectMeasureColumns as $tableSelectMeasureColumn) { $columnNames = $tableSelectMeasureColumn->parseColumns(); // searching which table contains the column $tableSection = NULL; if (isset($columnNames)) { foreach ($columnNames as $columnName) { $formattedColumnAlias = ReferencePathHelper::assembleDatabaseColumnName($datasourceHandler->getMaximumEntityNameLength(), $columnName); foreach ($tableStatement->tables as $table) { if ($table->findColumnByAlias($formattedColumnAlias) != NULL) { if (isset($tableSection)) { if ($tableSection->alias !== $table->alias) { // FIXME we should not have such functionality // checking if the same column is used for several times in a table under different aliases $tableSectionColumns = $tableSection->findColumns($formattedColumnAlias); $tableColumns = $table->findColumns($formattedColumnAlias); $isTableSelected = FALSE; if ($tableSectionColumns > 0 && $tableColumns > 0) { if ($tableSectionColumns > $tableColumns) { $tableSection = $table; $isTableSelected = TRUE; } elseif ($tableColumns > $tableSectionColumns) { $isTableSelected = TRUE; } } if (!$isTableSelected) { throw new UnsupportedOperationException(t('Aggregation function bases on several tables')); } } } else { $tableSection = $table; } } } } } if (!isset($tableSection)) { $tableSection = $tableStatement->tables[0]; } $tableSelectMeasureColumn->attachTo($tableSection); } } // updating join statement table aliases $sourceTableAlias = $TABLE_ALIAS__SOURCE . $orderIndex; foreach ($tableStatement->tables as $table) { $oldTableAlias = $table->alias; $newTableAlias = $sourceTableAlias . (isset($oldTableAlias) ? '_' . $oldTableAlias : ''); $tableStatement->updateTableAlias($oldTableAlias, $newTableAlias); // updating statement conditions which are used to join levels foreach ($datasetConfigs as $nextOrderIndex => $nextDatasetConfig) { if ($nextOrderIndex <= $orderIndex || !isset($nextDatasetConfig->conditions)) { continue; } foreach ($nextDatasetConfig->conditions as $condition) { if ($condition instanceof JoinConditionSection && $condition->joinValue instanceof TableColumnConditionSectionValue && $condition->joinValue->tableAlias === $sourceTableAlias && ($table->findColumn($condition->joinValue->columnName) != NULL || count($tableStatement->tables) === 1)) { $condition->joinValue->tableAlias = $newTableAlias; } } } // updating aggregation statement conditions if (isset($aggrStatement->conditions)) { foreach ($aggrStatement->conditions as $condition) { if ($condition->subjectTableAlias === $sourceTableAlias && $table->findColumn($condition->subjectColumnName) != NULL) { // checking if any other table in the statement support the column as an alias $otherColumnFound = FALSE; foreach ($tableStatement->tables as $subjectColumnTable) { $subjectColumn = $subjectColumnTable->findColumnByAlias($condition->subjectColumnName); if (isset($subjectColumn) && $subjectColumn instanceof ColumnSection) { if ($subjectColumnTable->alias != $table->alias) { $condition->subjectTableAlias = $sourceTableAlias . (isset($subjectColumnTable->alias) ? '_' . $subjectColumnTable->alias : ''); $condition->subjectColumnName = $subjectColumn->name; $otherColumnFound = TRUE; } } } if (!$otherColumnFound) { $condition->subjectTableAlias = $newTableAlias; } } } } } $aggrStatement->merge($tableStatement); } return $aggrStatement; }