1 /***
2 * Copyright 2007 ATG DUST Project Licensed under the Apache License, Version
3 * 2.0 (the "License"); you may not use this file except in compliance with the
4 * License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 * or agreed to in writing, software distributed under the License is
7 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 * KIND, either express or implied. See the License for the specific language
9 * governing permissions and limitations under the License.
10 */
11
12 package atg.adapter.gsa;
13
14 import java.sql.Connection;
15 import java.sql.DatabaseMetaData;
16 import java.sql.ResultSet;
17 import java.sql.SQLException;
18 import java.sql.Statement;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.StringTokenizer;
24
25 import javax.sql.DataSource;
26
27 import atg.core.util.StringUtils;
28 import atg.dtm.TransactionDemarcation;
29 import atg.dtm.TransactionDemarcationException;
30 import atg.nucleus.GenericService;
31 import atg.nucleus.ServiceException;
32
33 /***
34 * This class is designed to assist with database table manipulation such as
35 * adding tables. Parts copied from atg.service.idgen.?? by mgk
36 *
37 * @author mf
38 * @version 1.0
39 **/
40 public class SQLProcessorEngine extends GenericService {
41
42
43 public static final String APACHE_DERBY = "Apache Derby";
44
45
46
47 /***
48 * empty constructor
49 */
50 public SQLProcessorEngine() {
51 };
52
53 /***
54 * Construct a generator
55 **/
56 public SQLProcessorEngine(GSARepository pRep) {
57 setRepository(pRep);
58 mDataSource = getRepository().getDataSource();
59 }
60
61
62 /***
63 * DataSource from which to get DB connections this property is NOT a public
64 * property because it is extracted from the repository property
65 */
66 DataSource mDataSource;
67
68 private void setDataSource(DataSource pDataSource) {
69 mDataSource = pDataSource;
70 }
71
72 private DataSource getDataSource() {
73 return mDataSource;
74 }
75
76 /***
77 * GSARespository from which to get the DataSource and TransactionManager
78 */
79 GSARepository mRepository;
80
81 public void setRepository(GSARepository pRep) {
82 mRepository = pRep;
83 }
84
85 public GSARepository getRepository() {
86 return mRepository;
87 }
88
89 /***
90 * String executed to determine whether a table exists. The table name is
91 * appended to the end of the string before execution occurs.
92 */
93 String mDetermineTableExistsSQL = "SELECT count(*) from";
94
95 public void setDetermineTableExistsSQL(String pStr) {
96 mDetermineTableExistsSQL = pStr;
97 }
98
99 public String getDetermineTableExistsSQL() {
100 return mDetermineTableExistsSQL;
101 }
102
103 /***
104 * String executed to drop a table. The table name is appended to the end of
105 * the string before execution
106 */
107 String mDropTableSQL = "DROP TABLE";
108
109 public void setDropTableSQL(String pStr) {
110 mDropTableSQL = pStr;
111 }
112
113 public String getDropTableSQL() {
114 return mDropTableSQL;
115 }
116
117 /***
118 * String delimiter used to separate the large String passed to createTables()
119 * into an array of individual Create Table statements default value is
120 * "CREATE TABLE" This delimiter _will_ be included in the final create
121 * statements
122 */
123 String mCreateTableBeginDelimiter = "CREATE TABLE";
124
125 public void setCreateTableBeginDelimiter(String pStr) {
126 mCreateTableBeginDelimiter = pStr;
127 }
128
129 public String getCreateTableBeginDelimiter() {
130 return mCreateTableBeginDelimiter;
131 }
132
133 /***
134 * String delimiter used to separate the large String passed to createTables()
135 * into an array of individual Create Table statements default value is ";"
136 * This delimiter _will not_ be included in the final create statements
137 */
138 String mCreateTableEndDelimiter = ";";
139
140 public void setCreateTableEndDelimiter(String pStr) {
141 mCreateTableEndDelimiter = pStr;
142 }
143
144 public String getCreateTableEndDelimiter() {
145 return mCreateTableEndDelimiter;
146 }
147
148
149
150 /***
151 * method to execute when starting this component
152 */
153 public void doStartService() throws ServiceException {
154 if (getRepository() == null)
155 throw new ServiceException("Repository property is null.");
156
157 setDataSource(getRepository().getDataSource());
158 }
159
160 /***
161 * Get a DB connection
162 *
163 * @return the connection
164 * @exception SQLProcessorException
165 * if there is DB trouble or DataSource trouble
166 **/
167 Connection getConnection() throws SQLProcessorException {
168 try {
169 DataSource ds = getDataSource();
170 if (ds == null)
171 throw new SQLProcessorException("no DataSource");
172 else
173 return ds.getConnection();
174 } catch (SQLException sqle) {
175 if (isLoggingDebug()) {
176 SQLException next = sqle;
177 while (next != null) {
178 logDebug(next);
179 next = next.getNextException();
180 }
181 }
182 throw new SQLProcessorException(sqle);
183 }
184 }
185
186
187 /***
188 * Close a DB connection, logging any SQLExceptions. It is okay to pass a null
189 * connection here
190 *
191 * @param pConnection
192 * connection to close, may be null
193 **/
194 private final void close(Connection pConnection) {
195 if (pConnection != null) {
196 try {
197 pConnection.close();
198 } catch (SQLException sqle) {
199 if (isLoggingError())
200 logError(sqle);
201 }
202 }
203 }
204
205
206 /***
207 * Close a result set, logging any SQLExceptions. It is okay to pass a null
208 * here
209 *
210 * @param pResultSet
211 * result set to close, may be null
212 **/
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 /***
231 * Close a statement, logging any SQLExceptions. It is okay to pass a null
232 * here.
233 *
234 * @param pStatement
235 * statement to close, may be null
236 **/
237 private final void close(Statement pStatement) {
238 if (pStatement != null) {
239 try {
240 pStatement.close();
241 } catch (SQLException sqle) {
242 if (isLoggingError())
243 logError(sqle);
244 }
245 }
246 }
247
248
249 /***
250 * Perform the specified SQL statement in a new transaction which is commited.
251 *
252 * @param pSQL
253 * SQL to execute
254 * @return the # of rows affected
255 * @exception SQLProcessorException
256 * if there is DB or xact trouble
257 **/
258 private int performSQL(String pSQL) throws SQLProcessorException {
259 TransactionDemarcation td = new TransactionDemarcation();
260 SQLProcessorException error = null;
261 int rows = 0;
262 try {
263 td.begin(mRepository.getTransactionManager(),
264 TransactionDemarcation.REQUIRES_NEW);
265 Connection c = null;
266 Statement s = null;
267 try {
268
269 c = getConnection();
270
271
272
273
274
275 s = c.createStatement();
276
277 s.execute(pSQL);
278 } catch (SQLException sqle) {
279 error = new SQLProcessorException(sqle);
280 } finally {
281 close(s);
282 close(c);
283 }
284 } catch (TransactionDemarcationException e1) {
285 if (error == null)
286 error = new SQLProcessorException(e1);
287 else if (isLoggingError())
288 logError(e1);
289 } finally {
290 try {
291 td.end();
292 } catch (TransactionDemarcationException e2) {
293 if (error == null)
294 error = new SQLProcessorException(e2);
295 else if (isLoggingError())
296 logError(e2);
297 }
298 }
299
300 if (error != null)
301 throw error;
302 else
303 return rows;
304 }
305
306 /***
307 * This method is used to create tables in a database. It takes a String that
308 * contains all of the table creation statements and is of the format: CREATE
309 * TABLE foo ( <field specifications> ); ... CREATE TABLE bar ( <field
310 * specifications> ); Specifically, this is the format output by the GSA when
311 * a call is made to generateSQL(); Before making the tables, this large
312 * String will be split apart into an array of individual CREATE TABLE
313 * statements using the createTableBeginDelimiter and createTableEndDelimiter
314 * properties. By default, createTableBeginDelimiter = "CREATE TABLE" and
315 * createTableEndDelimiter = ";"
316 *
317 * @param String
318 * pStr - the String containing the CREATE TABLE statements
319 * @param boolean pDrop - indicates whether to drop tables and recreate them
320 * if the tables already exist in the database
321 * @return boolean true if any tables were created ( or dropped and created )
322 * @exception SQLProcessorException
323 * if an error occurs trying to create the tables
324 */
325 public boolean createTables(List<String> pStatements, boolean pDrop)
326 throws SQLProcessorException {
327 boolean createdTables = false;
328
329
330
331 if (isLoggingDebug())
332 logDebug("Reordering CREATE TABLE statements so references don't fail...");
333 List<String> statements = reorderCreateStatements(pStatements);
334
335
336
337 List<String> tableNames = getTableNames(statements);
338 if (pDrop) {
339 if (isLoggingInfo())
340 logInfo("Dropping tables...");
341 dropTables(tableNames);
342 }
343
344
345
346
347
348 if (isLoggingInfo())
349 logInfo("Creating tables...");
350 Iterator<String> iter = statements.iterator();
351 while (iter.hasNext()) {
352 String statement = iter.next();
353 String name = getTableName(statement);
354 boolean exists = tableExists(name);
355
356 if (name != null && !exists) {
357 if (isLoggingDebug())
358 logDebug("Creating table: " + name);
359 if (this.getRepository() instanceof InitializingGSA) {
360 if (!isLoggingDebug()
361 && ((InitializingGSA) this.getRepository())
362 .isLoggingCreateTables())
363 logDebug(statement);
364 }
365 if (this.getRepository() instanceof InitializingVersionRepository) {
366 if (!isLoggingDebug()
367 && ((InitializingVersionRepository) this.getRepository())
368 .isLoggingCreateTables())
369 logDebug(statement);
370 }
371 if (isDerby())
372 statement = stripNull(statement);
373 createTable(statement);
374 createdTables = true;
375 } else if (name != null && !pDrop) {
376 if (isLoggingInfo())
377 logInfo("Table already exists and dropTablesIfExist is false - not creating: "
378 + name);
379
380
381 } else {
382
383
384 logWarning("The table "
385 + name
386 + " was not created because name was null or table couldn't be dropped.");
387 }
388 }
389
390 return createdTables;
391 }
392
393 /***
394 * Removes any occurrence of the string "NULL" from a create statement if it
395 * is not preceded by the word "NOT".
396 *
397 * @param statement
398 * @return
399 */
400 private String stripNull(String statement) {
401
402
403 StringBuffer subStatements = new StringBuffer();
404 String tempStatement = statement.toUpperCase();
405 StringTokenizer st = new StringTokenizer(tempStatement, ",");
406 while (st.hasMoreTokens()) {
407 String tok = st.nextToken();
408 int notNullIndex = tok.indexOf("NOT NULL");
409 if (notNullIndex > -1) {
410
411 subStatements.append(tok + ",\n");
412 } else if (tok.indexOf("NULL") > -1) {
413
414
415 String temp = StringUtils.replace(tok, "NULL", "");
416
417 subStatements.append(temp.trim() + ",\n");
418 } else {
419
420 if (st.hasMoreTokens())
421 subStatements.append(tok + ",\n");
422 else
423
424 subStatements.append(tok);
425 }
426 }
427 return subStatements.toString();
428 }
429
430 private boolean mIsDerby = false;
431 private boolean mIsDerbySet = false;
432
433 /***
434 * Returns true if the current database is Apache Derby. The first invocation
435 * to this method will cache its answer.
436 */
437 public boolean isDerby() throws SQLProcessorException {
438 if (!mIsDerbySet) {
439 mIsDerby = isDerbyUncached();
440 mIsDerbySet = true;
441 }
442 return mIsDerby;
443 }
444
445 /***
446 * Returns true if the current database is Apache Derby This method call is
447 * not cached and will make a database connection attempt on each invocation.
448 *
449 * @return
450 * @throws SQLProcessorException
451 */
452 private boolean isDerbyUncached() throws SQLProcessorException {
453 boolean isDerby = false;
454 Connection c = null;
455 try {
456 c = getConnection();
457 DatabaseMetaData meta = c.getMetaData();
458 if (APACHE_DERBY.equals(meta.getDatabaseProductName())) {
459 isDerby = true;
460 }
461 return isDerby;
462 } catch (SQLException e) {
463 throw new SQLProcessorException(e);
464 } finally {
465 if (c != null) {
466 try {
467 c.close();
468 } catch (SQLException e) {
469 ;
470 }
471 }
472 }
473 }
474
475 /***
476 * This is a method that is used to execute a 'CREATE TABLE' call. The String
477 * you pass in is expected to be of the format CREATE TABLE ( ..... )
478 *
479 * @return void
480 * @exception SQLProcessorException
481 * thrown if an error occurs creating the table
482 */
483 private void createTable(String pStr) throws SQLProcessorException {
484 try {
485 performSQL(pStr);
486 } catch (SQLProcessorException spe) {
487 throw new SQLProcessorException(
488 "Caught exception executing create table statement \"" + pStr + "\"",
489 spe);
490 }
491 }
492
493 /***
494 * This method is used to iteratively drop tables. The iterative effort is
495 * necessary because tables may have references. ASSUMPTION: references only
496 * exist for tables that are defined within this repository. If references
497 * exist from tables outside this repository, this method will throw a
498 * SQLProcessorException
499 *
500 * @param Vector
501 * of CREATE TABLE statements indicating which tables to drop
502 * @exception SQLProcessorException
503 * thrown if all tables can not be dropped
504 */
505 public void dropTablesFromCreateStatements(List<String> pCreateStatements)
506 throws SQLProcessorException {
507 List<String> names = getTableNames(pCreateStatements);
508 dropTables(names);
509 }
510
511 /***
512 * This method is used to iteratively drop tables. The iterative effort is
513 * necessary because tables may have references. ASSUMPTION: references only
514 * exist for tables that are defined within this repository. If references
515 * exist from tables outside this repository, this method will throw a
516 * SQLProcessorException
517 *
518 * @param Vector
519 * of names of tables to be dropped
520 * @exception SQLProcessorException
521 * thrown if all tables can not be dropped
522 */
523 private void dropTables(List<String> pNames) throws SQLProcessorException {
524
525
526 int maxIterations = pNames.size();
527
528
529 List<String> tablesToDrop = pNames;
530
531 List<String> remainingTables;
532 int attempt = 0;
533 do {
534 remainingTables = new ArrayList<String>();
535 Iterator<String> tables = tablesToDrop.iterator();
536 while (tables.hasNext()) {
537 String table = tables.next();
538 if (tableExists(table)) {
539 try {
540 logInfo("Attempting to drop table: " + table);
541 dropTable(table);
542 logInfo("Dropped table: " + table);
543 } catch (SQLProcessorException spe) {
544
545 if (attempt + 1 >= maxIterations)
546 throw spe;
547
548
549 remainingTables.add(table);
550 }
551 }
552 }
553 tablesToDrop = remainingTables;
554
555 } while ((attempt++ < maxIterations) && (!remainingTables.isEmpty()));
556 }
557
558 /***
559 * This is a method that is used to execute a 'Drop Table' call. The method
560 * creates the drop table statement by appending the name passed as a method
561 * with the SQL that has been set as the dropTableSQL property. By default,
562 * this property is set to "Drop table"
563 *
564 * @param String
565 * - the name of the table to drop
566 * @exception SQLProcessorException
567 * thrown if an error occurs trying to drop the table
568 */
569 private void dropTable(String pName) throws SQLProcessorException {
570 String sql = getDropTableSQL() + " " + pName;
571
572 try {
573
574 logDebug("Attempting to drop table: " + pName);
575
576 performSQL(sql);
577
578 } catch (SQLProcessorException spe) {
579 throw new SQLProcessorException(
580 "Caught exception executing drop table statement \"" + sql + "\"",
581 spe);
582 }
583 }
584
585 /***
586 * This method is used to extract table names from a Vector of CREATE
587 * statements returned by either a call to getCreateStatements() or
588 * getOrderedCreateStatements()
589 *
590 * @return Vector of table names
591 */
592 private List<String> getTableNames(List<String> pStatements) {
593 if (isLoggingDebug())
594 logDebug("Getting table names...");
595
596 List<String> names = new ArrayList<String>();
597
598
599 List<String> createStatements = pStatements;
600
601
602 Iterator<String> iter = createStatements.iterator();
603 while (iter.hasNext()) {
604 String thisName = getTableName(iter.next());
605
606 if (thisName != null && !names.contains(thisName)) {
607 names.add(thisName);
608 if (isLoggingDebug())
609 logDebug("Found table name: " + thisName);
610 }
611 }
612
613 return names;
614 }
615
616 /***
617 * This is a method used to extract the table name from a CREATE TABLE
618 * statement. It operates by finding the createTableBeginDelimiter and
619 * extracting the next word after the delimiter.
620 *
621 * @param String
622 * - the create table statement
623 * @return String - the name of the table; null if name can't be found
624 */
625 private String getTableName(String pStr) {
626 String STATEMENT_BEGIN = getCreateTableBeginDelimiter();
627
628 if (isLoggingDebug() && (this.getRepository().getDebugLevel() > 6)) {
629 logDebug("Extracting table name from create table statement: " + pStr);
630 logDebug("Name is taken as word after createTableBeginDelimiter. Delimiter is set to: "
631 + getCreateTableBeginDelimiter());
632 }
633
634 int index = pStr.indexOf(STATEMENT_BEGIN);
635 if (index == -1) {
636 if (isLoggingWarning())
637 logWarning("Could not extract name because start delimiter could not be found. Returning null.");
638 return null;
639 }
640
641 pStr = pStr.substring(index + STATEMENT_BEGIN.length());
642
643
644 while (pStr.startsWith(" ") && (pStr.length() > 1)) {
645 pStr = pStr.substring(1);
646 }
647
648 int first_blank = pStr.indexOf(" ");
649 if (!(first_blank > 0)) {
650 if (isLoggingDebug())
651 logDebug("Could not extract name because no word was found after the start delimiter. Returning null.");
652 return null;
653 }
654
655 String name = pStr.substring(0, first_blank);
656 if (isLoggingDebug())
657 logDebug("Extracted table name: " + name);
658 return name;
659 }
660
661 /***
662 * This method is used to break the large string passed to createTables() into
663 * an array of CREATE TABLE statements. The string is split apart using the
664 * createTableBeginDelimiter and createTableEndDelimiter Strings. These can be
665 * set as the createTableBeginDelimiter and createTableEndDelimiter
666 * properties.
667 *
668 * @param String
669 * - String containing all the Create Table statements
670 * @return Vector of CREATE TABLE statements
671 */
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711 /***
712 * This method is used to order CREATE TABLE statments such that we do not try
713 * to create a table before any tables that it references. NOTE: if a
714 * reference exists for a table outside of this repository we will print a
715 * warning, but will _not_ throw an exception. If the referenced table doesn't
716 * exist, an exception will be thrown when the referencing table is created.
717 *
718 * @param String
719 * containing all of the CREATE TABLE statements as generated by a
720 * call to GSARepository.generateSQL()
721 * @return Vector of individual CREATE statements that are in the proper order
722 * to execute
723 * @exception SQLProcessorException
724 * if we detect a bad loop trying to resolve references
725 */
726 private List<String> reorderCreateStatements(List<String> pStatements)
727 throws SQLProcessorException {
728 List<String> statements = pStatements;
729 List<String> names = getTableNames(statements);
730 List<String> orderedStatements = new ArrayList<String>();
731
732
733
734 HashMap<String, List<String>> refersTo = new HashMap<String, List<String>>();
735
736
737 HashMap<String, List<String>> referencedBy = new HashMap<String, List<String>>();
738
739
740 Iterator<String> iter = statements.iterator();
741 while (iter.hasNext()) {
742 String statement = iter.next();
743 String tableName = getTableName(statement);
744 List<String> references = getTableReferences(statement, tableName);
745
746 if (references.size() < 1) {
747 orderedStatements.add(statement);
748 } else {
749
750 if (!checkReferencesInRepository(names, references)) {
751 if (isLoggingWarning())
752 logWarning("Table " + tableName
753 + " references a table outside the repository.");
754 }
755
756
757 refersTo.put(tableName, references);
758
759
760 Iterator<String> refs = references.iterator();
761 while (refs.hasNext()) {
762 String ref = refs.next();
763 List<String> v;
764 if (!referencedBy.containsKey(ref)) {
765 v = new ArrayList<String>();
766 v.add(tableName);
767 referencedBy.put(ref, v);
768 } else {
769 v = referencedBy.get(ref);
770 v.add(tableName);
771 }
772 }
773 }
774 }
775
776
777 iter = orderedStatements.iterator();
778 while (iter.hasNext()) {
779 String statement = iter.next();
780 statements.remove(statement);
781 }
782
783
784
785
786 int maxTries = statements.size();
787 int attempt = 0;
788 while (statements.size() > 0) {
789 Iterator<String> iterator = statements.iterator();
790 List<String> newlyAdded = new ArrayList<String>();
791 while (iterator.hasNext()) {
792 String statement = iterator.next();
793 String tableName = getTableName(statement);
794
795
796 if (!refersTo.containsKey(tableName)) {
797
798 } else {
799 List<String> waitingOnTables = refersTo.get(tableName);
800 boolean okToAdd = true;
801 Iterator<String> i = waitingOnTables.iterator();
802 while (i.hasNext()) {
803 String waitingOn = i.next();
804 if (refersTo.containsKey(waitingOn)) {
805 okToAdd = false;
806 }
807 }
808
809 if (okToAdd) {
810 orderedStatements.add(statement);
811 newlyAdded.add(statement);
812
813 if (referencedBy.containsKey(tableName)) {
814 List<String> tablesWaiting = referencedBy.get(tableName);
815 Iterator<String> j = tablesWaiting.iterator();
816 while (j.hasNext()) {
817 String table = j.next();
818 List<String> v = refersTo.get(table);
819 v.remove(tableName);
820 }
821 }
822 }
823 }
824 }
825
826
827 Iterator<String> k = newlyAdded.iterator();
828 while (k.hasNext()) {
829 String s = k.next();
830 statements.remove(s);
831 }
832
833
834 if (attempt++ > maxTries) {
835 if (isLoggingError()) {
836 logError("Still trying to resolve: ");
837 Iterator<String> left = statements.iterator();
838 while (left.hasNext()) {
839 String table = left.next();
840 logError(table);
841 }
842 }
843 throw new SQLProcessorException(
844 "Could not order tables appropriately...failing. Turn on loggingDebug for more info.");
845 }
846 }
847
848 return orderedStatements;
849 }
850
851 /***
852 * This method is used to extract the names of other tables that a table
853 * references. expected format is: CREATE TABLE foo ( x int not null
854 * references bar(id), y varchar null references doo(id), ... )
855 *
856 * @param String
857 * the CREATE TABLE statement
858 * @param String
859 * the name of the table
860 * @return Vector containing names of referenced tables
861 * @exception SQLProcessorException
862 * if the table has a reference to itself
863 */
864 private List<String> getTableReferences(String pStr, String tableName)
865 throws SQLProcessorException {
866 String REFERENCES = " references ";
867 List<String> refs = new ArrayList<String>();
868
869 int start = pStr.toLowerCase().indexOf(REFERENCES);
870 while (start != -1) {
871 pStr = pStr.substring(start + REFERENCES.length());
872 String ref = pStr;
873
874 int stop = ref.indexOf("(");
875 ref = ref.substring(0, stop);
876
877 ref = ref.trim();
878
879
880
881
882
883
884 if (ref.equalsIgnoreCase(tableName)) {
885
886
887
888
889 } else if ((ref.length() > 0) && !refs.contains(ref))
890 refs.add(ref);
891
892 start = pStr.toLowerCase().indexOf(REFERENCES);
893 }
894
895 if (isLoggingDebug()) {
896 Iterator<String> i = refs.iterator();
897 while (i.hasNext()) {
898 String s = i.next();
899 logDebug("Found reference: " + s);
900 }
901 }
902
903 return refs;
904 }
905
906 /***
907 * This method is used to determine whether all the items in the second Vector
908 * are contained in the first Vector.
909 *
910 * @param Vector
911 * of the names of all the tables in the repository
912 * @param Vector
913 * of the names of all the tables to check for
914 * @return boolean true if all items are in the Vector; false otherwise
915 */
916 private boolean checkReferencesInRepository(List<String> pRepositoryTables,
917 List<String> pCheckTables) {
918 Iterator<String> iter = pCheckTables.iterator();
919 while (iter.hasNext()) {
920 String name = iter.next();
921 if (!pRepositoryTables.contains(name))
922 return false;
923 }
924 return true;
925 }
926
927 /***
928 * Method to determine whether a table already exists in the database. The
929 * method operates by appending the name passed as a parameter to the String
930 * that has been set in the determineTableExistsSQL property
931 *
932 * @param String
933 * - name of table to check for existence of
934 * @return boolean - true if table exists; false otherwise
935 */
936 private boolean tableExists(String pTableName) {
937
938 if (pTableName == null || pTableName.length() == 0)
939 return false;
940
941
942 String sql = getDetermineTableExistsSQL() + " " + pTableName;
943
944
945 try {
946
947 performSQL(sql);
948
949 } catch (SQLProcessorException spe) {
950
951
952 if (isLoggingDebug()) {
953 logDebug("Table existence is determined by whether an exception is received when querying the table.");
954 logDebug("Caught exception checking whether table exists, so table doesn't exist.");
955 logDebug("Checked for existence with this statement \"" + sql + "\"");
956 logDebug("Set repository debugLevel > 6 to see full exception.");
957 if (this.getRepository().getDebugLevel() > 6)
958 logDebug(spe);
959 }
960
961 return false;
962 }
963
964 return true;
965 }
966
967 /***
968 * Returns true if there is at least one table in this schema
969 * This is handy for Derby since it will throw an error if one
970 * attempts to try a select statement to determine if a table
971 * exists and the schema has not yet been created.
972 * @return
973 */
974 private boolean hasAnyTables() {
975 boolean foundTables = false;
976 Connection c = null;
977 try {
978 c = getConnection();
979 DatabaseMetaData metadata = null;
980 metadata = c.getMetaData();
981 String[] names = { "TABLE" };
982 ResultSet tableNames = metadata.getTables(null, null, null, names);
983 while (tableNames.next()) {
984 String tab = tableNames.getString("TABLE_NAME");
985 foundTables = true;
986 break;
987 }
988 tableNames.close();
989 } catch (SQLProcessorException e) {
990 e.printStackTrace();
991 } catch (SQLException e) {
992 e.printStackTrace();
993 } finally {
994 try {
995 c.close();
996 } catch (SQLException e) {
997 ;
998 }
999 }
1000 return foundTables;
1001 }
1002
1003
1004
1005
1006 /*** SQL to insert a new id space into the DB table */
1007 transient String mInsertSQL;
1008
1009 /***
1010 * Get property <code>InsertSQL</code>. The SQL is lazily generated.
1011 *
1012 * @beaninfo description: SQL to insert a new id space into the DB table
1013 * @return InsertSQL
1014 **/
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042 /*** SQL to execute to update a specific id space in the DB */
1043 transient String mUpdateSQL;
1044
1045 /***
1046 * Get property <code>UpdateSQL</code>. The SQL is lazily generated.
1047 *
1048 * @beaninfo description: SQL to execute to update a specific id space int the
1049 * D0B
1050 * @return UpdateSQL
1051 **/
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 /*** SQL to execute to load a specific id space from the DB */
1077 transient String mSelectSQL;
1078
1079 /***
1080 * Get property <code>SelectSQL</code>. The SQL is lazily generated.
1081 *
1082 * @beaninfo description: SQL to execute to load a specific id space from the
1083 * DB
1084 * @return SelectSQL
1085 **/
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110 }