Skip to content

Loading…

DDC-2134: Add referential integrity check for MySQL to console commands #2822

Open
doctrinebot opened this Issue · 0 comments

2 participants

@doctrinebot

Jira issue originally created by user holtkamp:

Today I spent some time solving a PHP 'White Screen of Death'. I traced it back to a Entity of which the proxy's _load() function was invoked because af a EXTRA_LAZY association. Due to incorrect database contents (the entry ID was changed due to an update: referential integrity broke), the __load() query resulted in no results. The EntityNotFoundException did for some reason not show up in our logs, probably because the lazy load was triggered by a magic _toString() function.

The cause is because of the way we populate or tables with domain data:

SET FOREIGN*KEY*CHECKS = 0;
#IMPORT STUFF from CSV
SET FOREIGN*KEY*CHECKS = 1;

MySQL does not trigger any errors when the foreign key checks are turned back on, leaving the table in an inconsistent state.

To prevent this, I found some information in this post: http://www.mysqlperformanceblog.com/2011/11/18/eventual-consistency-in-mysql/, which I used to come with the following queries

#Check the constraints of a specific database
SELECT *
    FROM INFORMATION*SCHEMA.KEY_COLUMN*USAGE 
        WHERE TABLE_SCHEMA = 'databaseName'
        AND REFERENCED*TABLE*NAME IS NOT NULL

#Generate table specific queries to find orphaned entries
SELECT CONCAT(
     'SELECT ', GROUP*CONCAT(DISTINCT CONCAT(K.CONSTRAINT_NAME, '.', P.COLUMN*NAME,
      ' AS `', P.TABLE*SCHEMA, '.', P.TABLE_NAME, '.', P.COLUMN_NAME, '`') ORDER BY P.ORDINAL*POSITION), ' ',
        'FROM ', K.TABLE*SCHEMA, '.', K.TABLE_NAME, ' AS ', K.CONSTRAINT*NAME, ' ',
            'LEFT OUTER JOIN ', K.REFERENCED*TABLE_SCHEMA, '.', K.REFERENCED_TABLE_NAME, ' AS ', K.REFERENCED_TABLE*NAME, ' ',
            ' ON (', GROUP*CONCAT(CONCAT(K.CONSTRAINT_NAME, '.', K.COLUMN_NAME) ORDER BY K.ORDINAL*POSITION),
            ') = (', GROUP*CONCAT(CONCAT(K.REFERENCED_TABLE_NAME, '.', K.REFERENCED_COLUMN_NAME) ORDER BY K.ORDINAL*POSITION), ') ',
            'WHERE ', K.REFERENCED*TABLE_NAME, '.', K.REFERENCED_COLUMN*NAME, ' IS NULL;'
      )
    INTO OUTFILE '/tmp/verifyDatabaseTableIntegrity.sql'
    FROM INFORMATION*SCHEMA.KEY_COLUMN*USAGE K
      INNER JOIN INFORMATION*SCHEMA.KEY_COLUMN*USAGE P
        ON (K.TABLE*SCHEMA, K.TABLE_NAME) = (P.TABLE_SCHEMA, P.TABLE*NAME)
        AND P.CONSTRAINT_NAME = 'PRIMARY'
    WHERE K.TABLE_SCHEMA = 'databaseName'
      AND K.REFERENCED*TABLE*NAME IS NOT NULL
      GROUP BY K.CONSTRAINT_NAME;

By running the generated queries, we can now easily find the records that break referential integrity.

It might be an idea of adding this functionality to the orm:validate-schema, or a new orm:validate-database-integrity?

@beberlei beberlei was assigned by doctrinebot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.