コード例 #1
0
    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;
    }
コード例 #2
0
 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;
 }