EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.upgrade]

COVERAGE SUMMARY FOR SOURCE FILE [DbUpgrade.java]

nameclass, %method, %block, %line, %
DbUpgrade.java100% (1/1)29%  (2/7)17%  (71/407)20%  (17/84)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DbUpgrade100% (1/1)29%  (2/7)17%  (71/407)20%  (17/84)
DbUpgrade (): void 0%   (0/1)0%   (0/3)0%   (0/1)
connectWithOldVersion (String, Properties): Connection 0%   (0/1)0%   (0/18)0%   (0/2)
setDeleteOldDb (boolean): void 0%   (0/1)0%   (0/3)0%   (0/2)
setScriptInTempDir (boolean): void 0%   (0/1)0%   (0/3)0%   (0/2)
upgrade (ConnectionInfo, Properties): void 0%   (0/1)0%   (0/282)0%   (0/53)
connectOrUpgrade (String, Properties): Connection 100% (1/1)71%  (67/94)68%  (15/22)
<static initializer> 100% (1/1)100% (4/4)100% (2/2)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.upgrade;
7 
8import java.io.File;
9import java.sql.Connection;
10import java.sql.DriverManager;
11import java.sql.SQLException;
12import java.sql.Statement;
13import java.util.Properties;
14import java.util.UUID;
15import org.h2.engine.ConnectionInfo;
16import org.h2.engine.Constants;
17import org.h2.jdbc.JdbcConnection;
18import org.h2.message.DbException;
19import org.h2.store.fs.FileUtils;
20import org.h2.util.StringUtils;
21import org.h2.util.Utils;
22 
23/**
24 * This class starts the conversion from older database versions to the current
25 * version if the respective classes are found.
26 */
27public class DbUpgrade {
28 
29    private static final boolean UPGRADE_CLASSES_PRESENT;
30 
31    private static boolean scriptInTempDir;
32    private static boolean deleteOldDb;
33 
34    static {
35        UPGRADE_CLASSES_PRESENT = Utils.isClassPresent("org.h2.upgrade.v1_1.Driver");
36    }
37 
38    /**
39     * If the upgrade classes are present, upgrade the database, or connect
40     * using the old version (if the parameter NO_UPGRADE is set to true). If
41     * the database is upgraded, or if no upgrade is possible or needed, this
42     * methods returns null.
43     *
44     * @param url the database URL
45     * @param info the properties
46     * @return the connection if connected with the old version (NO_UPGRADE)
47     */
48    public static Connection connectOrUpgrade(String url, Properties info)
49            throws SQLException {
50        if (!UPGRADE_CLASSES_PRESENT) {
51            return null;
52        }
53        Properties i2 = new Properties();
54        i2.putAll(info);
55        // clone so that the password (if set as a char array) is not cleared
56        Object o = info.get("password");
57        if (o instanceof char[]) {
58            i2.put("password", StringUtils.cloneCharArray((char[]) o));
59        }
60        info = i2;
61        ConnectionInfo ci = new ConnectionInfo(url, info);
62        if (ci.isRemote() || !ci.isPersistent()) {
63            return null;
64        }
65        String name = ci.getName();
66        if (FileUtils.exists(name + Constants.SUFFIX_PAGE_FILE)) {
67            return null;
68        }
69        if (!FileUtils.exists(name + Constants.SUFFIX_OLD_DATABASE_FILE)) {
70            return null;
71        }
72        if (ci.removeProperty("NO_UPGRADE", false)) {
73            return connectWithOldVersion(url, info);
74        }
75        synchronized (DbUpgrade.class) {
76            upgrade(ci, info);
77            return null;
78        }
79    }
80 
81    /**
82     * The conversion script file will per default be created in the db
83     * directory. Use this method to change the directory to the temp
84     * directory.
85     *
86     * @param scriptInTempDir true if the conversion script should be
87     *        located in the temp directory.
88     */
89    public static void setScriptInTempDir(boolean scriptInTempDir) {
90        DbUpgrade.scriptInTempDir = scriptInTempDir;
91    }
92 
93    /**
94     * Old files will be renamed to .backup after a successful conversion. To
95     * delete them after the conversion, use this method with the parameter
96     * 'true'.
97     *
98     * @param deleteOldDb if true, the old db files will be deleted.
99     */
100    public static void setDeleteOldDb(boolean deleteOldDb) {
101        DbUpgrade.deleteOldDb = deleteOldDb;
102    }
103 
104    private static Connection connectWithOldVersion(String url, Properties info)
105            throws SQLException {
106        url = "jdbc:h2v1_1:" + url.substring("jdbc:h2:".length()) +
107                ";IGNORE_UNKNOWN_SETTINGS=TRUE";
108        return DriverManager.getConnection(url, info);
109    }
110 
111    private static void upgrade(ConnectionInfo ci, Properties info)
112            throws SQLException {
113        String name = ci.getName();
114        String data = name + Constants.SUFFIX_OLD_DATABASE_FILE;
115        String index = name + ".index.db";
116        String lobs = name + ".lobs.db";
117        String backupData = data + ".backup";
118        String backupIndex = index + ".backup";
119        String backupLobs = lobs + ".backup";
120        String script = null;
121        try {
122            if (scriptInTempDir) {
123                new File(Utils.getProperty("java.io.tmpdir", ".")).mkdirs();
124                script = File.createTempFile(
125                        "h2dbmigration", "backup.sql").getAbsolutePath();
126            } else {
127                script = name + ".script.sql";
128            }
129            String oldUrl = "jdbc:h2v1_1:" + name +
130                    ";UNDO_LOG=0;LOG=0;LOCK_MODE=0";
131            String cipher = ci.getProperty("CIPHER", null);
132            if (cipher != null) {
133                oldUrl += ";CIPHER=" + cipher;
134            }
135            Connection conn = DriverManager.getConnection(oldUrl, info);
136            Statement stat = conn.createStatement();
137            String uuid = UUID.randomUUID().toString();
138            if (cipher != null) {
139                stat.execute("script to '" + script +
140                        "' cipher aes password '" + uuid + "' --hide--");
141            } else {
142                stat.execute("script to '" + script + "'");
143            }
144            conn.close();
145            FileUtils.move(data, backupData);
146            FileUtils.move(index, backupIndex);
147            if (FileUtils.exists(lobs)) {
148                FileUtils.move(lobs, backupLobs);
149            }
150            ci.removeProperty("IFEXISTS", false);
151            conn = new JdbcConnection(ci, true);
152            stat = conn.createStatement();
153            if (cipher != null) {
154                stat.execute("runscript from '" + script +
155                        "' cipher aes password '" + uuid + "' --hide--");
156            } else {
157                stat.execute("runscript from '" + script + "'");
158            }
159            stat.execute("analyze");
160            stat.execute("shutdown compact");
161            stat.close();
162            conn.close();
163            if (deleteOldDb) {
164                FileUtils.delete(backupData);
165                FileUtils.delete(backupIndex);
166                FileUtils.deleteRecursive(backupLobs, false);
167            }
168        } catch (Exception e)  {
169            if (FileUtils.exists(backupData)) {
170                FileUtils.move(backupData, data);
171            }
172            if (FileUtils.exists(backupIndex)) {
173                FileUtils.move(backupIndex, index);
174            }
175            if (FileUtils.exists(backupLobs)) {
176                FileUtils.move(backupLobs, lobs);
177            }
178            FileUtils.delete(name + ".h2.db");
179            throw DbException.toSQLException(e);
180        } finally {
181            if (script != null) {
182                FileUtils.delete(script);
183            }
184        }
185    }
186 
187}

[all classes][org.h2.upgrade]
EMMA 2.0.5312 (C) Vladimir Roubtsov