1 /*******************************************************************************
\r
2 * ============LICENSE_START==================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
25 package com.att.research.datarouter.provisioning.utils;
\r
27 import java.io.File;
\r
28 import java.io.FileReader;
\r
29 import java.io.IOException;
\r
30 import java.io.InputStream;
\r
31 import java.io.LineNumberReader;
\r
32 import java.lang.reflect.Constructor;
\r
33 import java.lang.reflect.InvocationTargetException;
\r
34 import java.sql.Connection;
\r
35 import java.sql.DatabaseMetaData;
\r
36 import java.sql.DriverManager;
\r
37 import java.sql.PreparedStatement;
\r
38 import java.sql.ResultSet;
\r
39 import java.sql.SQLException;
\r
40 import java.sql.Statement;
\r
41 import java.util.HashSet;
\r
42 import java.util.LinkedList;
\r
43 import java.util.NoSuchElementException;
\r
44 import java.util.Properties;
\r
45 import java.util.Queue;
\r
46 import java.util.Set;
\r
48 import org.apache.log4j.Logger;
\r
50 import com.att.research.datarouter.provisioning.beans.DeliveryRecord;
\r
51 import com.att.research.datarouter.provisioning.beans.ExpiryRecord;
\r
52 import com.att.research.datarouter.provisioning.beans.Loadable;
\r
53 import com.att.research.datarouter.provisioning.beans.PublishRecord;
\r
56 * Load the DB JDBC driver, and manage a simple pool of connections to the DB.
\r
58 * @author Robert Eby
\r
62 /** The name of the properties file (in CLASSPATH) */
\r
63 public static final String CONFIG_FILE = "provserver.properties";
\r
65 private static String DB_DRIVER = "com.mysql.jdbc.Driver";
\r
66 private static String DB_URL = "jdbc:mysql://127.0.0.1:3306/datarouter";
\r
67 private static String DB_LOGIN = "datarouter";
\r
68 private static String DB_PASSWORD = "datarouter";
\r
69 private static Properties props;
\r
70 private static Logger intlogger = Logger.getLogger("com.att.research.datarouter.provisioning.internal");
\r
71 private static Queue<Connection> queue = new LinkedList<Connection>();
\r
73 public static String HTTPS_PORT;
\r
74 public static String HTTP_PORT;
\r
77 * Construct a DB object. If this is the very first creation of this object, it will load a copy
\r
78 * of the properties for the server, and attempt to load the JDBC driver for the database. If a fatal
\r
79 * error occurs (e.g. either the properties file or the DB driver is missing), the JVM will exit.
\r
82 if (props == null) {
\r
83 props = new Properties();
\r
84 InputStream inStream = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE);
\r
86 props.load(inStream);
\r
87 DB_DRIVER = (String) props.get("com.att.research.datarouter.db.driver");
\r
88 DB_URL = (String) props.get("com.att.research.datarouter.db.url");
\r
89 DB_LOGIN = (String) props.get("com.att.research.datarouter.db.login");
\r
90 DB_PASSWORD = (String) props.get("com.att.research.datarouter.db.password");
\r
91 HTTPS_PORT = (String) props.get("com.att.research.datarouter.provserver.https.port");
\r
92 HTTP_PORT = (String) props.get("com.att.research.datarouter.provserver.http.port");
\r
93 Class.forName(DB_DRIVER);
\r
94 } catch (IOException e) {
\r
95 intlogger.fatal("PROV9003 Opening properties: "+e.getMessage());
\r
96 e.printStackTrace();
\r
98 } catch (ClassNotFoundException e) {
\r
99 intlogger.fatal("PROV9004 cannot find the DB driver: "+e);
\r
100 e.printStackTrace();
\r
105 } catch (IOException e) {
\r
111 * Get the provisioning server properties (loaded from provserver.properties).
\r
112 * @return the Properties object
\r
114 public Properties getProperties() {
\r
118 * Get a JDBC connection to the DB from the pool. Creates a new one if none are available.
\r
119 * @return the Connection
\r
120 * @throws SQLException
\r
122 @SuppressWarnings("resource")
\r
123 public Connection getConnection() throws SQLException {
\r
124 Connection c = null;
\r
125 while (c == null) {
\r
126 synchronized (queue) {
\r
128 c = queue.remove();
\r
129 } catch (NoSuchElementException e) {
\r
132 // Try up to 3 times to get a connection
\r
134 c = DriverManager.getConnection(DB_URL, DB_LOGIN, DB_PASSWORD);
\r
135 } catch (SQLException e1) {
\r
139 } while (c == null);
\r
142 if (c != null && !c.isValid(1)) {
\r
150 * Returns a JDBC connection to the pool.
\r
151 * @param c the Connection to return
\r
152 * @throws SQLException
\r
154 public void release(Connection c) {
\r
156 synchronized (queue) {
\r
157 if (!queue.contains(c))
\r
164 * Run all necessary retrofits required to bring the database up to the level required for this version
\r
165 * of the provisioning server. This should be run before the server itself is started.
\r
166 * @return true if all retrofits worked, false otherwise
\r
168 public boolean runRetroFits() {
\r
177 && retroFit9() //New retroFit call to add CREATED_DATE column Rally:US674199 - 1610
\r
178 && retroFit10() //New retroFit call to add BUSINESS_DESCRIPTION column Rally:US708102 - 1610
\r
179 && retroFit11() //New retroFit call for groups feature Rally:US708115 - 1610
\r
183 * Retrofit 1 - Make sure the expected tables are in MySQL and are initialized.
\r
184 * Uses mysql_init_0000 and mysql_init_0001 to setup the DB.
\r
185 * @return true if the retrofit worked, false otherwise
\r
187 private boolean retroFit1() {
\r
188 final String[] expected_tables = {
\r
189 "FEEDS", "FEED_ENDPOINT_ADDRS", "FEED_ENDPOINT_IDS", "PARAMETERS", "SUBSCRIPTIONS"
\r
191 Connection c = null;
\r
193 c = getConnection();
\r
194 Set<String> tables = getTableSet(c);
\r
195 boolean initialize = false;
\r
196 for (String s : expected_tables) {
\r
197 initialize |= !tables.contains(s);
\r
200 intlogger.info("PROV9001: First time startup; The database is being initialized.");
\r
201 runInitScript(c, 0); // script 0 creates the provisioning tables
\r
202 runInitScript(c, 1); // script 1 initializes PARAMETERS
\r
204 } catch (SQLException e) {
\r
205 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
214 * Retrofit 2 - if the LOG_RECORDS table is missing, add it.
\r
215 * Uses mysql_init_0002 to create this table.
\r
216 * @return true if the retrofit worked, false otherwise
\r
218 private boolean retroFit2() {
\r
219 Connection c = null;
\r
221 // If LOG_RECORDS table is missing, add it
\r
222 c = getConnection();
\r
223 Set<String> tables = getTableSet(c);
\r
224 if (!tables.contains("LOG_RECORDS")) {
\r
225 intlogger.info("PROV9002: Creating LOG_RECORDS table.");
\r
226 runInitScript(c, 2); // script 2 creates the LOG_RECORDS table
\r
228 } catch (SQLException e) {
\r
229 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
238 * Retrofit 3 - if the FEEDS_UNIQUEID table (from release 1.0.*) exists, drop it.
\r
239 * If SUBSCRIPTIONS.SUBID still has the auto_increment attribute, remove it.
\r
240 * @return true if the retrofit worked, false otherwise
\r
242 @SuppressWarnings("resource")
\r
243 private boolean retroFit3() {
\r
244 Connection c = null;
\r
246 // if SUBSCRIPTIONS.SUBID still has auto_increment, remove it
\r
247 boolean doremove = false;
\r
248 c = getConnection();
\r
249 DatabaseMetaData md = c.getMetaData();
\r
250 ResultSet rs = md.getColumns("datarouter", "", "SUBSCRIPTIONS", "SUBID");
\r
252 while (rs.next()) {
\r
253 doremove = rs.getString("IS_AUTOINCREMENT").equals("YES");
\r
259 intlogger.info("PROV9002: Modifying SUBSCRIPTIONS SUBID column to remove auto increment.");
\r
260 Statement s = c.createStatement();
\r
261 s.execute("ALTER TABLE SUBSCRIPTIONS MODIFY COLUMN SUBID INT UNSIGNED NOT NULL");
\r
265 // Remove the FEEDS_UNIQUEID table, if it exists
\r
266 Set<String> tables = getTableSet(c);
\r
267 if (tables.contains("FEEDS_UNIQUEID")) {
\r
268 intlogger.info("PROV9002: Dropping FEEDS_UNIQUEID table.");
\r
269 Statement s = c.createStatement();
\r
270 s.execute("DROP TABLE FEEDS_UNIQUEID");
\r
273 } catch (SQLException e) {
\r
274 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
282 private long nextid = 0; // used for initial creation of LOG_RECORDS table.
\r
284 * Retrofit 4 - if old log tables exist (from release 1.0.*), copy them to LOG_RECORDS, then drop them.
\r
285 * @return true if the retrofit worked, false otherwise
\r
287 @SuppressWarnings("resource")
\r
288 private boolean retroFit4() {
\r
289 Connection c = null;
\r
291 c = getConnection();
\r
292 Set<String> tables = getTableSet(c);
\r
293 if (tables.contains("PUBLISH_RECORDS")) {
\r
294 intlogger.info("PROV9002: Copying PUBLISH_RECORDS to LOG_RECORDS table.");
\r
295 copyLogTable("PUBLISH_RECORDS", PublishRecord.class);
\r
296 intlogger.info("PROV9002: Dropping PUBLISH_RECORDS table.");
\r
297 Statement s = c.createStatement();
\r
298 s.execute("DROP TABLE PUBLISH_RECORDS");
\r
301 if (tables.contains("DELIVERY_RECORDS")) {
\r
302 intlogger.info("PROV9002: Copying DELIVERY_RECORDS to LOG_RECORDS table.");
\r
303 copyLogTable("DELIVERY_RECORDS", DeliveryRecord.class);
\r
304 intlogger.info("PROV9002: Dropping DELIVERY_RECORDS table.");
\r
305 Statement s = c.createStatement();
\r
306 s.execute("DROP TABLE DELIVERY_RECORDS");
\r
309 if (tables.contains("EXPIRY_RECORDS")) {
\r
310 intlogger.info("PROV9002: Copying EXPIRY_RECORDS to LOG_RECORDS table.");
\r
311 copyLogTable("EXPIRY_RECORDS", ExpiryRecord.class);
\r
312 intlogger.info("PROV9002: Dropping EXPIRY_RECORDS table.");
\r
313 Statement s = c.createStatement();
\r
314 s.execute("DROP TABLE EXPIRY_RECORDS");
\r
317 } catch (SQLException e) {
\r
318 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
327 * Retrofit 5 - Create the new routing tables required for Release 2.
\r
328 * Adds a new "SUSPENDED" column to FEEDS and SUBSCRIPTIONS.
\r
329 * Modifies the LOG_RECORDS table to handle new R2 records.
\r
330 * @return true if the retrofit worked, false otherwise
\r
332 @SuppressWarnings("resource")
\r
333 private boolean retroFit5() {
\r
334 final String[] expected_tables = {
\r
335 "INGRESS_ROUTES", "EGRESS_ROUTES", "NETWORK_ROUTES", "NODESETS", "NODES"
\r
337 Connection c = null;
\r
339 // If expected tables are not present, then add new routing tables
\r
340 c = getConnection();
\r
341 Set<String> tables = getTableSet(c);
\r
342 boolean initialize = false;
\r
343 for (String s : expected_tables) {
\r
344 initialize |= !tables.contains(s);
\r
347 intlogger.info("PROV9002: Adding routing tables for Release 2.0.");
\r
348 runInitScript(c, 3); // script 3 creates the routing tables
\r
351 // Add SUSPENDED column to FEEDS/SUBSCRIPTIONS
\r
352 DatabaseMetaData md = c.getMetaData();
\r
353 for (String tbl : new String[] {"FEEDS", "SUBSCRIPTIONS" }) {
\r
354 boolean add_col = true;
\r
355 ResultSet rs = md.getColumns("datarouter", "", tbl, "SUSPENDED");
\r
357 add_col = !rs.next();
\r
362 intlogger.info("PROV9002: Adding SUSPENDED column to "+tbl+" table.");
\r
363 Statement s = c.createStatement();
\r
364 s.execute("ALTER TABLE "+tbl+" ADD COLUMN SUSPENDED BOOLEAN DEFAULT FALSE");
\r
369 // Modify LOG_RECORDS for R2
\r
370 intlogger.info("PROV9002: Modifying LOG_RECORDS table.");
\r
371 Statement s = c.createStatement();
\r
372 s.execute("ALTER TABLE LOG_RECORDS MODIFY COLUMN TYPE ENUM('pub', 'del', 'exp', 'pbf', 'dlx') NOT NULL");
\r
374 s = c.createStatement();
\r
375 s.execute("ALTER TABLE LOG_RECORDS MODIFY COLUMN REASON ENUM('notRetryable', 'retriesExhausted', 'diskFull', 'other')");
\r
377 boolean add_col = true;
\r
378 ResultSet rs = md.getColumns("datarouter", "", "LOG_RECORDS", "CONTENT_LENGTH_2");
\r
380 add_col = !rs.next();
\r
385 intlogger.info("PROV9002: Fixing two columns in LOG_RECORDS table (this may take some time).");
\r
386 s = c.createStatement();
\r
387 s.execute("ALTER TABLE LOG_RECORDS MODIFY COLUMN CONTENT_LENGTH BIGINT NOT NULL, ADD COLUMN CONTENT_LENGTH_2 BIGINT AFTER RECORD_ID");
\r
390 } catch (SQLException e) {
\r
391 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
400 * Retrofit 6 - Adjust LOG_RECORDS.USER to be 50 chars (MR #74).
\r
401 * @return true if the retrofit worked, false otherwise
\r
403 @SuppressWarnings("resource")
\r
404 private boolean retroFit6() {
\r
405 Connection c = null;
\r
407 c = getConnection();
\r
408 // Modify LOG_RECORDS for R2
\r
409 intlogger.info("PROV9002: Modifying LOG_RECORDS.USER length.");
\r
410 Statement s = c.createStatement();
\r
411 s.execute("ALTER TABLE LOG_RECORDS MODIFY COLUMN USER VARCHAR(50)");
\r
413 } catch (SQLException e) {
\r
414 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
423 * Retrofit 7 - Adjust LOG_RECORDS.FEED_FILEID and LOG_RECORDS.DELIVERY_FILEID to be 256 chars.
\r
424 * @return true if the retrofit worked, false otherwise
\r
426 @SuppressWarnings("resource")
\r
427 private boolean retroFit7() {
\r
428 Connection c = null;
\r
430 c = getConnection();
\r
431 // Modify LOG_RECORDS for long (>128) FILEIDs
\r
432 intlogger.info("PROV9002: Modifying LOG_RECORDS.USER length.");
\r
433 Statement s = c.createStatement();
\r
434 s.execute("ALTER TABLE LOG_RECORDS MODIFY COLUMN FEED_FILEID VARCHAR(256), MODIFY COLUMN DELIVERY_FILEID VARCHAR(256)");
\r
436 } catch (SQLException e) {
\r
437 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
446 * Retrofit 8 - Adjust FEEDS.NAME to be 255 chars (MR #74).
\r
447 * @return true if the retrofit worked, false otherwise
\r
449 @SuppressWarnings("resource")
\r
450 private boolean retroFit8() {
\r
451 Connection c = null;
\r
453 c = getConnection();
\r
454 intlogger.info("PROV9002: Modifying FEEDS.NAME length.");
\r
455 Statement s = c.createStatement();
\r
456 s.execute("ALTER TABLE FEEDS MODIFY COLUMN NAME VARCHAR(255)");
\r
458 } catch (SQLException e) {
\r
459 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
469 * Retrofit 9 - Add column FEEDS.CREATED_DATE and SUBSCRIPTIONS.CREATED_DATE, 1610 release user story US674199.
\r
470 * @return true if the retrofit worked, false otherwise
\r
473 @SuppressWarnings("resource")
\r
474 private boolean retroFit9() {
\r
475 Connection c = null;
\r
477 c = getConnection();
\r
478 // Add CREATED_DATE column to FEEDS/SUBSCRIPTIONS tables
\r
479 DatabaseMetaData md = c.getMetaData();
\r
480 for (String tbl : new String[] {"FEEDS", "SUBSCRIPTIONS" }) {
\r
481 boolean add_col = true;
\r
482 ResultSet rs = md.getColumns("datarouter", "", tbl, "CREATED_DATE");
\r
484 add_col = !rs.next();
\r
489 intlogger.info("PROV9002: Adding CREATED_DATE column to "+tbl+" table.");
\r
490 Statement s = c.createStatement();
\r
491 s.execute("ALTER TABLE "+tbl+" ADD COLUMN CREATED_DATE timestamp DEFAULT CURRENT_TIMESTAMP");
\r
495 } catch (SQLException e) {
\r
496 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
506 * Retrofit 10 -Adding business BUSINESS_DESCRIPTION to FEEDS table (Rally
\r
509 * @return true if the retrofit worked, false otherwise
\r
512 @SuppressWarnings("resource")
\r
513 private boolean retroFit10() {
\r
514 Connection c = null;
\r
515 boolean addColumn = true;
\r
519 c = getConnection();
\r
520 // Add BUSINESS_DESCRIPTION column to FEEDS table
\r
521 DatabaseMetaData md = c.getMetaData();
\r
522 boolean add_col = true;
\r
523 ResultSet rs = md.getColumns("datarouter", "", "FEEDS", "BUSINESS_DESCRIPTION");
\r
525 add_col = !rs.next();
\r
531 .info("PROV9002: Adding BUSINESS_DESCRIPTION column to FEEDS table.");
\r
532 Statement s = c.createStatement();
\r
533 s.execute("ALTER TABLE FEEDS ADD COLUMN BUSINESS_DESCRIPTION varchar(1000) DEFAULT NULL AFTER DESCRIPTION, MODIFY COLUMN DESCRIPTION VARCHAR(1000)");
\r
537 catch (SQLException e) {
\r
539 .fatal("PROV9000: The database credentials are not working: "
\r
550 /*New retroFit method is added for groups feature Rally:US708115 - 1610
\r
553 * @return - boolean if table and fields are created (Group table, group id in FEEDS, SUBSCRIPTION TABLES)
\r
555 @SuppressWarnings("resource")
\r
556 private boolean retroFit11() {
\r
557 final String[] expected_tables = {
\r
560 Connection c = null;
\r
563 // If expected tables are not present, then add new routing tables
\r
564 c = getConnection();
\r
565 Set<String> tables = getTableSet(c);
\r
566 boolean initialize = false;
\r
567 for (String s : expected_tables) {
\r
568 initialize |= !tables.contains(s);
\r
571 intlogger.info("PROV9002: Adding GROUPS table for Release 1610.");
\r
572 runInitScript(c, 4); // script 4 creates the routing tables
\r
575 // Add GROUPID column to FEEDS/SUBSCRIPTIONS
\r
576 DatabaseMetaData md = c.getMetaData();
\r
577 for (String tbl : new String[] {"FEEDS", "SUBSCRIPTIONS" }) {
\r
578 boolean add_col = true;
\r
579 ResultSet rs = md.getColumns("datarouter", "", tbl, "GROUPID");
\r
581 add_col = !rs.next();
\r
586 intlogger.info("PROV9002: Adding GROUPID column to "+tbl+" table.");
\r
587 Statement s = c.createStatement();
\r
588 s.execute("ALTER TABLE "+tbl+" ADD COLUMN GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0 AFTER FEEDID");
\r
592 } catch (SQLException e) {
\r
593 intlogger.fatal("PROV9000: The database credentials are not working: "+e.getMessage());
\r
604 * Copy the log table <i>table_name</i> to LOG_RECORDS;
\r
605 * @param table_name the name of the old (1.0.*) table to copy
\r
606 * @param table_class the class used to instantiate a record from the table
\r
607 * @throws SQLException if there is a problem getting a MySQL connection
\r
609 @SuppressWarnings("resource")
\r
610 private void copyLogTable(String table_name, Class<? extends Loadable> table_class) throws SQLException {
\r
611 long start = System.currentTimeMillis();
\r
613 Connection c1 = getConnection();
\r
614 Connection c2 = getConnection();
\r
617 Constructor<? extends Loadable> cnst = table_class.getConstructor(ResultSet.class);
\r
618 PreparedStatement ps = c2.prepareStatement(LogfileLoader.INSERT_SQL);
\r
619 Statement stmt = c1.createStatement();
\r
620 ResultSet rs = stmt.executeQuery("select * from "+table_name);
\r
621 while (rs.next()) {
\r
622 Loadable rec = cnst.newInstance(rs);
\r
624 ps.setLong(18, ++nextid);
\r
625 ps.executeUpdate();
\r
626 if ((++n % 10000) == 0)
\r
627 intlogger.debug(" "+n+" records done.");
\r
631 } catch (SQLException e) {
\r
632 e.printStackTrace();
\r
633 } catch (NoSuchMethodException e) {
\r
634 e.printStackTrace();
\r
635 } catch (SecurityException e) {
\r
636 e.printStackTrace();
\r
637 } catch (InstantiationException e) {
\r
638 e.printStackTrace();
\r
639 } catch (IllegalAccessException e) {
\r
640 e.printStackTrace();
\r
641 } catch (IllegalArgumentException e) {
\r
642 e.printStackTrace();
\r
643 } catch (InvocationTargetException e) {
\r
644 e.printStackTrace();
\r
649 long x = (System.currentTimeMillis() - start);
\r
650 intlogger.debug(" "+n+" records done in "+x+" ms.");
\r
654 * Get a set of all table names in the DB.
\r
655 * @param c a DB connection
\r
656 * @return the set of table names
\r
658 private Set<String> getTableSet(Connection c) {
\r
659 Set<String> tables = new HashSet<String>();
\r
661 DatabaseMetaData md = c.getMetaData();
\r
662 ResultSet rs = md.getTables("datarouter", "", "", null);
\r
664 while (rs.next()) {
\r
665 tables.add(rs.getString("TABLE_NAME"));
\r
669 } catch (SQLException e) {
\r
674 * Initialize the tables by running the initialization scripts located in the directory specified
\r
675 * by the property <i>com.att.research.datarouter.provserver.dbscripts</i>. Scripts have names of
\r
676 * the form mysql_init_NNNN.
\r
677 * @param c a DB connection
\r
678 * @param n the number of the mysql_init_NNNN script to run
\r
680 private void runInitScript(Connection c, int n) {
\r
681 String scriptdir = (String) props.get("com.att.research.datarouter.provserver.dbscripts");
\r
682 StringBuilder sb = new StringBuilder();
\r
684 String scriptfile = String.format("%s/mysql_init_%04d", scriptdir, n);
\r
685 if (!(new File(scriptfile)).exists())
\r
688 LineNumberReader in = new LineNumberReader(new FileReader(scriptfile));
\r
690 while ((line = in.readLine()) != null) {
\r
691 if (!line.startsWith("--")) {
\r
692 line = line.trim();
\r
694 if (line.endsWith(";")) {
\r
695 // Execute one DDL statement
\r
696 String sql = sb.toString();
\r
698 Statement s = c.createStatement();
\r
706 } catch (Exception e) {
\r
707 intlogger.fatal("PROV9002 Error when initializing table: "+e.getMessage());
\r