File Source: DatabaseInstaller.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.business.startup;
20
21 import java.io.IOException;
22 import java.sql.Connection;
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.util.ArrayList;
28 import java.util.Date;
29 import java.util.List;
30 import java.util.Properties;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.roller.weblogger.business.DatabaseProvider;
34 import org.apache.roller.weblogger.pojos.WeblogPermission;
35
36
37 /**
38 * Handles the install/upgrade of the Roller Weblogger database when the user
39 * has configured their installation type to 'auto'.
40 */
41 public class DatabaseInstaller {
42
/*
P/P * Method: org.apache.roller.weblogger.business.startup.DatabaseInstaller__static_init
*
* Postconditions:
* init'ed(log)
*/
43 private static Log log = LogFactory.getLog(DatabaseInstaller.class);
44
45 private final DatabaseProvider db;
46 private final DatabaseScriptProvider scripts;
47 private final String version;
48 private List<String> messages = new ArrayList<String>();
49
50 // the name of the property which holds the dbversion value
51 private static final String DBVERSION_PROP = "roller.database.version";
52
53
/*
P/P * Method: void org.apache.roller.weblogger.business.startup.DatabaseInstaller(DatabaseProvider, DatabaseScriptProvider)
*
* Preconditions:
* (soft) log != null
*
* Presumptions:
* java.lang.Object:getClass(...)@60 != null
*
* Postconditions:
* this.db == dbProvider
* init'ed(this.db)
* this.messages == &new ArrayList(DatabaseInstaller#1)
* this.scripts == scriptProvider
* init'ed(this.scripts)
* init'ed(this.version)
* new ArrayList(DatabaseInstaller#1) num objects == 1
*/
54 public DatabaseInstaller(DatabaseProvider dbProvider, DatabaseScriptProvider scriptProvider) {
55 db = dbProvider;
56 scripts = scriptProvider;
57
58 Properties props = new Properties();
59 try {
60 props.load(getClass().getResourceAsStream("/roller-version.properties"));
61 } catch (IOException e) {
62 log.error("roller-version.properties not found", e);
63 }
64
65 version = props.getProperty("ro.version", "UNKNOWN");
66 }
67
68
69 /**
70 * Determine if database schema needs to be upgraded.
71 */
72 public boolean isCreationRequired() {
/*
P/P * Method: bool isCreationRequired()
*
* Preconditions:
* this.db != null
* init'ed(this.db.type)
* (soft) this.db.dataSource != null
* (soft) init'ed(this.db.jdbcConnectionURL)
* (soft) this.db.props != null
* (soft) this.db.props._tainted == 0
*
* Postconditions:
* init'ed(return_value)
*/
73 Connection con = null;
74 try {
75 con = db.getConnection();
76
77 // just check for a couple key Roller tables
+ 78 if (tableExists(con, "rolleruser") && tableExists(con, "userrole")) {
79 return false;
80 }
81
82 } catch (Throwable t) {
83 throw new RuntimeException("Error checking for tables", t);
84 } finally {
+ 85 try { if (con != null) con.close(); } catch (Exception ignored) {}
86 }
87
88 return true;
89 }
90
91
92 /**
93 * Determine if database schema needs to be upgraded.
94 */
95 public boolean isUpgradeRequired() {
/*
P/P * Method: bool isUpgradeRequired()
*
* Preconditions:
* this.version != null
* (soft) log != null
* (soft) this.db != null
* (soft) this.db.dataSource != null
* (soft) init'ed(this.db.jdbcConnectionURL)
* (soft) this.db.props != null
* (soft) this.db.props._tainted == 0
* (soft) init'ed(this.db.type)
* (soft) this.messages != null
*
* Postconditions:
* init'ed(return_value)
*/
96 int desiredVersion = parseVersionString(version);
97 int databaseVersion;
98 try {
99 databaseVersion = getDatabaseVersion();
100 } catch (StartupException ex) {
101 throw new RuntimeException(ex);
102 }
103
104 // if dbversion is unset then assume a new install, otherwise compare
105 if (databaseVersion < 0) {
106 // if this is a fresh db then we need to set the database version
107 Connection con = null;
108 try {
109 con = db.getConnection();
+ 110 setDatabaseVersion(con, version);
+ 111 } catch (Exception ioe) {
112 errorMessage("ERROR setting database version");
113 } finally {
114 try {
115 if (con != null) {
116 con.close();
117 }
118 } catch (Exception ignored) {
119 }
120 }
121
122 return false;
123 } else {
124 return databaseVersion < desiredVersion;
125 }
126 }
127
128
129 public List<String> getMessages() {
/*
P/P * Method: List getMessages()
*
* Preconditions:
* init'ed(this.messages)
*
* Postconditions:
* return_value == this.messages
* init'ed(return_value)
*/
130 return messages;
131 }
132
133
134 private void errorMessage(String msg) {
/*
P/P * Method: void errorMessage(String)
*
* Preconditions:
* log != null
* this.messages != null
*/
135 messages.add(msg);
136 log.error(msg);
137 }
138
139
140 private void errorMessage(String msg, Throwable t) {
/*
P/P * Method: void errorMessage(String, Throwable)
*
* Preconditions:
* log != null
* this.messages != null
*/
141 messages.add(msg);
142 log.error(msg, t);
143 }
144
145
146 private void successMessage(String msg) {
/*
P/P * Method: void successMessage(String)
*
* Preconditions:
* log != null
* this.messages != null
*/
147 messages.add(msg);
148 log.trace(msg);
149 }
150
151
152 /**
153 * Create datatabase tables.
154 */
155 public void createDatabase() throws StartupException {
156
/*
P/P * Method: void createDatabase()
*
* Preconditions:
* log != null
* org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* this.db != null
* init'ed(this.db.type)
* this.messages != null
* this.scripts != null
* this.version != null
* (soft) this.db.dataSource != null
* (soft) init'ed(this.db.jdbcConnectionURL)
* (soft) this.db.props != null
* ...
*/
157 log.info("Creating Roller Weblogger database tables.");
158
159 Connection con = null;
160 SQLScriptRunner create = null;
161 try {
162 con = db.getConnection();
+ 163 String handle = getDatabaseHandle(con);
164 create = new SQLScriptRunner(scripts.getDatabaseScript(handle + "/createdb.sql"));
165 create.runScript(con, true);
166 messages.addAll(create.getMessages());
167
168 setDatabaseVersion(con, version);
169
170 } catch (SQLException sqle) {
171 log.error("ERROR running SQL in database creation script", sqle);
172 if (create != null) messages.addAll(create.getMessages());
173 errorMessage("ERROR running SQL in database creation script");
174 throw new StartupException("Error running sql script", sqle);
175
176 } catch (Exception ioe) {
177 log.error("ERROR running database creation script", ioe);
178 if (create != null) messages.addAll(create.getMessages());
179 errorMessage("ERROR reading/parsing database creation script");
180 throw new StartupException("Error running sql script", ioe);
181
182 } finally {
+ 183 try { if (con != null) con.close(); } catch (Exception ignored) {}
184 }
185 }
186
187
188 /**
189 * Upgrade database if dbVersion is older than desiredVersion.
190 */
191 public void upgradeDatabase(boolean runScripts) throws StartupException {
192
/*
P/P * Method: void upgradeDatabase(bool)
*
* Preconditions:
* this.version != null
* (soft) log != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.db != null
* (soft) this.db.dataSource != null
* (soft) init'ed(this.db.jdbcConnectionURL)
* (soft) this.db.props != null
* (soft) this.db.props._tainted == 0
* (soft) init'ed(this.db.type)
* (soft) this.messages != null
* ...
*/
193 int myVersion = parseVersionString(version);
194 int dbversion = getDatabaseVersion();
195
196 log.debug("Database version = "+dbversion);
197 log.debug("Desired version = "+myVersion);
198
199 Connection con = null;
200 try {
201 con = db.getConnection();
202 if(dbversion < 0) {
203 String msg = "Cannot upgrade database tables, Roller database version cannot be determined";
204 errorMessage(msg);
+ 205 throw new StartupException(msg);
206 } else if(dbversion >= myVersion) {
207 log.info("Database is current, no upgrade needed");
208 return;
209 }
210
211 log.info("Database is old, beginning upgrade to version "+myVersion);
212
213 // iterate through each upgrade as needed
214 // to add to the upgrade sequence simply add a new "if" statement
215 // for whatever version needed and then define a new method upgradeXXX()
216 if(dbversion < 130) {
+ 217 upgradeTo130(con, runScripts);
218 dbversion = 130;
219 }
220 if (dbversion < 200) {
+ 221 upgradeTo200(con, runScripts);
222 dbversion = 200;
223 }
224 if(dbversion < 210) {
+ 225 upgradeTo210(con, runScripts);
226 dbversion = 210;
227 }
228 if(dbversion < 230) {
+ 229 upgradeTo230(con, runScripts);
230 dbversion = 230;
231 }
232 if(dbversion < 240) {
+ 233 upgradeTo240(con, runScripts);
234 dbversion = 240;
235 }
236 if(dbversion < 300) {
+ 237 upgradeTo300(con, runScripts);
238 dbversion = 300;
239 }
240 if(dbversion < 310) {
+ 241 upgradeTo310(con, runScripts);
242 dbversion = 310;
243 }
244 if(dbversion < 400) {
+ 245 upgradeTo400(con, runScripts);
246 dbversion = 400;
247 }
248 if(dbversion < 401) {
+ 249 upgradeTo401(con, runScripts);
+ 250 dbversion = 401;
251 }
252
253 // make sure the database version is the exact version
254 // we are upgrading too.
+ 255 updateDatabaseVersion(con, myVersion);
256
257 } catch (SQLException e) {
258 throw new StartupException("ERROR obtaining connection");
259 } finally {
+ 260 try { if (con != null) con.close(); } catch (Exception ignored) {}
261 }
262 }
263
264
265 /**
266 * Upgrade database for Roller 1.3.0
267 */
268 private void upgradeTo130(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo130(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* this.messages != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.scripts != null
*
* Presumptions:
* java.sql.Connection:prepareStatement(...)@296 != null
*
* Test Vectors:
* runScripts: {0}, {1}
* java.sql.Connection:getAutoCommit(...)@302: {1}, {0}
*/
269 SQLScriptRunner runner = null;
270 try {
271 if (runScripts) {
272 String handle = getDatabaseHandle(con);
273 String scriptPath = handle + "/120-to-130-migration.sql";
274 successMessage("Running database upgrade script: "+scriptPath);
275 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
276 runner.runScript(con, true);
277 messages.addAll(runner.getMessages());
278 }
279
280 /*
281 * The new theme management code is going into place and it uses
282 * the old website.themeEditor attribute to store a users theme.
283 *
284 * In pre-1.3 Roller *all* websites are considered to be using a
285 * custom theme, so we need to make sure this is properly defined
286 * by setting the theme on all websites to custom.
287 *
288 * NOTE: If we don't do this then nothing would break, but some users
289 * would be suprised that their template customizations are no longer
290 * in effect because they are using a shared theme instead.
291 */
292
293 successMessage("Doing upgrade to 130 ...");
294 successMessage("Ensuring that all website themes are set to custom");
295
296 PreparedStatement setCustomThemeStmt = con.prepareStatement(
297 "update website set editortheme = ?");
298
299 setCustomThemeStmt.setString(1, org.apache.roller.weblogger.pojos.WeblogTheme.CUSTOM);
300 setCustomThemeStmt.executeUpdate();
301
302 if (!con.getAutoCommit()) con.commit();
303
304 successMessage("Upgrade to 130 complete.");
305
306 } catch (Exception e) {
307 log.error("ERROR running 310 database upgrade script", e);
308 if (runner != null) messages.addAll(runner.getMessages());
309
310 errorMessage("Problem upgrading database to version 130", e);
311 throw new StartupException("Problem upgrading database to version 130", e);
312 }
313
314 updateDatabaseVersion(con, 130);
315 }
316
317 /**
318 * Upgrade database for Roller 2.0.0
319 */
320 private void upgradeTo200(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo200(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* this.messages != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.scripts != null
*
* Presumptions:
* java.sql.Connection:prepareStatement(...)@335 != null
* java.sql.Connection:prepareStatement(...)@338 != null
* java.sql.Connection:prepareStatement(...)@340 != null
* java.sql.Connection:prepareStatement(...)@344 != null
* java.sql.PreparedStatement:executeQuery(...)@350 != null
* ...
*
* Test Vectors:
* runScripts: {0}, {1}
* java.sql.Connection:getAutoCommit(...)@389: {1}, {0}
* java.sql.ResultSet:next(...)@351: {0}, {1}
*/
321 SQLScriptRunner runner = null;
322 try {
323 if (runScripts) {
324 String handle = getDatabaseHandle(con);
325 String scriptPath = handle + "/130-to-200-migration.sql";
326 successMessage("Running database upgrade script: "+scriptPath);
327 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
328 runner.runScript(con, true);
329 messages.addAll(runner.getMessages());
330 }
331
332 successMessage("Doing upgrade to 200 ...");
333 successMessage("Populating roller_user_permissions table");
334
335 PreparedStatement websitesQuery = con.prepareStatement(
336 "select w.id as wid, u.id as uid, u.username as uname from "
337 + "website as w, rolleruser as u where u.id=w.userid");
338 PreparedStatement websiteUpdate = con.prepareStatement(
339 "update website set handle=? where id=?");
340 PreparedStatement entryUpdate = con.prepareStatement(
341 "update weblogentry set userid=?, status=?, "
342 + "pubtime=pubtime, updatetime=updatetime "
343 + "where publishentry=? and websiteid=?");
344 PreparedStatement permsInsert = con.prepareStatement(
345 "insert into roller_user_permissions "
346 + "(id, website_id, user_id, permission_mask, pending) "
347 + "values (?,?,?,?,?)");
348
349 // loop through websites, each has a user
350 ResultSet websiteSet = websitesQuery.executeQuery();
351 while (websiteSet.next()) {
352 String websiteid = websiteSet.getString("wid");
353 String userid = websiteSet.getString("uid");
354 String handle = websiteSet.getString("uname");
355 successMessage("Processing website: " + handle);
356
357 // use website user's username as website handle
358 websiteUpdate.clearParameters();
359 websiteUpdate.setString(1, handle);
360 websiteUpdate.setString(2, websiteid);
361 websiteUpdate.executeUpdate();
362
363 // update all of pubished entries to include userid and status
364 entryUpdate.clearParameters();
365 entryUpdate.setString( 1, userid);
366 entryUpdate.setString( 2, "PUBLISHED");
367 entryUpdate.setBoolean(3, true);
368 entryUpdate.setString( 4, websiteid);
369 entryUpdate.executeUpdate();
370
371 // update all of draft entries to include userid and status
372 entryUpdate.clearParameters();
373 entryUpdate.setString( 1, userid);
374 entryUpdate.setString( 2, "DRAFT");
375 entryUpdate.setBoolean(3, false);
376 entryUpdate.setString( 4, websiteid);
377 entryUpdate.executeUpdate();
378
379 // add permission for user in website
380 permsInsert.clearParameters();
381 permsInsert.setString( 1, websiteid+"p");
382 permsInsert.setString( 2, websiteid);
383 permsInsert.setString( 3, userid);
384 permsInsert.setShort( 4,WeblogPermission.ADMIN);
385 permsInsert.setBoolean(5, false);
386 permsInsert.executeUpdate();
387 }
388
389 if (!con.getAutoCommit()) con.commit();
390
391 successMessage("Upgrade to 200 complete.");
392
393 } catch (Exception e) {
394 log.error("ERROR running 310 database upgrade script", e);
395 if (runner != null) messages.addAll(runner.getMessages());
396
397 errorMessage("Problem upgrading database to version 200", e);
398 throw new StartupException("Problem upgrading database to version 200", e);
399 }
400
401 updateDatabaseVersion(con, 200);
402 }
403
404
405 /**
406 * Upgrade database for Roller 2.1.0
407 */
408 private void upgradeTo210(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo210(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* this.messages != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.scripts != null
*
* Presumptions:
* java.sql.Connection:prepareStatement(...)@434 != null
* java.sql.Connection:prepareStatement(...)@439 != null
* java.sql.Connection:prepareStatement(...)@442 != null
* java.sql.Connection:prepareStatement(...)@446 != null
* java.sql.Connection:prepareStatement(...)@452 != null
* ...
*
* Test Vectors:
* runScripts: {0}, {1}
* java.sql.Connection:getAutoCommit(...)@508: {1}, {0}
* java.sql.ResultSet:next(...)@460: {0}, {1}
* java.sql.ResultSet:next(...)@473: {0}, {1}
*/
409 SQLScriptRunner runner = null;
410 try {
411 if (runScripts) {
412 String handle = getDatabaseHandle(con);
413 String scriptPath = handle + "/200-to-210-migration.sql";
414 successMessage("Running database upgrade script: "+scriptPath);
415 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
416 runner.runScript(con, true);
417 messages.addAll(runner.getMessages());
418 }
419
420 /*
421 * For Roller 2.1.0 we are going to standardize some of the
422 * weblog templates and make them less editable. To do this
423 * we need to do a little surgery.
424 *
425 * The goal for this upgrade is to ensure that ALL weblogs now have
426 * the required "Weblog" template as their default template.
427 */
428
429 successMessage("Doing upgrade to 210 ...");
430 successMessage("Ensuring that all weblogs use the 'Weblog' template as their default page");
431
432 // this query will give us all websites that have modified their
433 // default page to link to something other than "Weblog"
434 PreparedStatement selectUpdateWeblogs = con.prepareStatement(
435 "select website.id,template,website.handle from website,webpage "+
436 "where webpage.id = website.defaultpageid "+
437 "and webpage.link != 'Weblog'");
438
439 PreparedStatement selectWeblogTemplate = con.prepareStatement(
440 "select id from webpage where websiteid = ? and link = 'Weblog'");
441
442 PreparedStatement updateWeblogTemplate = con.prepareStatement(
443 "update webpage set template = ? where id = ?");
444
445 // insert a new template for a website
446 PreparedStatement insertWeblogTemplate = con.prepareStatement(
447 "insert into webpage"+
448 "(id, name, description, link, websiteid, template, updatetime) "+
449 "values(?,?,?,?,?,?,?)");
450
451 // update the default page for a website
452 PreparedStatement updateDefaultPage = con.prepareStatement(
453 "update website set defaultpageid = ? "+
454 "where id = ?");
455
456 String description = "This template is used to render the main "+
457 "page of your weblog.";
458 ResultSet websiteSet = selectUpdateWeblogs.executeQuery();
459 Date now = new Date();
460 while (websiteSet.next()) {
461 String websiteid = websiteSet.getString(1);
462 String template = websiteSet.getString(2);
463 String handle = websiteSet.getString(3);
464 successMessage("Processing website: " + handle);
465
466 String defaultpageid = null;
467
468 // it's possible that this weblog has a "Weblog" template, but just
469 // isn't using it as their default. if so we need to fix that.
470 selectWeblogTemplate.clearParameters();
471 selectWeblogTemplate.setString(1, websiteid);
472 ResultSet weblogPageSet = selectWeblogTemplate.executeQuery();
473 if(weblogPageSet.next()) {
474 // this person already has a "Weblog" template, so update it
475 String id = weblogPageSet.getString(1);
476
477 updateWeblogTemplate.clearParameters();
478 updateWeblogTemplate.setString(1, template);
479 updateWeblogTemplate.setString(2, id);
480 updateWeblogTemplate.executeUpdate();
481
482 // make sure and adjust what default page id we want to use
483 defaultpageid = id;
484 } else {
485 // no "Weblog" template, so insert a new one
486 insertWeblogTemplate.clearParameters();
487 insertWeblogTemplate.setString( 1, websiteid+"q");
488 insertWeblogTemplate.setString( 2, "Weblog");
489 insertWeblogTemplate.setString( 3, description);
490 insertWeblogTemplate.setString( 4, "Weblog");
491 insertWeblogTemplate.setString( 5, websiteid);
492 insertWeblogTemplate.setString( 6, template);
493 insertWeblogTemplate.setDate( 7, new java.sql.Date(now.getTime()));
494 insertWeblogTemplate.executeUpdate();
495
496 // set the new default page id
497 defaultpageid = websiteid+"q";
498 }
499
500 // update defaultpageid value
501 updateDefaultPage.clearParameters();
502 updateDefaultPage.setString( 1, defaultpageid);
503 updateDefaultPage.setString( 2, websiteid);
504 updateDefaultPage.executeUpdate();
505 }
506
507
508 if (!con.getAutoCommit()) con.commit();
509
510 successMessage("Upgrade to 210 complete.");
511
512 } catch (Exception e) {
513 log.error("ERROR running 310 database upgrade script", e);
514 if (runner != null) messages.addAll(runner.getMessages());
515
516 log.error("Problem upgrading database to version 210", e);
517 throw new StartupException("Problem upgrading database to version 210", e);
518 }
519
520 updateDatabaseVersion(con, 210);
521 }
522
523
524 /**
525 * Upgrade database for Roller 2.3.0
526 */
527 private void upgradeTo230(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo230(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.messages != null
* (soft) this.scripts != null
*
* Test Vectors:
* runScripts: {0}, {1}
*/
528 SQLScriptRunner runner = null;
529 try {
530 if (runScripts) {
531 String handle = getDatabaseHandle(con);
532 String scriptPath = handle + "/210-to-230-migration.sql";
533 successMessage("Running database upgrade script: "+scriptPath);
534 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
535 runner.runScript(con, true);
536 messages.addAll(runner.getMessages());
537 }
538 } catch (Exception e) {
539 log.error("ERROR running 310 database upgrade script", e);
540 if (runner != null) messages.addAll(runner.getMessages());
541
542 errorMessage("Problem upgrading database to version 230", e);
543 throw new StartupException("Problem upgrading database to version 230", e);
544 }
545
546 updateDatabaseVersion(con, 230);
547 }
548
549
550 /**
551 * Upgrade database for Roller 2.4.0
552 */
553 private void upgradeTo240(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo240(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.messages != null
* (soft) this.scripts != null
*
* Test Vectors:
* runScripts: {0}, {1}
*/
554 SQLScriptRunner runner = null;
555 try {
556 if (runScripts) {
557 String handle = getDatabaseHandle(con);
558 String scriptPath = handle + "/230-to-240-migration.sql";
559 successMessage("Running database upgrade script: "+scriptPath);
560 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
561 runner.runScript(con, true);
562 messages.addAll(runner.getMessages());
563 }
564 } catch (Exception e) {
565 log.error("ERROR running 310 database upgrade script", e);
566 if (runner != null) messages.addAll(runner.getMessages());
567
568 errorMessage("Problem upgrading database to version 240", e);
569 throw new StartupException("Problem upgrading database to version 240", e);
570 }
571
572 updateDatabaseVersion(con, 240);
573 }
574
575
576 /**
577 * Upgrade database for Roller 3.0.0
578 */
579 private void upgradeTo300(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo300(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* this.messages != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.scripts != null
*
* Presumptions:
* java.sql.Connection:prepareStatement(...)@608 != null
* java.sql.Connection:prepareStatement(...)@611 != null
* java.sql.Connection:prepareStatement(...)@622 != null
* java.sql.Connection:prepareStatement(...)@628 != null
* java.sql.PreparedStatement:executeQuery(...)@631 != null
* ...
*
* Test Vectors:
* runScripts: {0}, {1}
* java.sql.Connection:getAutoCommit(...)@644: {1}, {0}
* java.sql.ResultSet:next(...)@632: {0}, {1}
*/
580 SQLScriptRunner runner = null;
581 try {
582 if (runScripts) {
583 String handle = getDatabaseHandle(con);
584 String scriptPath = handle + "/240-to-300-migration.sql";
585 successMessage("Running database upgrade script: "+scriptPath);
586 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
587 runner.runScript(con, true);
588 messages.addAll(runner.getMessages());
589 }
590
591 /*
592 * For Roller 3.0.0 we are allowing each weblogentry to track a
593 * locale now so that we can support multi-lingual blogs. As part
594 * of the upgrade process we want to do 2 things ..
595 *
596 * 1. make sure all weblogs have a locale
597 * 2. set the locale on all entries to the locale for the weblog
598 */
599
600 successMessage("Doing upgrade to 300 ...");
601
602 // get system default language
603 String locale = java.util.Locale.getDefault().getLanguage();
604
605 successMessage("Setting website locale to "+locale+" for websites with no locale");
606
607 // update all weblogs where locale is "null"
608 PreparedStatement updateNullWeblogLocale = con.prepareStatement(
609 "update website set locale = ? where locale is NULL");
610 // update all weblogs where locale is empty string ""
611 PreparedStatement updateEmptyWeblogLocale = con.prepareStatement(
612 "update website set locale = ? where locale = ''");
613 updateNullWeblogLocale.setString( 1, locale);
614 updateEmptyWeblogLocale.setString( 1, locale);
615 updateNullWeblogLocale.executeUpdate();
616 updateEmptyWeblogLocale.executeUpdate();
617
618
619 successMessage("Setting weblogentry locales to website locale");
620
621 // get all entries and the locale of its website
622 PreparedStatement selectWeblogsLocale = con.prepareStatement(
623 "select weblogentry.id,website.locale "+
624 "from weblogentry,website "+
625 "where weblogentry.websiteid = website.id");
626
627 // set the locale for an entry
628 PreparedStatement updateWeblogLocale = con.prepareStatement(
629 "update weblogentry set locale = ? where id = ?");
630
631 ResultSet websiteSet = selectWeblogsLocale.executeQuery();
632 while (websiteSet.next()) {
633 String entryid = websiteSet.getString(1);
634 String entrylocale = websiteSet.getString(2);
635
636 // update entry locale
637 updateWeblogLocale.clearParameters();
638 updateWeblogLocale.setString( 1, entrylocale);
639 updateWeblogLocale.setString( 2, entryid);
640 updateWeblogLocale.executeUpdate();
641 }
642
643
644 if (!con.getAutoCommit()) con.commit();
645
646 successMessage("Upgrade to 300 complete.");
647
648 } catch (Exception e) {
649 log.error("ERROR running 310 database upgrade script", e);
650 if (runner != null) messages.addAll(runner.getMessages());
651
652 errorMessage("Problem upgrading database to version 300", e);
653 throw new StartupException("Problem upgrading database to version 300", e);
654 }
655
656 updateDatabaseVersion(con, 300);
657 }
658
659
660 /**
661 * Upgrade database for Roller 3.1.0
662 */
663 private void upgradeTo310(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo310(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.messages != null
* (soft) this.scripts != null
*
* Test Vectors:
* runScripts: {0}, {1}
*/
664 SQLScriptRunner runner = null;
665 try {
666 if (runScripts) {
667 String handle = getDatabaseHandle(con);
668 String scriptPath = handle + "/300-to-310-migration.sql";
669 successMessage("Running database upgrade script: "+scriptPath);
670 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
671 runner.runScript(con, true);
672 messages.addAll(runner.getMessages());
673 }
674 } catch (Exception e) {
675 log.error("ERROR running 310 database upgrade script", e);
676 if (runner != null) messages.addAll(runner.getMessages());
677
678 errorMessage("Problem upgrading database to version 310", e);
679 throw new StartupException("Problem upgrading database to version 310", e);
680 }
681
682 updateDatabaseVersion(con, 310);
683 }
684
685
686 /**
687 * Upgrade database for Roller 4.0.0
688 */
689 private void upgradeTo400(Connection con, boolean runScripts) throws StartupException {
690
/*
P/P * Method: void upgradeTo400(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* this.messages != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.scripts != null
*
* Presumptions:
* java.sql.Connection:prepareStatement(...)@1030 != null
* java.sql.Connection:prepareStatement(...)@1043 != null
* java.sql.Connection:prepareStatement(...)@1055 != null
* java.sql.Connection:prepareStatement(...)@1082 != null
* java.sql.Connection:prepareStatement(...)@1090 != null
* ...
*
* Test Vectors:
* runScripts: {0}, {1}
* java.lang.String:equals(...)@1035: {0}, {1}
* java.lang.String:equals(...)@1049: {1}, {0}
* java.lang.String:length(...)@989: {0}, {1..232-1}
* java.lang.String:startsWith(...)@1003: {0}, {1}
* java.sql.Connection:getAutoCommit(...)@1013: {1}, {0}
* java.sql.Connection:getAutoCommit(...)@1103: {1}, {0}
* java.sql.Connection:getAutoCommit(...)@762: {1}, {0}
* java.sql.Connection:getAutoCommit(...)@911: {1}, {0}
* java.sql.Connection:getAutoCommit(...)@966: {1}, {0}
* ...
*/
691 successMessage("Doing upgrade to 400 ...");
692
693 // first we need to run upgrade scripts
694 SQLScriptRunner runner = null;
695 try {
696 if (runScripts) {
697 String handle = getDatabaseHandle(con);
698 String scriptPath = handle + "/310-to-400-migration.sql";
699 successMessage("Running database upgrade script: "+scriptPath);
700 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
701 runner.runScript(con, true);
702 messages.addAll(runner.getMessages());
703 }
704 } catch(Exception ex) {
705 log.error("ERROR running 400 database upgrade script", ex);
706 if (runner != null) messages.addAll(runner.getMessages());
707
708 errorMessage("Problem upgrading database to version 400", ex);
709 throw new StartupException("Problem upgrading database to version 400", ex);
710 }
711
712
713 // now upgrade hierarchical objects data model
714 try {
715 successMessage("Populating parentid columns for weblogcategory and folder tables");
716
717 // Populate parentid in weblogcategory and folder tables.
718 //
719 // We'd like to do something like the below, but few databases
720 // support multiple table udpates, which are part of SQL-99
721 //
722 // update weblogcategory, weblogcategoryassoc
723 // set weblogcategory.parentid = weblogcategoryassoc.ancestorid
724 // where
725 // weblogcategory.id = weblogcategoryassoc.categoryid
726 // and weblogcategoryassoc.relation = 'PARENT';
727 //
728 // update folder,folderassoc
729 // set folder.parentid = folderassoc.ancestorid
730 // where
731 // folder.id = folderassoc.folderid
732 // and folderassoc.relation = 'PARENT';
733
734 PreparedStatement selectParents = con.prepareStatement(
735 "select categoryid, ancestorid from weblogcategoryassoc where relation='PARENT'");
736 PreparedStatement updateParent = con.prepareStatement(
737 "update weblogcategory set parentid=? where id=?");
738 ResultSet parentSet = selectParents.executeQuery();
739 while (parentSet.next()) {
740 String categoryid = parentSet.getString(1);
741 String parentid = parentSet.getString(2);
742 updateParent.clearParameters();
743 updateParent.setString( 1, parentid);
744 updateParent.setString( 2, categoryid);
745 updateParent.executeUpdate();
746 }
747
748 selectParents = con.prepareStatement(
749 "select folderid, ancestorid from folderassoc where relation='PARENT'");
750 updateParent = con.prepareStatement(
751 "update folder set parentid=? where id=?");
752 parentSet = selectParents.executeQuery();
753 while (parentSet.next()) {
754 String folderid = parentSet.getString(1);
755 String parentid = parentSet.getString(2);
756 updateParent.clearParameters();
757 updateParent.setString( 1, parentid);
758 updateParent.setString( 2, folderid);
759 updateParent.executeUpdate();
760 }
761
762 if (!con.getAutoCommit()) con.commit();
763
764 successMessage("Done populating parentid columns.");
765
766 } catch (Exception e) {
767 errorMessage("Problem upgrading database to version 320", e);
768 throw new StartupException("Problem upgrading database to version 320", e);
769 }
770
771
772 try {
773 successMessage("Populating path columns for weblogcategory and folder tables.");
774
775 // Populate path in weblogcategory and folder tables.
776 //
777 // It would be nice if there was a simple sql solution for doing
778 // this, but sadly the only real way to do it is through brute
779 // force walking the hierarchical trees. Luckily, it seems that
780 // most people don't create multi-level hierarchies, so hopefully
781 // this won't be too bad
782
783 // set path to '/' for nodes with no parents (aka root nodes)
784 PreparedStatement setRootPaths = con.prepareStatement(
785 "update weblogcategory set path = '/' where parentid is NULL");
786 setRootPaths.clearParameters();
787 setRootPaths.executeUpdate();
788
789 // select all nodes whose parent has no parent (aka 1st level nodes)
790 PreparedStatement selectL1Children = con.prepareStatement(
791 "select f.id, f.name from weblogcategory f, weblogcategory p "+
792 "where f.parentid = p.id and p.parentid is NULL");
793 // update L1 nodes with their path (/<name>)
794 PreparedStatement updateL1Children = con.prepareStatement(
795 "update weblogcategory set path=? where id=?");
796 ResultSet L1Set = selectL1Children.executeQuery();
797 while (L1Set.next()) {
798 String id = L1Set.getString(1);
799 String name = L1Set.getString(2);
800 updateL1Children.clearParameters();
801 updateL1Children.setString( 1, "/"+name);
802 updateL1Children.setString( 2, id);
803 updateL1Children.executeUpdate();
804 }
805
806 // now for the complicated part =(
807 // we need to keep iterating over L2, L3, etc nodes and setting
808 // their path until all nodes have been updated.
809
810 // select all nodes whose parent path has been set, excluding L1 nodes
811 PreparedStatement selectLxChildren = con.prepareStatement(
812 "select f.id, f.name, p.path from weblogcategory f, weblogcategory p "+
813 "where f.parentid = p.id and p.path <> '/' "+
814 "and p.path is not NULL and f.path is NULL");
815 // update Lx nodes with their path (<parentPath>/<name>)
816 PreparedStatement updateLxChildren = con.prepareStatement(
817 "update weblogcategory set path=? where id=?");
818
819 // this loop allows us to run this part of the upgrade process as
820 // long as is necessary based on the depth of the hierarchy, and
821 // we use the do/while construct to ensure it's run at least once
822 int catNumCounted = 0;
823 do {
824 log.debug("Doing pass over Lx children for categories");
825
826 // reset count for each iteration of outer loop
827 catNumCounted = 0;
828
829 ResultSet LxSet = selectLxChildren.executeQuery();
830 while (LxSet.next()) {
831 String id = LxSet.getString(1);
832 String name = LxSet.getString(2);
833 String parentPath = LxSet.getString(3);
834 updateLxChildren.clearParameters();
835 updateLxChildren.setString( 1, parentPath+"/"+name);
836 updateLxChildren.setString( 2, id);
837 updateLxChildren.executeUpdate();
838
839 // count the updated rows
+ 840 catNumCounted++;
841 }
842
843 log.debug("Updated "+catNumCounted+" Lx category paths");
844 } while(catNumCounted > 0);
845
846
847
848 // set path to '/' for nodes with no parents (aka root nodes)
849 setRootPaths = con.prepareStatement(
850 "update folder set path = '/' where parentid is NULL");
851 setRootPaths.clearParameters();
852 setRootPaths.executeUpdate();
853
854 // select all nodes whose parent has no parent (aka 1st level nodes)
855 selectL1Children = con.prepareStatement(
856 "select f.id, f.name from folder f, folder p "+
857 "where f.parentid = p.id and p.parentid is NULL");
858 // update L1 nodes with their path (/<name>)
859 updateL1Children = con.prepareStatement(
860 "update folder set path=? where id=?");
861 L1Set = selectL1Children.executeQuery();
862 while (L1Set.next()) {
863 String id = L1Set.getString(1);
864 String name = L1Set.getString(2);
865 updateL1Children.clearParameters();
866 updateL1Children.setString( 1, "/"+name);
867 updateL1Children.setString( 2, id);
868 updateL1Children.executeUpdate();
869 }
870
871 // now for the complicated part =(
872 // we need to keep iterating over L2, L3, etc nodes and setting
873 // their path until all nodes have been updated.
874
875 // select all nodes whose parent path has been set, excluding L1 nodes
876 selectLxChildren = con.prepareStatement(
877 "select f.id, f.name, p.path from folder f, folder p "+
878 "where f.parentid = p.id and p.path <> '/' "+
879 "and p.path is not NULL and f.path is NULL");
880 // update Lx nodes with their path (/<name>)
881 updateLxChildren = con.prepareStatement(
882 "update folder set path=? where id=?");
883
884 // this loop allows us to run this part of the upgrade process as
885 // long as is necessary based on the depth of the hierarchy, and
886 // we use the do/while construct to ensure it's run at least once
887 int folderNumUpdated = 0;
888 do {
889 log.debug("Doing pass over Lx children for folders");
890
891 // reset count for each iteration of outer loop
892 folderNumUpdated = 0;
893
894 ResultSet LxSet = selectLxChildren.executeQuery();
895 while (LxSet.next()) {
896 String id = LxSet.getString(1);
897 String name = LxSet.getString(2);
898 String parentPath = LxSet.getString(3);
899 updateLxChildren.clearParameters();
900 updateLxChildren.setString( 1, parentPath+"/"+name);
901 updateLxChildren.setString( 2, id);
902 updateLxChildren.executeUpdate();
903
904 // count the updated rows
+ 905 folderNumUpdated++;
906 }
907
908 log.debug("Updated "+folderNumUpdated+" Lx folder paths");
909 } while(folderNumUpdated > 0);
910
911 if (!con.getAutoCommit()) con.commit();
912
913 successMessage("Done populating path columns.");
914
915 } catch (SQLException e) {
916 log.error("Problem upgrading database to version 320", e);
917 throw new StartupException("Problem upgrading database to version 320", e);
918 }
919
920
921 // 4.0 changes the planet data model a bit, so we need to clean that up
922 try {
923 successMessage("Merging planet groups 'all' and 'external'");
924
925 // Move all subscriptions in the planet group 'external' to group 'all'
926
927 String allGroupId = null;
928 PreparedStatement selectAllGroupId = con.prepareStatement(
929 "select id from rag_group where handle = 'all'");
930 ResultSet rs = selectAllGroupId.executeQuery();
931 if (rs.next()) {
932 allGroupId = rs.getString(1);
933 }
934
935 String externalGroupId = null;
936 PreparedStatement selectExternalGroupId = con.prepareStatement(
937 "select id from rag_group where handle = 'external'");
938 rs = selectExternalGroupId.executeQuery();
939 if (rs.next()) {
940 externalGroupId = rs.getString(1);
941 }
942
943 // we only need to merge if both of those groups already existed
944 if(allGroupId != null && externalGroupId != null) {
945 PreparedStatement updateGroupSubs = con.prepareStatement(
946 "update rag_group_subscription set group_id = ? where group_id = ?");
947 updateGroupSubs.clearParameters();
948 updateGroupSubs.setString( 1, allGroupId);
949 updateGroupSubs.setString( 2, externalGroupId);
950 updateGroupSubs.executeUpdate();
951
952 // we no longer need the group 'external'
953 PreparedStatement deleteExternalGroup = con.prepareStatement(
954 "delete from rag_group where handle = 'external'");
955 deleteExternalGroup.executeUpdate();
956
957 // if we only have group 'external' then just rename it to 'all'
958 } else if(allGroupId == null && externalGroupId != null) {
959
960 // rename 'external' to 'all'
961 PreparedStatement renameExternalGroup = con.prepareStatement(
962 "update rag_group set handle = 'all' where handle = 'external'");
963 renameExternalGroup.executeUpdate();
964 }
965
966 if (!con.getAutoCommit()) con.commit();
967
968 successMessage("Planet group 'external' merged into group 'all'.");
969
970 } catch (Exception e) {
971 errorMessage("Problem upgrading database to version 400", e);
972 throw new StartupException("Problem upgrading database to version 400", e);
973 }
974
975
976 // update local planet subscriptions to use new local feed format
977 try {
978 successMessage("Upgrading local planet subscription feeds to new feed url format");
979
980 // need to start by looking up absolute site url
981 PreparedStatement selectAbsUrl =
982 con.prepareStatement("select value from roller_properties where name = 'site.absoluteurl'");
983 String absUrl = null;
984 ResultSet rs = selectAbsUrl.executeQuery();
985 if(rs.next()) {
986 absUrl = rs.getString(1);
987 }
988
989 if(absUrl != null && absUrl.length() > 0) {
990 PreparedStatement selectSubs =
991 con.prepareStatement("select id,feed_url,author from rag_subscription");
992
993 PreparedStatement updateSubUrl =
994 con.prepareStatement("update rag_subscription set last_updated=last_updated, feed_url = ? where id = ?");
995
996 ResultSet rset = selectSubs.executeQuery();
997 while (rset.next()) {
998 String id = rset.getString(1);
999 String feed_url = rset.getString(2);
1000 String handle = rset.getString(3);
1001
1002 // only work on local feed urls
1003 if (feed_url.startsWith(absUrl)) {
1004 // update feed_url to 'weblogger:<handle>'
1005 updateSubUrl.clearParameters();
1006 updateSubUrl.setString( 1, "weblogger:"+handle);
1007 updateSubUrl.setString( 2, id);
1008 updateSubUrl.executeUpdate();
1009 }
1010 }
1011 }
1012
1013 if (!con.getAutoCommit()) con.commit();
1014
1015 successMessage("Comments successfully updated to use new comment plugins.");
1016
1017 } catch (Exception e) {
1018 errorMessage("Problem upgrading database to version 400", e);
1019 throw new StartupException("Problem upgrading database to version 400", e);
1020 }
1021
1022
1023 // upgrade comments to use new plugin mechanism
1024 try {
1025 successMessage("Upgrading existing comments with content-type & plugins");
1026
1027 // look in db and see if comment autoformatting is enabled
1028 boolean autoformatEnabled = false;
1029 String autoformat = null;
1030 PreparedStatement selectIsAutoformtEnabled = con.prepareStatement(
1031 "select value from roller_properties where name = 'users.comments.autoformat'");
1032 ResultSet rs = selectIsAutoformtEnabled.executeQuery();
1033 if (rs.next()) {
1034 autoformat = rs.getString(1);
1035 if(autoformat != null && "true".equals(autoformat)) {
1036 autoformatEnabled = true;
1037 }
1038 }
1039
1040 // look in db and see if comment html escaping is enabled
1041 boolean htmlEnabled = false;
1042 String escapehtml = null;
1043 PreparedStatement selectIsEscapehtmlEnabled = con.prepareStatement(
1044 "select value from roller_properties where name = 'users.comments.escapehtml'");
1045 ResultSet rs1 = selectIsEscapehtmlEnabled.executeQuery();
1046 if (rs1.next()) {
1047 escapehtml = rs1.getString(1);
1048 // NOTE: we allow html only when html escaping is OFF
1049 if(escapehtml != null && !"true".equals(escapehtml)) {
1050 htmlEnabled = true;
1051 }
1052 }
1053
1054 // first lets set the new 'users.comments.htmlenabled' property
1055 PreparedStatement addCommentHtmlProp = con.prepareStatement("insert into roller_properties(name,value) values(?,?)");
1056 addCommentHtmlProp.clearParameters();
1057 addCommentHtmlProp.setString(1, "users.comments.htmlenabled");
1058 if(htmlEnabled) {
1059 addCommentHtmlProp.setString(2, "true");
1060 } else {
1061 addCommentHtmlProp.setString(2, "false");
1062 }
1063 addCommentHtmlProp.executeUpdate();
1064
1065 // determine content-type for existing comments
1066 String contentType = "text/plain";
1067 if(htmlEnabled) {
1068 contentType = "text/html";
1069 }
1070
1071 // determine plugins for existing comments
1072 String plugins = "";
1073 if(htmlEnabled && autoformatEnabled) {
1074 plugins = "HTMLSubset,AutoFormat";
1075 } else if(htmlEnabled) {
1076 plugins = "HTMLSubset";
1077 } else if(autoformatEnabled) {
1078 plugins = "AutoFormat";
1079 }
1080
1081 // set new comment plugins configuration property 'users.comments.plugins'
1082 PreparedStatement addCommentPluginsProp =
1083 con.prepareStatement("insert into roller_properties(name,value) values(?,?)");
1084 addCommentPluginsProp.clearParameters();
1085 addCommentPluginsProp.setString(1, "users.comments.plugins");
1086 addCommentPluginsProp.setString(2, plugins);
1087 addCommentPluginsProp.executeUpdate();
1088
1089 // set content-type for all existing comments
1090 PreparedStatement updateCommentsContentType =
1091 con.prepareStatement("update roller_comment set posttime=posttime, contenttype = ?");
1092 updateCommentsContentType.clearParameters();
1093 updateCommentsContentType.setString(1, contentType);
1094 updateCommentsContentType.executeUpdate();
1095
1096 // set plugins for all existing comments
1097 PreparedStatement updateCommentsPlugins =
1098 con.prepareStatement("update roller_comment set posttime=posttime, plugins = ?");
1099 updateCommentsPlugins.clearParameters();
1100 updateCommentsPlugins.setString(1, plugins);
1101 updateCommentsPlugins.executeUpdate();
1102
1103 if (!con.getAutoCommit()) con.commit();
1104
1105 successMessage("Comments successfully updated to use new comment plugins.");
1106
1107 } catch (Exception e) {
1108 errorMessage("Problem upgrading database to version 400", e);
1109 throw new StartupException("Problem upgrading database to version 400", e);
1110 }
1111
1112 // finally, upgrade db version string to 400
1113 updateDatabaseVersion(con, 400);
1114 }
1115
1116
1117 /**
1118 * Use database product name to get the database script directory name.
1119 */
1120 public String getDatabaseHandle(Connection con) throws SQLException {
1121
/*
P/P * Method: String getDatabaseHandle(Connection)
*
* Preconditions:
* con != null
*
* Presumptions:
* java.sql.Connection:getMetaData(...)@1122 != null
* java.sql.DatabaseMetaData:getDatabaseProductName(...)@1122 != null
*
* Postconditions:
* return_value in Addr_Set{&"mysql",&"derby",&"oracle",&"db2",&"mssql",&"postgresql",&"hsqldb"}
*
* Test Vectors:
* java.lang.String:indexOf(...)@1124: {-1}, {-231..-2, 0..232-1}
* java.lang.String:indexOf(...)@1126: {-1}, {-231..-2, 0..232-1}
* java.lang.String:indexOf(...)@1128: {-1}, {-231..-2, 0..232-1}
* java.lang.String:indexOf(...)@1130: {-1}, {-231..-2, 0..232-1}
* java.lang.String:indexOf(...)@1132: {-1}, {-231..-2, 0..232-1}
* java.lang.String:indexOf(...)@1134: {-1}, {-231..-2, 0..232-1}
* java.lang.String:indexOf(...)@1136: {-1}, {-231..-2, 0..232-1}
*/
1122 String productName = con.getMetaData().getDatabaseProductName();
1123 String handle = "mysql";
1124 if ( productName.toLowerCase().indexOf("mysql") != -1) {
1125 handle = "mysql";
1126 } else if (productName.toLowerCase().indexOf("derby") != -1) {
1127 handle = "derby";
1128 } else if (productName.toLowerCase().indexOf("hsql") != -1) {
1129 handle = "hsqldb";
1130 } else if (productName.toLowerCase().indexOf("postgres") != -1) {
1131 handle = "postgresql";
1132 } else if (productName.toLowerCase().indexOf("oracle") != -1) {
1133 handle = "oracle";
1134 } else if (productName.toLowerCase().indexOf("microsoft") != -1) {
1135 handle = "mssql";
1136 } else if (productName.toLowerCase().indexOf("db2") != -1) {
1137 handle = "db2";
1138 }
1139
1140 return handle;
1141 }
1142
1143
1144 /**
1145 * Return true if named table exists in database.
1146 */
1147 private boolean tableExists(Connection con, String tableName) throws SQLException {
/*
P/P * Method: bool tableExists(Connection, String)
*
* Preconditions:
* con != null
* (soft) tableName != null
*
* Presumptions:
* java.sql.Connection:getMetaData(...)@1149 != null
* java.sql.DatabaseMetaData:getTables(...)@1149 != null
* java.sql.ResultSet:getString(...)@1151 != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.lang.String:equals(...)@1151: {0}, {1}
* java.sql.ResultSet:next(...)@1150: {0}, {1}
*/
+ 1148 String[] types = {"TABLE"};
1149 ResultSet rs = con.getMetaData().getTables(null, null, "%", null);
1150 while (rs.next()) {
1151 if (tableName.toLowerCase().equals(rs.getString("TABLE_NAME").toLowerCase())) {
1152 return true;
1153 }
1154 }
1155 return false;
1156 }
1157
1158
1159 private int getDatabaseVersion() throws StartupException {
/*
P/P * Method: int getDatabaseVersion()
*
* Preconditions:
* (soft) log != null
* (soft) this.db != null
* (soft) this.db.dataSource != null
* (soft) init'ed(this.db.jdbcConnectionURL)
* (soft) this.db.props != null
* (soft) this.db.props._tainted == 0
* (soft) init'ed(this.db.type)
*
* Presumptions:
* java.sql.Connection:createStatement(...)@1166 != null
* java.sql.Statement:executeQuery(...)@1169 != null
* java.sql.Statement:executeQuery(...)@1179 != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.sql.ResultSet:next(...)@1172: {0}, {1}
*/
1160 int dbversion = -1;
1161
1162 // get the current db version
1163 Connection con = null;
1164 try {
1165 con = db.getConnection();
+ 1166 Statement stmt = con.createStatement();
1167
1168 // just check in the roller_properties table
1169 ResultSet rs = stmt.executeQuery(
1170 "select value from roller_properties where name = '"+DBVERSION_PROP+"'");
1171
1172 if(rs.next()) {
1173 dbversion = Integer.parseInt(rs.getString(1));
1174
1175 } else {
1176 // tough to know if this is an upgrade with no db version :/
1177 // however, if roller_properties is not empty then we at least
1178 // we have someone upgrading from 1.2.x
1179 rs = stmt.executeQuery("select count(*) from roller_properties");
1180 if(rs.next()) {
1181 if(rs.getInt(1) > 0)
1182 dbversion = 120;
1183 }
1184 }
1185
1186 } catch(Exception e) {
1187 // that's strange ... hopefully we didn't need to upgrade
1188 log.error("Couldn't lookup current database version", e);
1189 } finally {
1190 try { if (con != null) con.close(); } catch (Exception ignored) {}
1191 }
1192 return dbversion;
1193 }
1194
1195
1196 /**
1197 * Upgrade database for Roller 4.0.1
1198 */
1199 private void upgradeTo401(Connection con, boolean runScripts) throws StartupException {
/*
P/P * Method: void upgradeTo401(Connection, bool)
*
* Preconditions:
* con != null
* log != null
* (soft) org/apache/roller/weblogger/business/startup/SQLScriptRunner.log != null
* (soft) this.messages != null
* (soft) this.scripts != null
*
* Test Vectors:
* runScripts: {0}, {1}
*/
1200 SQLScriptRunner runner = null;
1201 try {
1202 if (runScripts) {
1203 String handle = getDatabaseHandle(con);
1204 String scriptPath = handle + "/400-to-401-migration.sql";
1205 successMessage("Running database upgrade script: "+scriptPath);
1206 runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
1207 runner.runScript(con, true);
1208 messages.addAll(runner.getMessages());
1209 }
1210 } catch (Exception e) {
1211 log.error("ERROR running 401 database upgrade script", e);
1212 if (runner != null) messages.addAll(runner.getMessages());
1213
1214 errorMessage("Problem upgrading database to version 401", e);
1215 throw new StartupException("Problem upgrading database to version 401", e);
1216 }
1217
1218 updateDatabaseVersion(con, 310);
1219 }
1220
1221
1222 private int parseVersionString(String vstring) {
/*
P/P * Method: int parseVersionString(String)
*
* Preconditions:
* vstring != null
*
* Presumptions:
* java.lang.Integer:parseInt(...)@1236 >= -214_748_364
*
* Postconditions:
* (soft) return_value >= -231+8
*
* Test Vectors:
* java.lang.Integer:parseInt(...)@1236: {100..232-1}, {-214_748_364..99}
* java.lang.String:length(...)@1231: {0..3}, {4..232-1}
*/
1223 int myversion = 0;
1224
1225 // NOTE: this assumes a maximum of 3 digits for the version number
1226 // so if we get to 10.0 then we'll need to upgrade this
1227
1228 // strip out non-digits
1229 vstring = vstring.replaceAll("\\Q.\\E", "");
1230 vstring = vstring.replaceAll("\\D", "");
1231 if(vstring.length() > 3)
1232 vstring = vstring.substring(0, 3);
1233
1234 // parse to an int
1235 try {
1236 int parsed = Integer.parseInt(vstring);
1237 if(parsed < 100) myversion = parsed * 10;
1238 else myversion = parsed;
1239 } catch(Exception e) {}
1240
1241 return myversion;
1242 }
1243
1244
1245 /**
1246 * Insert a new database.version property.
1247 * This should only be called once for new installations
1248 */
1249 private void setDatabaseVersion(Connection con, String version)
1250 throws StartupException {
/*
P/P * Method: void setDatabaseVersion(Connection, String)
*
* Preconditions:
* con != null
* log != null
* version != null
*/
1251 setDatabaseVersion(con, parseVersionString(version));
1252 }
1253
1254 /**
1255 * Insert a new database.version property.
1256 * This should only be called once for new installations
1257 */
1258 private void setDatabaseVersion(Connection con, int version)
1259 throws StartupException {
1260
1261 try {
/*
P/P * Method: void setDatabaseVersion(Connection, int)
*
* Preconditions:
* con != null
* log != null
*
* Presumptions:
* java.sql.Connection:createStatement(...)@1262 != null
*/
1262 Statement stmt = con.createStatement();
1263 stmt.executeUpdate("insert into roller_properties "+
1264 "values('"+DBVERSION_PROP+"', '"+version+"')");
1265
1266 log.debug("Set database verstion to "+version);
1267 } catch(SQLException se) {
1268 throw new StartupException("Error setting database version.", se);
1269 }
1270 }
1271
1272
1273 /**
1274 * Update the existing database.version property
1275 */
1276 private void updateDatabaseVersion(Connection con, int version)
1277 throws StartupException {
1278
1279 try {
/*
P/P * Method: void updateDatabaseVersion(Connection, int)
*
* Preconditions:
* con != null
* log != null
*
* Presumptions:
* java.sql.Connection:createStatement(...)@1280 != null
*/
1280 Statement stmt = con.createStatement();
1281 stmt.executeUpdate("update roller_properties "+
1282 "set value = '"+version+"'"+
1283 "where name = '"+DBVERSION_PROP+"'");
1284
1285 log.debug("Updated database verstion to "+version);
1286 } catch(SQLException se) {
1287 throw new StartupException("Error setting database version.", se);
1288 }
1289 }
1290
1291 }
SofCheck Inspector Build Version : 2.18479
| DatabaseInstaller.java |
2009-Jan-02 14:25:30 |
| DatabaseInstaller.class |
2009-Sep-04 03:12:31 |