don't change h_queue.job type under non-mysql, takes forever on large dbs, RT#6946
[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 =
64   grep { $_ !~ /^CREATE +INDEX +h_queue/i } #useless, holds up queue insertion
65        dbdef->sql_update_schema( dbdef_dist(datasrc), $dbh );
66
67 unless ( driver_name =~ /^mysql/i ) {
68   #not necessary under non-mysql, takes forever on big db
69   @statements =
70     grep { $_ !~ /^ *ALTER +TABLE +h_queue +ALTER +COLUMN +job +TYPE +varchar\(512\) *$/ }
71          @statements;
72 }
73
74 if ( $DRY_RUN ) {
75   print
76     join(";\n", @bugfix, @statements ). ";\n";
77   exit;
78 } else {
79   foreach my $statement ( @bugfix, @statements ) {
80     $dbh->do( $statement )
81       or die "Error: ". $dbh->errstr. "\n executing: $statement";
82   }
83
84 #  warn "Pre-schema change upgrades completed in ". (time-$start). " seconds\n"; # if $DEBUG;
85 #  $start = time;
86
87 #  dbdef->update_schema( dbdef_dist(datasrc), $dbh );
88 }
89
90 warn "Schema upgrade completed in ". (time-$start). " seconds\n"; # if $DEBUG;
91 $start = time;
92
93 my $hashref = {};
94 $hashref->{dry_run} = 1 if $DRY_RUN;
95 $hashref->{debug} = 1 if $DEBUG && $DRY_RUN;
96 prune_applications($hashref) unless $opt_s;
97
98 warn "Application pruning completed in ". (time-$start). " seconds\n"; # if $DEBUG;
99 $start = time;
100
101 print "\n" if $DRY_RUN;
102
103 if ( $dbh->{Driver}->{Name} =~ /^mysql/i && ! $opt_s ) {
104
105   foreach my $table (qw( svc_acct svc_phone )) {
106
107     my $sth = $dbh->prepare(
108       "SELECT COUNT(*) FROM duplicate_lock WHERE lockname = '$table'"
109     ) or die $dbh->errstr;
110
111     $sth->execute or die $sth->errstr;
112
113     unless ( $sth->fetchrow_arrayref->[0] ) {
114
115       $sth = $dbh->prepare(
116         "INSERT INTO duplicate_lock ( lockname ) VALUES ( '$table' )"
117       ) or die $dbh->errstr;
118
119       $sth->execute or die $sth->errstr;
120
121     }
122
123   }
124
125   warn "Duplication lock creation completed in ". (time-$start). " seconds\n"; # if $DEBUG;
126   $start = time;
127
128 }
129
130 $dbh->commit or die $dbh->errstr;
131
132 dbdef_create($dbh, $dbdef_file);
133
134 $dbh->disconnect or die $dbh->errstr;
135
136 delete $FS::Schema::dbdef_cache{$dbdef_file}; #force an actual reload
137 $FS::UID::AutoCommit = 0;
138 $FS::UID::callback_hack = 1;
139 $dbh = adminsuidsetup($user);
140 $FS::UID::callback_hack = 0;
141 unless ( $DRY_RUN || $opt_s ) {
142   my $dir = "%%%FREESIDE_CONF%%%/conf.". datasrc;
143   if (!scalar(qsearch('conf', {}))) {
144     my $error = FS::Conf::init_config($dir);
145     if ($error) {
146       warn "CONFIGURATION UPGRADE FAILED\n";
147       $dbh->rollback or die $dbh->errstr;
148       die $error;
149     }
150   }
151 }
152 $dbh->commit or die $dbh->errstr;
153 $dbh->disconnect or die $dbh->errstr;
154
155 $dbh = adminsuidsetup($user);
156
157 warn "Re-initialization with updated schema completed in ". (time-$start). " seconds\n"; # if $DEBUG;
158 $start = time;
159
160 upgrade()
161   unless $DRY_RUN || $opt_s;
162
163 $dbh->commit or die $dbh->errstr;
164
165 warn "Table updates completed in ". (time-$start). " seconds\n"; # if $DEBUG;
166 $start = time;
167
168 upgrade_sqlradius()
169   unless $DRY_RUN || $opt_s || $opt_r;
170
171 warn "SQL RADIUS updates completed in ". (time-$start). " seconds\n"; # if $DEBUG;
172 $start = time;
173
174 $dbh->commit or die $dbh->errstr;
175 $dbh->disconnect or die $dbh->errstr;
176
177 warn "Final commit and disconnection completed in ". (time-$start). " seconds; upgrade done!\n"; # if $DEBUG;
178
179 ###
180
181 sub dbdef_create { # reverse engineer the schema from the DB and save to file
182   my( $dbh, $file ) = @_;
183   my $dbdef = new_native DBIx::DBSchema $dbh;
184   $dbdef->save($file);
185 }
186
187 sub usage {
188   die "Usage:\n  freeside-upgrade [ -d ] [ -r ] [ -s ] [ -q | -v ] user\n"; 
189 }
190
191 =head1 NAME
192
193 freeside-upgrade - Upgrades database schema for new freeside verisons.
194
195 =head1 SYNOPSIS
196
197   freeside-upgrade [ -d ] [ -r ] [ -s ] [ -q | -v ]
198
199 =head1 DESCRIPTION
200
201 Reads your existing database schema and updates it to match the current schema,
202 adding any columns or tables necessary.
203
204 Also performs other upgrade functions:
205
206 =over 4
207
208 =item Calls FS:: Misc::prune::prune_applications (probably unnecessary every upgrade, but simply won't find any records to change)
209
210 =item If necessary, moves your configuration information from the filesystem in /usr/local/etc/freeside/conf.<datasrc> to the database.
211
212 =back
213
214   [ -d ]: Dry run; output SQL statements (to STDOUT) only, but do not execute
215           them.
216
217   [ -q ]: Run quietly.  This may become the default at some point.
218
219   [ -r ]: Skip sqlradius updates.  Useful for occassions where the sqlradius
220           databases may be inaccessible.
221
222   [ -v ]: Run verbosely, sending debugging information to STDERR.  This is the
223           current default.
224
225   [ -s ]: Schema changes only.  Useful for Pg/slony slaves where the data
226           changes will be replicated from the Pg/slony master.
227
228 =head1 SEE ALSO
229
230 =cut
231