1
22
23 package com.liferay.portal.tools.sql;
24
25 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
26 import com.liferay.portal.kernel.log.Log;
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
28 import com.liferay.portal.kernel.util.FileUtil;
29 import com.liferay.portal.kernel.util.GetterUtil;
30 import com.liferay.portal.kernel.util.StringPool;
31 import com.liferay.portal.kernel.util.StringUtil;
32 import com.liferay.portal.util.PropsValues;
33 import com.liferay.portal.velocity.VelocityUtil;
34 import com.liferay.util.SimpleCounter;
35
36 import java.io.BufferedReader;
37 import java.io.File;
38 import java.io.FileReader;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.io.StringReader;
42
43 import java.sql.Connection;
44 import java.sql.SQLException;
45 import java.sql.Statement;
46
47 import java.util.HashMap;
48 import java.util.Map;
49
50 import javax.naming.NamingException;
51
52 import org.hibernate.dialect.DB2Dialect;
53 import org.hibernate.dialect.DerbyDialect;
54 import org.hibernate.dialect.Dialect;
55 import org.hibernate.dialect.FirebirdDialect;
56 import org.hibernate.dialect.HSQLDialect;
57 import org.hibernate.dialect.InformixDialect;
58 import org.hibernate.dialect.IngresDialect;
59 import org.hibernate.dialect.InterbaseDialect;
60 import org.hibernate.dialect.JDataStoreDialect;
61 import org.hibernate.dialect.MySQLDialect;
62 import org.hibernate.dialect.Oracle10gDialect;
63 import org.hibernate.dialect.Oracle8iDialect;
64 import org.hibernate.dialect.Oracle9Dialect;
65 import org.hibernate.dialect.Oracle9iDialect;
66 import org.hibernate.dialect.OracleDialect;
67 import org.hibernate.dialect.PostgreSQLDialect;
68 import org.hibernate.dialect.SAPDBDialect;
69 import org.hibernate.dialect.SQLServerDialect;
70 import org.hibernate.dialect.SybaseDialect;
71
72
78 public abstract class DBUtil implements DB {
79
80 public static final int MINIMAL = 1;
81
82 public static final int POPULATED = 0;
83
84 public static final int SHARDED = 2;
85
86 public static final String TYPE_DB2 = "db2";
87
88 public static final String TYPE_DERBY = "derby";
89
90 public static final String TYPE_FIREBIRD = "firebird";
91
92 public static final String TYPE_HYPERSONIC = "hypersonic";
93
94 public static final String TYPE_INFORMIX = "informix";
95
96 public static final String TYPE_INGRES = "ingres";
97
98 public static final String TYPE_INTERBASE = "interbase";
99
100 public static final String TYPE_JDATASTORE = "jdatastore";
101
102 public static final String TYPE_MYSQL = "mysql";
103
104 public static final String TYPE_ORACLE = "oracle";
105
106 public static final String TYPE_POSTGRESQL = "postgresql";
107
108 public static final String TYPE_SAP = "sap";
109
110 public static final String TYPE_SQLSERVER = "sqlserver";
111
112 public static final String TYPE_SYBASE = "sybase";
113
114 public static final String[] TYPE_ALL = {
115 TYPE_DB2, TYPE_DERBY, TYPE_FIREBIRD, TYPE_HYPERSONIC, TYPE_INFORMIX,
116 TYPE_INGRES, TYPE_INTERBASE, TYPE_JDATASTORE, TYPE_MYSQL, TYPE_ORACLE,
117 TYPE_POSTGRESQL, TYPE_SAP, TYPE_SQLSERVER, TYPE_SYBASE
118 };
119
120 public static DBUtil getInstance() {
121 if (_dbUtil == null) {
122 try {
123 if (_log.isInfoEnabled()) {
124 _log.info("Using dialect " + PropsValues.HIBERNATE_DIALECT);
125 }
126
127 Dialect dialect = (Dialect)Class.forName(
128 PropsValues.HIBERNATE_DIALECT).newInstance();
129
130 setInstance(dialect);
131 }
132 catch (Exception e) {
133 _log.error(e, e);
134 }
135 }
136
137 return _dbUtil;
138 }
139
140 public static DBUtil getInstance(String type) {
141 DBUtil dbUtil = null;
142
143 if (type.equals(TYPE_DB2)) {
144 dbUtil = DB2Util.getInstance();
145 }
146 else if (type.equals(TYPE_DERBY)) {
147 dbUtil = DerbyUtil.getInstance();
148 }
149 else if (type.equals(TYPE_FIREBIRD)) {
150 dbUtil = FirebirdUtil.getInstance();
151 }
152 else if (type.equals(TYPE_HYPERSONIC)) {
153 dbUtil = HypersonicUtil.getInstance();
154 }
155 else if (type.equals(TYPE_INFORMIX)) {
156 dbUtil = InformixUtil.getInstance();
157 }
158 else if (type.equals(TYPE_INGRES)) {
159 dbUtil = IngresUtil.getInstance();
160 }
161 else if (type.equals(TYPE_INTERBASE)) {
162 dbUtil = InterBaseUtil.getInstance();
163 }
164 else if (type.equals(TYPE_JDATASTORE)) {
165 dbUtil = JDataStoreUtil.getInstance();
166 }
167 else if (type.equals(TYPE_MYSQL)) {
168 dbUtil = MySQLUtil.getInstance();
169 }
170 else if (type.equals(TYPE_ORACLE)) {
171 dbUtil = OracleUtil.getInstance();
172 }
173 else if (type.equals(TYPE_POSTGRESQL)) {
174 dbUtil = PostgreSQLUtil.getInstance();
175 }
176 else if (type.equals(TYPE_SAP)) {
177 dbUtil = SAPUtil.getInstance();
178 }
179 else if (type.equals(TYPE_SQLSERVER)) {
180 dbUtil = SQLServerUtil.getInstance();
181 }
182 else if (type.equals(TYPE_SYBASE)) {
183 dbUtil = SybaseUtil.getInstance();
184 }
185
186 return dbUtil;
187 }
188
189 public static void setInstance(Dialect dialect) {
190 if (_dbUtil != null) {
191 return;
192 }
193
194 if (dialect instanceof DB2Dialect) {
195 if (dialect instanceof DerbyDialect) {
196 _dbUtil = DerbyUtil.getInstance();
197 }
198 else {
199 _dbUtil = DB2Util.getInstance();
200 }
201 }
202 else if (dialect instanceof HSQLDialect) {
203 _dbUtil = HypersonicUtil.getInstance();
204 }
205 else if (dialect instanceof InformixDialect) {
206 _dbUtil = InformixUtil.getInstance();
207 }
208 else if (dialect instanceof IngresDialect) {
209 _dbUtil = IngresUtil.getInstance();
210 }
211 else if (dialect instanceof InterbaseDialect) {
212 if (dialect instanceof FirebirdDialect) {
213 _dbUtil = FirebirdUtil.getInstance();
214 }
215 else {
216 _dbUtil = InterBaseUtil.getInstance();
217 }
218 }
219 else if (dialect instanceof JDataStoreDialect) {
220 _dbUtil = JDataStoreUtil.getInstance();
221 }
222 else if (dialect instanceof MySQLDialect) {
223 _dbUtil = MySQLUtil.getInstance();
224 }
225 else if (dialect instanceof OracleDialect ||
226 dialect instanceof Oracle8iDialect ||
227 dialect instanceof Oracle9Dialect ||
228 dialect instanceof Oracle9iDialect ||
229 dialect instanceof Oracle10gDialect) {
230
231 _dbUtil = OracleUtil.getInstance();
232 }
233 else if (dialect instanceof PostgreSQLDialect) {
234 _dbUtil = PostgreSQLUtil.getInstance();
235 }
236 else if (dialect instanceof SAPDBDialect) {
237 _dbUtil = SAPUtil.getInstance();
238 }
239 else if (dialect instanceof SybaseDialect) {
240 if (dialect instanceof SQLServerDialect) {
241 _dbUtil = SQLServerUtil.getInstance();
242 }
243 else {
244 _dbUtil = SybaseUtil.getInstance();
245 }
246 }
247 }
248
249 public void buildCreateFile(String databaseName) throws IOException {
250 buildCreateFile(databaseName, POPULATED);
251 buildCreateFile(databaseName, MINIMAL);
252 buildCreateFile(databaseName, SHARDED);
253 }
254
255 public void buildCreateFile(String databaseName, int population)
256 throws IOException {
257
258 String suffix = getSuffix(population);
259
260 File file = new File(
261 "../sql/create" + suffix + "/create" + suffix + "-" +
262 getServerName() + ".sql");
263
264 if (population != SHARDED) {
265 String content = buildCreateFileContent(databaseName, population);
266
267 if (content != null) {
268 FileUtil.write(file, content);
269 }
270 }
271 else {
272 String content = buildCreateFileContent(databaseName, MINIMAL);
273
274 if (content != null) {
275 FileUtil.write(file, content);
276 }
277
278 content = buildCreateFileContent(databaseName + "1", MINIMAL);
279
280 if (content != null) {
281 FileUtil.write(file, content, false, true);
282 }
283
284 content = buildCreateFileContent(databaseName + "2", MINIMAL);
285
286 if (content != null) {
287 FileUtil.write(file, content, false, true);
288 }
289 }
290 }
291
292 public abstract String buildSQL(String template) throws IOException;
293
294 public void buildSQLFile(String fileName) throws IOException {
295 String template = buildTemplate(fileName);
296
297 template = buildSQL(template);
298
299 FileUtil.write(
300 "../sql/" + fileName + "/" + fileName + "-" + getServerName() +
301 ".sql",
302 template);
303 }
304
305 public String getTemplateFalse() {
306 return getTemplate()[2];
307 }
308
309 public String getTemplateTrue() {
310 return getTemplate()[1];
311 }
312
313 public String getType() {
314 return _type;
315 }
316
317 public boolean isSupportsAlterColumnName() {
318 return _SUPPORTS_ALTER_COLUMN_NAME;
319 }
320
321 public boolean isSupportsAlterColumnType() {
322 return _SUPPORTS_ALTER_COLUMN_TYPE;
323 }
324
325 public boolean isSupportsDateMilliseconds() {
326 return _SUPPORTS_DATE_MILLISECONDS;
327 }
328
329 public boolean isSupportsStringCaseSensitiveQuery() {
330 return _supportsStringCaseSensitiveQuery;
331 }
332
333 public boolean isSupportsUpdateWithInnerJoin() {
334 return _SUPPORTS_UPDATE_WITH_INNER_JOIN;
335 }
336
337 public void runSQL(String sql) throws IOException, SQLException {
338 runSQL(new String[] {sql});
339 }
340
341 public void runSQL(Connection con, String sql)
342 throws IOException, SQLException {
343
344 runSQL(con, new String[] {sql});
345 }
346
347 public void runSQL(String[] sqls) throws IOException, SQLException {
348 Connection con = DataAccess.getConnection();
349
350 try {
351 runSQL(con, sqls);
352 }
353 finally {
354 DataAccess.cleanUp(con);
355 }
356 }
357
358 public void runSQL(Connection con, String[] sqls)
359 throws IOException, SQLException {
360
361 Statement s = null;
362
363 try {
364 s = con.createStatement();
365
366 for (int i = 0; i < sqls.length; i++) {
367 String sql = buildSQL(sqls[i]);
368
369 sql = sql.trim();
370
371 if (sql.endsWith(";")) {
372 sql = sql.substring(0, sql.length() - 1);
373 }
374
375 if (sql.endsWith("go")) {
376 sql = sql.substring(0, sql.length() - 2);
377 }
378
379 if (_log.isDebugEnabled()) {
380 _log.debug(sql);
381 }
382
383 try {
384 s.executeUpdate(sql);
385 }
386 catch (SQLException sqle) {
387 throw sqle;
388 }
389 }
390 }
391 finally {
392 DataAccess.cleanUp(s);
393 }
394 }
395
396 public void runSQLTemplate(String path)
397 throws IOException, NamingException, SQLException {
398
399 runSQLTemplate(path, true);
400 }
401
402 public void runSQLTemplate(String path, boolean failOnError)
403 throws IOException, NamingException, SQLException {
404
405 Thread currentThread = Thread.currentThread();
406
407 ClassLoader classLoader = currentThread.getContextClassLoader();
408
409 InputStream is = classLoader.getResourceAsStream(
410 "com/liferay/portal/tools/sql/dependencies/" + path);
411
412 if (is == null) {
413 is = classLoader.getResourceAsStream(path);
414 }
415
416 if (is == null) {
417 _log.error("Invalid path " + path);
418 }
419
420 String template = StringUtil.read(is);
421
422 is.close();
423
424 boolean evaluate = path.endsWith(".vm");
425
426 runSQLTemplateString(template, evaluate, failOnError);
427 }
428
429 public void runSQLTemplateString(
430 String template, boolean evaluate, boolean failOnError)
431 throws IOException, NamingException, SQLException {
432
433 if (evaluate) {
434 try {
435 template = evaluateVM(template);
436 }
437 catch (Exception e) {
438 _log.error(e, e);
439 }
440 }
441
442 StringBuilder sb = new StringBuilder();
443
444 BufferedReader br = new BufferedReader(new StringReader(template));
445
446 String line = null;
447
448 while ((line = br.readLine()) != null) {
449 if (!line.startsWith("##")) {
450 if (line.startsWith("@include ")) {
451 int pos = line.indexOf(" ");
452
453 String includeFileName = line.substring(pos + 1);
454
455 Thread currentThread = Thread.currentThread();
456
457 ClassLoader classLoader =
458 currentThread.getContextClassLoader();
459
460 InputStream is = classLoader.getResourceAsStream(
461 "com/liferay/portal/tools/sql/dependencies/" +
462 includeFileName);
463
464 if (is == null) {
465 is = classLoader.getResourceAsStream(includeFileName);
466 }
467
468 String include = StringUtil.read(is);
469
470 is.close();
471
472 if (includeFileName.endsWith(".vm")) {
473 try {
474 include = evaluateVM(include);
475 }
476 catch (Exception e) {
477 _log.error(e, e);
478 }
479 }
480
481 include = convertTimestamp(include);
482 include = replaceTemplate(include, getTemplate());
483
484 runSQLTemplateString(include, false, true);
485 }
486 else{
487 sb.append(line);
488
489 if (line.endsWith(";")) {
490 String sql = sb.toString();
491
492 sb = new StringBuilder();
493
494 try {
495 if (!sql.equals("COMMIT_TRANSACTION;")) {
496 runSQL(sql);
497 }
498 else {
499 if (_log.isDebugEnabled()) {
500 _log.debug("Skip commit sql");
501 }
502 }
503 }
504 catch (IOException ioe) {
505 if (failOnError) {
506 throw ioe;
507 }
508 else if (_log.isWarnEnabled()) {
509 _log.warn(ioe.getMessage());
510 }
511 }
512 catch (SQLException sqle) {
513 if (failOnError) {
514 throw sqle;
515 }
516 else if (_log.isWarnEnabled()) {
517 String message = GetterUtil.getString(
518 sqle.getMessage());
519
520 if (!message.startsWith("Duplicate key name")) {
521 _log.warn(message + ": " + sql);
522 }
523
524 if (message.startsWith("Duplicate entry") ||
525 message.startsWith(
526 "Specified key was too long")) {
527
528 _log.error(line);
529 }
530 }
531 }
532 }
533 }
534 }
535 }
536
537 br.close();
538 }
539
540 public void setSupportsStringCaseSensitiveQuery(
541 boolean supportsStringCaseSensitiveQuery) {
542
543 if (_log.isInfoEnabled()) {
544 if (supportsStringCaseSensitiveQuery) {
545 _log.info("Database supports case sensitive queries");
546 }
547 else {
548 _log.info("Database does not support case sensitive queries");
549 }
550 }
551
552 _supportsStringCaseSensitiveQuery = supportsStringCaseSensitiveQuery;
553 }
554
555 protected DBUtil(String type) {
556 _type = type;
557 }
558
559 protected abstract String buildCreateFileContent(
560 String databaseName, int population)
561 throws IOException;
562
563 protected String[] buildColumnNameTokens(String line) {
564 String[] words = StringUtil.split(line, " ");
565
566 if (words.length == 7) {
567 words[5] = "not null;";
568 }
569
570 String[] template = {
571 words[1], words[2], words[3], words[4], words[5]
572 };
573
574 return template;
575 }
576
577 protected String[] buildColumnTypeTokens(String line) {
578 String[] words = StringUtil.split(line, " ");
579
580 String nullable = "";
581
582 if (words.length == 6) {
583 nullable = "not null;";
584 }
585 else if (words.length == 5) {
586 nullable = words[4];
587 }
588 else if (words.length == 4) {
589 nullable = "not null;";
590
591 if (words[3].endsWith(";")) {
592 words[3] = words[3].substring(0, words[3].length() - 1);
593 }
594 }
595
596 String[] template = {
597 words[1], words[2], "", words[3], nullable
598 };
599
600 return template;
601 }
602
603 protected String buildTemplate(String fileName) throws IOException {
604 File file = new File("../sql/" + fileName + ".sql");
605
606 String template = FileUtil.read(file);
607
608 if (fileName.equals("portal") || fileName.equals("portal-minimal") ||
609 fileName.equals("update-5.0.1-5.1.0")) {
610
611 BufferedReader br = new BufferedReader(new StringReader(template));
612
613 StringBuilder sb = new StringBuilder();
614
615 String line = null;
616
617 while ((line = br.readLine()) != null) {
618 if (line.startsWith("@include ")) {
619 int pos = line.indexOf(" ");
620
621 String includeFileName = line.substring(pos + 1);
622
623 File includeFile = new File("../sql/" + includeFileName);
624
625 if (!includeFile.exists()) {
626 continue;
627 }
628
629 String include = FileUtil.read(includeFile);
630
631 if (includeFileName.endsWith(".vm")) {
632 try {
633 include = evaluateVM(include);
634 }
635 catch (Exception e) {
636 _log.error(e, e);
637 }
638 }
639
640 include = convertTimestamp(include);
641 include = replaceTemplate(include, getTemplate());
642
643 sb.append(include);
644 sb.append("\n\n");
645 }
646 else {
647 sb.append(line);
648 sb.append("\n");
649 }
650 }
651
652 br.close();
653
654 template = sb.toString();
655 }
656
657 if (fileName.equals("indexes") && (this instanceof SybaseUtil)) {
658 template = removeBooleanIndexes(template);
659 }
660
661 return template;
662 }
663
664 protected String convertTimestamp(String data) {
665 String s = null;
666
667 if (this instanceof MySQLUtil) {
668 s = StringUtil.replace(data, "SPECIFIC_TIMESTAMP_", "");
669 }
670 else {
671 s = data.replaceAll(
672 "SPECIFIC_TIMESTAMP_" + "\\d+", "CURRENT_TIMESTAMP");
673 }
674
675 return s;
676 }
677
678 protected String evaluateVM(String template) throws Exception {
679 Map<String, Object> variables = new HashMap<String, Object>();
680
681 variables.put("counter", new SimpleCounter());
682
683 template = VelocityUtil.evaluate(template, variables);
684
685
687 BufferedReader br = new BufferedReader(new StringReader(template));
688
689 StringBuilder sb = new StringBuilder();
690
691 String line = null;
692
693 while ((line = br.readLine()) != null) {
694 line = line.trim();
695
696 sb.append(line);
697 sb.append("\n");
698 }
699
700 br.close();
701
702 template = sb.toString();
703 template = StringUtil.replace(template, "\n\n\n", "\n\n");
704
705 return template;
706 }
707
708 protected abstract String getServerName();
709
710 protected String getSuffix(int type) {
711 if (type == MINIMAL) {
712 return "-minimal";
713 }
714 else if (type == SHARDED) {
715 return "-sharded";
716 }
717 else {
718 return StringPool.BLANK;
719 }
720 }
721
722 protected abstract String[] getTemplate();
723
724 protected String readSQL(String fileName, String comments, String eol)
725 throws IOException {
726
727 BufferedReader br = new BufferedReader(
728 new FileReader(new File(fileName)));
729
730 StringBuilder sb = new StringBuilder();
731
732 String line = null;
733
734 while ((line = br.readLine()) != null) {
735 if (!line.startsWith(comments)) {
736 line = StringUtil.replace(
737 line,
738 new String[] {"\n", "\t"},
739 new String[] {"", ""});
740
741 if (line.endsWith(";")) {
742 sb.append(line.substring(0, line.length() - 1));
743 sb.append(eol);
744 }
745 else {
746 sb.append(line);
747 }
748 }
749 }
750
751 br.close();
752
753 return sb.toString();
754 }
755
756 protected String removeBooleanIndexes(String data) throws IOException {
757 String portalData = FileUtil.read("../sql/portal-tables.sql");
758
759 BufferedReader br = new BufferedReader(new StringReader(data));
760
761 StringBuilder sb = new StringBuilder();
762
763 String line = null;
764
765 while ((line = br.readLine()) != null) {
766 boolean append = true;
767
768 int x = line.indexOf(" on ");
769
770 if (x != -1) {
771 int y = line.indexOf(" (", x);
772
773 String table = line.substring(x + 4, y);
774
775 x = y + 2;
776 y = line.indexOf(")", x);
777
778 String[] columns = StringUtil.split(line.substring(x, y));
779
780 x = portalData.indexOf("create table " + table + " (");
781 y = portalData.indexOf(");", x);
782
783 String portalTableData = portalData.substring(x, y);
784
785 for (int i = 0; i < columns.length; i++) {
786 if (portalTableData.indexOf(
787 columns[i].trim() + " BOOLEAN") != -1) {
788
789 append = false;
790
791 break;
792 }
793 }
794 }
795
796 if (append) {
797 sb.append(line);
798 sb.append("\n");
799 }
800 }
801
802 br.close();
803
804 return sb.toString();
805 }
806
807 protected String removeInserts(String data) throws IOException {
808 BufferedReader br = new BufferedReader(new StringReader(data));
809
810 StringBuilder sb = new StringBuilder();
811
812 String line = null;
813
814 while ((line = br.readLine()) != null) {
815 if (!line.startsWith("insert into ") &&
816 !line.startsWith("update ")) {
817
818 sb.append(line);
819 sb.append("\n");
820 }
821 }
822
823 br.close();
824
825 return sb.toString();
826 }
827
828 protected String removeLongInserts(String data) throws IOException {
829 BufferedReader br = new BufferedReader(new StringReader(data));
830
831 StringBuilder sb = new StringBuilder();
832
833 String line = null;
834
835 while ((line = br.readLine()) != null) {
836 if (!line.startsWith("insert into Image (") &&
837 !line.startsWith("insert into JournalArticle (") &&
838 !line.startsWith("insert into JournalStructure (") &&
839 !line.startsWith("insert into JournalTemplate (")) {
840
841 sb.append(line);
842 sb.append("\n");
843 }
844 }
845
846 br.close();
847
848 return sb.toString();
849 }
850
851 protected String removeNull(String content) {
852 content = StringUtil.replace(content, " not null", " not_null");
853 content = StringUtil.replace(content, " null", "");
854 content = StringUtil.replace(content, " not_null", " not null");
855
856 return content;
857 }
858
859 protected String replaceTemplate(String template, String[] actual) {
860 if ((template == null) || (TEMPLATE == null) || (actual == null)) {
861 return null;
862 }
863
864 if (TEMPLATE.length != actual.length) {
865 return template;
866 }
867
868 for (int i = 0; i < TEMPLATE.length; i++) {
869 if (TEMPLATE[i].equals("##") ||
870 TEMPLATE[i].equals("'01/01/1970'")) {
871
872 template = template.replaceAll(TEMPLATE[i], actual[i]);
873 }
874 else {
875 template = template.replaceAll(
876 "\\b" + TEMPLATE[i] + "\\b", actual[i]);
877 }
878 }
879
880 return template;
881 }
882
883 protected abstract String reword(String data) throws IOException;
884
885 protected static String ALTER_COLUMN_TYPE = "alter_column_type ";
886
887 protected static String ALTER_COLUMN_NAME = "alter_column_name ";
888
889 protected static String DROP_PRIMARY_KEY = "drop primary key";
890
891 protected static String[] REWORD_TEMPLATE = {
892 "@table@", "@old-column@", "@new-column@", "@type@", "@nullable@"
893 };
894
895 protected static String[] TEMPLATE = {
896 "##", "TRUE", "FALSE",
897 "'01/01/1970'", "CURRENT_TIMESTAMP",
898 " BLOB", " BOOLEAN", " DATE",
899 " DOUBLE", " INTEGER", " LONG",
900 " STRING", " TEXT", " VARCHAR",
901 " IDENTITY", "COMMIT_TRANSACTION"
902 };
903
904 private static boolean _SUPPORTS_ALTER_COLUMN_NAME = true;
905
906 private static boolean _SUPPORTS_ALTER_COLUMN_TYPE = true;
907
908 private static boolean _SUPPORTS_DATE_MILLISECONDS = true;
909
910 private static boolean _SUPPORTS_UPDATE_WITH_INNER_JOIN;
911
912 private static Log _log = LogFactoryUtil.getLog(DBUtil.class);
913
914 private static DBUtil _dbUtil;
915
916 private String _type;
917 private boolean _supportsStringCaseSensitiveQuery;
918
919 }