[ 
https://issues.apache.org/jira/browse/ZETACOMP-107?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Suwandi Tanuwijaya updated ZETACOMP-107:
----------------------------------------

    Priority: Major  (was: Critical)
    
> Repairing dropped index during compare schemas on sqlitewriter
> --------------------------------------------------------------
>
>                 Key: ZETACOMP-107
>                 URL: https://issues.apache.org/jira/browse/ZETACOMP-107
>             Project: Zeta Components
>          Issue Type: Improvement
>          Components: DatabaseSchema
>         Environment: Ubuntu Natty
> PHP 5.3.6
> SimpleTest
>            Reporter: Suwandi Tanuwijaya
>              Labels: improvement, patch
>   Original Estimate: 2h
>  Remaining Estimate: 2h
>
> I need improvement of this component since implementation of sqlitewriter has 
> been trying to emulate ALTER FIELD ( Sqlite had not native syntax to achieve 
> this ), but forgot to restore the index attached on it.
> ezcDbSchemaComparator component emulate this altering field with this logic:
>   * reading the schema of changed table
>   * create temporary table, and then copy data of the changed table to 
> temporary
>   * drop the original change table
>   * create new schema of the original table with modified schema
>   * transfer back the data from temporary to the new one
> Unfortunately, this logic forgot to restore indexes that attached to the 
> table.
> And, testingApply1 on ezcDatabaseSchemaGenericDiffTest should be failed 
> because some index was not found.
> So, I need improvement ( or bug fixes, depends on your point of view ) of 
> this database schema components.
> My quickhacked is, put repairingDroppedIndex function on dbschema writer, on 
> this case Sqlitewriter. This function reads the index structure using pragma 
> method. I bound this function on applyDiffToDb method on 
> ezcDbSchemaSqliteWriter.
> The idea is, to put DDL ( with repairing dropped index sql syntax on it ) 
> before the loop. 
> And, for this purpose, I modify the index naming by default to include its 
> table name with underscore ( tablename_indexname ) to avoid clashes with 
> other same naming index ( instead of. just _pri for primary index ) .
> The Complete of my quickhacked code is:
> repairedDroppedIndex method:
> {{{
> protected function repaireDroppedIndex( Abstraction\PdoHandler $db, $schemas, 
> $tableName )
>     {
>         $indexes = $this->generateIndexFromPragmaSql( $db, $tableName );
>         if( count( $indexes ) > 0 )
>         {
>             foreach( $indexes as $indexName => $indexDefinition )
>             {
>                 $query = $this->generateDropIndexSql( $tableName, $indexName 
> );
>                 $schemas [] = $query;
>                 
>                 $needle = array( 'CREATE INDEX ', 'CREATE UNIQUE INDEX ' );
>                 $replace = array( 'CREATE INDEX IF NOT EXISTS ', 'CREATE 
> UNIQUE INDEX IF NOT EXISTS ' ); 
>                 
>                 $query = str_replace( $needle, $replace, 
> $this->generateAddIndexSql( $tableName, $indexName, $indexDefinition ));
>                 $schemas [] = $query;
>             }
>         }
>         
>         return $schemas;
>     }
> }}}
> generateIndexFromPragmaSql method:
> {{{
> protected function generateIndexFromPragmaSql( Abstraction\PdoHandler $db, 
> $tableName )
>     {
>         $query = 'PRAGMA INDEX_LIST (\''.$tableName.'\');';
>         $statement = $db->query( $query );
>         $statement->setFetchMode( \PDO::FETCH_ASSOC );
>         $resultArray = $statement->fetchAll();
>         
>         $indexes = array();
>         $indexFields = array();
>         foreach( $resultArray as $key => $index )
>         {
>             $query = 'PRAGMA INDEX_INFO (\''.$index['name'].'\');';
>             $indexArray = $db->query( $query );
>             $indexArray->setFetchMode( \PDO::FETCH_ASSOC );
>             
>             foreach( $indexArray as $dummy => $indexField )
>             {
>                 $indexFields [$indexField['name']] = new 
> Entity\DbSchemaIndexField();
>             }
>             
>             $primary = FALSE;
>             if( strstr( $index['name'], '_pri') ) $primary = TRUE;
>             
>             $unique = FALSE;
>             if( $index['unique'] === '1' OR $index['unique'] === TRUE ) 
> $unique = TRUE;
>             
>             $indexes[$index['name']] = new Entity\DbSchemaIndex(
>                 $indexFields, $primary, $unique
>             );
>         }
>         
>         return $indexes;
>     }
> }}}
> and modified applyDiffToDb method:
> {{{
> ...
>         $schemas = $this->convertDiffToDDL( $dbSchemaDiff );
>         
>         foreach( $schemas as $query )
>         {
>             if( strstr( $query, 'DROP COLUMN' ) )
>             {
>                 preg_match( '@ALTER TABLE (.*) DROP COLUMN (.*)@', $query, 
> $matches );
>                 if( ! $matches ) throw new 
> Entity\DbSchemaSqliteDropFieldException( 
>                 'Can\'t fetch field for droping from SQL query: '.$query );
>                         
>                 $tableName = trim( $matches[1], "'" );
>                 $schemas = $this->repaireDroppedIndex( $db, $schemas, 
> $tableName );
>             }
>             elseif( strstr( $query, 'CHANGE' ) )
>             {
>                 preg_match( '@ALTER TABLE (.*) CHANGE (.*?) (.*?) (.*)@', 
> $query, $matches );
>                 if( ! $matches ) throw new 
> Entity\DbSchemaSqliteDropFieldException( 
>                 'Can\'t fetch field for droping from SQL query: '.$query );
>                 
>                 $tableName = trim( $matches[1], "'" );
>                 $schemas = $this->repaireDroppedIndex( $db, $schemas, 
> $tableName );
>             }
>         }
> /* and so on  */
> ...
> }}}

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to