undo damage from DBIx::DBSchema 0.37_03
[freeside.git] / FS / bin / freeside-upgrade
1 #!/usr/bin/perl -w
2
3 use strict;
4 use vars qw($opt_d $opt_s $opt_q $opt_v $opt_r);
5 use vars qw($DEBUG $DRY_RUN);
6 use Getopt::Std;
7 use DBIx::DBSchema 0.31;
8 use FS::UID qw(adminsuidsetup checkeuid datasrc driver_name);  #getsecrets);
9 use FS::CurrentUser;
10 use FS::Schema qw( dbdef dbdef_dist reload_dbdef );
11 use FS::Misc::prune qw(prune_applications);
12 use FS::Conf;
13 use FS::Record qw(qsearch);
14 use FS::Upgrade qw(upgrade upgrade_sqlradius);
15
16 my $start = time;
17
18 die "Not running uid freeside!" unless checkeuid();
19
20 getopts("dqrs");
21
22 $DEBUG = !$opt_q;
23 #$DEBUG = $opt_v;
24
25 $DRY_RUN = $opt_d;
26
27 my $user = shift or die &usage;
28 $FS::CurrentUser::upgrade_hack = 1;
29 $FS::UID::callback_hack = 1;
30 my $dbh = adminsuidsetup($user);
31 $FS::UID::callback_hack = 0;
32
33 #needs to match FS::Schema...
34 my $dbdef_file = "%%%FREESIDE_CONF%%%/dbdef.". datasrc;
35
36 dbdef_create($dbh, $dbdef_file);
37
38 delete $FS::Schema::dbdef_cache{$dbdef_file}; #force an actual reload
39 reload_dbdef($dbdef_file);
40
41 warn "Upgrade startup completed in ". (time-$start). " seconds\n"; # if $DEBUG;
42 $start = time;
43
44 #$DBIx::DBSchema::DEBUG = $DEBUG;
45 #$DBIx::DBSchema::Table::DEBUG = $DEBUG;
46 #$DBIx::DBSchema::Index::DEBUG = $DEBUG;
47
48 my @bugfix = ();
49
50 if (dbdef->table('cust_main')->column('agent_custid') && ! $opt_s) { 
51   push @bugfix,
52     "UPDATE cust_main SET agent_custid = NULL where agent_custid = ''";
53
54   push @bugfix,
55     "UPDATE h_cust_main SET agent_custid = NULL where agent_custid = ''"
56       if (dbdef->table('h_cust_main')); 
57 }
58
59 #you should have run fs-migrate-part_svc ages ago, when you upgraded
60 #from 1.3 to 1.4... if not, it needs to be hooked into -upgrade here or
61 #you'll lose all the part_svc settings it migrates to part_svc_column
62
63 my @statements = dbdef->sql_update_schema( dbdef_dist(datasrc),
64                                            $dbh,
65                                            { 'nullify_default' => 1, },
66                                          );
67
68 @statements = 
69   grep { $_ !~ /^CREATE +INDEX +h_queue/i } #useless, holds up queue insertion
70        @statements;
71
72 unless ( driver_name =~ /^mysql/i ) {
73   #not necessary under non-mysql, takes forever on big db
74   @statements =
75     grep { $_ !~ /^ *ALTER +TABLE +h_queue +ALTER +COLUMN +job +TYPE +varchar\(512\) *$/i }
76          @statements;
77 }
78
79 if ( $DRY_RUN ) {
80   print
81     join(";\n", @bugfix, @statements ). ";\n";
82   exit;
83 } else {
84   foreach my $statement ( @bugfix, @statements ) {
85     warn "$statement\n";
86     $dbh->do( $statement )
87       or die "Error: ". $dbh->errstr. "\n executing: $statement";
88   }
89
90 #  warn "Pre-schema change upgrades completed in ". (time-$start). " seconds\n"; # if $DEBUG;
91 #  $start = time;
92
93 #  dbdef->update_schema( dbdef_dist(datasrc), $dbh );
94 }
95
96 warn "Schema upgrade completed in ". (time-$start). " seconds\n"; # if $DEBUG;
97 $start = time;
98
99 my $hashref = {};
100 $hashref->{dry_run} = 1 if $DRY_RUN;
101 $hashref->{debug} = 1 if $DEBUG && $DRY_RUN;
102 prune_applications($hashref) unless $opt_s;
103
104 warn "Application pruning completed in ". (time-$start). " seconds\n"; # if $DEBUG;
105 $start = time;
106
107 print "\n" if $DRY_RUN;
108
109 if ( $dbh->{Driver}->{Name} =~ /^mysql/i && ! $opt_s ) {
110
111   foreach my $table (qw( svc_acct svc_phone )) {
112
113     my $sth = $dbh->prepare(
114       "SELECT COUNT(*) FROM duplicate_lock WHERE lockname = '$table'"
115     ) or die $dbh->errstr;
116
117     $sth->execute or die $sth->errstr;
118
119     unless ( $sth->fetchrow_arrayref->[0] ) {
120
121       $sth = $dbh->prepare(
122         "INSERT INTO duplicate_lock ( lockname ) VALUES ( '$table' )"
123       ) or die $dbh->errstr;
124
125       $sth->execute or die $sth->errstr;
126
127     }
128
129   }
130
131   warn "Duplication lock creation completed in ". (time-$start). " seconds\n"; # if $DEBUG;
132   $start = time;
133
134 }
135
136 $dbh->commit or die $dbh->errstr;
137
138 dbdef_create($dbh, $dbdef_file);
139
140 $dbh->disconnect or die $dbh->errstr;
141
142 delete $FS::Schema::dbdef_cache{$dbdef_file}; #force an actual reload
143 $FS::UID::AutoCommit = 0;
144 $FS::UID::callback_hack = 1;
145 $dbh = adminsuidsetup($user);
146 $FS::UID::callback_hack = 0;
147 unless ( $DRY_RUN || $opt_s ) {
148   my $dir = "%%%FREESIDE_CONF%%%/conf.". datasrc;
149   if (!scalar(qsearch('conf', {}))) {
150     my $error = FS::Conf::init_config($dir);
151     if ($error) {
152       warn "CONFIGURATION UPGRADE FAILED\n";
153       $dbh->rollback or die $dbh->errstr;
154       die $error;
155     }
156   }
157 }
158 $dbh->commit or die $dbh->errstr;
159 $dbh->disconnect or die $dbh->errstr;
160
161 $dbh = adminsuidsetup($user);
162
163 warn "Re-initialization with updated schema completed in ". (time-$start). " seconds\n"; # if $DEBUG;
164 $start = time;
165
166 upgrade()
167   unless $DRY_RUN || $opt_s;
168
169 $dbh->commit or die $dbh->errstr;
170
171 warn "Table updates completed in ". (time-$start). " seconds\n"; # if $DEBUG;
172 $start = time;
173
174 upgrade_sqlradius()
175   unless $DRY_RUN || $opt_s || $opt_r;
176
177 warn "SQL RADIUS updates completed in ". (time-$start). " seconds\n"; # if $DEBUG;
178 $start = time;
179
180 $dbh->commit or die $dbh->errstr;
181 $dbh->disconnect or die $dbh->errstr;
182
183 warn "Final commit and disconnection completed in ". (time-$start). " seconds; upgrade done!\n"; # if $DEBUG;
184
185 ###
186
187 sub dbdef_create { # reverse engineer the schema from the DB and save to file
188   my( $dbh, $file ) = @_;
189   my $dbdef = new_native DBIx::DBSchema $dbh;
190   $dbdef->save($file);
191 }
192
193 sub usage {
194   die "Usage:\n  freeside-upgrade [ -d ] [ -r ] [ -s ] [ -q | -v ] user\n"; 
195 }
196
197 =head1 NAME
198
199 freeside-upgrade - Upgrades database schema for new freeside verisons.
200
201 =head1 SYNOPSIS
202
203   freeside-upgrade [ -d ] [ -r ] [ -s ] [ -q | -v ]
204
205 =head1 DESCRIPTION
206
207 Reads your existing database schema and updates it to match the current schema,
208 adding any columns or tables necessary.
209
210 Also performs other upgrade functions:
211
212 =over 4
213
214 =item Calls FS:: Misc::prune::prune_applications (probably unnecessary every upgrade, but simply won't find any records to change)
215
216 =item If necessary, moves your configuration information from the filesystem in /usr/local/etc/freeside/conf.<datasrc> to the database.
217
218 =back
219
220   [ -d ]: Dry run; output SQL statements (to STDOUT) only, but do not execute
221           them.
222
223   [ -q ]: Run quietly.  This may become the default at some point.
224
225   [ -r ]: Skip sqlradius updates.  Useful for occassions where the sqlradius
226           databases may be inaccessible.
227
228   [ -v ]: Run verbosely, sending debugging information to STDERR.  This is the
229           current default.
230
231   [ -s ]: Schema changes only.  Useful for Pg/slony slaves where the data
232           changes will be replicated from the Pg/slony master.
233
234 =head1 SEE ALSO
235
236 =cut
237