protected function permitLookupDatasetStorageChanges(DataControllerCallContext $callcontext, DatasetMetaData $originalLogicalDataset, DatasetMetaData $modifiedLogicalDataset) {
        $metamodel = data_controller_get_metamodel();

        $originalPrimaryKeyColumnName = $originalLogicalDataset->getKeyColumn()->name;

        // checking if the primary key changed
        $doesPrimaryKeyMatch = FALSE;
        $modifiedPrimaryKeyColumnNames = $modifiedLogicalDataset->findKeyColumnNames();
        if (count($modifiedPrimaryKeyColumnNames) == 1) {
            $modifiedPrimaryKeyColumnName = reset($modifiedPrimaryKeyColumnNames);
            $doesPrimaryKeyMatch = $originalPrimaryKeyColumnName == $modifiedPrimaryKeyColumnName;
        }
        if ($doesPrimaryKeyMatch) {
            return;
        }

        // checking if this dataset was used as lookup somewhere
        foreach ($metamodel->datasets as $dataset) {
            foreach ($dataset->getColumns(FALSE, TRUE) as $column) {
                if ($column->type->getReferencedDatasetName() == $originalLogicalDataset->name) {
                    throw new IllegalArgumentException(t(
                        '%datasetName dataset is referenced by other datasets. Changes to the primary key is not permitted unless the references are removed first',
                        array('%datasetName' => $modifiedLogicalDataset->publicName)));
                }
            }
        }
    }
    /**
     * @param DataControllerCallContext $callcontext
     * @param DatasetMetaData $originalDataset
     * @param DatasetMetaData $modifiedDataset
     * @param DatasetStorageObserver[] $observers
     * @throws Exception
     */
    protected function updateProperties(DataControllerCallContext $callcontext, DatasetMetaData $originalDataset, DatasetMetaData $modifiedDataset, array $observers = NULL) {
        $justPersistedColumns = NULL;
        ArrayHelper::merge($justPersistedColumns, $callcontext->changeAction->newIncludedColumns);
        ArrayHelper::merge($justPersistedColumns, $callcontext->changeAction->restoredColumns);
        ArrayHelper::merge($justPersistedColumns, $callcontext->changeAction->updatedDataTypeIncludedColumns);

        $columns = $justPersistedColumns;
        ArrayHelper::merge($columns, $callcontext->changeAction->updatedColumns);
        if ($callcontext->changeAction->isDatasetUpdated || isset($columns) || $callcontext->changeAction->isKeyUpdated) {
            MetaModelFactory::getInstance()->startGlobalModification();
            try {
                $transaction = db_transaction();
                try {
                    if (isset($columns)) {
                        foreach ($columns as $column) {
                            if (isset($justPersistedColumns[$column->name])) {
                                $column->used = TRUE;
                            }

                            if (isset($callcontext->changeAction->updatedColumns[$column->name])) {
                                $modifiedColumn = $modifiedDataset->getColumn($column->name);

                                $column->publicName = $modifiedColumn->publicName;
                                $column->description = $modifiedColumn->description;
                                $column->source = $modifiedColumn->source;
                                $column->key = $modifiedColumn->key;
                            }

                            if (isset($observers)) {
                                foreach ($observers as $observer) {
                                    $observer->updateColumn($callcontext, $originalDataset, $column->name);
                                }
                            }
                        }
                    }

                    if ($callcontext->changeAction->isDatasetUpdated) {
                        $originalDataset->publicName = $modifiedDataset->publicName;
                        $originalDataset->description = $modifiedDataset->description;
                        $originalDataset->initializeSourceFrom($modifiedDataset->source, TRUE);
                        $originalDataset->initializeAliasesFrom($modifiedDataset->aliases, TRUE);

                        if (isset($observers)) {
                            foreach ($observers as $observer) {
                                $observer->updateDataset($callcontext, $originalDataset);
                            }
                        }
                    }

                    if ($callcontext->changeAction->isKeyUpdated) {
                        $modifiedDatasetKeyColumnNames = $modifiedDataset->findKeyColumnNames();
                        if (isset($modifiedDatasetKeyColumnNames)) {
                            $this->executeDatasetUpdateOperations(
                                $callcontext,
                                $originalDataset,
                                array(new CreateDatasetKeyOperation()));
                        }
                    }
                }
                catch (Exception $e) {
                    $transaction->rollback();
                    throw $e;
                }
            }
            catch (Exception $e) {
                MetaModelFactory::getInstance()->finishGlobalModification(FALSE);
                throw $e;
            }
            MetaModelFactory::getInstance()->finishGlobalModification(TRUE);
        }
    }
    protected function allowPrimaryKeyCreation(DataSourceHandler $handler, DataControllerCallContext $callcontext, DatasetMetaData $dataset) {
        $primaryKeyColumnNames = $dataset->findKeyColumnNames();
        if (isset($primaryKeyColumnNames)) {
            $environment_metamodel = data_controller_get_environment_metamodel();

            $datasource = $environment_metamodel->getDataSource($dataset->datasourceName);

            $assembledTableName = assemble_database_entity_name($handler, $datasource->name, $dataset->source);

            $datasourceQueryHandler = DataSourceQueryFactory::getInstance()->getHandler($datasource->type);

            // checking if there are any records with NULL values
            $nullValueConditions = array();
            foreach ($primaryKeyColumnNames as $columnName) {
                $nullValueConditions[] = "$columnName IS NULL";
            }
            $nullValueSQL = 'SELECT ' . implode(', ', $primaryKeyColumnNames) . " FROM $assembledTableName WHERE " . implode(' OR ', $nullValueConditions);
            $datasourceQueryHandler->getExtension('applyPagination')->apply($datasourceQueryHandler, $nullValueSQL, 0, 1);
            LogHelper::log_info(new StatementLogMessage('dataset.update.primaryKey.data.check.null', $nullValueSQL));
            $nullColumnRecords = $datasourceQueryHandler->executeQuery($callcontext, $datasource, $nullValueSQL);
            $isTruncateRequired = isset($nullColumnRecords);

            // checking for non-unique values
            if (!$isTruncateRequired) {
                $nonUniqueValueSQL = 'SELECT ' . implode(', ', $primaryKeyColumnNames)
                    . " FROM $assembledTableName GROUP BY " . implode(', ', $primaryKeyColumnNames) . ' HAVING COUNT(*) > 1';
                $datasourceQueryHandler->getExtension('applyPagination')->apply($datasourceQueryHandler, $nonUniqueValueSQL, 0, 1);
                LogHelper::log_info(new StatementLogMessage('dataset.update.primaryKey.data.check', $nonUniqueValueSQL));
                $nonUniqueColumnRecords = $datasourceQueryHandler->executeQuery($callcontext, $datasource, $nonUniqueValueSQL);
                $isTruncateRequired = isset($nonUniqueColumnRecords);
            }

            if ($isTruncateRequired) {
                $truncateDatasetSQL = $handler->getExtension('truncateTable')->generate($handler, $dataset);
                LogHelper::log_info(new StatementLogMessage('dataset.update.primaryKey.data.truncate', $truncateDatasetSQL));
                $handler->executeStatement($datasource, $truncateDatasetSQL);
            }
        }
    }