001
014
015 package com.liferay.portal.dao.db;
016
017 import com.liferay.counter.service.CounterLocalServiceUtil;
018 import com.liferay.portal.dao.orm.common.SQLTransformer;
019 import com.liferay.portal.kernel.dao.db.DB;
020 import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
021 import com.liferay.portal.kernel.dao.db.Index;
022 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
023 import com.liferay.portal.kernel.exception.SystemException;
024 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
025 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
026 import com.liferay.portal.kernel.log.Log;
027 import com.liferay.portal.kernel.log.LogFactoryUtil;
028 import com.liferay.portal.kernel.util.FileUtil;
029 import com.liferay.portal.kernel.util.GetterUtil;
030 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
031 import com.liferay.portal.kernel.util.PropertiesUtil;
032 import com.liferay.portal.kernel.util.StringBundler;
033 import com.liferay.portal.kernel.util.StringPool;
034 import com.liferay.portal.kernel.util.StringUtil;
035 import com.liferay.portal.kernel.util.Validator;
036 import com.liferay.portal.velocity.VelocityUtil;
037 import com.liferay.util.SimpleCounter;
038
039 import java.io.File;
040 import java.io.FileReader;
041 import java.io.IOException;
042 import java.io.InputStream;
043
044 import java.sql.Connection;
045 import java.sql.SQLException;
046 import java.sql.Statement;
047
048 import java.util.Collections;
049 import java.util.Enumeration;
050 import java.util.HashMap;
051 import java.util.HashSet;
052 import java.util.List;
053 import java.util.Map;
054 import java.util.Properties;
055 import java.util.Set;
056 import java.util.regex.Matcher;
057 import java.util.regex.Pattern;
058
059 import javax.naming.NamingException;
060
061
066 public abstract class BaseDB implements DB {
067
068 public void buildCreateFile(String sqlDir, String databaseName)
069 throws IOException {
070
071 buildCreateFile(sqlDir, databaseName, POPULATED);
072 buildCreateFile(sqlDir, databaseName, MINIMAL);
073 buildCreateFile(sqlDir, databaseName, SHARDED);
074 }
075
076 public void buildCreateFile(
077 String sqlDir, String databaseName, int population)
078 throws IOException {
079
080 String suffix = getSuffix(population);
081
082 File file = new File(
083 sqlDir + "/create" + suffix + "/create" + suffix + "-" +
084 getServerName() + ".sql");
085
086 if (population != SHARDED) {
087 String content = buildCreateFileContent(
088 sqlDir, databaseName, population);
089
090 if (content != null) {
091 FileUtil.write(file, content);
092 }
093 }
094 else {
095 String content = buildCreateFileContent(
096 sqlDir, databaseName, MINIMAL);
097
098 if (content != null) {
099 FileUtil.write(file, content);
100 }
101
102 content = buildCreateFileContent(
103 sqlDir, databaseName + "1", MINIMAL);
104
105 if (content != null) {
106 FileUtil.write(file, content, false, true);
107 }
108
109 content = buildCreateFileContent(
110 sqlDir, databaseName + "2", MINIMAL);
111
112 if (content != null) {
113 FileUtil.write(file, content, false, true);
114 }
115 }
116 }
117
118 public abstract String buildSQL(String template) throws IOException;
119
120 public void buildSQLFile(String sqlDir, String fileName)
121 throws IOException {
122
123 String template = buildTemplate(sqlDir, fileName);
124
125 if (Validator.isNull(template)) {
126 return;
127 }
128
129 template = buildSQL(template);
130
131 FileUtil.write(
132 sqlDir + "/" + fileName + "/" + fileName + "-" + getServerName() +
133 ".sql",
134 template);
135 }
136
137 @SuppressWarnings("unused")
138 public List<Index> getIndexes() throws SQLException {
139 return Collections.emptyList();
140 }
141
142 public String getTemplateFalse() {
143 return getTemplate()[2];
144 }
145
146 public String getTemplateTrue() {
147 return getTemplate()[1];
148 }
149
150 public String getType() {
151 return _type;
152 }
153
154 public long increment() throws SystemException {
155 return CounterLocalServiceUtil.increment();
156 }
157
158 public long increment(String name) throws SystemException {
159 return CounterLocalServiceUtil.increment(name);
160 }
161
162 public boolean isSupportsAlterColumnName() {
163 return _SUPPORTS_ALTER_COLUMN_NAME;
164 }
165
166 public boolean isSupportsAlterColumnType() {
167 return _SUPPORTS_ALTER_COLUMN_TYPE;
168 }
169
170 public boolean isSupportsDateMilliseconds() {
171 return _SUPPORTS_DATE_MILLISECONDS;
172 }
173
174 public boolean isSupportsInlineDistinct() {
175 return _SUPPORTS_INLINE_DISTINCT;
176 }
177
178 public boolean isSupportsScrollableResults() {
179 return _SUPPORTS_SCROLLABLE_RESULTS;
180 }
181
182 public boolean isSupportsStringCaseSensitiveQuery() {
183 return _supportsStringCaseSensitiveQuery;
184 }
185
186 public boolean isSupportsUpdateWithInnerJoin() {
187 return _SUPPORTS_UPDATE_WITH_INNER_JOIN;
188 }
189
190 public void runSQL(String sql) throws IOException, SQLException {
191 runSQL(new String[] {sql});
192 }
193
194 public void runSQL(Connection con, String sql)
195 throws IOException, SQLException {
196
197 runSQL(con, new String[] {sql});
198 }
199
200 public void runSQL(String[] sqls) throws IOException, SQLException {
201 Connection con = DataAccess.getConnection();
202
203 try {
204 runSQL(con, sqls);
205 }
206 finally {
207 DataAccess.cleanUp(con);
208 }
209 }
210
211 public void runSQL(Connection con, String[] sqls)
212 throws IOException, SQLException {
213
214 Statement s = null;
215
216 try {
217 s = con.createStatement();
218
219 for (int i = 0; i < sqls.length; i++) {
220 String sql = buildSQL(sqls[i]);
221
222 sql = SQLTransformer.transform(sql.trim());
223
224 if (sql.endsWith(";")) {
225 sql = sql.substring(0, sql.length() - 1);
226 }
227
228 if (sql.endsWith("go")) {
229 sql = sql.substring(0, sql.length() - 2);
230 }
231
232 if (_log.isDebugEnabled()) {
233 _log.debug(sql);
234 }
235
236 try {
237 s.executeUpdate(sql);
238 }
239 catch (SQLException sqle) {
240 throw sqle;
241 }
242 }
243 }
244 finally {
245 DataAccess.cleanUp(s);
246 }
247 }
248
249 public void runSQLTemplate(String path)
250 throws IOException, NamingException, SQLException {
251
252 runSQLTemplate(path, true);
253 }
254
255 public void runSQLTemplate(String path, boolean failOnError)
256 throws IOException, NamingException, SQLException {
257
258 Thread currentThread = Thread.currentThread();
259
260 ClassLoader classLoader = currentThread.getContextClassLoader();
261
262 InputStream is = classLoader.getResourceAsStream(
263 "com/liferay/portal/tools/sql/dependencies/" + path);
264
265 if (is == null) {
266 is = classLoader.getResourceAsStream(path);
267 }
268
269 if (is == null) {
270 _log.error("Invalid path " + path);
271
272 if (failOnError) {
273 throw new IOException("Invalid path " + path);
274 }
275 else {
276 return;
277 }
278 }
279
280 String template = StringUtil.read(is);
281
282 is.close();
283
284 boolean evaluate = path.endsWith(".vm");
285
286 runSQLTemplateString(template, evaluate, failOnError);
287 }
288
289 public void runSQLTemplateString(
290 String template, boolean evaluate, boolean failOnError)
291 throws IOException, NamingException, SQLException {
292
293 if (evaluate) {
294 try {
295 template = evaluateVM(template);
296 }
297 catch (Exception e) {
298 _log.error(e, e);
299 }
300 }
301
302 StringBundler sb = new StringBundler();
303
304 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
305 new UnsyncStringReader(template));
306
307 String line = null;
308
309 while ((line = unsyncBufferedReader.readLine()) != null) {
310 if (!line.startsWith("##")) {
311 if (line.startsWith("@include ")) {
312 int pos = line.indexOf(" ");
313
314 String includeFileName = line.substring(pos + 1);
315
316 Thread currentThread = Thread.currentThread();
317
318 ClassLoader classLoader =
319 currentThread.getContextClassLoader();
320
321 InputStream is = classLoader.getResourceAsStream(
322 "com/liferay/portal/tools/sql/dependencies/" +
323 includeFileName);
324
325 if (is == null) {
326 is = classLoader.getResourceAsStream(includeFileName);
327 }
328
329 String include = StringUtil.read(is);
330
331 is.close();
332
333 if (includeFileName.endsWith(".vm")) {
334 try {
335 include = evaluateVM(include);
336 }
337 catch (Exception e) {
338 _log.error(e, e);
339 }
340 }
341
342 include = convertTimestamp(include);
343 include = replaceTemplate(include, getTemplate());
344
345 runSQLTemplateString(include, false, true);
346 }
347 else{
348 sb.append(line);
349
350 if (line.endsWith(";")) {
351 String sql = sb.toString();
352
353 sb.setIndex(0);
354
355 try {
356 if (!sql.equals("COMMIT_TRANSACTION;")) {
357 runSQL(sql);
358 }
359 else {
360 if (_log.isDebugEnabled()) {
361 _log.debug("Skip commit sql");
362 }
363 }
364 }
365 catch (IOException ioe) {
366 if (failOnError) {
367 throw ioe;
368 }
369 else if (_log.isWarnEnabled()) {
370 _log.warn(ioe.getMessage());
371 }
372 }
373 catch (SQLException sqle) {
374 if (failOnError) {
375 throw sqle;
376 }
377 else if (_log.isWarnEnabled()) {
378 String message = GetterUtil.getString(
379 sqle.getMessage());
380
381 if (!message.startsWith("Duplicate key name")) {
382 _log.warn(message + ": " + buildSQL(sql));
383 }
384
385 if (message.startsWith("Duplicate entry") ||
386 message.startsWith(
387 "Specified key was too long")) {
388
389 _log.error(line);
390 }
391 }
392 }
393 }
394 }
395 }
396 }
397
398 unsyncBufferedReader.close();
399 }
400
401 public void setSupportsStringCaseSensitiveQuery(
402 boolean supportsStringCaseSensitiveQuery) {
403
404 if (_log.isInfoEnabled()) {
405 if (supportsStringCaseSensitiveQuery) {
406 _log.info("Database supports case sensitive queries");
407 }
408 else {
409 _log.info("Database does not support case sensitive queries");
410 }
411 }
412
413 _supportsStringCaseSensitiveQuery = supportsStringCaseSensitiveQuery;
414 }
415
416 public void updateIndexes(
417 String tablesSQL, String indexesSQL, String indexesProperties,
418 boolean dropIndexes)
419 throws IOException, SQLException {
420
421 List<Index> indexes = getIndexes();
422
423 Set<String> validIndexNames = null;
424
425 if (dropIndexes) {
426 validIndexNames = dropIndexes(
427 tablesSQL, indexesSQL, indexesProperties, indexes);
428 }
429 else {
430 validIndexNames = new HashSet<String>();
431
432 for (Index index : indexes) {
433 String indexName = index.getIndexName().toUpperCase();
434
435 validIndexNames.add(indexName);
436 }
437 }
438
439 addIndexes(indexesSQL, validIndexNames);
440 }
441
442 protected BaseDB(String type) {
443 _type = type;
444
445 String[] actual = getTemplate();
446
447 for (int i = 0; i < TEMPLATE.length; i++) {
448 _templateMap.put(TEMPLATE[i], actual[i]);
449 }
450 }
451
452 protected void addIndexes(String indexesSQL, Set<String> validIndexNames)
453 throws IOException {
454
455 if (_log.isInfoEnabled()) {
456 _log.info("Adding indexes");
457 }
458
459 DB db = DBFactoryUtil.getDB();
460
461 UnsyncBufferedReader bufferedReader = new UnsyncBufferedReader(
462 new UnsyncStringReader(indexesSQL));
463
464 String sql = null;
465
466 while ((sql = bufferedReader.readLine()) != null) {
467 if (Validator.isNull(sql)) {
468 continue;
469 }
470
471 int y = sql.indexOf(" on ");
472 int x = sql.lastIndexOf(" ", y - 1);
473
474 String indexName = sql.substring(x + 1, y);
475
476 if (validIndexNames.contains(indexName)) {
477 continue;
478 }
479
480 if (_log.isInfoEnabled()) {
481 _log.info(sql);
482 }
483
484 try {
485 db.runSQL(sql);
486 }
487 catch (Exception e) {
488 if (_log.isWarnEnabled()) {
489 _log.warn(e.getMessage() + ": " + sql);
490 }
491 }
492 }
493 }
494
495 protected abstract String buildCreateFileContent(
496 String sqlDir, String databaseName, int population)
497 throws IOException;
498
499 protected String[] buildColumnNameTokens(String line) {
500 String[] words = StringUtil.split(line, ' ');
501
502 if (words.length == 7) {
503 words[5] = "not null;";
504 }
505
506 String[] template = {
507 words[1], words[2], words[3], words[4], words[5]
508 };
509
510 return template;
511 }
512
513 protected String[] buildColumnTypeTokens(String line) {
514 String[] words = StringUtil.split(line, ' ');
515
516 String nullable = "";
517
518 if (words.length == 6) {
519 nullable = "not null;";
520 }
521 else if (words.length == 5) {
522 nullable = words[4];
523 }
524 else if (words.length == 4) {
525 nullable = "not null;";
526
527 if (words[3].endsWith(";")) {
528 words[3] = words[3].substring(0, words[3].length() - 1);
529 }
530 }
531
532 String[] template = {
533 words[1], words[2], "", words[3], nullable
534 };
535
536 return template;
537 }
538
539 protected String buildTemplate(String sqlDir, String fileName)
540 throws IOException {
541
542 String template = readFile(sqlDir + "/" + fileName + ".sql");
543
544 if (fileName.equals("portal") || fileName.equals("portal-minimal") ||
545 fileName.equals("update-5.0.1-5.1.0")) {
546
547 UnsyncBufferedReader unsyncBufferedReader =
548 new UnsyncBufferedReader(new UnsyncStringReader(template));
549
550 StringBundler sb = new StringBundler();
551
552 String line = null;
553
554 while ((line = unsyncBufferedReader.readLine()) != null) {
555 if (line.startsWith("@include ")) {
556 int pos = line.indexOf(" ");
557
558 String includeFileName = line.substring(pos + 1);
559
560 File includeFile = new File(
561 sqlDir + "/" + includeFileName);
562
563 if (!includeFile.exists()) {
564 continue;
565 }
566
567 String include = FileUtil.read(includeFile);
568
569 if (includeFileName.endsWith(".vm")) {
570 try {
571 include = evaluateVM(include);
572 }
573 catch (Exception e) {
574 _log.error(e, e);
575 }
576 }
577
578 include = convertTimestamp(include);
579 include = replaceTemplate(include, getTemplate());
580
581 sb.append(include);
582 sb.append("\n\n");
583 }
584 else {
585 sb.append(line);
586 sb.append("\n");
587 }
588 }
589
590 unsyncBufferedReader.close();
591
592 template = sb.toString();
593 }
594
595 if (fileName.equals("indexes") && (this instanceof SybaseDB)) {
596 template = removeBooleanIndexes(sqlDir, template);
597 }
598
599 return template;
600 }
601
602 protected String convertTimestamp(String data) {
603 String s = null;
604
605 if (this instanceof MySQLDB) {
606 s = StringUtil.replace(data, "SPECIFIC_TIMESTAMP_", "");
607 }
608 else {
609 Matcher matcher = _timestampPattern.matcher(data);
610
611 s = matcher.replaceAll("CURRENT_TIMESTAMP");
612 }
613
614 return s;
615 }
616
617 protected Set<String> dropIndexes(
618 String tablesSQL, String indexesSQL, String indexesProperties,
619 List<Index> indexes)
620 throws IOException, SQLException {
621
622 if (_log.isInfoEnabled()) {
623 _log.info("Dropping stale indexes");
624 }
625
626 Set<String> validIndexNames = new HashSet<String>();
627
628 if (indexes.isEmpty()) {
629 return validIndexNames;
630 }
631
632 DB db = DBFactoryUtil.getDB();
633
634 String tablesSQLLowerCase = tablesSQL.toLowerCase();
635 String indexesSQLLowerCase = indexesSQL.toLowerCase();
636
637 Properties indexesPropertiesObj = PropertiesUtil.load(
638 indexesProperties);
639
640 Enumeration<String> enu =
641 (Enumeration<String>)indexesPropertiesObj.propertyNames();
642
643 while (enu.hasMoreElements()) {
644 String key = enu.nextElement();
645
646 String value = indexesPropertiesObj.getProperty(key);
647
648 indexesPropertiesObj.setProperty(key.toLowerCase(), value);
649 }
650
651 for (Index index : indexes) {
652 String indexNameUpperCase = index.getIndexName().toUpperCase();
653 String indexNameLowerCase = indexNameUpperCase.toLowerCase();
654 String tableName = index.getTableName();
655 String tableNameLowerCase = tableName.toLowerCase();
656 boolean unique = index.isUnique();
657
658 validIndexNames.add(indexNameUpperCase);
659
660 if (indexesPropertiesObj.containsKey(indexNameLowerCase)) {
661 if (unique &&
662 indexesSQLLowerCase.contains(
663 "create unique index " + indexNameLowerCase + " ")) {
664
665 continue;
666 }
667
668 if (!unique &&
669 indexesSQLLowerCase.contains(
670 "create index " + indexNameLowerCase + " ")) {
671
672 continue;
673 }
674 }
675 else {
676 if (!tablesSQLLowerCase.contains(
677 "create table " + tableNameLowerCase + " (")) {
678
679 continue;
680 }
681 }
682
683 validIndexNames.remove(indexNameUpperCase);
684
685 db.runSQL("drop index " + indexNameUpperCase + " on " + tableName);
686 }
687
688 return validIndexNames;
689 }
690
691 protected String evaluateVM(String template) throws Exception {
692 Map<String, Object> variables = new HashMap<String, Object>();
693
694 variables.put("counter", new SimpleCounter());
695
696 Thread currentThread = Thread.currentThread();
697
698 ClassLoader classLoader = currentThread.getContextClassLoader();
699
700 try {
701 currentThread.setContextClassLoader(
702 PortalClassLoaderUtil.getClassLoader());
703
704 template = VelocityUtil.evaluate(template, variables);
705 }
706 finally {
707 currentThread.setContextClassLoader(classLoader);
708 }
709
710
711
712 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
713 new UnsyncStringReader(template));
714
715 StringBundler sb = new StringBundler();
716
717 String line = null;
718
719 while ((line = unsyncBufferedReader.readLine()) != null) {
720 line = line.trim();
721
722 sb.append(line);
723 sb.append("\n");
724 }
725
726 unsyncBufferedReader.close();
727
728 template = sb.toString();
729 template = StringUtil.replace(template, "\n\n\n", "\n\n");
730
731 return template;
732 }
733
734 protected abstract String getServerName();
735
736 protected String getSuffix(int type) {
737 if (type == MINIMAL) {
738 return "-minimal";
739 }
740 else if (type == SHARDED) {
741 return "-sharded";
742 }
743 else {
744 return StringPool.BLANK;
745 }
746 }
747
748 protected abstract String[] getTemplate();
749
750 protected String readFile(String fileName) throws IOException {
751 if (FileUtil.exists(fileName)) {
752 return FileUtil.read(fileName);
753 }
754 else {
755 return StringPool.BLANK;
756 }
757 }
758
759 protected String readSQL(String fileName, String comments, String eol)
760 throws IOException {
761
762 if (!FileUtil.exists(fileName)) {
763 return StringPool.BLANK;
764 }
765
766 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
767 new FileReader(new File(fileName)));
768
769 StringBundler sb = new StringBundler();
770
771 String line = null;
772
773 while ((line = unsyncBufferedReader.readLine()) != null) {
774 if (!line.startsWith(comments)) {
775 line = StringUtil.replace(
776 line,
777 new String[] {"\n", "\t"},
778 new String[] {"", ""});
779
780 if (line.endsWith(";")) {
781 sb.append(line.substring(0, line.length() - 1));
782 sb.append(eol);
783 }
784 else {
785 sb.append(line);
786 }
787 }
788 }
789
790 unsyncBufferedReader.close();
791
792 return sb.toString();
793 }
794
795 protected String removeBooleanIndexes(String sqlDir, String data)
796 throws IOException {
797
798 String portalData = readFile(sqlDir + "/portal-tables.sql");
799
800 if (Validator.isNull(portalData)) {
801 return StringPool.BLANK;
802 }
803
804 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
805 new UnsyncStringReader(data));
806
807 StringBundler sb = new StringBundler();
808
809 String line = null;
810
811 while ((line = unsyncBufferedReader.readLine()) != null) {
812 boolean append = true;
813
814 int x = line.indexOf(" on ");
815
816 if (x != -1) {
817 int y = line.indexOf(" (", x);
818
819 String table = line.substring(x + 4, y);
820
821 x = y + 2;
822 y = line.indexOf(")", x);
823
824 String[] columns = StringUtil.split(line.substring(x, y));
825
826 x = portalData.indexOf("create table " + table + " (");
827 y = portalData.indexOf(");", x);
828
829 String portalTableData = portalData.substring(x, y);
830
831 for (int i = 0; i < columns.length; i++) {
832 if (portalTableData.indexOf(
833 columns[i].trim() + " BOOLEAN") != -1) {
834
835 append = false;
836
837 break;
838 }
839 }
840 }
841
842 if (append) {
843 sb.append(line);
844 sb.append("\n");
845 }
846 }
847
848 unsyncBufferedReader.close();
849
850 return sb.toString();
851 }
852
853 protected String removeInserts(String data) throws IOException {
854 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
855 new UnsyncStringReader(data));
856
857 StringBundler sb = new StringBundler();
858
859 String line = null;
860
861 while ((line = unsyncBufferedReader.readLine()) != null) {
862 if (!line.startsWith("insert into ") &&
863 !line.startsWith("update ")) {
864
865 sb.append(line);
866 sb.append("\n");
867 }
868 }
869
870 unsyncBufferedReader.close();
871
872 return sb.toString();
873 }
874
875 protected String removeLongInserts(String data) throws IOException {
876 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
877 new UnsyncStringReader(data));
878
879 StringBundler sb = new StringBundler();
880
881 String line = null;
882
883 while ((line = unsyncBufferedReader.readLine()) != null) {
884 if (!line.startsWith("insert into Image (") &&
885 !line.startsWith("insert into JournalArticle (") &&
886 !line.startsWith("insert into JournalStructure (") &&
887 !line.startsWith("insert into JournalTemplate (")) {
888
889 sb.append(line);
890 sb.append("\n");
891 }
892 }
893
894 unsyncBufferedReader.close();
895
896 return sb.toString();
897 }
898
899 protected String removeNull(String content) {
900 content = StringUtil.replace(content, " = null", " = NULL");
901 content = StringUtil.replace(content, " is null", " IS NULL");
902 content = StringUtil.replace(content, " not null", " not_null");
903 content = StringUtil.replace(content, " null", "");
904 content = StringUtil.replace(content, " not_null", " not null");
905
906 return content;
907 }
908
909 protected String replaceTemplate(String template, String[] actual) {
910 if ((template == null) || (TEMPLATE == null) || (actual == null)) {
911 return null;
912 }
913
914 if (TEMPLATE.length != actual.length) {
915 return template;
916 }
917
918 StringBundler sb = null;
919
920 int endIndex = 0;
921
922 Matcher matcher = _templatePattern.matcher(template);
923
924 while (matcher.find()) {
925 int startIndex = matcher.start();
926
927 if (sb == null) {
928 sb = new StringBundler();
929 }
930
931 sb.append(template.substring(endIndex, startIndex));
932
933 endIndex = matcher.end();
934
935 String matched = template.substring(startIndex, endIndex);
936
937 sb.append(_templateMap.get(matched));
938 }
939
940 if (sb == null) {
941 return template;
942 }
943
944 if (template.length() > endIndex) {
945 sb.append(template.substring(endIndex));
946 }
947
948 return sb.toString();
949 }
950
951 protected abstract String reword(String data) throws IOException;
952
953 protected static String ALTER_COLUMN_TYPE = "alter_column_type ";
954
955 protected static String ALTER_COLUMN_NAME = "alter_column_name ";
956
957 protected static String DROP_INDEX = "drop index";
958
959 protected static String DROP_PRIMARY_KEY = "drop primary key";
960
961 protected static String[] REWORD_TEMPLATE = {
962 "@table@", "@old-column@", "@new-column@", "@type@", "@nullable@"
963 };
964
965 protected static String[] TEMPLATE = {
966 "##", "TRUE", "FALSE",
967 "'01/01/1970'", "CURRENT_TIMESTAMP",
968 " BLOB", " BOOLEAN", " DATE",
969 " DOUBLE", " INTEGER", " LONG",
970 " STRING", " TEXT", " VARCHAR",
971 " IDENTITY", "COMMIT_TRANSACTION"
972 };
973
974 private static final boolean _SUPPORTS_ALTER_COLUMN_NAME = true;
975
976 private static final boolean _SUPPORTS_ALTER_COLUMN_TYPE = true;
977
978 private static final boolean _SUPPORTS_DATE_MILLISECONDS = true;
979
980 private static final boolean _SUPPORTS_INLINE_DISTINCT = true;
981
982 private static final boolean _SUPPORTS_SCROLLABLE_RESULTS = true;
983
984 private static final boolean _SUPPORTS_UPDATE_WITH_INNER_JOIN = true;
985
986 private static Log _log = LogFactoryUtil.getLog(BaseDB.class);
987
988 private static Pattern _templatePattern;
989 private static Pattern _timestampPattern = Pattern.compile(
990 "SPECIFIC_TIMESTAMP_\\d+");
991
992 private Map<String, String> _templateMap = new HashMap<String, String>();
993 private String _type;
994 private boolean _supportsStringCaseSensitiveQuery;
995
996 static {
997 StringBundler sb = new StringBundler(TEMPLATE.length * 3 - 3);
998
999 for (int i = 0; i < TEMPLATE.length; i++) {
1000 String variable = TEMPLATE[i];
1001
1002 if (variable.equals("##") || variable.equals("'01/01/1970'")) {
1003 sb.append(variable);
1004 }
1005 else {
1006 sb.append(variable);
1007 sb.append("\\b");
1008 }
1009
1010 if (i < TEMPLATE.length - 1) {
1011 sb.append(StringPool.PIPE);
1012 }
1013 }
1014
1015 _templatePattern = Pattern.compile(sb.toString());
1016 }
1017
1018 }