1 /*
2 * $Source: /usr/cvsroot/melati/poem/src/main/java/org/melati/poem/Table.java,v $
3 * $Revision: 1.240 $
4 *
5 * Copyright (C) 2000 William Chesters
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * William Chesters <williamc At paneris.org>
42 * http://paneris.org/~williamc
43 * Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44 */
45
46 package org.melati.poem;
47
48 import org.melati.poem.util.Cache;
49
50 import java.util.Enumeration;
51 import java.io.PrintStream;
52 import java.sql.ResultSet;
53
54 /**
55 * A table.
56 *
57 * @since 14-Apr-2008
58 */
59 public interface Table {
60 /**
61 * The database to which the table is attached.
62 * @return the db
63 */
64 Database getDatabase();
65
66 /**
67 * Initialise the table.
68 */
69 void init();
70 /**
71 * Do stuff immediately after table initialisation.
72 * <p>
73 * This base method clears the column info caches and adds a listener
74 * to the column info table to maintain the caches.
75 * <p>
76 * It may be overridden to perform other actions. For example to
77 * ensure required rows exist in tables that define numeric ID's for
78 * codes.
79 *
80 * @see #notifyColumnInfo(ColumnInfo)
81 * @see #clearColumnInfoCaches()
82 */
83 void postInitialise();
84
85 /**
86 * Create the (possibly overridden) TableInfo if it has not yet been created.
87 */
88 void createTableInfo();
89 /**
90 * The table's programmatic name. Identical with its name in the DSD (if the
91 * table was defined there) and in its <TT>tableinfo</TT> entry.
92 * This will normally be the same as the name in the RDBMS itself, however that name
93 * may be translated to avoid DBMS specific name clashes.
94 *
95 * @return the table name, case as defined in the DSD
96 * @see org.melati.poem.dbms.Dbms#melatiName(String)
97 */
98 String getName();
99
100 /**
101 * @return table name quoted using the DBMS' specific quoting rules.
102 */
103 String quotedName();
104
105 /**
106 * The human-readable name of the table. POEM itself doesn't use this, but
107 * it's available to applications and Melati's generic admin system as a
108 * default label for the table and caption for its records.
109 * @return The human-readable name of the table
110 */
111 String getDisplayName();
112
113 /**
114 * A brief description of the table's function. POEM itself doesn't use
115 * this, but it's available to applications and Melati's generic admin system
116 * as a default label for the table and caption for its records.
117 * @return the brief description
118 */
119 String getDescription();
120
121 /**
122 * The category of this table. POEM itself doesn't use
123 * this, but it's available to applications and Melati's generic admin system
124 * as a default label for the table and caption for its records.
125 *
126 * @return the category
127 */
128 TableCategory getCategory();
129
130 /**
131 * @return the {@link org.melati.poem.TableInfo} for this table
132 */
133 TableInfo getInfo();
134
135 /**
136 * The troid (<TT>id</TT>) of the table's entry in the <TT>tableinfo</TT>
137 * table. It will always have one (except during initialisation, which the
138 * application programmer will never see).
139 *
140 * @return id in TableInfo metadata table
141 */
142 Integer tableInfoID();
143
144 /**
145 * The table's column with a given name. If the table is defined in the DSD
146 * under the name <TT><I>foo</I></TT>, there will be an
147 * application-specialised <TT>Table</TT> subclass, called
148 * <TT><I>Foo</I>Table</TT> (and available as <TT>get<I>Foo</I>Table</TT>
149 * from the application-specialised <TT>Database</TT> subclass) which has
150 * extra named methods for accessing the table's predefined <TT>Column</TT>s.
151 *
152 * @param nameP name of column to get
153 * @return column of that name
154 * @throws org.melati.poem.NoSuchColumnPoemException if there is no column with that name
155 */
156 Column getColumn(String nameP) throws NoSuchColumnPoemException;
157
158 /**
159 * All the table's columns.
160 *
161 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
162 * @see org.melati.poem.Column
163 */
164 Enumeration columns();
165
166 /**
167 * @return the number of columns in this table.
168 */
169 int getColumnsCount();
170
171 /**
172 * @param columnInfoID
173 * @return the Column with a TROID equal to columnInfoID
174 */
175 Column columnWithColumnInfoID(int columnInfoID);
176
177 /**
178 * The table's troid column. Every table in a POEM database must have a
179 * troid (table row ID, or table-unique non-nullable integer primary key),
180 * often but not necessarily called <TT>id</TT>, so that it can be
181 * conveniently `named'.
182 *
183 * @return the id column
184 * @see #getObject(Integer)
185 */
186 Column troidColumn();
187
188 /**
189 * @return The table's deleted-flag column, if any.
190 */
191 Column deletedColumn();
192
193 /**
194 * The table's primary display column, the Troid column if not set.
195 * This is the column used to represent records from the table
196 * concisely in reports or whatever. It is determined
197 * at initialisation time by examining the <TT>Column</TT>s
198 * <TT>getPrimaryDisplay()</TT> flags.
199 *
200 * @return the table's display column, or <TT>null</TT> if it hasn't got one
201 *
202 * see Column#setColumnInfo
203 * @see org.melati.poem.ReferencePoemType#_stringOfCooked
204 * @see org.melati.poem.DisplayLevel#primary
205 */
206 Column displayColumn();
207
208 /**
209 * @param column the display column to set
210 */
211 void setDisplayColumn(Column column);
212
213 /**
214 * In a similar manner to the primary display column, each table can have
215 * one primary criterion column.
216 * <p>
217 * The Primary Criterion is the main grouping field of the table,
218 * ie the most important non-unique type field.
219 * <p>
220 * For example the Primary Criterion for a User table might be Nationality.
221 *
222 * @return the search column, if any
223 * @see org.melati.poem.Searchability
224 */
225 Column primaryCriterionColumn();
226
227 /**
228 * @param column the search column to set
229 */
230 void setSearchColumn(Column column);
231
232 /**
233 * If the troidColumn has yet to be set then returns an empty string.
234 *
235 * @return comma separated list of the columns to order by
236 */
237 String defaultOrderByClause();
238
239 /**
240 * Clear caches.
241 */
242 void clearColumnInfoCaches();
243
244 /**
245 * Clears columnInfo caches, normally a no-op.
246 *
247 * @param infoP the possibly null ColumnInfo meta-data persistent
248 */
249 void notifyColumnInfo(ColumnInfo infoP);
250
251 /**
252 * Return columns at a display level in display order.
253 *
254 * @param level the {@link org.melati.poem.DisplayLevel} to select
255 * @return an Enumeration of columns at the given level
256 */
257 Enumeration displayColumns(DisplayLevel level);
258
259 /**
260 * @param level the {@link org.melati.poem.DisplayLevel} to select
261 * @return the number of columns at a display level.
262 */
263 int displayColumnsCount(DisplayLevel level);
264
265 /**
266 * The table's columns for detailed display in display order.
267 *
268 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
269 * @see org.melati.poem.Column
270 * @see #displayColumns(org.melati.poem.DisplayLevel)
271 * @see org.melati.poem.DisplayLevel#detail
272 */
273 Enumeration getDetailDisplayColumns();
274
275 /**
276 * @return the number of columns at display level <tt>Detail</tt>
277 */
278 int getDetailDisplayColumnsCount();
279
280 /**
281 * The table's columns designated for display in a record, in display order.
282 *
283 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
284 * @see org.melati.poem.Column
285 * @see #displayColumns(org.melati.poem.DisplayLevel)
286 * @see org.melati.poem.DisplayLevel#record
287 */
288 Enumeration getRecordDisplayColumns();
289
290 /**
291 * @return the number of columns at display level <tt>Record</tt>
292 */
293 int getRecordDisplayColumnsCount();
294
295 /**
296 * The table's columns designated for display in a record summary, in display
297 * order.
298 *
299 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
300 * @see org.melati.poem.Column
301 * @see #displayColumns(org.melati.poem.DisplayLevel)
302 * @see org.melati.poem.DisplayLevel#summary
303 */
304 Enumeration getSummaryDisplayColumns();
305
306 /**
307 * @return the number of columns at display level <tt>Summary</tt>
308 */
309 int getSummaryDisplayColumnsCount();
310
311 /**
312 * The table's columns designated for use as search criteria, in display
313 * order.
314 *
315 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
316 * @see org.melati.poem.Column
317 */
318 Enumeration getSearchCriterionColumns();
319
320 /**
321 * @return the number of columns which are searchable
322 */
323 int getSearchCriterionColumnsCount();
324
325 /**
326 * Use this for DDL statements, ie those which alter the structure of the db.
327 * Postgresql in particular does not like DDL statements being executed within a transaction.
328 *
329 * @param sql the SQL DDL statement to execute
330 * @throws org.melati.poem.StructuralModificationFailedPoemException
331 */
332 void dbModifyStructure(String sql)
333 throws StructuralModificationFailedPoemException;
334
335 /**
336 * Constraints are not used in POEM, but you might want to use them if
337 * exporting the db or using schema visualisation tools.
338 */
339 void dbAddConstraints();
340
341 /**
342 * When deleting a table and used in tests.
343 */
344 void invalidateTransactionStuffs();
345
346 /**
347 * @param transaction possibly null if working with the committed transaction
348 * @param persistent the Persistent to load
349 */
350 void load(PoemTransaction transaction, Persistent persistent);
351
352 /**
353 * The Transaction cannot be null, as this is trapped in
354 * #deleteLock(SessionToken).
355 * @param troid id of row to delete
356 * @param transaction a non-null transaction
357 */
358 void delete(Integer troid, PoemTransaction transaction);
359
360 /**
361 * @param transaction our PoemTransaction
362 * @param p the Persistent to write
363 */
364 void writeDown(PoemTransaction transaction, Persistent p);
365
366 /**
367 * Invalidate table cache.
368 *
369 * NOTE Invalidated cache elements are reloaded when next read
370 */
371 void uncache();
372
373 /**
374 * @param maxSize new maximum size
375 */
376 void trimCache(int maxSize);
377
378 /**
379 * @return the Cache Info object
380 */
381 Cache.Info getCacheInfo();
382
383 /**
384 * Add a {@link org.melati.poem.TableListener} to this Table.
385 */
386 void addListener(TableListener listener);
387
388 /**
389 * Notify the table that one if its records is about to be changed in a
390 * transaction. You can (with care) use this to support cacheing of
391 * frequently-used facts about the table's records.
392 *
393 * @param transaction the transaction in which the change will be made
394 * @param persistent the record to be changed
395 */
396 void notifyTouched(PoemTransaction transaction, Persistent persistent);
397
398 /**
399 * @return the Transaction serial
400 */
401 long serial(PoemTransaction transaction);
402
403 /**
404 * Lock this record.
405 */
406 void readLock();
407
408 /**
409 * The object from the table with a given troid.
410 *
411 * @param troid Every record (object) in a POEM database must have a
412 * troid (table row ID, or table-unique non-nullable
413 * integer primary key), often but not necessarily called
414 * <TT>id</TT>, so that it can be conveniently `named' for
415 * retrieval by this method.
416 *
417 * @return A <TT>Persistent</TT> of the record with the given troid;
418 * or, if the table was defined in the DSD under the name
419 * <TT><I>foo</I></TT>, an application-specialised subclass
420 * <TT><I>Foo</I></TT> of <TT>Persistent</TT>. In that case, there
421 * will also be an application-specialised <TT>Table</TT> subclass,
422 * called <TT><I>Foo</I>Table</TT> (and available as
423 * <TT>get<I>Foo</I>Table</TT> from the application-specialised
424 * <TT>Database</TT> subclass), which has a matching method
425 * <TT>get<I>Foo</I>Object</TT> for obtaining the specialised object
426 * under its own type. Note that no access checks are done at this
427 * stage: you may not be able to do anything with the object handle
428 * returned from this method without provoking a
429 * <TT>PoemAccessException</TT>.
430 *
431 * @exception org.melati.poem.NoSuchRowPoemException
432 * if there is no row in the table with the given troid
433 *
434 * @see org.melati.poem.Persistent#getTroid()
435 */
436 Persistent getObject(Integer troid) throws NoSuchRowPoemException;
437
438 /**
439 * The object from the table with a given troid. See previous.
440 *
441 * @param troid the table row id
442 * @return the Persistent
443 * @throws org.melati.poem.NoSuchRowPoemException if not found
444 * @see #getObject(Integer)
445 */
446 Persistent getObject(int troid) throws NoSuchRowPoemException;
447
448 /**
449 * The from clause has been added as an argument because it is
450 * inextricably linked to the when clause, but the default is
451 * {@link #quotedName()}.
452 *
453 * It is the programmer's responsibility to ensure that the where clause
454 * is suitable for the target DBMS.
455 *
456 * @param fromClause Comma separated list of table names or null for default.
457 * @param whereClause SQL fragment
458 * @param orderByClause Comma separated list
459 * @param includeDeleted Flag as to whether to include soft deleted records
460 * @param excludeUnselectable Whether to append unselectable exclusion SQL
461 * @todo Should work within some kind of limit
462 * @return an SQL SELECT statement put together from the arguments and
463 * default order by clause.
464 */
465 String selectionSQL(String fromClause, String whereClause,
466 String orderByClause, boolean includeDeleted,
467 boolean excludeUnselectable);
468
469 /**
470 * It is the programmer's responsibility to ensure that the where clause
471 * is suitable for the target DBMS.
472 *
473 * @return an {@link java.util.Enumeration} of Troids satisfying the criteria.
474 */
475 Enumeration troidSelection(String whereClause, String orderByClause,
476 boolean includeDeleted,
477 PoemTransaction transaction);
478
479 /**
480 *
481 * @see #troidSelection(String, String, boolean, org.melati.poem.PoemTransaction)
482 * @param criteria Represents selection criteria possibly on joined tables
483 * @param transaction A transaction or null for
484 * {@link org.melati.poem.PoemThread#transaction()}
485 * @return a selection of troids given arguments specifying a query
486 */
487 Enumeration troidSelection(Persistent criteria, String orderByClause,
488 boolean includeDeleted,
489 boolean excludeUnselectable,
490 PoemTransaction transaction);
491
492 /**
493 * @param flag whether to remember or forget
494 */
495 void rememberAllTroids(boolean flag);
496
497 /**
498 * @param limit the limit to set
499 */
500 void setCacheLimit(Integer limit);
501
502 /**
503 * A <TT>SELECT</TT>ion of troids of objects from the table meeting given
504 * criteria.
505 *
506 * It is the programmer's responsibility to ensure that the where clause
507 * is suitable for the target DBMS.
508 *
509 * If the orderByClause is null, then the default order by clause is applied.
510 * If the orderByClause is an empty string, ie "", then no ordering is
511 * applied.
512 *
513 * @param whereClause an SQL snippet
514 * @param orderByClause an SQL snippet
515 * @param includeDeleted whether to include deleted records, if any
516 *
517 * @return an <TT>Enumeration</TT> of <TT>Integer</TT>s, which can be mapped
518 * onto <TT>Persistent</TT> objects using <TT>getObject</TT>;
519 * or you can just use <TT>selection</TT>
520 *
521 * @see #getObject(Integer)
522 * @see #selection(String, String, boolean)
523 */
524 Enumeration troidSelection(String whereClause, String orderByClause,
525 boolean includeDeleted)
526 throws SQLPoemException;
527
528 /**
529 * All the objects in the table.
530 *
531 * @return An <TT>Enumeration</TT> of <TT>Persistent</TT>s, or, if the table
532 * was defined in the DSD under the name <TT><I>foo</I></TT>, of
533 * application-specialised subclasses <TT><I>Foo</I></TT>. Note
534 * that no access checks are done at this stage: you may not be able
535 * to do anything with some of the object handles in the enumeration
536 * without provoking a <TT>PoemAccessException</TT>. If the table
537 * has a <TT>deleted</TT> column, the objects flagged as deleted will
538 * be passed over.
539 * @see Selectable#selection()
540 */
541 Enumeration selection() throws SQLPoemException;
542
543 /**
544 * A <TT>SELECT</TT>ion of objects from the table meeting given criteria.
545 * This is one way to run a search against the database and return the
546 * results as a series of typed POEM objects.
547 *
548 * It is the programmer's responsibility to ensure that the where clause
549 * is suitable for the target DBMS.
550 *
551 * @param whereClause SQL <TT>SELECT</TT>ion criteria for the search:
552 * the part that should appear after the
553 * <TT>WHERE</TT> keyword
554 *
555 * @return An <TT>Enumeration</TT> of <TT>Persistent</TT>s, or, if the table
556 * was defined in the DSD under the name <TT><I>foo</I></TT>, of
557 * application-specialised subclasses <TT><I>Foo</I></TT>. Note
558 * that no access checks are done at this stage: you may not be able
559 * to do anything with some of the object handles in the enumeration
560 * without provoking a <TT>PoemAccessException</TT>. If the table
561 * has a <TT>deleted</TT> column, the objects flagged as deleted will
562 * be passed over.
563 *
564 * @see org.melati.poem.Column#selectionWhereEq(Object)
565 */
566 Enumeration selection(String whereClause)
567 throws SQLPoemException;
568
569 /**
570 * Get an object satisfying the where clause.
571 * It is the programmer's responsibility to use this in a
572 * context where only one result will be found, if more than one
573 * actually exist only the first will be returned.
574 *
575 * It is the programmer's responsibility to ensure that the where clause
576 * is suitable for the target DBMS.
577 *
578 * @param whereClause SQL <TT>SELECT</TT>ion criteria for the search:
579 * the part that should appear after the
580 * <TT>WHERE</TT> keyword
581 * @return the first item satisfying criteria
582 */
583 Persistent firstSelection(String whereClause);
584
585 /**
586 * A <TT>SELECT</TT>ion of objects from the table meeting given criteria,
587 * possibly including those flagged as deleted.
588 *
589 * If the orderByClause is null, then the default order by clause is applied.
590 * If the orderByClause is an empty string, ie "", then no ordering is
591 * applied.
592 *
593 * It is the programmer's responsibility to ensure that the where clause
594 * is suitable for the target DBMS.
595 *
596 * @param includeDeleted whether to return objects flagged as deleted
597 * (ignored if the table doesn't have a
598 * <TT>deleted</TT> column)
599 * @return a ResultSet as an Enumeration
600 * @see #selection(String)
601 */
602 Enumeration selection(String whereClause, String orderByClause,
603 boolean includeDeleted)
604 throws SQLPoemException;
605
606 /**
607 * Return a selection of rows given an exemplar.
608 *
609 * @param criteria Represents selection criteria possibly on joined tables
610 * @return an enumeration of like objects
611 * @see #selection(String, String, boolean)
612 */
613 Enumeration selection(Persistent criteria)
614 throws SQLPoemException;
615
616 /**
617 * Return a selection of rows given arguments specifying a query.
618 *
619 * @see #selection(String, String, boolean)
620 * @param criteria Represents selection criteria possibly on joined tables
621 * @param orderByClause Comma separated list
622 * @return an enumeration of like objects with the specified ordering
623 */
624 Enumeration selection(Persistent criteria, String orderByClause)
625 throws SQLPoemException;
626
627 /**
628 * Return a selection of rows given arguments specifying a query.
629 *
630 * @see #selection(String, String, boolean)
631 * @param criteria Represents selection criteria possibly on joined tables
632 * @param orderByClause Comma separated list
633 * @param excludeUnselectable Whether to append unselectable exclusion SQL
634 * @return an enumeration of like Persistents
635 */
636 Enumeration selection(Persistent criteria, String orderByClause,
637 boolean includeDeleted, boolean excludeUnselectable)
638 throws SQLPoemException;
639
640
641 /**
642 * @param whereClause
643 * @return the SQL string for the current SQL dialect
644 */
645 String countSQL(String whereClause);
646
647 /**
648 * Return an SQL statement to count rows put together from the arguments.
649 *
650 * It is the programmer's responsibility to ensure that the where clause
651 * is suitable for the target DBMS.
652 *
653 * @param fromClause Comma separated list of table names
654 * @return the SQL query
655 */
656 String countSQL(String fromClause, String whereClause,
657 boolean includeDeleted, boolean excludeUnselectable);
658
659 /**
660 * It is the programmer's responsibility to ensure that the where clause
661 * is suitable for the target DBMS.
662 *
663 * @return the number records satisfying criteria.
664 */
665 int count(String whereClause,
666 boolean includeDeleted, boolean excludeUnselectable)
667 throws SQLPoemException;
668
669 /**
670 * It is the programmer's responsibility to ensure that the where clause
671 * is suitable for the target DBMS.
672 *
673 * @return the number records satisfying criteria.
674 */
675 int count(String whereClause, boolean includeDeleted)
676 throws SQLPoemException;
677
678 /**
679 * It is the programmer's responsibility to ensure that the where clause
680 * is suitable for the target DBMS.
681 *
682 * @return the number of records satisfying criteria.
683 */
684 int count(String whereClause)
685 throws SQLPoemException;
686
687 /**
688 * @return the number records in this table.
689 */
690 int count()
691 throws SQLPoemException;
692
693 /**
694 * It is the programmer's responsibility to ensure that the where clause
695 * is suitable for the target DBMS.
696 *
697 * @param whereClause the SQL criteria
698 * @return whether any records satisfy criteria.
699 */
700 boolean exists(String whereClause) throws SQLPoemException;
701
702 /**
703 * @param persistent a {@link org.melati.poem.Persistent} with some fields filled in
704 * @return whether any records exist with the same fields filled
705 */
706 boolean exists(Persistent persistent);
707
708 /**
709 * Append an SQL logical expression to the given buffer to match rows
710 * according to criteria represented by the given object.
711 * <p>
712 * This default selects rows for which the non-null fields in the
713 * given object match, but subtypes may add other criteria.
714 * <p>
715 * The column names are now qualified with the table name so that
716 * subtypes can append elements of a join but there is no filtering
717 * by canselect columns.
718 *
719 * @todo Add mechanism for searching for Nulls (that would be query
720 * constructs as per SQL parse tree, but efferent not afferent)
721 *
722 * @see #notifyColumnInfo(org.melati.poem.ColumnInfo)
723 * @see #clearColumnInfoCaches()
724 */
725 void appendWhereClause(StringBuffer clause, Persistent persistent);
726
727 /**
728 * Return an SQL WHERE clause to select rows that match the non-null
729 * fields of the given object.
730 * <p>
731 * This does not filter out any rows with a capability the user
732 * does not have in a canselect column, nor did it ever filter
733 * out rows deleted according to a "deleted" column.
734 * But the caller usually gets a second chance to do both.
735 * @return an SQL fragment
736 */
737 String whereClause(Persistent criteria);
738
739 /**
740 * Return an SQL WHERE clause to select rows using the given object
741 * as a selection criteria and optionally deleted rows or those
742 * included rows the user is not capable of selecting.
743 * <p>
744 * This is currently implemented in terms of
745 * {@link org.melati.poem.Table#appendWhereClause(StringBuffer, org.melati.poem.Persistent)}.
746 * @return an SQL fragment
747 */
748 String whereClause(Persistent criteria,
749 boolean includeDeleted, boolean excludeUnselectable);
750
751 /**
752 * @return an SQL fragment
753 * @see #cnfWhereClause(java.util.Enumeration, boolean, boolean)
754 * @see #whereClause(org.melati.poem.Persistent)
755 */
756 String cnfWhereClause(Enumeration persistents);
757
758 /**
759 * Return a Conjunctive Normal Form (CNF) where clause.
760 * See http://en.wikipedia.org/wiki/Conjunctive_normal_form.
761 *
762 * @return an SQL fragment
763 */
764 String cnfWhereClause(Enumeration persistents,
765 boolean includeDeleted, boolean excludeUnselectable);
766
767 /**
768 * All the objects in the table which refer to a given object. If none of
769 * the table's columns are reference columns, the <TT>Enumeration</TT>
770 * returned will obviously be empty.
771 * <p>
772 * It is not guaranteed to be quick to execute!
773 *
774 * @return an <TT>Enumeration</TT> of <TT>Persistent</TT>s
775 */
776
777 Enumeration referencesTo(Persistent object);
778
779 /**
780 * All the columns in the table which refer to the given table.
781 *
782 * @param table
783 * @return an Enumeration of Columns referring to the specified Table
784 */
785 Enumeration referencesTo(Table table);
786
787 /**
788 * @return the current highest troid
789 */
790 int getMostRecentTroid();
791
792 /**
793 * @param persistent unused parameter, but might be needed in another troid schema
794 * @return the next Troid
795 */
796 Integer troidFor(Persistent persistent);
797
798 /**
799 * Write a new row containing the given object.
800 * <p>
801 * The given object will be assigned the next troid and its internal
802 * state will also be modified.
803 *
804 * @exception org.melati.poem.InitialisationPoemException The object failed validation
805 * (currently one of its field values failed).
806 */
807 void create(Persistent p)
808 throws AccessPoemException, ValidationPoemException,
809 InitialisationPoemException;
810
811 /**
812 * Create a new object (record) in the table.
813 *
814 * @param initialiser A piece of code for setting the new object's
815 * initial values. You'll probably want to define
816 * it as an anonymous class.
817 *
818 * @return A <TT>Persistent</TT> representing the new object, or, if the
819 * table was defined in the DSD under the name <TT><I>foo</I></TT>,
820 * an application-specialised subclass <TT><I>Foo</I></TT> of
821 * <TT>Persistent</TT>.
822 *
823 * @exception org.melati.poem.AccessPoemException
824 * if <TT>initialiser</TT> provokes one during its work (which
825 * is unlikely, since POEM's standard checks are disabled
826 * while it runs)
827 * @exception org.melati.poem.ValidationPoemException
828 * if <TT>initialiser</TT> provokes one during its work
829 * @exception org.melati.poem.InitialisationPoemException
830 * if the object is left by <TT>initialiser</TT> in a state in
831 * which not all of its fields have legal values, or in which
832 * the calling thread would not be allowed write access to the
833 * object under its <TT>AccessToken</TT>---<I>i.e.</I> you
834 * can't create objects you wouldn't be allowed to write to.
835 *
836 * @see org.melati.poem.Initialiser#init(Persistent)
837 * @see org.melati.poem.PoemThread#accessToken()
838 * @see #getCanCreate()
839 */
840 Persistent create(Initialiser initialiser)
841 throws AccessPoemException, ValidationPoemException,
842 InitialisationPoemException;
843
844 /**
845 * @return A freshly minted floating <TT>Persistent</TT> object for this table,
846 * ie one without a troid set
847 */
848 Persistent newPersistent();
849
850 /**
851 * It is the programmer's responsibility to ensure that the where clause
852 * is suitable for the target DBMS.
853 *
854 * @param whereClause the criteria
855 */
856 void delete_unsafe(String whereClause);
857
858 /**
859 * The number of `extra' (non-DSD-defined) columns in the table.
860 */
861 int extrasCount();
862
863 /**
864 * The capability required for reading records from the table, unless
865 * overridden in the record itself. This simply comes from the table's
866 * record in the <TT>tableinfo</TT> table.
867 *
868 * @return the capability needed to read this table
869 */
870 Capability getDefaultCanRead();
871
872 /**
873 * The capability required for updating records in the table, unless
874 * overridden in the record itself. This simply comes from the table's
875 * record in the <TT>tableinfo</TT> table.
876 *
877 * @return the default {@link org.melati.poem.Capability} required to write a
878 * {@link org.melati.poem.Persistent}, if any
879 */
880 Capability getDefaultCanWrite();
881
882 /**
883 * The capability required for deleting records in the table, unless
884 * overridden in the record itself. This simply comes from the table's
885 * record in the <TT>tableinfo</TT> table.
886 * @return the default {@link org.melati.poem.Capability} required to delete a
887 * {@link org.melati.poem.Persistent}, if any
888 */
889 Capability getDefaultCanDelete();
890
891 /**
892 * The capability required for creating records in the table. This simply
893 * comes from the table's record in the <TT>tableinfo</TT> table.
894 *
895 * @return the Capability required to write to this table
896 * @see #create(Initialiser)
897 */
898 Capability getCanCreate();
899
900 /**
901 * @return the canReadColumn or the canSelectColumn or null
902 */
903 Column canReadColumn();
904
905 /**
906 * @return the canSelectColumn or null
907 */
908 Column canSelectColumn();
909
910 /**
911 * @return the canWriteColumn or null
912 */
913 Column canWriteColumn();
914
915 /**
916 * @return the canDeleteColumn or null
917 */
918 Column canDeleteColumn();
919
920 /**
921 * Add a {@link org.melati.poem.Column} to the database and the {@link org.melati.poem.TableInfo} table.
922 *
923 * @param infoP the meta data about the {@link org.melati.poem.Column}
924 * @return the newly added column
925 */
926 Column addColumnAndCommit(ColumnInfo infoP) throws PoemException;
927
928 /**
929 * @param columnInfo metadata about the column to delete, which is itself deleted
930 */
931 void deleteColumnAndCommit(ColumnInfo columnInfo) throws PoemException;
932
933 /**
934 * A concise string to stand in for the table. The table's name and a
935 * description of where it was defined (the DSD, the metadata tables or the
936 * JDBC metadata).
937 * {@inheritDoc}
938 * @see Object#toString()
939 */
940 String toString();
941
942 /**
943 * Print some diagnostic information about the contents and consistency of
944 * POEM's cache for this table to stderr.
945 */
946 void dumpCacheAnalysis();
947
948 /**
949 * Print information about the structure of the table to stdout.
950 */
951 void dump();
952
953 /**
954 * Print information to PrintStream.
955 *
956 * @param ps PrintStream to dump to
957 */
958 void dump(PrintStream ps);
959
960 /**
961 * A mechanism for caching a selection of records.
962 *
963 * It is the programmer's responsibility to ensure that the where clause
964 * is suitable for the target DBMS.
965 *
966 * @param whereClause raw SQL selection clause appropriate for this DBMS
967 * @param orderByClause which field to order by or null
968 * @return the results
969 */
970 CachedSelection cachedSelection(String whereClause,
971 String orderByClause);
972
973 /**
974 * A mechanism for caching a record count.
975 *
976 * It is the programmer's responsibility to ensure that the where clause
977 * is suitable for the target DBMS.
978 *
979 * @param whereClause raw SQL selection clause appropriate for this DBMS
980 * @param includeDeleted whether to include soft deleted records
981 * @return a cached count
982 */
983 CachedCount cachedCount(String whereClause, boolean includeDeleted);
984
985 /**
986 * A mechanism for caching a record count.
987 *
988 * It is the programmer's responsibility to ensure that the where clause
989 * is suitable for the target DBMS.
990 *
991 * @param whereClause raw SQL selection clause appropriate for this DBMS
992 * @param includeDeleted whether to include soft deleted records
993 * @param excludeUnselectable whether to exclude columns which cannot be selected
994 * @return a cached count
995 */
996 CachedCount cachedCount(String whereClause, boolean includeDeleted,
997 boolean excludeUnselectable);
998
999 /**
1000 * A mechanism for caching a record count.
1001 *
1002 * @param criteria a {@link org.melati.poem.Persistent} with selection fields filled
1003 * @param includeDeleted whether to include soft deleted records
1004 * @param excludeUnselectable whether to exclude columns which cannot be selected
1005 * @return a cached count
1006 */
1007 CachedCount cachedCount(Persistent criteria, boolean includeDeleted,
1008 boolean excludeUnselectable);
1009
1010 /**
1011 * @param criteria a Persistent to extract where clause from
1012 * @return a CachedCount of records matching Criteria
1013 */
1014 CachedCount cachedCount(Persistent criteria);
1015
1016 /**
1017 * A mechanism for caching a record count.
1018 *
1019 * It is the programmer's responsibility to ensure that the where clause
1020 * is suitable for the target DBMS.
1021 *
1022 * @param whereClause raw SQL selection clause appropriate for this DBMS
1023 * @return a cached count
1024 */
1025 CachedCount cachedCount(String whereClause);
1026
1027 /**
1028 * A mechanism for caching an existance.
1029 *
1030 * It is the programmer's responsibility to ensure that the where clause
1031 * is suitable for the target DBMS.
1032 *
1033 * NOTE It is possible for the count to be written simultaneously,
1034 * but the cache will end up with the same result.
1035 *
1036 * @param whereClause raw SQL selection clause appropriate for this DBMS
1037 * @return a cached exists
1038 */
1039 CachedExists cachedExists(String whereClause);
1040
1041 /**
1042 * A mechanism for caching a record count.
1043 *
1044 * It is the programmer's responsibility to ensure that the where clause
1045 * is suitable for the target DBMS.
1046 *
1047 * @param whereClause raw SQL selection clause appropriate for this DBMS
1048 * @param orderByClause raw SQL order clause appropriate for this DBMS
1049 * @param nullable whether the ReferencePoemType is nullable
1050 * @return a {@link org.melati.poem.RestrictedReferencePoemType}
1051 */
1052 RestrictedReferencePoemType cachedSelectionType(String whereClause,
1053 String orderByClause, boolean nullable);
1054
1055 /**
1056 * Make up a <TT>Field</TT> object whose possible values are a selected
1057 * subset of the records in the table. You can make a "dropdown" offering a
1058 * choice of your green customers by putting this in your handler
1059 *
1060 * <BLOCKQUOTE><PRE>
1061 * context.put("greens",
1062 * melati.getDatabase().getCustomerTable().cachedSelectionField(
1063 * "colour = 'green'", null, true, null, "greens"));
1064 * </PRE></BLOCKQUOTE>
1065 *
1066 * and this in your template
1067 *
1068 * <BLOCKQUOTE><PRE>
1069 * Select a customer: $ml.input($greens)
1070 * </PRE></BLOCKQUOTE>
1071 *
1072 * The list of member records is implicitly cached---permanently, and however
1073 * big it turns out to be. So don't go mad with this. It is recomputed on
1074 * demand if the contents of the table are changed. The <TT>whereClause</TT>
1075 * and <TT>orderByClause</TT> you pass in are checked to see if you have
1076 * asked for the same list before, so however many times you call this
1077 * method, you should only trigger actual <TT>SELECT</TT>s when the table
1078 * contents have changed. The list is also transaction-safe, in that it will
1079 * always reflect the state of affairs within your transaction even if you
1080 * haven't done a commit.
1081 *
1082 * It is the programmer's responsibility to ensure that the where clause
1083 * is suitable for the target DBMS.
1084 *
1085 * @param whereClause an SQL expression (the bit after the
1086 * <TT>SELECT</TT> ... <TT>WHERE</TT>) for picking
1087 * out the records you want
1088 *
1089 * @param orderByClause a comma-separated list of column names which
1090 * determine the order in which the records are
1091 * presented; if this is <TT>null</TT>, the
1092 * <TT>displayorderpriority</TT> attributes of the
1093 * table's columns determine the order
1094 *
1095 * @param nullable whether to allow a blank <TT>NULL</TT> option
1096 * as the first possibility
1097 *
1098 * @param selectedTroid the troid of the record to which the
1099 * <TT>SELECT</TT> field should initially be set
1100 *
1101 * @param nameP the HTML name attribute of the field,
1102 * <I>i.e.</I>
1103 * <TT><SELECT NAME=<I>name</I>></TT>
1104 * @return a Field object
1105 */
1106 Field cachedSelectionField(
1107 String whereClause, String orderByClause, boolean nullable,
1108 Integer selectedTroid, String nameP);
1109
1110 /**
1111 * Don't call this in your application code.
1112 * Columns should be defined either in the DSD (in which
1113 * case the boilerplate code generated by the preprocessor will call this
1114 * method) or directly in the RDBMS (in which case the initialisation code
1115 * will).
1116 */
1117 void defineColumn(Column column)
1118 throws DuplicateColumnNamePoemException,
1119 DuplicateTroidColumnPoemException,
1120 DuplicateDeletedColumnPoemException;
1121
1122 /**
1123 * @return incremented extra columns index
1124 */
1125 int getNextExtrasIndex();
1126
1127 /**
1128 * @param tableInfo the TableInfo to set
1129 */
1130 void setTableInfo(TableInfo tableInfo);
1131
1132 /**
1133 * @return the {@link org.melati.poem.TableInfo} for this table.
1134 */
1135 TableInfo getTableInfo();
1136
1137 /**
1138 * @return a DBMS table type eg TEXT
1139 */
1140 String getDbmsTableType();
1141
1142 /**
1143 * Public method used in DSD.wm.
1144 * Duplicated because <code>defaultDisplayName()</code>
1145 * above is overwritten.
1146 *
1147 * @return the capitalised name
1148 */
1149 String getDsdName();
1150
1151 /**
1152 * Match columnInfo with this Table's columns.
1153 * Conversely, create a ColumnInfo for any columns which don't have one.
1154 */
1155 void unifyWithColumnInfo() throws PoemException;
1156
1157 /**
1158 * Unify the JDBC description of this table with the
1159 * meta data held in the {@link org.melati.poem.TableInfo}
1160 *
1161 * @param colDescs a JDBC {@link java.sql.ResultSet} describing the columns
1162 */
1163 void unifyWithDB(ResultSet colDescs)
1164 throws PoemException;
1165 }