1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.melati.poem;
46
47 import java.io.PrintStream;
48 import java.sql.Connection;
49 import java.sql.PreparedStatement;
50 import java.sql.ResultSet;
51 import java.sql.SQLException;
52 import java.sql.Statement;
53 import java.util.Enumeration;
54 import java.util.Hashtable;
55 import java.util.Vector;
56
57 import org.melati.poem.dbms.Dbms;
58 import org.melati.poem.transaction.Transactioned;
59 import org.melati.poem.transaction.TransactionedSerial;
60 import org.melati.poem.util.ArrayEnumeration;
61 import org.melati.poem.util.ArrayUtils;
62 import org.melati.poem.util.Cache;
63 import org.melati.poem.util.CachedIndexFactory;
64 import org.melati.poem.util.EnumUtils;
65 import org.melati.poem.util.MappedEnumeration;
66 import org.melati.poem.util.Procedure;
67 import org.melati.poem.util.FilteredEnumeration;
68 import org.melati.poem.util.FlattenedEnumeration;
69 import org.melati.poem.util.Order;
70 import org.melati.poem.util.SortUtils;
71 import org.melati.poem.util.StringUtils;
72
73
74
75
76
77 public class JdbcTable implements Selectable, Table {
78
79
80 private static final int CACHE_LIMIT_DEFAULT = 100;
81 private static final int DISPLAY_ORDER_DEFAULT = 100;
82
83 private JdbcTable _this = this;
84
85 private Database database;
86 private String name;
87 private String quotedName;
88 private DefinitionSource definitionSource;
89
90 private TableInfo info = null;
91
92 private TableListener[] listeners = {};
93
94 private Column[] columns = {};
95 private Hashtable columnsByName = new Hashtable();
96
97 private Column troidColumn = null;
98 private Column deletedColumn = null;
99 private Column canReadColumn = null;
100 private Column canSelectColumn = null;
101 private Column canWriteColumn = null;
102 private Column canDeleteColumn = null;
103 private Column displayColumn = null;
104 private Column searchColumn = null;
105
106 private String defaultOrderByClause = null;
107
108 private Column[][] displayColumns = new Column[DisplayLevel.count()][];
109 private Column[] searchColumns = null;
110
111 private TransactionedSerial serial;
112
113 private CachedSelection allTroids = null;
114 private Hashtable cachedSelections = new Hashtable();
115 private Hashtable cachedCounts = new Hashtable();
116 private Hashtable cachedExists = new Hashtable();
117
118 private int mostRecentTroid = -1;
119 private int extrasIndex = 0;
120
121
122
123
124
125 public JdbcTable(Database database, String name,
126 DefinitionSource definitionSource) {
127 this.database = database;
128 this.name = name;
129
130
131
132 this.definitionSource = definitionSource;
133 serial = new TransactionedSerial(database);
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 public void postInitialise() {
150 clearColumnInfoCaches();
151 database.getColumnInfoTable().addListener(
152 new TableListener() {
153 public void notifyTouched(PoemTransaction transaction, Table table,
154 Persistent persistent) {
155 _this.notifyColumnInfo((ColumnInfo)persistent);
156 }
157
158 public void notifyUncached(Table table) {
159 _this.clearColumnInfoCaches();
160 }
161 });
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public final Database getDatabase() {
175 return database;
176 }
177
178
179
180
181
182
183
184
185
186
187 public final String getName() {
188 return name;
189 }
190
191
192
193
194 public final String quotedName() {
195 if (quotedName == null) quotedName = database.quotedName(name);
196 return quotedName;
197 }
198
199
200
201
202
203
204
205 public final String getDisplayName() {
206 return info.getDisplayname();
207 }
208
209
210
211
212
213
214
215 public final String getDescription() {
216 return info.getDescription();
217 }
218
219
220
221
222
223
224
225
226 public final TableCategory getCategory() {
227 return info.getCategory();
228 }
229
230
231
232
233 public final TableInfo getInfo() {
234 return info;
235 }
236
237
238
239
240
241
242
243
244 public final Integer tableInfoID() {
245 return info == null ? null : info.troid();
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260 public final Column getColumn(String nameP) throws NoSuchColumnPoemException {
261 Column column = _getColumn(nameP);
262 if (column == null)
263 throw new NoSuchColumnPoemException(this, nameP);
264 else
265 return column;
266 }
267 protected final Column _getColumn(String nameP) {
268 Column column = (Column)columnsByName.get(nameP.toLowerCase());
269 return column;
270 }
271
272
273
274
275
276
277
278 public final Enumeration columns() {
279 return new ArrayEnumeration(columns);
280 }
281
282
283
284
285 public final int getColumnsCount() {
286 return columns.length;
287 }
288
289
290
291
292
293 public Column columnWithColumnInfoID(int columnInfoID) {
294 for (Enumeration c = columns(); c.hasMoreElements();) {
295 Column column = (Column)c.nextElement();
296 Integer id = column.columnInfoID();
297 if (id != null && id.intValue() == columnInfoID)
298 return column;
299 }
300 return null;
301 }
302
303
304
305
306
307
308
309
310
311
312 public final Column troidColumn() {
313 return troidColumn;
314 }
315
316
317
318
319 public final Column deletedColumn() {
320 return deletedColumn;
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336 public final Column displayColumn() {
337 return displayColumn == null ? troidColumn : displayColumn;
338 }
339
340
341
342
343 public final void setDisplayColumn(Column column) {
344 displayColumn = column;
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359 public final Column primaryCriterionColumn() {
360 return searchColumn;
361 }
362
363
364
365
366 public void setSearchColumn(Column column) {
367 searchColumn = column;
368 }
369
370
371
372
373
374
375 public String defaultOrderByClause() {
376 String clause = defaultOrderByClause;
377
378 if (clause == null) {
379 clause = EnumUtils.concatenated(
380 ", ",
381 new MappedEnumeration(new ArrayEnumeration(SortUtils.sorted(
382 new Order() {
383 public boolean lessOrEqual(Object a, Object b) {
384 return
385 ((Column)a).getDisplayOrderPriority().intValue() <=
386 ((Column)b).getDisplayOrderPriority().intValue();
387 }
388 },
389 new FilteredEnumeration(columns()) {
390 public boolean isIncluded(Object column) {
391 return ((Column)column).getDisplayOrderPriority() != null;
392 }
393 }))) {
394 public Object mapped(Object column) {
395 String sort = ((Column)column).fullQuotedName();
396 if (((Column)column).getSortDescending()) sort += " desc";
397 return sort;
398 }
399 });
400
401 if (clause.equals("") && displayColumn() != null)
402 clause = displayColumn().fullQuotedName();
403
404 defaultOrderByClause = clause;
405 }
406
407 return clause;
408 }
409
410
411
412
413 public void clearColumnInfoCaches() {
414 defaultOrderByClause = null;
415 for (int i = 0; i < displayColumns.length; ++i)
416 displayColumns[i] = null;
417 }
418
419
420
421
422
423
424 public void notifyColumnInfo(ColumnInfo infoP) {
425
426 if (infoP == null || infoP.getTableinfo_unsafe().equals(tableInfoID()))
427 clearColumnInfoCaches();
428 }
429
430
431
432
433
434
435
436
437
438
439 private Column[] columnsWhere(String whereClause) {
440
441 Enumeration colIDs =
442 getDatabase().getColumnInfoTable().troidSelection(
443 database.quotedName("tableinfo") + " = " + tableInfoID() +
444 " AND (" + whereClause + ")",
445 null, false, PoemThread.inSession() ? PoemThread.transaction() : null);
446
447 Vector them = new Vector();
448 while (colIDs.hasMoreElements()) {
449 Column column =
450 columnWithColumnInfoID(((Integer)colIDs.nextElement()).intValue());
451
452 if (column != null)
453 them.addElement(column);
454 }
455
456 Column[] columnsLocal = new Column[them.size()];
457 them.copyInto(columnsLocal);
458 return columnsLocal;
459 }
460
461
462
463
464
465
466
467 public final Enumeration displayColumns(DisplayLevel level) {
468 Column[] columnsLocal = displayColumns[level.getIndex().intValue()];
469
470 if (columnsLocal == null) {
471 columnsLocal =
472 columnsWhere(database.quotedName("displaylevel") + " <= " +
473 level.getIndex());
474 displayColumns[level.getIndex().intValue()] = columnsLocal;
475 }
476 return new ArrayEnumeration(columnsLocal);
477 }
478
479
480
481
482
483 public final int displayColumnsCount(DisplayLevel level) {
484 int l = level.getIndex().intValue();
485 if (displayColumns[l] == null)
486
487 displayColumns(level);
488
489 return displayColumns[l].length;
490 }
491
492
493
494
495
496
497
498
499
500 public final Enumeration getDetailDisplayColumns() {
501 return displayColumns(DisplayLevel.detail);
502 }
503
504
505
506
507 public final int getDetailDisplayColumnsCount() {
508 return displayColumnsCount(DisplayLevel.detail);
509 }
510
511
512
513
514
515
516
517
518
519 public final Enumeration getRecordDisplayColumns() {
520 return displayColumns(DisplayLevel.record);
521 }
522
523
524
525
526 public final int getRecordDisplayColumnsCount() {
527 return displayColumnsCount(DisplayLevel.record);
528 }
529
530
531
532
533
534
535
536
537
538
539 public final Enumeration getSummaryDisplayColumns() {
540 return displayColumns(DisplayLevel.summary);
541 }
542
543
544
545
546 public final int getSummaryDisplayColumnsCount() {
547 return displayColumnsCount(DisplayLevel.summary);
548 }
549
550
551
552
553
554
555
556
557 public final Enumeration getSearchCriterionColumns() {
558 Column[] columnsLocal = searchColumns;
559
560 if (columnsLocal == null) {
561 columnsLocal =
562 columnsWhere(database.quotedName("searchability") + " <= " +
563 Searchability.yes.getIndex());
564 searchColumns = columnsLocal;
565 }
566 return new ArrayEnumeration(searchColumns);
567 }
568
569
570
571
572 public final int getSearchCriterionColumnsCount() {
573 if (searchColumns == null)
574
575 getSearchCriterionColumns();
576
577 return searchColumns.length;
578 }
579
580 private Dbms dbms() {
581 return getDatabase().getDbms();
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 public void dbModifyStructure(String sql)
604 throws StructuralModificationFailedPoemException {
605
606
607 if (PoemThread.inSession())
608 PoemThread.commit();
609
610 try {
611 if (database.logSQL()) database.log("about to execute:" + sql);
612
613 Statement updateStatement = database.getCommittedConnection().createStatement();
614 updateStatement.executeUpdate(sql);
615 updateStatement.close();
616 database.getCommittedConnection().commit();
617 if (database.logCommits()) database.log(new CommitLogEvent(null));
618 if (database.logSQL()) database.log(new StructuralModificationLogEvent(sql));
619 database.incrementQueryCount(sql);
620 }
621 catch (SQLException e) {
622 throw new StructuralModificationFailedPoemException(sql, e);
623 }
624 }
625
626 private void dbCreateTable() {
627 String createTableSql = dbms().createTableSql(this);
628 dbModifyStructure(createTableSql);
629 String tableSetup = database.getDbms().tableInitialisationSql(this);
630 if (tableSetup != null) {
631 dbModifyStructure(tableSetup);
632 }
633 }
634
635
636
637
638
639
640
641 public String getDbmsTableType() {
642 return null;
643 }
644
645
646
647
648
649 public void dbAddConstraints() {
650 StringBuffer sqb = new StringBuffer();
651 for (int c = 0; c < columns.length; ++c) {
652 if (columns[c].getSQLType() instanceof TroidPoemType){
653 sqb.append("ALTER TABLE " + quotedName());
654 sqb.append(dbms().getPrimaryKeyDefinition(
655 columns[c].getName()));
656 try {
657 dbModifyStructure(sqb.toString());
658 } catch (StructuralModificationFailedPoemException e) {
659
660
661 e = null;
662 }
663 }
664 }
665 for (int c = 0; c < columns.length; ++c) {
666 if (columns[c].getSQLType() instanceof ReferencePoemType){
667 IntegrityFix fix = columns[c].getIntegrityFix();
668 sqb = new StringBuffer();
669 sqb.append("ALTER TABLE " + quotedName());
670 sqb.append(dbms().getForeignKeyDefinition(
671 getName(),
672 columns[c].getName(),
673 ((ReferencePoemType)columns[c].getSQLType()).
674 targetTable().getName(),
675 ((ReferencePoemType)columns[c].getSQLType()).
676 targetTable().troidColumn().getName(),
677 fix.getName()));
678 try {
679 dbModifyStructure(sqb.toString());
680 } catch (StructuralModificationFailedPoemException e) {
681
682
683 e = null;
684 }
685 }
686 }
687
688
689 }
690
691 private void dbAddColumn(Column column) {
692 if (column.getType().getNullable()) {
693 dbModifyStructure(
694 "ALTER TABLE " + quotedName() +
695 " ADD " + column.quotedName() +
696 " " + column.getSQLType().sqlDefinition(dbms()));
697 } else {
698 dbModifyStructure(
699 "ALTER TABLE " + quotedName() +
700 " ADD " + column.quotedName() +
701 " " + column.getSQLType().sqlTypeDefinition(dbms()));
702 dbModifyStructure(
703 "UPDATE " + quotedName() +
704 " SET " + column.quotedName() +
705 " = " + dbms().getQuotedValue(column.getSQLType(),
706 column.getSQLType().sqlDefaultValue(dbms())));
707 dbModifyStructure(
708 dbms().alterColumnNotNullableSQL(name, column));
709 }
710 }
711
712
713 private void dbCreateIndex(Column column) {
714 if (column.getIndexed()) {
715 if (!dbms().canBeIndexed(column)) {
716 database.log(new UnindexableLogEvent(column));
717 } else {
718 dbModifyStructure(
719 "CREATE " + (column.getUnique() ? "UNIQUE " : "") + "INDEX " +
720 indexName(column) +
721 " ON " + quotedName() + " " +
722 "(" + column.quotedName() +
723 dbms().getIndexLength(column) + ")");
724 }
725 }
726 }
727
728 private String indexName(Column column) {
729 return database.quotedName(
730 dbms().unreservedName(name) + "_" +
731 dbms().unreservedName(column.getName()) + "_index");
732 }
733
734
735
736
737
738
739
740
741
742
743
744 private PreparedStatement simpleInsert(Connection connection) {
745 StringBuffer sql = new StringBuffer();
746 sql.append("INSERT INTO " + quotedName() + " (");
747 for (int c = 0; c < columns.length; ++c) {
748 if (c > 0) sql.append(", ");
749 sql.append(columns[c].quotedName());
750 }
751 sql.append(") VALUES (");
752 for (int c = 0; c < columns.length; ++c) {
753 if (c > 0) sql.append(", ");
754 sql.append("?");
755 }
756
757 sql.append(")");
758
759 try {
760 return connection.prepareStatement(sql.toString());
761 }
762 catch (SQLException e) {
763 throw new SimplePrepareFailedPoemException(sql.toString(), e);
764 }
765 }
766
767 private PreparedStatement simpleGet(Connection connection) {
768 StringBuffer sql = new StringBuffer();
769 sql.append("SELECT ");
770 for (int c = 0; c < columns.length; ++c) {
771 if (c > 0) sql.append(", ");
772 sql.append(columns[c].quotedName());
773 }
774 sql.append(" FROM " + quotedName() +
775 " WHERE " + troidColumn.quotedName() + " = ?");
776
777 try {
778 return connection.prepareStatement(sql.toString());
779 }
780 catch (SQLException e) {
781 throw new SimplePrepareFailedPoemException(sql.toString(), e);
782 }
783 }
784
785 private PreparedStatement simpleModify(Connection connection) {
786
787 StringBuffer sql = new StringBuffer();
788 sql.append("UPDATE " + quotedName() + " SET ");
789 for (int c = 0; c < columns.length; ++c) {
790 if (c > 0) sql.append(", ");
791 sql.append(columns[c].quotedName());
792 sql.append(" = ?");
793 }
794 sql.append(" WHERE " + troidColumn.quotedName() + " = ?");
795
796 try {
797 return connection.prepareStatement(sql.toString());
798 }
799 catch (SQLException e) {
800 throw new SimplePrepareFailedPoemException(sql.toString(), e);
801 }
802 }
803
804
805
806
807
808
809
810 private class TransactionStuff {
811 PreparedStatement insert, modify, get;
812 TransactionStuff(Connection connection) {
813 insert = _this.simpleInsert(connection);
814 modify = _this.simpleModify(connection);
815 get = _this.simpleGet(connection);
816 }
817 }
818
819 private CachedIndexFactory transactionStuffs = new CachedIndexFactory() {
820 public Object reallyGet(int index) {
821
822 return new TransactionStuff(
823 JdbcTable.this.database.poemTransaction(index).getConnection());
824 }
825 };
826
827 private TransactionStuff committedTransactionStuff = null;
828
829
830
831
832 public void invalidateTransactionStuffs() {
833 transactionStuffs.invalidate();
834 }
835
836
837
838
839
840 private synchronized TransactionStuff getCommittedTransactionStuff() {
841 if (committedTransactionStuff == null)
842 committedTransactionStuff =
843 new TransactionStuff(database.getCommittedConnection());
844 return committedTransactionStuff;
845 }
846
847
848
849
850
851
852
853 private void load(PreparedStatement select, Persistent p) {
854 JdbcPersistent persistent = (JdbcPersistent)p;
855 try {
856 synchronized (select) {
857 select.setInt(1, persistent.troid().intValue());
858 ResultSet rs = select.executeQuery();
859 if (database.logSQL())
860 database.log(new SQLLogEvent(select.toString()));
861 database.incrementQueryCount(select.toString());
862 try {
863 if (!rs.next())
864 persistent.setStatusNonexistent();
865 else {
866 persistent.setStatusExistent();
867 for (int c = 0; c < columns.length; ++c)
868 columns[c].load_unsafe(rs, c + 1, persistent);
869 }
870 persistent.setDirty(false);
871 persistent.markValid();
872 if (rs.next())
873 throw new DuplicateTroidPoemException(this, persistent.troid());
874 }
875 finally {
876 try { rs.close(); } catch (Exception e) {
877 System.err.println("Cannot close resultset after exception.");
878 }
879 }
880 }
881 }
882 catch (SQLException e) {
883 throw new SimpleRetrievalFailedPoemException(e, select.toString());
884 }
885 catch (ValidationPoemException e) {
886 throw new UnexpectedValidationPoemException(e);
887 }
888 }
889
890
891
892
893
894 public void load(PoemTransaction transaction, Persistent persistent) {
895 load(transaction == null ?
896 getCommittedTransactionStuff().get :
897 ((TransactionStuff)transactionStuffs.get(transaction.index)).get,
898 persistent);
899 }
900
901 private void modify(PoemTransaction transaction, Persistent persistent) {
902 PreparedStatement modify =
903 ((TransactionStuff)transactionStuffs.get(transaction.index)).modify;
904 synchronized (modify) {
905 for (int c = 0; c < columns.length; ++c)
906 columns[c].save_unsafe(persistent, modify, c + 1);
907
908 try {
909 modify.setInt(columns.length + 1, persistent.troid().intValue());
910 }
911 catch (SQLException e) {
912 throw new SQLSeriousPoemException(e);
913 }
914
915 try {
916 modify.executeUpdate();
917 }
918 catch (SQLException e) {
919 throw dbms().exceptionForUpdate(this, modify, false, e);
920 }
921 database.incrementQueryCount(modify.toString());
922
923 if (database.logSQL())
924 database.log(new SQLLogEvent(modify.toString()));
925 }
926 persistent.postModify();
927 }
928
929 private void insert(PoemTransaction transaction, Persistent persistent) {
930
931 PreparedStatement insert =
932 ((TransactionStuff)transactionStuffs.get(transaction.index)).insert;
933 synchronized (insert) {
934 for (int c = 0; c < columns.length; ++c)
935 columns[c].save_unsafe(persistent, insert, c + 1);
936 try {
937 insert.executeUpdate();
938 }
939 catch (SQLException e) {
940 throw dbms().exceptionForUpdate(this, insert, true, e);
941 }
942 database.incrementQueryCount(insert.toString());
943 if (database.logSQL())
944 database.log(new SQLLogEvent(insert.toString()));
945 }
946 persistent.postInsert();
947 }
948
949
950
951
952
953
954
955 public void delete(Integer troid, PoemTransaction transaction) {
956 String sql =
957 "DELETE FROM " + quotedName() +
958 " WHERE " + troidColumn.quotedName() + " = " +
959 troid.toString();
960 try {
961 transaction.writeDown();
962 Connection connection = transaction.getConnection();
963
964 Statement deleteStatement = connection.createStatement();
965 int deleted = deleteStatement.executeUpdate(sql);
966 if (deleted != 1) {
967 throw new RowDisappearedPoemException(this,troid);
968 }
969 deleteStatement.close();
970 database.incrementQueryCount(sql);
971 if (database.logSQL())
972 database.log(new SQLLogEvent(sql));
973
974 cache.delete(troid);
975 }
976 catch (SQLException e) {
977 throw new ExecutingSQLPoemException(sql, e);
978 }
979 }
980
981
982
983
984
985 public void writeDown(PoemTransaction transaction, Persistent p) {
986 JdbcPersistent persistent = (JdbcPersistent)p;
987
988
989
990 if (persistent.isDirty()) {
991 troidColumn.setRaw_unsafe(persistent, persistent.troid());
992
993 if (persistent.statusExistent()) {
994 modify(transaction, persistent);
995 } else if (persistent.statusNonexistent()) {
996 insert(transaction, persistent);
997 persistent.setStatusExistent();
998 }
999
1000 persistent.setDirty(false);
1001 persistent.postWrite();
1002 }
1003 }
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 private Cache cache = new Cache(CACHE_LIMIT_DEFAULT);
1018
1019 private static final Procedure invalidator =
1020 new Procedure() {
1021 public void apply(Object arg) {
1022 ((Transactioned)arg).invalidate();
1023 }
1024 };
1025
1026
1027
1028
1029
1030
1031 public void uncache() {
1032 cache.iterate(invalidator);
1033 serial.invalidate();
1034 TableListener[] listenersLocal = this.listeners;
1035 for (int l = 0; l < listenersLocal.length; ++l)
1036 listenersLocal[l].notifyUncached(this);
1037 }
1038
1039
1040
1041
1042 public void trimCache(int maxSize) {
1043 cache.trim(maxSize);
1044 }
1045
1046
1047
1048
1049 public Cache.Info getCacheInfo() {
1050 return cache.getInfo();
1051 }
1052
1053
1054
1055
1056 public void addListener(TableListener listener) {
1057 listeners = (TableListener[])ArrayUtils.added(listeners, listener);
1058 }
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068 public void notifyTouched(PoemTransaction transaction, Persistent persistent) {
1069 serial.increment(transaction);
1070
1071 TableListener[] listenersLocal = this.listeners;
1072 for (int l = 0; l < listenersLocal.length; ++l)
1073 listenersLocal[l].notifyTouched(transaction, this, persistent);
1074 }
1075
1076
1077
1078
1079 public long serial(PoemTransaction transaction) {
1080 return serial.current(transaction);
1081 }
1082
1083
1084
1085
1086 public void readLock() {
1087 serial(PoemThread.transaction());
1088 }
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124 public Persistent getObject(Integer troid) throws NoSuchRowPoemException {
1125 JdbcPersistent persistent = (JdbcPersistent)cache.get(troid);
1126
1127 if (persistent == null) {
1128 persistent = (JdbcPersistent)newPersistent();
1129 claim(persistent, troid);
1130 load(PoemThread.transaction(), persistent);
1131 if (persistent.statusExistent())
1132 synchronized (cache) {
1133 JdbcPersistent tryAgain = (JdbcPersistent)cache.get(troid);
1134 if (tryAgain == null)
1135 cache.put(troid, persistent);
1136 else
1137 persistent = tryAgain;
1138 }
1139 }
1140
1141 if (!persistent.statusExistent())
1142 throw new NoSuchRowPoemException(this, troid);
1143
1144 persistent.existenceLock(PoemThread.sessionToken());
1145
1146 return persistent;
1147 }
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 public Persistent getObject(int troid) throws NoSuchRowPoemException {
1158 return getObject(new Integer(troid));
1159 }
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184 public String selectionSQL(String fromClause, String whereClause,
1185 String orderByClause, boolean includeDeleted,
1186 boolean excludeUnselectable) {
1187 return selectOrCountSQL(troidColumn().fullQuotedName(),
1188 fromClause, whereClause, orderByClause,
1189 includeDeleted, excludeUnselectable);
1190 }
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 private ResultSet selectionResultSet(String fromClause, String whereClause,
1208 String orderByClause,
1209 boolean includeDeleted,
1210 boolean excludeUnselectable,
1211 PoemTransaction transaction)
1212 throws SQLPoemException {
1213
1214 String sql = selectionSQL(fromClause, whereClause, orderByClause,
1215 includeDeleted, excludeUnselectable);
1216
1217
1218 try {
1219 Connection connection;
1220 if (transaction == null) {
1221 connection = getDatabase().getCommittedConnection();
1222 } else {
1223 transaction.writeDown();
1224 connection = transaction.getConnection();
1225 }
1226
1227 Statement selectionStatement = connection.createStatement();
1228 ResultSet rs = selectionStatement.executeQuery(sql);
1229 database.incrementQueryCount(sql);
1230
1231 SessionToken token = PoemThread._sessionToken();
1232 if (token != null) {
1233 token.toTidy().add(rs);
1234 token.toTidy().add(selectionStatement);
1235 }
1236 if (database.logSQL())
1237 database.log(new SQLLogEvent(sql));
1238 return rs;
1239 }
1240 catch (SQLException e) {
1241 throw new ExecutingSQLPoemException(sql, e);
1242 }
1243 }
1244
1245
1246
1247
1248
1249
1250
1251 public Enumeration troidSelection(String whereClause, String orderByClause,
1252 boolean includeDeleted,
1253 PoemTransaction transaction) {
1254 return troidsFrom(selectionResultSet(null, whereClause, orderByClause,
1255 includeDeleted, true,
1256 transaction));
1257 }
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267 public Enumeration troidSelection(Persistent criteria, String orderByClause,
1268 boolean includeDeleted,
1269 boolean excludeUnselectable,
1270 PoemTransaction transaction) {
1271 return troidsFrom(selectionResultSet(((JdbcPersistent)criteria).fromClause(),
1272 whereClause(