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