protected function processReferences(SystemTableMetaModelLoaderCallContext $callcontext, DataSourceMetaData $datasource) {
        $foreignKeyConstraintCount = 0;

        $constraintsProperties = $this->loadReferenceConstraintsProperties($callcontext, $datasource);
        if (isset($constraintsProperties)) {
            $constraintsColumnsPropertyFormatter = new QueryKeyResultFormatter(array(self::CN_TABLE_OWNER, self::CN_OBJECT_NAME), FALSE);
            $constraintsColumnsProperties = $constraintsColumnsPropertyFormatter->formatRecords(
                $this->loadConstraintColumnsProperties(
                    $callcontext, $datasource,
                    array(self::CONSTRAINT_TYPE__PRIMARY_KEY, self::CONSTRAINT_TYPE__REFERENCE)));

            foreach ($constraintsProperties as $constraintProperties) {
                $tableOwner = $this->adjustOwnerName($constraintProperties[self::CN_TABLE_OWNER]);

                // ---------- preparing referring constraint properties
                $constraintName = $constraintProperties[self::CN_OBJECT_NAME];
                $constraintAccessKey = ArrayHelper::prepareCompositeKey(array($tableOwner, $constraintName));
                // for some reason we do not have access to column configuration for referring constraint
                if (!isset($constraintsColumnsProperties[$constraintAccessKey])) {
                    continue;
                }
                $constraintColumnsProperties = $constraintsColumnsProperties[$constraintAccessKey];
                // we do not support composite references yet
                if (count($constraintColumnsProperties) > 1) {
                    continue;
                }

                // ----------- preparing referenced constraint properties
                $refConstraintName = $constraintProperties[self::CN_REFERENCED_OBJECT_NAME];
                $refConstraintAccessKey = ArrayHelper::prepareCompositeKey(array($tableOwner, $refConstraintName));
                // for some reason we do not have access to column configuration for referenced constraint
                if (!isset($constraintsColumnsProperties[$refConstraintAccessKey])) {
                    continue;
                }

                $constraintColumnProperties = $constraintColumnsProperties[0];
                $tableName = $this->adjustTableName($constraintColumnProperties[self::CN_TABLE_NAME]);
                $tableAccessKey = ArrayHelper::prepareCompositeKey(array($tableOwner, $tableName));
                if (!isset($callcontext->datasets[$tableAccessKey])) {
                    continue;
                }

                $refConstraintColumnProperties = $constraintsColumnsProperties[$refConstraintAccessKey][0];
                $refTableName = $this->adjustTableName($refConstraintColumnProperties[self::CN_TABLE_NAME]);
                $refTableAccessKey = ArrayHelper::prepareCompositeKey(array($tableOwner, $refTableName));
                if (!isset($callcontext->datasets[$refTableAccessKey])) {
                    continue;
                }

                $columnName = $this->adjustColumnName($constraintColumnProperties[self::CN_COLUMN_NAME]);
                $refColumnName = $this->adjustColumnName($refConstraintColumnProperties[self::CN_COLUMN_NAME]);

                if ($tableName == $refTableName) {
                    LogHelper::log_warn(t(
                        "Self-reference is not supported yet: @tableName(@columnName)",
                        array('@tableName' => $tableName, '@columnName' => $columnName)));
                    continue;
                }

                $dataset = $callcontext->datasets[$tableAccessKey];
                $column = $dataset->findColumn($columnName);
                if (!isset($column)) {
                    continue;
                }

                $refDataset = $callcontext->datasets[$refTableAccessKey];
                $refColumn = $refDataset->findColumn($refColumnName);
                if (!isset($refColumn)) {
                    continue;
                }

                $logicalApplicationType = ReferencePathHelper::assembleReference($refDataset->name, $refColumnName);
                if (isset($column->type->logicalApplicationType)) {
                    LogHelper::log_warn(t(
                        "Multi-reference is not supported yet for '@columnName' column from '@tableName' table: [@referenceExisting, @referenceNew]",
                        array(
                            '@tableName' => $tableName,
                            '@columnName' => $columnName,
                            '@referenceExisting' => $column->type->logicalApplicationType,
                            '@referenceNew' => $logicalApplicationType)));
                    continue;
                }

                $column->type->logicalApplicationType = $logicalApplicationType;
                $foreignKeyConstraintCount++;
            }
        }

        LogHelper::log_info(t(
            'Processed system meta data about @constraintCount foreign key constraint(s)',
            array('@constraintCount' => $foreignKeyConstraintCount)));
    }
    public function insertOrUpdateOrDeleteDatasetRecords(DataControllerCallContext $callcontext, AbstractDatasetManipulationRequest $request) {
        $environment_metamodel = data_controller_get_environment_metamodel();
        $metamodel = data_controller_get_metamodel();

        $datasourceQueryHandler = DataSourceQueryFactory::getInstance()->getHandler($this->getDataSourceType());

        $dataset = $metamodel->getDataset($request->datasetName);
        $datasource = $environment_metamodel->getDataSource($dataset->datasourceName);
        $recordMetaData = isset($request->recordsHolder->recordMetaData) ? $request->recordsHolder->recordMetaData : $dataset;

        $isRecordIndexed = $request->recordsHolder instanceof IndexedRecordsHolder;

        $keyColumnNames = $recordMetaData->getKeyColumnNames();
        $nonkeyColumnNames = $recordMetaData->findNonKeyColumnNames();

        // preparing a request to find existing records
        $queryRequest = new DatasetQueryRequest($request->datasetName);
        // loading only key columns from database
        $queryRequest->addColumns($keyColumnNames);
        // a request can be more efficient for single column key
        if (count($keyColumnNames) == 1) {
            list($keyColumnIndex, $keyColumnName) = each($keyColumnNames);
            $keyColumnIdentifier = $isRecordIndexed ? $keyColumnIndex : $keyColumnName;

            $keyValues = NULL;
            foreach ($request->recordsHolder->records as $record) {
                ArrayHelper::addUniqueValue($keyValues, $record->getColumnValue($keyColumnIdentifier, TRUE));
            }

            $queryRequest->addQueryValue(
                0,
                $keyColumnName, OperatorFactory::getInstance()->initiateHandler(EqualOperatorHandler::OPERATOR__NAME, array($keyValues)));
        }
        else {
            for ($i = 0, $count = count($request->recordsHolder->records); $i < $count; $i++) {
                $record = $request->recordsHolder->records[$i];
                foreach ($keyColumnNames as $keyColumnIndex => $keyColumnName) {
                    $keyColumnIdentifier = $isRecordIndexed ? $keyColumnIndex : $keyColumnName;

                    $keyColumnValue = $record->getColumnValue($keyColumnIdentifier, TRUE);
                    $queryRequest->addQueryValue(
                        $i,
                        $keyColumnName, OperatorFactory::getInstance()->initiateHandler(EqualOperatorHandler::OPERATOR__NAME, $keyColumnValue));
                }
            }
        }

        // loading existing records ... if any
        $existingRecordFormatter = new QueryKeyResultFormatter($keyColumnNames);
        $existingRecords = $existingRecordFormatter->formatRecords($datasourceQueryHandler->queryDataset($callcontext, $queryRequest));

        // sorting out records for insert, update and delete operations
        $keyedRecords = $insertedRecordKeys = $updatedRecordKeys = $deletedRecordKeys = NULL;
        foreach ($request->recordsHolder->records as $record) {
            $keyParts = NULL;
            foreach ($keyColumnNames as $keyColumnIndex => $keyColumnName) {
                $keyColumnIdentifier = $isRecordIndexed ? $keyColumnIndex : $keyColumnName;
                $keyParts[] = $record->getColumnValue($keyColumnIdentifier, TRUE);
            }
            $key = ArrayHelper::prepareCompositeKey($keyParts);
            $keyedRecords[$key] = $record;

            // checking if the record has to be deleted
            $isDeletable = TRUE;
            if (isset($nonkeyColumnNames)) {
                foreach ($nonkeyColumnNames as $columnIndex => $columnName) {
                    $columnIdentifier = $isRecordIndexed ? $columnIndex : $columnName;
                    if ($record->getColumnValue($columnIdentifier) != NULL) {
                        $isDeletable = FALSE;
                        break;
                    }
                }
            }
            else {
                // the dataset has NO non-key columns. We should not delete these records
                $isDeletable = FALSE;
            }

            if ($isDeletable) {
                unset($insertedRecordKeys[$key]);
                unset($updatedRecordKeys[$key]);
                // the record physically present in database and needs to be deleted
                if (isset($existingRecords[$key])) {
                    unset($existingRecords[$key]);
                    $deletedRecordKeys[$key] = TRUE;
                }
            }
            elseif (isset($insertedRecordKeys[$key])) {
                // the key has been already used to insert a record within this batch. This record needs to be part of update operation
                $updatedRecordKeys[$key] = TRUE;
            }
            elseif (isset($existingRecords[$key])) {
                $updatedRecordKeys[$key] = TRUE;
            }
            else {
                $insertedRecordKeys[$key] = TRUE;
            }
        }

        $sqls = NULL;

        // deleting existing records
        $deletedRecordCount = 0;
        if (isset($deletedRecordKeys)) {
            $deleteRecordHolder = $this->prepareRecordHolder($request, $keyedRecords, $deletedRecordKeys);
            // preparing request
            $deleteRequest = new DatasetDeleteRequest($request->datasetName, $deleteRecordHolder);
            // preparing statements to delete records from the database
            ArrayHelper::appendValue($sqls, $this->prepareDeleteDatasetRecordStatements($callcontext, $deleteRequest));

            $deletedRecordCount = count($deleteRecordHolder->records);
        }

        // inserting new records
        $insertedRecordCount = 0;
        if (isset($insertedRecordKeys)) {
            $insertRecordHolder = $this->prepareRecordHolder($request, $keyedRecords, $insertedRecordKeys);
            // preparing request
            $insertRequest = new DatasetInsertRequest($request->datasetName, $insertRecordHolder);
            // preparing statements to insert records into the database
            ArrayHelper::appendValue($sqls, $this->prepareInsertDatasetRecordStatements($callcontext, $insertRequest));

            $insertedRecordCount = count($insertRecordHolder->records);
        }

        // updating existing records
        $updatedRecordCount = 0;
        if (isset($updatedRecordKeys)) {
            $updateRecordHolder = $this->prepareRecordHolder($request, $keyedRecords, $updatedRecordKeys);
            // preparing request
            $updateRequest = new DatasetUpdateRequest($request->datasetName, $updateRecordHolder);
            // preparing statements to update records in the database
            ArrayHelper::appendValue($sqls, $this->prepareUpdateDatasetRecordStatements($callcontext, $updateRequest));

            $updatedRecordCount = count($updateRecordHolder->records);
        }

        $affectedRecordCount = isset($sqls) ? $this->executeManipulationStatementBatch($datasource, $sqls) : 0;
        if (($insertedRecordCount + $updatedRecordCount + $deletedRecordCount) < $affectedRecordCount) {
            throw new IllegalStateException(t('Number of affected records is greater than expected number of inserted, updated and deleted records'));
        }

        return array($insertedRecordCount, $updatedRecordCount, $deletedRecordCount);
    }