Changeset 1938

Show
Ignore:
Timestamp:
04/16/08 23:19:39 (6 months ago)
Author:
bchoate
Message:

Added support for upgrading custom fields from meta column to narrow tables. BugId:69022

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/release-35/build/mt-dists/default.mk

    r1931 r1938  
    22 
    33PRODUCT_VERSION = 4.15 
    4 SCHEMA_VERSION = 4.0056 
     4SCHEMA_VERSION = 4.0057 
    55API_VERSION = 4.15 
    66 
  • branches/release-35/lib/MT/Upgrade.pm

    r1927 r1938  
    878878            }, 
    879879        }, 
    880     } 
     880        'core_upgrade_meta' => { 
     881            version_limit => 4.0057, 
     882            priority => 3.2, 
     883            code => \&core_upgrade_meta, 
     884        }, 
     885 
     886        # Helper upgrade routine for core_upgrade_meta 
     887        # and possibly other object types that require 
     888        # this migration; version_limit is unspecified, so 
     889        # this can only be invoked if another upgrade 
     890        # operation utilizes it. 
     891        'core_upgrade_meta_for_table' => { 
     892            priority => 3.3, 
     893            code => \&core_upgrade_meta_for_table, 
     894        }, 
     895    }; 
     896
     897 
     898sub core_upgrade_meta { 
     899    my $self = shift; 
     900    # we could possibly determine the list of types to process 
     901    # programmatically, but this will do... 
     902    $self->add_step('core_upgrade_meta_for_table', type => 'entry'); 
     903    $self->add_step('core_upgrade_meta_for_table', type => 'author'); 
     904    $self->add_step('core_upgrade_meta_for_table', type => 'blog'); 
     905    $self->add_step('core_upgrade_meta_for_table', type => 'template'); 
     906    $self->add_step('core_upgrade_meta_for_table', type => 'asset'); 
     907    $self->add_step('core_upgrade_meta_for_table', type => 'category', 
     908        plugindata => 1); 
     909    return 0; 
     910
     911 
     912sub core_upgrade_meta_for_table { 
     913    my $self = shift; 
     914    my (%param) = @_; 
     915    my $type = $param{type}; 
     916    return 0 unless $type; 
     917    my $class = MT->model($type); 
     918    return 0 unless $class; 
     919    my $cfclass = MT->model('field'); 
     920    my $plugindata = $param{plugindata} || 0; 
     921 
     922    if ($cfclass) { 
     923        # this looks weird, but it winds up invoking 
     924        # the loading of custom field types and the 
     925        # installation of their meta properties 
     926        MT->registry('tags'); 
     927    } 
     928 
     929    # special case for types that use CustomField plugindata 
     930    # for storing their custom field metadata instead of a 'meta' 
     931    # column. 
     932    if ($cfclass && $plugindata) { 
     933        require CustomFields::Upgrade; 
     934        $self->progress($self->translate_escape('Moving metadata storage for categories...')); 
     935        CustomFields::Upgrade::customfields_move_meta($self, $type); 
     936        return 0; 
     937    } 
     938 
     939    my $offset = int($param{offset} || 0); 
     940    my $count = int($param{count} || 0); 
     941 
     942    my $pid = $param{step} . "_type"; 
     943 
     944    my $msg = MT->translate("Upgrading metadata storage for [_1]", $class->class_label_plural); 
     945 
     946    if (!$offset) { 
     947        $self->progress($msg, $pid); 
     948    } else { 
     949        my $count = $class->count(); 
     950        return 0 unless $count; 
     951        $self->progress(sprintf($msg . " (%d%%)", ($offset/$count*100)), $pid); 
     952    } 
     953 
     954    my $driver = $class->dbi_driver; 
     955    my $dbh = $driver->rw_handle; 
     956    my $dbd = $driver->dbd; 
     957    my $stmt = $dbd->sql_class->new; 
     958 
     959    # assumes 'meta' is the meta column name; should be for all core types 
     960    # we are processing 
     961    my $meta_col = $dbd->db_column_name($class->datasource, 
     962        $param{meta_column} || 'meta'); 
     963    my $id_col = $dbd->db_column_name($class->datasource, 'id'); 
     964    $stmt->add_where( $meta_col => { not_null => 1 } ); 
     965    $stmt->limit( 101 ); 
     966    $stmt->offset( $offset ) if $offset; 
     967 
     968    my $sql = join ' ', 'SELECT', $meta_col, ',', $id_col, 'FROM', 
     969        $driver->table_for($class), 
     970        $stmt->as_sql_where(), 
     971        $stmt->as_limit; 
     972 
     973    my $sth = $dbh->prepare($sql) 
     974        or return $self->error($dbh->errstr || $DBI::errstr); 
     975    $sth->execute 
     976        or return $self->error($dbh->errstr || $DBI::errstr); 
     977 
     978    my $rows = 0; 
     979 
     980    require MT::Serialize; 
     981    my $ser = MT::Serialize->new('MT'); 
     982    my %fields; 
     983 
     984    my @ids; 
     985    while (my $row = $sth->fetchrow_arrayref) { 
     986        $rows++; 
     987        my ($rawmeta, $id) = @$row; 
     988        if ($rawmeta =~ m/^SERG/) { 
     989            # deserialize 
     990            my $metadataref = $ser->unserialize($rawmeta); 
     991            if ($metadataref) { 
     992                my $metadata = $$metadataref; 
     993                my $obj = $class->load($id); 
     994                if ($obj) { 
     995                    my $changed = 0; 
     996                    foreach my $metaname (keys %$metadata) { 
     997                        my $metavalue = $metadata->{$metaname}; 
     998                        if ($metaname eq 'customfields') { 
     999                            next unless $cfclass; 
     1000 
     1001                            # extra work for custom fields; a hash into itself 
     1002                            my $cfdata = $metavalue; 
     1003                            next unless ref $cfdata eq 'HASH'; 
     1004 
     1005                            foreach my $cfname (keys %$cfdata) { 
     1006                                my $cfvalue = $cfdata->{$cfname}; 
     1007                                # make sure CustomFields::Field exists 
     1008                                my $fld = $fields{$cfname} ||= $cfclass->load({ basename => $cfname, obj_type => $type }); 
     1009                                next unless $fld; 
     1010 
     1011                                $changed++; 
     1012                                $obj->meta('field.' . $cfname, $cfvalue); 
     1013                            } 
     1014                        } else { 
     1015                            $changed++; 
     1016                            $obj->meta($metaname, $metavalue); 
     1017                        } 
     1018                    } 
     1019                    if ($changed) { 
     1020                        $obj->save if $changed; 
     1021                        push @ids, $obj->id; 
     1022                    } 
     1023                } 
     1024            } 
     1025        } 
     1026        last if $rows == 100; 
     1027    } 
     1028    $sth->finish; 
     1029 
     1030    # now, clear the meta column for each of the objects touched 
     1031    if (@ids) { 
     1032        my $list = join ",", @ids; 
     1033        my $sql = join " ", "UPDATE", $driver->table_for($class), 
     1034            "SET", $meta_col, "=NULL WHERE", $id_col, " IN ($list)"; 
     1035        $dbh->do($sql); 
     1036    } 
     1037 
     1038    if ($rows == 101) { 
     1039        $offset += 100; 
     1040    } else { 
     1041        # done, so lets drop that meta column, what say you? 
     1042        $sql = $dbd->ddl_class->drop_column_sql($class, $param{meta_column} || 'meta'); 
     1043        $dbh->do($sql); 
     1044        $offset = 0;  # done! 
     1045    } 
     1046    return $offset; 
    8811047} 
    8821048