1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.efaps.db.databases;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.IOException;
25 import java.io.UnsupportedEncodingException;
26 import java.sql.Connection;
27 import java.sql.DatabaseMetaData;
28 import java.sql.ResultSet;
29 import java.sql.ResultSetMetaData;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.zip.Adler32;
35 import java.util.zip.CheckedInputStream;
36
37 import org.apache.commons.dbutils.BasicRowProcessor;
38 import org.apache.commons.dbutils.RowProcessor;
39 import org.efaps.db.databases.information.TableInformation;
40 import org.efaps.util.EFapsException;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
45
46
47
48
49
50
51
52
53
54 public class OracleDatabase
55 extends AbstractDatabase<OracleDatabase>
56 {
57
58
59
60
61 private static final Logger LOG = LoggerFactory.getLogger(OracleDatabase.class);
62
63
64
65
66
67
68
69 private static final String SQL_UNIQUE_KEYS = "select "
70 + "a.index_name as INDEX_NAME, "
71 + "a.table_name as TABLE_NAME, "
72 + "b.column_name as COLUMN_NAME, "
73 + "b.position as ORDINAL_POSITION "
74 + "from "
75 + "user_constraints a, "
76 + "user_cons_columns b "
77 + "where "
78 + "a.constraint_type='U' "
79 + "and a.index_name = b.constraint_name";
80
81
82
83
84
85
86
87 private static final String SQL_FOREIGN_KEYS = "select "
88 + "ucc1.TABLE_NAME as TABLE_NAME, "
89 + "uc.constraint_name as FK_NAME, "
90 + "ucc1.column_name as FKCOLUMN_NAME, "
91 + "case "
92 + "when uc.delete_rule='NO ACTION' then '" + DatabaseMetaData.importedKeyNoAction + "' "
93 + "when uc.delete_rule='CASCASE' then '" + DatabaseMetaData.importedKeyCascade + "' "
94 + "else '' end as DELETE_RULE, "
95 + "ucc2.table_name as PKTABLE_NAME, "
96 + "ucc2.column_name as PKCOLUMN_NAME "
97 + "from "
98 + "user_constraints uc, "
99 + "user_cons_columns ucc1, "
100 + "user_cons_columns ucc2 "
101 + "where "
102 + "uc.constraint_name = ucc1.constraint_name "
103 + "and uc.r_constraint_name = ucc2.constraint_name "
104 + "and ucc1.POSITION = ucc2.POSITION "
105 + "and uc.constraint_type = 'R'";
106
107
108
109
110
111
112
113
114 private static final RowProcessor ROWPROCESSOR = new BasicRowProcessor()
115 {
116
117
118
119
120
121
122
123
124
125
126
127
128 @Override
129 public Object[] toArray(final ResultSet _rs)
130 throws SQLException
131 {
132 final ResultSetMetaData metaData = _rs.getMetaData();
133 final int cols = metaData.getColumnCount();
134 final Object[] result = new Object[cols];
135
136 for (int i = 0; i < cols; i++) {
137 switch (metaData.getColumnType(i + 1)) {
138 case java.sql.Types.TIMESTAMP:
139 result[i] = _rs.getTimestamp(i + 1);
140 break;
141 case java.sql.Types.NUMERIC:
142 if (metaData.getScale(i + 1) > 0) {
143 result[i] = _rs.getBigDecimal(i + 1);
144 } else {
145 result[i] = _rs.getLong(i + 1);
146 }
147 break;
148 default:
149 result[i] = _rs.getObject(i + 1);
150 }
151 }
152
153 return result;
154 }
155 };
156
157
158
159
160
161 public OracleDatabase()
162 {
163 super();
164 addMapping(ColumnType.INTEGER, "number(*,0)", "null", "number(38,0)");
165 addMapping(ColumnType.DECIMAL, "numeric", "null", "decimal", "numeric");
166 addMapping(ColumnType.REAL, "number", "null", "number");
167 addMapping(ColumnType.STRING_SHORT, "varchar2", "null", "varchar2", "char");
168 addMapping(ColumnType.STRING_LONG, "varchar2", "null", "varchar2");
169 addMapping(ColumnType.DATETIME, "timestamp", "null", "timestamp", "timestamp(6)", "date");
170 addMapping(ColumnType.BLOB, "blob", "null", "blob");
171 addMapping(ColumnType.CLOB, "nclob", "null", "nclob");
172 addMapping(ColumnType.BOOLEAN, "number", "null", "number");
173 }
174
175
176
177
178
179 @Override
180 public boolean isConnected(final Connection _connection)
181 throws SQLException
182 {
183 boolean ret = false;
184 final Statement stmt = _connection.createStatement();
185 try {
186 final ResultSet resultset = stmt
187 .executeQuery("select product from product_component_version where product like 'Oracle%'");
188 ret = resultset.next();
189 resultset.close();
190 } finally {
191 stmt.close();
192 }
193 return ret;
194 }
195
196
197
198
199 @Override
200 public int getMaxExpressions()
201 {
202 return 999;
203 }
204
205
206
207
208
209
210
211 @Override
212 public String getCurrentTimeStamp()
213 {
214 return "sysdate";
215 }
216
217
218
219
220 @Override
221 public String getTimestampValue(final String _isoDateTime)
222 {
223 final String format = "'yyyy-mm-dd\"T\"hh24:mi:ss.ff3'";
224 return "to_timestamp('" + _isoDateTime + "', " + format + ")";
225 }
226
227
228
229
230 @Override
231 public Object getBooleanValue(final Boolean _value)
232 {
233 Integer ret = 0;
234 if (_value) {
235 ret = 1;
236 }
237 return ret;
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 @Override
256 @SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
257 public void deleteAll(final Connection _con)
258 throws SQLException
259 {
260 final Statement stmtSel = _con.createStatement();
261 final Statement stmtExec = _con.createStatement();
262
263 try {
264
265 if (OracleDatabase.LOG.isInfoEnabled()) {
266 OracleDatabase.LOG.info("Remove all Views");
267 }
268 ResultSet rs = stmtSel.executeQuery("select VIEW_NAME from USER_VIEWS");
269 while (rs.next()) {
270 final String viewName = rs.getString(1);
271 if (OracleDatabase.LOG.isDebugEnabled()) {
272 OracleDatabase.LOG.debug(" - View '" + viewName + "'");
273 }
274 stmtExec.execute("drop view " + viewName);
275 }
276 rs.close();
277
278
279 if (OracleDatabase.LOG.isInfoEnabled()) {
280 OracleDatabase.LOG.info("Remove all Tables");
281 }
282 rs = stmtSel.executeQuery("select TABLE_NAME from USER_TABLES");
283 while (rs.next()) {
284 final String tableName = rs.getString(1);
285 if (OracleDatabase.LOG.isDebugEnabled()) {
286 OracleDatabase.LOG.debug(" - Table '" + tableName + "'");
287 }
288 stmtExec.execute("drop table " + tableName + " cascade constraints");
289 }
290 rs.close();
291
292
293 if (OracleDatabase.LOG.isInfoEnabled()) {
294 OracleDatabase.LOG.info("Remove all Sequences");
295 }
296 rs = stmtSel.executeQuery("select SEQUENCE_NAME from USER_SEQUENCES");
297 while (rs.next()) {
298 final String seqName = rs.getString(1);
299 if (OracleDatabase.LOG.isDebugEnabled()) {
300 OracleDatabase.LOG.debug(" - Sequence '" + seqName + "'");
301 }
302 stmtExec.execute("drop sequence " + seqName);
303 }
304 rs.close();
305 } finally {
306 stmtSel.close();
307 stmtExec.close();
308 }
309 }
310
311
312
313
314 @Override
315 public OracleDatabase deleteView(final Connection _con,
316 final String _name)
317 throws SQLException
318 {
319 final Statement stmtExec = _con.createStatement();
320 stmtExec.execute("drop view " + _name);
321 return this;
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345 @Override
346 public OracleDatabase createTable(final Connection _con,
347 final String _table)
348 throws SQLException
349 {
350 final Statement stmt = _con.createStatement();
351
352 try {
353
354
355 final StringBuilder cmd = new StringBuilder()
356 .append("create table ").append(getTableName(_table)).append(" (")
357 .append(" ID number not null,")
358 .append(" constraint ");
359
360 final String consName = getConstrainName(_table + "_UK_ID");
361 cmd.append(consName).append(" unique(ID)");
362
363 cmd.append(")");
364 stmt.executeUpdate(cmd.toString());
365
366 } catch (final EFapsException e) {
367 e.printStackTrace();
368 } finally {
369 stmt.close();
370 }
371
372 return this;
373 }
374
375
376
377
378 @Override
379 public OracleDatabase defineTableAutoIncrement(final Connection _con,
380 final String _table)
381 throws SQLException
382 {
383 throw new Error("not implemented");
384 }
385
386
387
388
389
390
391
392
393
394
395
396 @Override
397 public long getNewId(final Connection _con,
398 final String _table,
399 final String _column)
400 throws SQLException
401 {
402 long ret = 0;
403 final Statement stmt = _con.createStatement();
404
405 try {
406 final StringBuilder cmd = new StringBuilder()
407 .append("select ").append(_table).append("_SEQ.nextval from DUAL");
408
409 final ResultSet rs = stmt.executeQuery(cmd.toString());
410 if (rs.next()) {
411 ret = rs.getLong(1);
412 }
413 rs.close();
414 } finally {
415 stmt.close();
416 }
417 return ret;
418 }
419
420
421
422
423 @Override
424 public OracleDatabase createSequence(final Connection _con,
425 final String _name,
426 final long _startValue)
427 throws SQLException
428 {
429 final Statement stmt = _con.createStatement();
430
431 final StringBuilder cmd = new StringBuilder()
432 .append("create sequence ").append(_name)
433 .append(" increment by 1 ")
434 .append(" start with ").append(_startValue)
435 .append(" nocache");
436 try {
437 stmt.executeUpdate(cmd.toString());
438 } finally {
439 stmt.close();
440 }
441
442 nextSequence(_con, _name);
443 return this;
444 }
445
446
447
448
449
450 @Override
451 public OracleDatabase deleteSequence(final Connection _con,
452 final String _name)
453 throws SQLException
454 {
455 final String cmd = new StringBuilder()
456 .append("drop sequence ").append(_name)
457 .toString();
458 final Statement stmt = _con.createStatement();
459 try {
460 stmt.executeUpdate(cmd);
461 } finally {
462 stmt.close();
463 }
464 return this;
465 }
466
467
468
469
470 @Override
471 @SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
472 public boolean existsSequence(final Connection _con,
473 final String _name)
474 throws SQLException
475 {
476 final boolean ret;
477 final String cmd = new StringBuilder()
478 .append("SELECT sequence_name FROM user_sequences WHERE sequence_name='")
479 .append(_name.toLowerCase()).append("'")
480 .toString();
481 final Statement stmt = _con.createStatement();
482 try {
483 final ResultSet resultset = stmt.executeQuery(cmd);
484 ret = resultset.next();
485 resultset.close();
486 } finally {
487 stmt.close();
488 }
489 return ret;
490 }
491
492
493
494
495 @Override
496 public long nextSequence(final Connection _con,
497 final String _name)
498 throws SQLException
499 {
500 final long ret;
501 final String cmd = new StringBuilder()
502 .append("SELECT " + _name + ".nextval from dual")
503 .toString();
504 final Statement stmt = _con.createStatement();
505 try {
506 final ResultSet resultset = stmt.executeQuery(cmd);
507 if (resultset.next()) {
508 ret = resultset.getLong(1);
509 } else {
510 throw new SQLException("fetching new value from sequence '" + _name + "' failed");
511 }
512 resultset.close();
513 } finally {
514 stmt.close();
515 }
516 return ret;
517 }
518
519
520
521
522 @Override
523 public OracleDatabase setSequence(final Connection _con,
524 final String _name,
525 final long _value)
526 throws SQLException
527 {
528 deleteSequence(_con, _name);
529 createSequence(_con, _name, _value);
530 return this;
531 }
532
533
534
535
536
537
538
539
540
541
542
543
544
545 @Override
546 protected void initTableInfoUniqueKeys(final Connection _con,
547 final String _sql,
548 final Map<String, TableInformation> _cache4Name)
549 throws SQLException
550 {
551 super.initTableInfoUniqueKeys(_con, OracleDatabase.SQL_UNIQUE_KEYS, _cache4Name);
552 }
553
554
555
556
557
558
559
560
561
562
563
564
565
566 @Override
567 protected void initTableInfoForeignKeys(final Connection _con,
568 final String _sql,
569 final Map<String, TableInformation> _cache4Name)
570 throws SQLException
571 {
572 super.initTableInfoForeignKeys(_con, OracleDatabase.SQL_FOREIGN_KEYS, _cache4Name);
573 }
574
575 @Override
576 protected void initTableInfoColumns(final Connection _con,
577 final String _sql,
578 final Map<String, TableInformation> _cache4Name)
579 throws SQLException
580 {
581 Statement stmt = null;
582 final ResultSet rs;
583 if (_sql == null) {
584 rs = _con.getMetaData().getColumns(getCatalog(), getSchemaPattern(), "%", "%");
585 } else {
586 stmt = _con.createStatement();
587 rs = stmt.executeQuery(_sql);
588 }
589 try {
590 while (rs.next()) {
591 final String tableName = rs.getString("TABLE_NAME").toUpperCase();
592 if (_cache4Name.containsKey(tableName)) {
593 final String colName = rs.getString("COLUMN_NAME").toUpperCase();
594 final String typeName = rs.getString("TYPE_NAME").toLowerCase();
595 final Set<AbstractDatabase.ColumnType> colTypes
596 = OracleDatabase.this.getReadColumnTypes(typeName);
597 if (colTypes == null) {
598 throw new SQLException("read unknown column type '"
599 + typeName + "' in column '" + colName + "' for table '" + tableName + "'");
600 }
601 final int size = rs.getInt("COLUMN_SIZE");
602 final int scale = rs.getInt("DECIMAL_DIGITS");
603 final boolean isNullable = !"NO".equalsIgnoreCase(rs.getString("IS_NULLABLE"));
604 _cache4Name.get(tableName).addColInfo(colName, colTypes, size, scale, isNullable);
605 }
606 }
607 } finally {
608 rs.close();
609 if (stmt != null) {
610 stmt.close();
611 }
612 }
613 }
614
615
616
617
618 @Override
619 public String getConstrainName(final String _name)
620 throws EFapsException
621 {
622 return getName4DB(_name, 30);
623 }
624
625
626
627
628
629
630
631 protected String getName4DB(final String _name,
632 final int _maxLength)
633 throws EFapsException
634 {
635 String ret = _name;
636 if (_name.length() > 30) {
637 try {
638 final byte[] buffer = _name.getBytes("UTF8");
639 final ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
640 final CheckedInputStream cis = new CheckedInputStream(bais, new Adler32());
641 final byte[] readBuffer = new byte[5];
642 long value = 0;
643 while (cis.read(readBuffer) >= 0) {
644 value = cis.getChecksum().getValue();
645 }
646 final String valueSt = String.valueOf(value);
647 ret = ret.substring(0, 30);
648 final int sizeSuf = ret.length() - valueSt.length();
649 ret = ret.substring(0, sizeSuf) + value;
650 } catch (final UnsupportedEncodingException e) {
651 throw new EFapsException("UnsupportedEncodingException", e);
652 } catch (final IOException e) {
653 throw new EFapsException("IOException", e);
654 }
655 }
656 return ret;
657 }
658
659
660
661
662 @Override
663 public String getTableName(final String _name)
664 throws EFapsException
665 {
666 return getName4DB(_name, 30);
667 }
668
669
670
671
672
673
674
675 @Override
676 public String getColumnQuote()
677 {
678 return "\"";
679 }
680
681
682
683
684 @Override
685 public String getHibernateDialect()
686 {
687 return "org.hibernate.dialect.Oracle10gDialect";
688 }
689
690
691
692
693 @Override
694 protected StringBuilder getAlterColumn(final String _columnName,
695 final org.efaps.db.databases.AbstractDatabase.ColumnType _columnType)
696 {
697 final StringBuilder ret = new StringBuilder()
698 .append(" modify ").append(getColumnQuote()).append(_columnName).append(getColumnQuote())
699 .append(" ")
700 .append(getWriteSQLTypeName(_columnType));
701 return ret;
702 }
703
704
705
706
707 @Override
708 protected StringBuilder getAlterColumnIsNotNull(final String _columnName,
709 final boolean _isNotNull)
710 {
711 final StringBuilder ret = new StringBuilder()
712 .append(" modify ").append(getColumnQuote()).append(_columnName).append(getColumnQuote())
713 .append(" ");
714 if (_isNotNull) {
715 ret.append(" not null ");
716 } else {
717 ret.append(" null ");
718 }
719 return ret;
720 }
721
722
723
724
725 @Override
726 protected boolean check4NullValues(final Connection _con,
727 final String _tableName,
728 final String _columnName)
729 throws SQLException
730 {
731 boolean ret = true;
732 final StringBuilder cmd = new StringBuilder();
733 cmd.append("select count(*) from ").append(getTableQuote()).append(_tableName).append(getTableQuote())
734 .append(" where ").append(getColumnQuote()).append(_columnName).append(getColumnQuote())
735 .append(" is null");
736
737 OracleDatabase.LOG.debug(" ..SQL> {}", cmd);
738
739 final Statement stmt = _con.createStatement();
740 ResultSet rs = null;
741 try {
742 rs = stmt.executeQuery(cmd.toString());
743 rs.next();
744 ret = rs.getInt(1) > 0;
745 } finally {
746 if (rs != null) {
747 rs.close();
748 }
749 stmt.close();
750 }
751 return ret;
752 }
753
754
755
756
757 @Override
758 public RowProcessor getRowProcessor()
759 {
760 return OracleDatabase.ROWPROCESSOR;
761 }
762 }