View Issue Details

This bug affects 1 person(s).
 4
IDProjectCategoryView StatusLast Update
16690Bug reportsOtherpublic2023-02-02 18:08
ReporterDenisChenu Assigned To 
PrioritynoneSeverityminor 
Status acknowledgedResolutionopen 
Product Version3.23.5 
Summary16690: Unable to use checkintegrity on big instance
Description

I have an instance with more than 400 survey , some with multiple language some not.
When i go to Data consensty check : it broke with a 500 error , i muts disable sole check to do the checkintegrety

Steps To Reproduce

Find a big instance , see time to show the 1 sta page …

Additional Information

Some solution :

  1. Allow to filter test :
    1. check inetregrit all
    2. Check integrity by checkbox for each for each part.
  2. Create a checkintegrity by command
  3. Add a checkintergrety by survey
TagsNo tags attached.
Bug heat4
Complete LimeSurvey version number (& build)3.22.25
I will donate to the project if issue is resolvedNo
Browsernot relevant ?
Database type & version{ "DriverDllName": "msodbcsql11.dll", "DriverODBCVer": "03.80", "DriverVer": "12.00.5543", "ExtensionVer": "5.6.1+11919" }
Server OS (if known)Windows NT LIMESURVEY-1 10.0 build 14393 (Windows Server 2016) AMD64
Webserver software & version (if known)Microsoft-IIS/10.0
PHP Version7.3.19

Relationships

related to 18614 closedc_schmitz lime_questions ERROR: Value '27373432210' is out of bounds for type integer at character 52 

Users monitoring this issue

There are no users monitoring this issue.

Activities

DenisChenu

DenisChenu

2020-09-23 10:52

developer   ~59936

Disable https://github.com/LimeSurvey/LimeSurvey/blob/d3037f91b9df63e0e2fe4db20a15eb1da72080a6/application/controllers/admin/checkintegrity.php#L597

(adding a break; after).

Seems really best …

This mus be in Survey only part in my opinion, no ?

DenisChenu

DenisChenu

2020-09-23 10:53

developer   ~59937

Or maybe : add a DB with "fixed" ?

uibklime1

uibklime1

2021-10-07 02:40

reporter   ~66781

@denischenu I'm sorry for responding so late. The emails are supposed to come to me, but for some reason, they go to our secretary which 90% of the time forwards them to me. This was one of the 10% that didn't get forwarded.

After 2.5 days of analysis, I determined the following:

  • The _checkintegrity function uses so much memory, that limesurvey cannot even generate a stack trace or output an error message properly to the upstream server. PHP-FPM generates a "200" status result for the query facepalm. The error logs eventually output the notice, but because of some kind of delay, it was hard to see.

  • Using many many Yii::trace calls and with memory_get_usage() calls, I found the precise problem:
    $oDB->schema->getTables();

    [06-Oct-2021 00:32:49 Europe/Vienna] PHP Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 20480 bytes) in /var/www/html/limesurvey/limesurvey3224/framework/db/CDbCommand.php on line 518

Prior to that call, approximately 120 MB has been used. Even if I allocated 2 GB for PHP, the problem occurred.

The root cause is that we have accumulated over 3200 surveys in our system. (University setting, students use it for teaching.) I suspect the Yii framework does not load the metadata in a very efficient format.

  • Unrelatedly, after solving the above issue, I then ran into a server timeout issue caused by the default setting of 60s timeout in the apache proxy service.

Back to the code, I am using 3.22.4, but I downloaded and installed the 3.27.19 version of the checkintegrity.php. Perhaps the framework has been improved, but I doubt it. It's also way past EOL.

The checkintegrity.php code is itself... sub-optimal. I strongly urge a refactoring. For my experiments, I wrapped the function into a large case statement. This allowed PHP to free up memory on a regular basis, and for me to monitor how much memory each step used. I have attached my version in the hopes it will provide you with insights into how to better refactor this function. (It doesn't work completely as-is for the "fix" stage. I would need to push the changes from "index()" into a wrapper function of _Checkintegrity().)

uibklime1

uibklime1

2021-10-07 02:42

reporter   ~66782

checkintegrity.php (48,345 bytes)   
<?php
/*
 * LimeSurvey
 * Copyright (C) 2007-2011 The LimeSurvey Project Team / Carsten Schmitz
 * All rights reserved.
 * License: GNU/GPL License v2 or later, see LICENSE.php
 * LimeSurvey is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 * See COPYRIGHT.php for copyright notices and details.
 *
 * From 3.25.19
 */
/**
 * CheckIntegrity Controller
 *
 * This controller performs database repair functions.
 *
 * @package       LimeSurvey
 * @subpackage    Backend
 */

declare(ticks=1);

class CheckIntegrity extends Survey_Common_Action
{

    private $chkstep = 0;
    private $steps_to_skip = array( 32, );
    private $steps_to_do = array( 1, 2, 3, 30, 32, 34, 35, 36, 37, 38, 39, 40, 45, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250  );

    public function __construct($controller, $id)
    {
        parent::__construct($controller, $id);

        if (!Permission::model()->hasGlobalPermission('superadmin', 'read')) {
            Yii::app()->setFlashMessage(gT("You do not have permission to access this page."), 'error');
            $this->getController()->redirect($this->getController()->createUrl("/admin/"));
        }

        Yii::app()->loadHelper('database');
        Yii::app()->loadHelper('surveytranslator');
    }
                                                                             
    public function index()
    {
        $aData = array(
       	    'defaultvalues' => 0,
	    'quotas' => 0,
	    'quotals' => 0,
	    'quotamembers' => 0,
	    'integrityok' => 0,
	    'redundancyok' => 0,
	    'messsages' => array(),
            'warnings' => array(),
            'errors' => array(),
	    'assessments' => array(),
	    'answers' => array(),
	    'surveys' => array(),
	    'surveylanguagesettings' => array(),
	    'questions' => array(),
	    'questionOrderDuplicates' => array(),
	    'groups' => array(),
	    'user_in_groups' => array(),
	    'orphansurveytables' => array(),
	    'orphantokentables' => array(),
	    'redundantsurveytables' => array(),
	    'redundanttokentables' => array(),
        );
        $aData['fullpagebar']['returnbutton']['url'] = 'admin/index';
        $aData['fullpagebar']['returnbutton']['text'] = gT('Return to admin home');

	// $bMemAllowed  = int(__return_bytes(ini_get('memory_limit')) * 4 / 5);
	# for ($this->chkstep = 1; $this->chkstep <= 250; ++$this->chkstep) { 
	foreach ($this->steps_to_do as $s) { 
	  $this->chkstep = $s;
	  if (! in_array($s, $this->steps_to_skip) ) {
	    $bMemUsedStart = memory_get_usage();

	    $aData = array_merge($aData, $this->_checkintegrity());

	    $mBMemUsed = intval(memory_get_usage() / 1024 / 1024 );
	    $mBMemUsedStep = intval((memory_get_usage() - $bMemUsedStart) / 1024 / 1024);
	    Yii::trace(get_class($this)."_checkintregrit step $this->chkstep: memused $mBMemUsedStep MB this step. Total used so far: $mBMemUsed","application.admin.checkintegrity");
	    Yii::getLogger()->flush(true);
	  }
	}

	if ($aData['defaultvalues'] == 0 && $aData['quotamembers'] == 0 &&
	    $aData['quotas'] == 0 && $aData['quotals'] == 0 && count($aData) == 4
	) {
	    $aData['integrityok'] = true;
	} else {
	    $aData['integrityok'] = false;
	}

	try { 
	  $this->_renderWrappedTemplate('checkintegrity', [ 'check_view' ] , $aData);
	} catch (Exception $e) { 
	  Yii:trace(get_class($this).":index:render failed:\n".  $e->getTraceAsString() );
	  throw new CHttpException(502, "502 Server error");
	}

	// Yii::trace(get_class($this).":index: aData = \n".  var_export($aData,true) );
	Yii::trace(get_class($this)."_checkintregrit finish render","application.admin.checkintegrity");
	Yii::getLogger()->flush(true);
    }

    public function fixredundancy()
    {
        $oldsmultidelete = Yii::app()->request->getPost('oldsmultidelete', array());
        $aData = [];
        $aData['messages'] = array();
        if (Permission::model()->hasGlobalPermission('settings', 'update') && Yii::app()->request->getPost('ok') == 'Y') {
            $aDelete = $this->_checkintegrity();
            if (isset($aDelete['redundanttokentables'])) {
                foreach ($aDelete['redundanttokentables'] as $aTokenTable) {
                    if (in_array($aTokenTable['table'], $oldsmultidelete)) {
                        Yii::app()->db->createCommand()->dropTable($aTokenTable['table']);
                        $aData['messages'][] = sprintf(gT('Deleting survey participants table: %s'), $aTokenTable['table']);
                    }
                }
            }
            if (isset($aDelete['redundantsurveytables'])) {
                foreach ($aDelete['redundantsurveytables'] as $aSurveyTable) {
                    if (in_array($aSurveyTable['table'], $oldsmultidelete)) {
                        Yii::app()->db->createCommand()->dropTable($aSurveyTable['table']);
                        $aData['messages'][] = sprintf(gT('Deleting survey table: %s'), $aSurveyTable['table']);
                    }
                }
            }
            if (count($aData['messages']) == 0) {
                $aData['messages'][] = gT('No old survey or survey participants table selected.');
            }
            $this->_renderWrappedTemplate('checkintegrity', 'fix_view', $aData);
        }
    }

    public function fixintegrity()
    {
        if(!Permission::model()->hasGlobalPermission('settings', 'update')) {
            throw new CHttpException(401, "401 Unauthorized");
        }
        if(Yii::app()->request->getPost('ok') != 'Y') {
            throw new CHttpException(403);
        }
        $aDelete = $this->_checkintegrity();
        $aData = array([
            'messsages' => array(),
            'warnings' => array(),
            'errors' => array(),
        ]);
        // TMSW Condition->Relevance:  Update this to process relevance instead
        if (isset($aDelete['conditions'])) {
            $aData = $this->_deleteConditions($aDelete['conditions'], $aData);
        }

        if (isset($aDelete['questionattributes'])) {
            $aData = $this->_deleteQuestionAttributes($aDelete['questionattributes'], $aData);
        }

        if ($aDelete['defaultvalues']) {
            $aData = $this->_deleteDefaultValues($aData);
        }

        if ($aDelete['quotas']) {
            $aData = $this->_deleteQuotas($aData);
        }

        if ($aDelete['quotals']) {
            $aData = $this->_deleteQuotaLanguageSettings($aData);
        }

        if ($aDelete['quotamembers']) {
            $aData = $this->_deleteQuotaMembers($aData);
        }

        if (isset($aDelete['assessments'])) {
            $aData = $this->_deleteAssessments($aDelete['assessments'], $aData);
        }

        if (isset($aDelete['answers'])) {
            $aData = $this->_deleteAnswers($aDelete['answers'], $aData);
        }

        if (isset($aDelete['surveys'])) {
            $aData = $this->_deleteSurveys($aDelete['surveys'], $aData);
        }

        if (isset($aDelete['surveylanguagesettings'])) {
            $aData = $this->_deleteSurveyLanguageSettings($aDelete['surveylanguagesettings'], $aData);
        }

        if (isset($aDelete['questions'])) {
            $aData = $this->_deleteQuestions($aDelete['questions'], $aData);
        }


        if (isset($aDelete['groups'])) {
            $aData = $this->_deleteGroups($aDelete['groups'], $aData);
        }

        if (isset($aDelete['user_in_groups'])) {
            $aData = $this->_deleteUserInGroups($aDelete['user_in_groups'], $aData);
        }

        if (isset($aDelete['orphansurveytables'])) {
            $aData = $this->_dropOrphanSurveyTables($aDelete['orphansurveytables'], $aData);
        }

        if (isset($aDelete['orphantokentables'])) {
            $aData = $this->_deleteOrphanTokenTables($aDelete['orphantokentables'], $aData);
        }

        $this->_renderWrappedTemplate('checkintegrity', 'fix_view', $aData);

    }

    private function _deleteOrphanTokenTables(array $tokenTables, array $aData)
    {
        foreach ($tokenTables as $aTokenTable) {
            Yii::app()->db->createCommand()->dropTable($aTokenTable);
            $aData['messages'][] = sprintf(gT('Deleting orphan survey participants table: %s'),$aTokenTable);
        }
        return $aData;
    }

    private function _dropOrphanSurveyTables(array $surveyTables, array $aData)
    {
        foreach ($surveyTables as $aSurveyTable) {
            Yii::app()->db->createCommand()->dropTable($aSurveyTable);
            $aData['messages'][] = sprintf(gT('Deleting orphan survey table: %s'),$aSurveyTable);
        }
        return $aData;
    }

    /**
     * This function deletes groups
     * @param array[] $groups to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteGroups(array $groups, array $aData)
    {
        $gids = array_unique(array_column($groups,'gid'));
        $count = 0;
        foreach ($gids as $gid) {
            $deleted = QuestionGroup::model()->deleteAll("gid = :gid",array(":gid"=> $gid));
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete question group %s'), $gid);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting groups: %u groups deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes UserInGroup
     * @param array[] $UserInGroup to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteUserInGroups(array $userInGroups, array $aData)
    {
        $ugids = array();
        foreach ($userInGroups as $group) {
            $ugids[] = $group['ugid'];
        }

        $criteria = new CDbCriteria;
        $criteria->addInCondition('ugid', $ugids);
        $deletedRows = UserInGroup::model()->deleteAll($criteria);
        if ($deletedRows === count($userInGroups)) {
            $aData['messages'][] = sprintf(gT('Deleting orphaned user group assignments: %u assignments deleted'), count($userInGroups));
        }
        return $aData;
    }

    /**
     * This function deletes questions
     * @param array[] $questions to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteQuestions(array $questions, array $aData)
    {
        $qids = array_unique(array_column($questions,'qid'));
        $count = 0;
        foreach ($qids as $qid) {
            $deleted = Question::model()->deleteAll("qid = :qid",array(":qid"=> $qid));
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete question %s'), $qid);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting questions: %u questions deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes surveyLanguageSettings
     * @param array[] $surveyLanguageSettings to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteSurveyLanguageSettings(array $surveyLanguageSettings, array $aData)
    {
        $slids = array_unique(array_column($surveyLanguageSettings,'slid'));
        $count = 0;
        foreach ($slids as $slid) {
            $deleted = SurveyLanguageSetting::model()->deleteAll("surveyls_survey_id = :slid",array(":slid"=> $slid));
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete survey languagesettings %s'), $slid);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting survey languagesettings: %u survey languagesettings deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes surveys
     * @param array[] $surveys to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteSurveys(array $surveys, array $aData)
    {
        $count = 0;
        foreach ($surveys as $survey) {
            $deleted = Survey::model()->deleteByPk($survey['sid']);
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete survey %s'), $survey['sid']);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting surveys: %u surveys deleted'), $count);
        return $aData;
    }

    /**
     * This function Deletes answers
     * @param array[] $answers to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteAnswers(array $answers, array $aData)
    {
        $answersDeleted = array();// Keep for multilingual survey (alt : make an array_unique_mutilplekeys function)
        $count = 0;
        foreach ($answers as $answer) {
            if(!in_array(array($answer['qid'],$answer['code']),$answersDeleted)) {
                $deleted = Answer::model()->deleteAll('qid=:qid AND code=:code', array(':qid'=>$answer['qid'], ':code'=>$answer['code']));
                if($deleted) {
                    $count += $deleted;
                    $answersDeleted[] = array($answer['qid'],$answer['code']);
                } else {
                    $aData['warnings'][] = sprintf(gT('Unable to delete answer %s, code %s'), $answer['qid'],$answer['code']);
                }
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting answers: %u answers deleted'),$count);
        return $aData;
    }

    /**
     * This function deletes Assessments
     * @param array[] $Assessments to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteAssessments(array $assessments, array $aData)
    {
        $assessmentids = array_unique(array_column($assessments,'id'));
        $count = 0;
        foreach ($assessmentids as $assessmentid) {
            $deleted = Assessment::model()->deleteAll("id = :id",array(":id" => $assessmentid));
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete assessment %s'), $assessmentid);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting assessments: %u assessment entries deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes QuotaMember by join on question
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteQuotaMembers(array $aData)
    {
        $oCriteria = new CDbCriteria;
        $oCriteria->join = 'LEFT JOIN {{questions}} q ON t.qid=q.qid LEFT JOIN {{surveys}} s ON t.sid=s.sid';
        $oCriteria->condition = '(q.qid IS NULL) OR (s.sid IS NULL)';
        $count = 0;
        $aRecords = QuotaMember::model()->findAll($oCriteria);
        foreach ($aRecords as $aRecord) {
            $deleted = QuotaMember::model()->deleteAllByAttributes($aRecord);
            $count += $deleted;
        }
        $aData['messages'][] = sprintf(gT('Deleting orphaned quota members: %u quota members deleted'), $count);
        return $aData;
    }

    /**
     * This function Deletes quota language settings without related main entries
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteQuotaLanguageSettings(array $aData)
    {
        $oCriteria = new CDbCriteria;
        $oCriteria->join = 'LEFT JOIN {{quota}} q ON {{quota_languagesettings}}.quotals_quota_id=q.id';
        $oCriteria->condition = '(q.id IS NULL)';
        $count = QuotaLanguageSetting::model()->deleteAll($oCriteria);
        $aData['messages'][] = sprintf(gT('Deleting orphaned quota languages: %u quota languages deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes quota entries which not having a related survey entry
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteQuotas(array $aData)
    {
        $oCriteria = new CDbCriteria;
        $oCriteria->join = 'LEFT JOIN {{surveys}} q ON {{quota}}.sid=q.sid';
        $oCriteria->condition = '(q.sid IS NULL)';
        $count = Quota::model()->deleteAll($oCriteria);
        $aData['messages'][] = sprintf(gT('Deleting orphaned quotas: %u quotas deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes default values by join on question
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteDefaultValues(array $aData)
    {
        $criteria = new CDbCriteria;
        $criteria->join = 'LEFT JOIN {{questions}} q ON t.qid=q.qid';
        $criteria->condition = 'q.qid IS NULL';

        $aRecords = DefaultValue::model()->findAll($criteria);
        $count = 0;
        foreach ($aRecords as $aRecord) {
            $deleted = DefaultValue::model()->deleteAllByAttributes($aRecord);
            $count += $deleted ;
        }
        $aData['messages'][] = sprintf(gT('Deleting orphaned default values: %u default values deleted.'),$count);
        return $aData;
    }

    /**
     * This function deletes questionAttributes
     * @param array[] $questionAttributes to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteQuestionAttributes(array $questionAttributes, array $aData)
    {
        $qids = array_unique(array_column($questionAttributes,'qid'));
        $count = 0;
        foreach ($qids as $qid) {
            $deleted = QuestionAttribute::model()->deleteAll("qid = :qid",array(":qid"=> $qid));
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete question attributes for question %s'), $qid);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting question attributes: %u attributes deleted'), $count);
        return $aData;
    }

    /**
     * This function deletes conditions
     * @param array[] $conditions to be deleted
     * @param array $aData for view generation
     * @return array
     */
    private function _deleteConditions(array $conditions, array $aData)
    {
        $cids = array_unique(array_column($conditions,'cid'));
        $count = 0;
        foreach ($cids as $cid) {
            $deleted = Condition::model()->deleteByPk($cid);
            if($deleted) {
                $count += $deleted;
            } else {
                $aData['warnings'][] = sprintf(gT('Unable to delete condition %s'), $cid);
            }
        }
        $aData['messages'][] = sprintf(gT('Deleting conditions: %u conditions deleted'), $count);
        return $aData;
    }


    /**
     * This function checks the LimeSurvey database for logical consistency and returns an according array
     * containing all issues in the particular tables.
     * @returns array Array with all found issues.
     */
    protected function _checkintegrity()
    {
      $aDelete = array();
      switch ($this->chkstep) {
      case 1:
      {
	  /* Find is some fix is done */
	  $bDirectlyFixed = false;
	  $aFullOldSIDs = array();
	  // Delete survey permissions if the user does not exist
	  $oCriteria = new CDbCriteria;
	  $oCriteria->join = 'LEFT JOIN {{users}} u ON {{permissions}}.uid=u.uid';
	  $oCriteria->condition = '(u.uid IS NULL)';
	  if (App()->db->driverName == 'pgsql') {
	      $oCriteria->join = 'USING {{users}} u';
	      $oCriteria->condition = '{{permissions}}.uid=u.uid AND (u.uid IS NULL)';
	  }
	  if (Permission::model()->deleteAll($oCriteria)) {
	      $bDirectlyFixed = true;
	  }
	  break;
      }
      case 2:
      {
	  // Delete survey permissions if the survey does not exist
	  $oCriteria = new CDbCriteria;
	  $oCriteria->join = 'LEFT JOIN {{surveys}} s ON {{permissions}}.entity_id=s.sid';
	  $oCriteria->condition = "(s.sid IS NULL AND entity='survey')";
	  if (App()->db->driverName == 'pgsql') {
	      $oCriteria->join = 'USING {{surveys}} s';
	      $oCriteria->condition = "{{permissions}}.entity_id=s.sid AND (s.sid IS NULL AND entity='survey')";
	  }
	  if (Permission::model()->deleteAll($oCriteria)) {
	      $bDirectlyFixed = true;
	  }
	  break;
      }

      case 30:
      {
	  $xx = 0;

	  // Deactivate surveys that have a missing response table
	  $oSurveys = Survey::model()->findAll();
	  $oDB = Yii::app()->getDb();
	  $oDB->schemaCachingDuration = 0; // Deactivate schema caching
	  Yii::app()->setConfig('Updating', true);

	  $sCount = sizeof($oSurveys);

if (false) {
	  foreach ($oSurveys as $oSurvey) {
	      if ($oSurvey->isActive && !$oSurvey->hasResponsesTable) {
		  Survey::model()->updateByPk($oSurvey->sid, array('active'=>'N'));
		  $bDirectlyFixed = true;
	      }
	  }
}


	  /** Check for active surveys if questions are in the correct group **/
	  foreach ($oSurveys as $oSurvey) {
	      $bMemUsedStart = memory_get_usage(true);
	      ++$xx;

	      // We get the active surveys
	      if ($oSurvey->isActive && $oSurvey->hasResponsesTable) {
		  $model    = SurveyDynamic::model($oSurvey->sid);
		  $aColumns = $model->getMetaData()->columns;
		  $aQids    = array();

		  // We get the columns of the reponses table
		  foreach ($aColumns as $oColumn) {
		      // Question columns start with the SID
		      if (strpos($oColumn->name, $oSurvey->sid) !== false) {

			  // Fileds are separated by X
			  $aFields   = explode('X', $oColumn->name);


			  if ( isset($aFields[1]) ){

			      $sGid      = $aFields[1];

			      // QID field can be more than just QID, like: 886other or 886A1
			      // So we clean it by finding the first alphabetical character
			      $sDirtyQid = $aFields[2];
			      preg_match('~[a-zA-Z_]~i', $sDirtyQid, $match, PREG_OFFSET_CAPTURE);

			      if (isset($match[0][1])){
				  $sQID      =  substr ($sDirtyQid, 0, $match[0][1]);
			      }else{
				  // It was just the QID....
				  $sQID      =  $sDirtyQid;
			      }

			      // Here, we get the question as defined in backend
			      $oQuestion = Question::model()->findByPk([ 'qid' => $sQID , 'language' => $oSurvey->language]);
			      if (is_a($oQuestion, 'Question')){

				  // We check if its GID is the same as the one defined in the column name
				  if ($oQuestion->gid != $sGid){

				      // If not, we change the column name
				      $sNvColName = $oSurvey->sid . 'X'. $oQuestion->groups->gid . 'X' . $sDirtyQid;

				      if ( array_key_exists( $sNvColName, $aColumns ) ){
					  // This case will not happen often, only when QID + Subquestion ID == QID of a question in the target group
					  // So we'll change the group of the question question group table (so in admin interface, not in frontend)
					  $oQuestion->gid = $sGid;
					  $oQuestion->save();

				      }else{
					  $oTransaction = $oDB->beginTransaction();
					  $oDB->createCommand()->renameColumn($model->tableName(), $oColumn->name , $sNvColName);
					  $oTransaction->commit();
				      }


				  }
			      }else{
				  // QID not found: we should do something...
				  // $aUnfoundQIDs[] = $sQID;
			      }
			  }
		      }
		  }

	      }
	      $bMemUsed = memory_get_usage(true);
	      $mBMemUsed = strval(round($bMemUsed / 1024 / 1024, 2));
	      $mBMemUsedStep = strval(round( ( $bMemUsed - $bMemUsedStart ) / 1024 / 1024, 2));
	      Yii::trace(get_class($this)."_checkintregrit step $this->chkstep: survey $xx / $sCount; sid = $oSurvey->sid; memused $mBMemUsedStep MB this step. Total used so far: $mBMemUsed","application.admin.checkintegrity");
	      Yii::getLogger()->flush(true);
	  }
	  $oDB->schemaCachingDuration = 3600;
	  // unset($oSurveys);
	  break;
      }

      case 32:
	  $oDB = Yii::app()->getDb();
	  $oDB->schema->getTables();
	  break;

      case 33:
	  $oDB = Yii::app()->getDb();
	  $oDB->schema->refresh();
	  break;

      case 34:
	  $oDB = Yii::app()->getDb();
	  $oDB->active = false;
	  $oDB->active = true;
	  break;

      case 35:
	  User::model()->refreshMetaData();
	  break;
      case 36:
	  Yii::app()->db->schema->getTable('{{surveys}}', true);
	  break;
      case 37:
	  Yii::app()->db->schema->getTable('{{templates}}', true);
	  Survey::model()->refreshMetaData();
	  break;
      case 38:
	  /* Check method before using #14596 */
	  if (method_exists(Yii::app()->cache, 'flush')) {
	      Yii::app()->cache->flush();
	  }
	  break;
      case 39:
	  if (method_exists(Yii::app()->cache, 'gc')) {
	      Yii::app()->cache->gc();
	  }
	  break;

      case 40:
	  Yii::app()->setConfig('Updating', false);
	  break;

      case 45:
      {
	// Fix subquestions
	fixSubquestions();
	break;
      }


      case 50:
      {
	/*** Check for active survey tables with missing survey entry and rename them ***/
	$sDBPrefix = Yii::app()->db->tablePrefix;
	$aResult = Yii::app()->db->createCommand(dbSelectTablesLike('{{survey}}\_%'))->queryColumn();
	$sSurveyIDs = Yii::app()->db->createCommand('select sid from {{surveys}}')->queryColumn();
	foreach ($aResult as $aRow) {
	    $sTableName = (string) substr($aRow, strlen($sDBPrefix));
	    if ($sTableName == 'survey_links' || $sTableName == 'survey_url_parameters') {
		continue;
	    }
	    $aTableName = explode('_', $sTableName);
	    if (isset($aTableName[1]) && ctype_digit($aTableName[1])) {
		$iSurveyID = $aTableName[1];
		if (!in_array($iSurveyID, $sSurveyIDs)) {
		    $sDate = (string) date('YmdHis').rand(1, 1000);
		    // Check if it's really a survey_XXX table mantis #14938 
		    if(empty($aTableName[2])) {
			$sOldTable = "survey_{$iSurveyID}";
			$sNewTable = "old_survey_{$iSurveyID}_{$sDate}";
			Yii::app()->db->createCommand()->renameTable("{{{$sOldTable}}}", "{{{$sNewTable}}}");
			$bDirectlyFixed = true;
		    }
		    if(!empty($aTableName[2]) && $aTableName[2] == "timings" && empty($aTableName[3])) {
			$sOldTable = "survey_{$iSurveyID}_timings";
			$sNewTable = "old_survey_{$iSurveyID}_timings_{$sDate}";
			Yii::app()->db->createCommand()->renameTable("{{{$sOldTable}}}", "{{{$sNewTable}}}");
			$bDirectlyFixed = true;
		    }
		    
		}
	    }
	}
	break;
      }

      case 60:
      {
	/*** Check for active survey participants tables with missing survey entry ***/
	$sDBPrefix = Yii::app()->db->tablePrefix;
	$aResult = Yii::app()->db->createCommand(dbSelectTablesLike('{{tokens}}\_%'))->queryColumn();
	$sSurveyIDs = Yii::app()->db->createCommand('select sid from {{surveys}}')->queryColumn();
	foreach ($aResult as $aRow) {
	    $sTableName = (string) substr($aRow, strlen($sDBPrefix));
	    $aTableName = explode('_', $sTableName);
	    $iSurveyID = (integer) substr($sTableName, strpos($sTableName, '_') + 1);
	    if (isset($aTableName[1]) && ctype_digit($aTableName[1]) && empty($aTableName[2])) { // Check if it's really a token_XXX table mantis #14938 
		if (!in_array($iSurveyID, $sSurveyIDs)) {
		    $sDate = (string) date('YmdHis').rand(1, 1000);
		    $sOldTable = "tokens_{$iSurveyID}";
		    $sNewTable = "old_tokens_{$iSurveyID}_{$sDate}";
		    Yii::app()->db->createCommand()->renameTable("{{{$sOldTable}}}", "{{{$sNewTable}}}");
		    $bDirectlyFixed = true;
		}
	    }
	}
	break;
      }

      case 70:
      {
	/**********************************************************************/
	/*     Check conditions                                               */
	/**********************************************************************/
	$okQuestion = array();
	$sQuery = 'SELECT cqid,cid,cfieldname FROM {{conditions}}';
	$aConditions = Yii::app()->db->createCommand($sQuery)->queryAll();
	// $aDelete = array();
	foreach ($aConditions as $condition) {
	    if ($condition['cqid'] != 0) {
		// skip case with cqid=0 for codnitions on {TOKEN:EMAIL} for instance
		if (!array_key_exists($condition['cqid'], $okQuestion)) {
		    $iRowCount = Question::model()->countByAttributes(array('qid' => $condition['cqid']));
		    if (!$iRowCount) {
			$aDelete['conditions'][] = array('cid' => $condition['cid'], 'reason' => gT('No matching CQID'));
		    } else {
			$okQuestion[$condition['cqid']] = $condition['cqid'];
		    }
		}
	    }
	    //Only do this if there actually is a 'cfieldname'
	    if ($condition['cfieldname']) {
		// only if cfieldname isn't Tag such as {TOKEN:EMAIL} or any other token
		if (preg_match('/^\+{0,1}[0-9]+X[0-9]+X*$/', $condition['cfieldname'])) {

		    list ($surveyid, $gid, $rest) = explode('X', $condition['cfieldname']);

		    $iRowCount = count(QuestionGroup::model()->findAllByAttributes(array('gid'=>$gid)));
		    if (!$iRowCount) {
			$aDelete['conditions'][] = array('cid' => $condition['cid'], 'reason' => gT('No matching CFIELDNAME group!')." ($gid) ({$condition['cfieldname']})");
		    }
		}
	    } elseif (!$condition['cfieldname']) {
		$aDelete['conditions'][] = array('cid' => $condition['cid'], 'reason' => gT('No CFIELDNAME field set!')." ({$condition['cfieldname']})");
	    }
	}
	unset($okQuestion);
	unset($aConditions);
	break;
      }

      case 80:
      {
	/**********************************************************************/
	/*     Check question attributes                                      */
	/**********************************************************************/
	$question_attributes = QuestionAttribute::model()->findAllBySql('select qid from {{question_attributes}} where qid not in (select qid from {{questions}})');
	foreach ($question_attributes as $question_attribute) {
	    $aDelete['questionattributes'][] = array('qid' => $question_attribute['qid']);
	} // foreach
	break;
      }


      case 90:
      {
	/**********************************************************************/
	/*     Check default values                                           */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{questions}} q ON t.qid=q.qid';
	$oCriteria->condition = 'q.qid IS NULL';
	$aRecords = DefaultValue::model()->findAll($oCriteria);
	$aDelete['defaultvalues'] = count($aRecords);

	break;
      }

      case 10:
      {
	/**********************************************************************/
	/*     Check quotas                                                   */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{surveys}} s ON t.sid=s.sid';
	$oCriteria->condition = '(s.sid IS NULL)';
	$aDelete['quotas'] = count(Quota::model()->findAll($oCriteria));
	break;
      }

      case 110:
      {
	/**********************************************************************/
	/*     Check quota languagesettings                                   */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{quota}} s ON t.quotals_quota_id=s.id';
	$oCriteria->condition = '(s.id IS NULL)';
	$aDelete['quotals'] = count(QuotaLanguageSetting::model()->findAll($oCriteria));
	break;
      }

      case 120:
      {
	/**********************************************************************/
	/*     Check quota members                                   */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{questions}} q ON t.qid=q.qid LEFT JOIN {{surveys}} s ON t.sid=s.sid';
	$oCriteria->condition = '(q.qid IS NULL) OR (s.sid IS NULL)';

	$aDelete['quotamembers'] = count(QuotaMember::model()->findAll($oCriteria));
	break;
      }

      case 130:
      {
	/**********************************************************************/
	/*     Check assessments                                              */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->compare('scope', 'T');
	$assessments = Assessment::model()->findAll($oCriteria);

	foreach ($assessments as $assessment) {
	    $iAssessmentCount = count(Survey::model()->findAllByPk($assessment['sid']));
	    if (!$iAssessmentCount) {
		$aDelete['assessments'][] = array('id' => $assessment['id'], 'assessment' => $assessment['name'], 'reason' => gT('No matching survey'));
	    }
	}
	break;
      }

      case 140:
      {
	$oCriteria = new CDbCriteria;
	$oCriteria->compare('scope', 'G');
	$assessments = Assessment::model()->findAll($oCriteria);
	foreach ($assessments as $assessment) {
	    $iAssessmentCount = count(QuestionGroup::model()->findAllByPk(array('gid'=>$assessment['gid'], 'language'=>$assessment['language'])));
	    if (!$iAssessmentCount) {
		$aDelete['assessments'][] = array('id' => $assessment['id'], 'assessment' => $assessment['name'], 'reason' => gT('No matching group'));
	    }
	}
	unset($assessments);

	break;
      }

      case 150:
      {
	/**********************************************************************/
	/*     Check answers                                                  */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{questions}} q ON t.qid=q.qid';
	$oCriteria->condition = '(q.qid IS NULL)';

	$answers = Answer::model()->findAll($oCriteria);
	foreach ($answers as $answer) {
	    $aDelete['answers'][] = array('qid' => $answer['qid'], 'code' => $answer['code'], 'reason' => gT('No matching question'));
	}
	/***************************************************************************/
	/*   Check survey languagesettings and restore them if they don't exist    */
	/***************************************************************************/

	$surveys = Survey::model()->findAll();
	foreach ($surveys as $survey) {
	    $aLanguages = $survey->additionalLanguages;
	    $aLanguages[] = $survey->language;
	    foreach ($aLanguages as $langname) {
		if ($langname) {
		    $oLanguageSettings = SurveyLanguageSetting::model()->find('surveyls_survey_id=:surveyid AND surveyls_language=:langname', array(':surveyid'=>$survey->sid, ':langname'=>$langname));
		    if (!$oLanguageSettings) {
			$oLanguageSettings = new SurveyLanguageSetting;
			$languagedetails = getLanguageDetails($langname);
			$insertdata = array(
			    'surveyls_survey_id' => $survey->sid,
			    'surveyls_language' => $langname,
			    'surveyls_title' => '',
			    'surveyls_dateformat' => $languagedetails['dateformat']
			);
			foreach ($insertdata as $k => $v) {
			    $oLanguageSettings->$k = $v;
			}
			$oLanguageSettings->save();
			$bDirectlyFixed = true;
		    }
		}
	    }
	}
	break;
      }

      case 160:
      {
	/**********************************************************************/
	/*     Check survey language settings                                 */
	/**********************************************************************/
	$surveys_languagesettings = SurveyLanguageSetting::model()->resetScope()->with('survey')->findAll(array(
	    'select' => 'surveyls_survey_id',
	    'condition' => 'survey.sid IS NULL'
	));
	foreach ($surveys_languagesettings as $surveys_languagesetting) {
	    $aDelete['surveylanguagesettings'][] = array('slid' => $surveys_languagesetting['surveyls_survey_id'], 'reason' => gT('The related survey is missing.'));
	}
	break;
      }

      case 170:
      {
	/**********************************************************************/
	/*     Check questions                                                */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{surveys}} s ON t.sid=s.sid LEFT JOIN {{groups}} g ON t.gid=g.gid';
	$oCriteria->condition = '(g.gid IS NULL) OR (s.sid IS NULL)';
	$questions = Question::model()->findAll($oCriteria);
	foreach ($questions as $question) {
	    $aDelete['questions'][] = array('qid' => $question['qid'], 'reason' => gT('No matching group')." ({$question['gid']})");
	}
	break;
      }

      case 180:
      {
	/**********************************************************************/
	/*     Check groups                                                   */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{surveys}} s ON t.sid=s.sid';
	$oCriteria->condition = '(s.sid IS NULL)';
	$groups = QuestionGroup::model()->findAll($oCriteria);
	/** @var QuestionGroup $group */
	foreach ($groups as $group) {
	    $aDelete['groups'][] = array('gid' => $group['gid'], 'reason' => gT('There is no matching survey.').' SID:'.$group['sid']);
	}
	break;
      }

      case 190:
      {
	/**********************************************************************/
	/*     Check orphan user_in_groups                                    */
	/**********************************************************************/
	$oCriteria = new CDbCriteria;
	$oCriteria->join = 'LEFT JOIN {{user_groups}} ug ON t.ugid=ug.ugid';
	$oCriteria->condition = '(ug.ugid IS NULL)';
	$userInGroups = UserInGroup::model()->findAll($oCriteria);
	/** @var UserInGroup[] $userInGroups */
	foreach ($userInGroups as $userInGroup) {
	    $aDelete['user_in_groups'][] = array('ugid' => $userInGroup->ugid,'uid' => $userInGroup->uid, 'reason' => sprintf(gT('There is no matching user %s in group %s.'),$userInGroup->uid,$userInGroup->ugid));
	}
	break;
      }

      case 200:
      {
	/**********************************************************************/
	/*     Check old survey tables                                        */
	/**********************************************************************/
	//1: Get list of 'old_survey' tables and extract the survey id
	//2: Check if that survey id still exists
	//3: If it doesn't offer it for deletion
	$sDBPrefix = Yii::app()->db->tablePrefix;
	$sQuery = dbSelectTablesLike('{{old_survey}}%');
	$aTables = Yii::app()->db->createCommand($sQuery)->queryColumn();

	$aOldSIDs = array();

	foreach ($aTables as $sTable) {
	    list($sOldText, $SurveyText, $iSurveyID, $sDate) = explode('_', substr($sTable, strlen($sDBPrefix)));
	    $aOldSIDs[] = $iSurveyID;
	    $aFullOldSIDs[$iSurveyID][] = $sTable;
	}
	$aOldSIDs = array_unique($aOldSIDs);
	//$sQuery = 'SELECT sid FROM {{surveys}} ORDER BY sid';
	//$oResult = dbExecuteAssoc($sQuery) or safeDie('Couldn\'t get unique survey ids');
	$surveys = Survey::model()->findAll();

	$aSIDs = array();
	foreach ($surveys as $survey) {
	    $aSIDs[] = $survey['sid'];
	}
	foreach ($aOldSIDs as $iOldSID) {
	    if (!in_array($iOldSID, $aSIDs)) {
		foreach ($aFullOldSIDs[$iOldSID] as $sTableName) {
		    $aDelete['orphansurveytables'][] = $sTableName;
		}
	    } else {
		foreach ($aFullOldSIDs[$iOldSID] as $sTableName) {

		    $aTableParts = explode('_', substr($sTableName, strlen($sDBPrefix)));
		    $sDateTime = $sType = '';
		    $iSurveyID = $aTableParts[2];

		    if (count($aTableParts) == 4) {

			$sDateTime = $aTableParts[3];
			$sType = gT('responses');
		    } elseif (count($aTableParts) == 5) {
			//This is a timings table (

			$sDateTime = $aTableParts[4];
			$sType = gT('timings');
		    }

		    $iYear = (int) substr($sDateTime, 0, 4);
		    $iMonth = (int) substr($sDateTime, 4, 2);
		    $iDay = (int) substr($sDateTime, 6, 2);
		    $iHour = (int) substr($sDateTime, 8, 2);
		    $iMinute = (int) substr($sDateTime, 10, 2);
		    $sDate = (string) date('Y-m-d H:i:s', (int) mktime($iHour, $iMinute, 0, $iMonth, $iDay, $iYear));

		    $dateformatdetails = getDateFormatData(Yii::app()->session['dateformat']);
		    Yii::app()->loadLibrary('Date_Time_Converter');
		    $datetimeobj = new date_time_converter(dateShift($sDate, 'Y-m-d H:i:s', getGlobalSetting('timeadjust')), 'Y-m-d H:i:s');
		    $sDate = $datetimeobj->convert($dateformatdetails['phpdate']." H:i");

		    $sQuery = 'SELECT count(*) as recordcount FROM '.$sTableName;
		    $aFirstRow = Yii::app()->db->createCommand($sQuery)->queryRow();
		    if ($aFirstRow['recordcount'] == 0) {
		    // empty table - so add it to immediate deletion
			$aDelete['orphansurveytables'][] = $sTableName;
		    } else {
			$aOldSurveyTableAsk[] = array('table' => $sTableName, 'details' => sprintf(gT('Survey ID %d saved at %s containing %d record(s) (%s)'), $iSurveyID, $sDate, $aFirstRow['recordcount'], $sType));
		    }
		}
	    }
	}

	break;
      }

      case 210:
      {
	/**********************************************************************/
	/*     CHECK OLD TOKEN  TABLES                                        */
	/**********************************************************************/
	//1: Get list of 'old_token' tables and extract the survey id
	//2: Check if that survey id still exists
	//3: If it doesn't offer it for deletion
	$sDBPrefix = Yii::app()->db->tablePrefix;
	$sQuery = dbSelectTablesLike('{{old_token}}%');
	$aTables = Yii::app()->db->createCommand($sQuery)->queryColumn();


	$aTokenSIDs = array();
	$aFullOldTokenSIDs = array();

	foreach ($aTables as $sTable) {
	    list($sOldText, $SurveyText, $iSurveyID, $sDateTime) = explode('_', substr($sTable, strlen($sDBPrefix)));
	    $aTokenSIDs[] = $iSurveyID;
	    $aFullOldTokenSIDs[$iSurveyID][] = $sTable;
	}
	$aOldTokenSIDs = array_unique($aTokenSIDs);
	$surveys = Survey::model()->findAll();

	$aSIDs = array();
	foreach ($surveys as $survey) {
	    $aSIDs[] = $survey['sid'];
	}
	foreach ($aOldTokenSIDs as $iOldTokenSID) {
	    if (!in_array($iOldTokenSID, $aOldTokenSIDs)) {
		foreach ($aFullOldTokenSIDs[$iOldTokenSID] as $sTableName) {
		    $aDelete['orphantokentables'][] = $sTableName;
		}
	    } else {
		foreach ($aFullOldTokenSIDs[$iOldTokenSID] as $sTableName) {
		    list($sOldText, $sTokensText, $iSurveyID, $sDateTime) = explode('_', substr($sTableName, strlen($sDBPrefix)));
		    $iYear = (int) substr($sDateTime, 0, 4);
		    $iMonth = (int) substr($sDateTime, 4, 2);
		    $iDay = (int) substr($sDateTime, 6, 2);
		    $iHour = (int) substr($sDateTime, 8, 2);
		    $iMinute = (int) substr($sDateTime, 10, 2);
		    $sDate = date('D, d M Y  h:i a', mktime($iHour, $iMinute, 0, $iMonth, $iDay, $iYear));
		    $sQuery = 'SELECT count(*) as recordcount FROM '.$sTableName;

		    $aFirstRow = Yii::app()->db->createCommand($sQuery)->queryRow();
		    if ($aFirstRow['recordcount'] == 0) {
			// empty table - so add it to immediate deletion
			$aDelete['orphantokentables'][] = $sTableName;
		    } else {
			$aOldTokenTableAsk[] = array('table' => $sTableName, 'details' => sprintf(gT('Survey ID %d saved at %s containing %d record(s)'), $iSurveyID, $sDate, $aFirstRow['recordcount']));
		    }
		}
	    }
	}

	break;
      }

      case 220:
      {
	/**********************************************************************/
	/*     Check group sort order duplicates                              */
	/**********************************************************************/
	$aDelete['groupOrderDuplicates'] = $this->checkGroupOrderDuplicates();
	break;
      }

      case 230:
      {
	/**********************************************************************/
	/*     Check question sort order duplicates                           */
	/**********************************************************************/
	$aDelete['questionOrderDuplicates'] = $this->checkQuestionOrderDuplicates();

	/**********************************************************************/
	/*     CHECK CPDB SURVEY_LINKS TABLE FOR REDUNDENT Survey participants tableS       */
	/**********************************************************************/
	//1: Get distinct list of survey_link survey ids, check if tokens
	//   table still exists for each one, and remove if not


	/* TODO */

	/**********************************************************************/
	/*     CHECK CPDB SURVEY_LINKS TABLE FOR REDUNDENT TOKEN ENTRIES      */
	/**********************************************************************/
	//1: For each survey_link, see if the matching entry still exists in
	//   the survey participants table and remove if it doesn't.

	break;
      }
      } // switch

      if (!isset($aOldTokenTableAsk) && !isset($aOldSurveyTableAsk)) {
	  $aDelete['redundancyok'] = true;
      } else {
	  $aDelete['redundancyok'] = false;
	  $aDelete['redundanttokentables'] = array();
	  $aDelete['redundantsurveytables'] = array();
	  if (isset($aOldTokenTableAsk)) {
	      $aDelete['redundanttokentables'] = $aOldTokenTableAsk;
	  }
	  if (isset($aOldSurveyTableAsk)) {
	      $aDelete['redundantsurveytables'] = $aOldSurveyTableAsk;
	  }
      }

      if (false){
	/* Show a alert message is some fix is done */
	if ($bDirectlyFixed) {
	    Yii::app()->setFlashMessage(gT("Some automatic fixes were already applied."), 'info');
	}
      }
	
      return $aDelete;
    }

    /**
     * Check group order duplicates.
     * @return array
     */
    protected function checkGroupOrderDuplicates()
    {
        $sQuery = "
            SELECT
                g.sid
            FROM {{groups}} g
            JOIN {{surveys}} s ON s.sid = g.sid
            WHERE g.language = s.language
            GROUP BY g.sid
            HAVING COUNT(DISTINCT g.group_order) != COUNT(g.gid)";
        $result = Yii::app()->db->createCommand($sQuery)->queryAll();
        if (!empty($result)) {
            foreach ($result as &$survey) {
                $survey['organizerLink'] = Yii::app()->getController()->createUrl(
                    'admin/survey',
                    [
                        'sa' => 'organize',
                        'surveyid' => $survey['sid'],
                    ]
                );
            }
        }
        return $result;
    }

    /**
     * Check question order duplicates.
     * @return array
     */
    protected function checkQuestionOrderDuplicates()
    {
        $sQuery = "
            SELECT
                q.sid,
                q.gid,
                q.parent_qid,
                q.scale_id
            FROM {{questions}} q
            JOIN {{groups}} g ON q.gid = g.gid
            JOIN {{surveys}} s ON s.sid = q.sid
            WHERE q.language = s.language AND g.language = s.language
            GROUP BY q.sid, q.gid, q.parent_qid, q.scale_id
            HAVING COUNT(DISTINCT question_order) != COUNT(qid);
            ";
        $result = Yii::app()->db->createCommand($sQuery)->queryAll();
        if (!empty($result)) {
            foreach ($result as &$info) {
                $info['viewSurveyLink'] = Yii::app()->getController()->createUrl(
                    'admin/survey',
                    [
                        'sa' => 'view',
                        'surveyid' => $info['sid'],
                    ]
                );
                $info['viewGroupLink'] = Yii::app()->getController()->createUrl(
                    'admin/questiongroups',
                    [
                        'sa' => 'view',
                        'surveyid' => $info['sid'],
                        'gid' => $info['gid']
                    ]
                );
                if ($info['parent_qid'] != 0) {
                    $info['questionSummaryLink'] = Yii::app()->getController()->createUrl(
                        'admin/questions',
                        [
                            'sa' => 'subquestions',
                            'surveyid' => $info['sid'],
                            'gid' => $info['gid'],
                            'qid' => $info['parent_qid']
                        ]
                    );

                }
            }
        }
        return $result;
    }

    /**
     * Renders template(s) wrapped in header and footer
     *
     * @param string $sAction Current action, the folder to fetch views from
     * @param string $aViewUrls View url(s)
     * @param array $aData Data to be passed on. Optional.
     */
    protected function _renderWrappedTemplate($sAction = 'checkintegrity', $aViewUrls = array(), $aData = array(), $sRenderFile = false)
    {
        parent::_renderWrappedTemplate($sAction, $aViewUrls, $aData, $sRenderFile);
    }
}
checkintegrity.php (48,345 bytes)   
DenisChenu

DenisChenu

2021-10-07 08:10

developer   ~66783

The checkintegrity.php code is itself... sub-optimal. I strongly urge a refactoring.

lol ! Totally right ;)

I wrapped the function into a large case statement.

Why not create a pull request ?

uibklime1

uibklime1

2021-10-07 13:34

reporter   ~66791

Why not create a pull request ?

  1. My solution is half-baked and I have no idea what is going on here, other than seeing the pattern of the code itself.

  2. I would do a pull request for 3.X LTS branch only. Until I install and work with 5, I will not make changes there.

  3. I should in any case coordinate with you.

Question: where do we discuss this potential development itself? IRC? email? discord?

Issue History

Date Modified Username Field Change
2020-09-23 09:02 DenisChenu New Issue
2020-09-23 10:52 DenisChenu Note Added: 59936
2020-09-23 10:53 DenisChenu Note Added: 59937
2021-10-07 02:40 uibklime1 Note Added: 66781
2021-10-07 02:40 uibklime1 Bug heat 2 => 4
2021-10-07 02:42 uibklime1 Note Added: 66782
2021-10-07 02:42 uibklime1 File Added: checkintegrity.php
2021-10-07 08:10 DenisChenu Note Added: 66783
2021-10-07 13:34 uibklime1 Note Added: 66791
2021-10-19 10:00 galads Assigned To => galads
2021-10-19 10:00 galads Status new => acknowledged
2023-02-02 18:06 DenisChenu Relationship added related to 18614
2023-02-02 18:08 DenisChenu Assigned To galads =>