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 | */ |
6 | package org.h2.tools; |
7 | |
8 | import java.sql.Connection; |
9 | import java.sql.DriverManager; |
10 | import java.sql.SQLException; |
11 | import java.sql.Statement; |
12 | |
13 | import org.h2.api.ErrorCode; |
14 | import org.h2.engine.Constants; |
15 | import org.h2.store.fs.FileUtils; |
16 | import org.h2.util.JdbcUtils; |
17 | import org.h2.util.Tool; |
18 | |
19 | /** |
20 | * Creates a cluster from a standalone database. |
21 | * <br /> |
22 | * Copies a database to another location if required. |
23 | * @h2.resource |
24 | */ |
25 | public class CreateCluster extends Tool { |
26 | |
27 | /** |
28 | * Options are case sensitive. Supported options are: |
29 | * <table> |
30 | * <tr><td>[-help] or [-?]</td> |
31 | * <td>Print the list of options</td></tr> |
32 | * <tr><td>[-urlSource "<url>"]</td> |
33 | * <td>The database URL of the source database (jdbc:h2:...)</td></tr> |
34 | * <tr><td>[-urlTarget "<url>"]</td> |
35 | * <td>The database URL of the target database (jdbc:h2:...)</td></tr> |
36 | * <tr><td>[-user <user>]</td> |
37 | * <td>The user name (default: sa)</td></tr> |
38 | * <tr><td>[-password <pwd>]</td> |
39 | * <td>The password</td></tr> |
40 | * <tr><td>[-serverList <list>]</td> |
41 | * <td>The comma separated list of host names or IP addresses</td></tr> |
42 | * </table> |
43 | * @h2.resource |
44 | * |
45 | * @param args the command line arguments |
46 | */ |
47 | public static void main(String... args) throws SQLException { |
48 | new CreateCluster().runTool(args); |
49 | } |
50 | |
51 | @Override |
52 | public void runTool(String... args) throws SQLException { |
53 | String urlSource = null; |
54 | String urlTarget = null; |
55 | String user = ""; |
56 | String password = ""; |
57 | String serverList = null; |
58 | for (int i = 0; args != null && i < args.length; i++) { |
59 | String arg = args[i]; |
60 | if (arg.equals("-urlSource")) { |
61 | urlSource = args[++i]; |
62 | } else if (arg.equals("-urlTarget")) { |
63 | urlTarget = args[++i]; |
64 | } else if (arg.equals("-user")) { |
65 | user = args[++i]; |
66 | } else if (arg.equals("-password")) { |
67 | password = args[++i]; |
68 | } else if (arg.equals("-serverList")) { |
69 | serverList = args[++i]; |
70 | } else if (arg.equals("-help") || arg.equals("-?")) { |
71 | showUsage(); |
72 | return; |
73 | } else { |
74 | showUsageAndThrowUnsupportedOption(arg); |
75 | } |
76 | } |
77 | if (urlSource == null || urlTarget == null || serverList == null) { |
78 | showUsage(); |
79 | throw new SQLException("Source URL, target URL, or server list not set"); |
80 | } |
81 | process(urlSource, urlTarget, user, password, serverList); |
82 | } |
83 | |
84 | /** |
85 | * Creates a cluster. |
86 | * |
87 | * @param urlSource the database URL of the original database |
88 | * @param urlTarget the database URL of the copy |
89 | * @param user the user name |
90 | * @param password the password |
91 | * @param serverList the server list |
92 | */ |
93 | public void execute(String urlSource, String urlTarget, |
94 | String user, String password, String serverList) throws SQLException { |
95 | process(urlSource, urlTarget, user, password, serverList); |
96 | } |
97 | |
98 | private void process(String urlSource, String urlTarget, |
99 | String user, String password, String serverList) throws SQLException { |
100 | Connection connSource = null, connTarget = null; |
101 | Statement statSource = null, statTarget = null; |
102 | String scriptFile = "backup.sql"; |
103 | try { |
104 | org.h2.Driver.load(); |
105 | |
106 | // verify that the database doesn't exist, |
107 | // or if it exists (an old cluster instance), it is deleted |
108 | boolean exists = true; |
109 | try { |
110 | connTarget = DriverManager.getConnection(urlTarget + |
111 | ";IFEXISTS=TRUE;CLUSTER=" + Constants.CLUSTERING_ENABLED, |
112 | user, password); |
113 | Statement stat = connTarget.createStatement(); |
114 | stat.execute("DROP ALL OBJECTS DELETE FILES"); |
115 | stat.close(); |
116 | exists = false; |
117 | connTarget.close(); |
118 | } catch (SQLException e) { |
119 | if (e.getErrorCode() == ErrorCode.DATABASE_NOT_FOUND_1) { |
120 | // database does not exists yet - ok |
121 | exists = false; |
122 | } else { |
123 | throw e; |
124 | } |
125 | } |
126 | if (exists) { |
127 | throw new SQLException( |
128 | "Target database must not yet exist. Please delete it first: " + |
129 | urlTarget); |
130 | } |
131 | |
132 | // use cluster='' so connecting is possible |
133 | // even if the cluster is enabled |
134 | connSource = DriverManager.getConnection(urlSource + |
135 | ";CLUSTER=''", user, password); |
136 | statSource = connSource.createStatement(); |
137 | |
138 | // enable the exclusive mode and close other connections, |
139 | // so that data can't change while restoring the second database |
140 | statSource.execute("SET EXCLUSIVE 2"); |
141 | |
142 | try { |
143 | |
144 | // backup |
145 | Script script = new Script(); |
146 | script.setOut(out); |
147 | Script.process(connSource, scriptFile, "", ""); |
148 | |
149 | // delete the target database and then restore |
150 | connTarget = DriverManager.getConnection( |
151 | urlTarget + ";CLUSTER=''", user, password); |
152 | statTarget = connTarget.createStatement(); |
153 | statTarget.execute("DROP ALL OBJECTS DELETE FILES"); |
154 | connTarget.close(); |
155 | |
156 | RunScript runScript = new RunScript(); |
157 | runScript.setOut(out); |
158 | runScript.process(urlTarget, user, password, scriptFile, null, false); |
159 | |
160 | connTarget = DriverManager.getConnection(urlTarget, user, password); |
161 | statTarget = connTarget.createStatement(); |
162 | |
163 | // set the cluster to the serverList on both databases |
164 | statSource.executeUpdate("SET CLUSTER '" + serverList + "'"); |
165 | statTarget.executeUpdate("SET CLUSTER '" + serverList + "'"); |
166 | } finally { |
167 | |
168 | // switch back to the regular mode |
169 | statSource.execute("SET EXCLUSIVE FALSE"); |
170 | } |
171 | } finally { |
172 | FileUtils.delete(scriptFile); |
173 | JdbcUtils.closeSilently(statSource); |
174 | JdbcUtils.closeSilently(statTarget); |
175 | JdbcUtils.closeSilently(connSource); |
176 | JdbcUtils.closeSilently(connTarget); |
177 | } |
178 | } |
179 | |
180 | } |