001: /**
002: * Objective Database Abstraction Layer (ODAL)
003: * Copyright (c) 2004, The ODAL Development Group
004: * All rights reserved.
005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
006: *
007: * Distributable under LGPL license.
008: * See terms of license at gnu.org.
009: */package com.completex.objective.components.persistency.core;
010:
011: import com.completex.objective.components.log.Log;
012: import com.completex.objective.components.persistency.Persistency;
013: import com.completex.objective.components.persistency.Query;
014: import com.completex.objective.components.persistency.QueryFactory;
015: import com.completex.objective.components.persistency.Record;
016: import com.completex.objective.components.persistency.transact.Transaction;
017:
018: import java.io.OutputStream;
019: import java.io.Writer;
020: import java.sql.Blob;
021: import java.sql.Clob;
022: import java.sql.SQLException;
023: import java.util.Date;
024:
025: /**
026: * Database policy. Has set of methods that "equalize" database differences.
027: *
028: * @author Gennady Krizhevsky
029: */
030: public interface DatabasePolicy {
031:
032: public static final DatabasePolicy NULL_DATABASE_POLICY = new NullDatabasePolicy();
033:
034: /**
035: * Limit locations:
036: */
037: int NO_LIMIT = 0;
038: int LIMIT_IN_SELECT = 1;
039: int LIMIT_IN_WHERE = 2;
040: int LIMIT_IN_THE_END = 3;
041:
042: /**
043: * Produces limit sql string fragment
044: *
045: * @param offset - zero based offset
046: * @param rowCount number rows to bring
047: * @return limit String
048: */
049: String getLimitSql(int offset, int rowCount);
050:
051: /**
052: * Produces limit sql string fragment
053: *
054: * @param rowCount number rows to bring
055: * @return limit String
056: */
057: String getLimitSql(int rowCount);
058:
059: /**
060: *
061: * @return one of int NO_LIMIT, LIMIT_IN_SELECT, LIMIT_IN_WHERE, LIMIT_IN_THE_END values
062: */
063: int getLimitLocation();
064:
065: /**
066: *
067: * @param lob
068: * @return BinaryOutputStream from Blob
069: * @throws SQLException
070: */
071: OutputStream getBinaryOutputStream(Blob lob) throws SQLException;
072:
073: /**
074: * Indicator for type handlers to whether to do Blob write processing as a "post-processing".
075: * In which case the type hadler will try to extract InputStream the value object.
076: * Otherwise binding for write is done in usual way by setObject method
077: *
078: * @return true if Blob is to be wtitten as post-processing
079: */
080: boolean useTwoStepBinaryUpdate();
081:
082: /**
083: * Indicator for type handlers to whether to do Clob write processing as a "post-processing".
084: * In which case the type hadler will try to extract InputStream the value object.
085: * Otherwise binding for write is done in usual way by setObject method
086: *
087: * @return true if Clob is to be wtitten as post-processing
088: */
089: boolean useClobOutputStream();
090:
091: /**
092: * Return a SQL string to get the next sequence number for a table. When executed, this SQL should return a one
093: * column, one row result set with an integer.
094: *
095: * @param objectName a value of type 'String'
096: * @return a value of type 'String'
097: */
098: public String nextSequenceSql(String objectName);
099:
100: //
101: // Locking:
102: //
103:
104: /**
105: * @return lock string getLockString(timeout = 0, forUpdateOf = null);
106: */
107: String getLockString();
108:
109: /**
110: *
111: * @param timeout
112: * @param forUpdateOf
113: * @return lock string
114: */
115: String getLockString(long timeout, String forUpdateOf);
116:
117: /**
118: * Something like "holdlock" in MySql
119: *
120: * @param lock
121: * @param tableName
122: * @return lock hint
123: */
124: String getLockHint(boolean lock, String tableName);
125:
126: /**
127: * Gets lock string that will cause throwing an exception in case of lock encountered
128: *
129: * @param forUpdateOf
130: * @return No Wait Lock String
131: */
132: String getNoWaitLockString(String forUpdateOf);
133:
134: /**
135: *
136: * @param e
137: * @return true if exception happend because of the lock
138: */
139: boolean isLocked(Exception e);
140:
141: //
142: // Date related:
143: //
144:
145: /**
146: * Something like oracle's "to_date"
147: *
148: * @param date
149: * @return date sql fragment
150: */
151: String dateSql(Date date);
152:
153: /**
154: *
155: * @return sql fragment with database system date
156: */
157: String nowSql();
158:
159: //
160: // Exception handling:
161: //
162:
163: /**
164: *
165: * @param e
166: * @return true if exception happend because of the duplicate record
167: */
168: boolean isDuplicate(Exception e);
169:
170: /**
171: *
172: * @return sql fragment that can be used to check if connection is active
173: */
174: String connectionActiveSql();
175:
176: /**
177: * Like clob.getCharacterOutputStream()
178: *
179: * @param lob
180: * @return Writer
181: * @throws SQLException
182: */
183: Writer getCharacterOutputStream(Clob lob) throws SQLException;
184:
185: /**
186: * Like clob.getAsciiOutputStream();
187: *
188: * @param lob
189: * @return OutputStream
190: * @throws SQLException
191: */
192: OutputStream getAsciiOutputStream(Clob lob) throws SQLException;
193:
194: /**
195: * @see DatabasePolicy#proprietoryJoin(Join)
196: * @return true if ANSI join is to be used. Otherwise proprietoryJoin has to be defined
197: */
198: boolean useAnsiJoin();
199:
200: /**
201: * Builds proprietory Join sql fragment
202: *
203: * @param join
204: * @return proprietory Join sql fragment
205: */
206: String proprietoryJoin(Join join);
207:
208: /**
209: * Method will be called after insert to enable populating certain values in the Record
210: *
211: * @param transaction
212: * @param persistency
213: * @param record
214: * @param logger
215: * @throws SQLException
216: */
217: void handlePostInsert(Transaction transaction,
218: Persistency persistency, Record record, Log logger)
219: throws SQLException;
220:
221: /**
222: *
223: * @return policy name
224: */
225: String getName();
226:
227: /**
228: * Defines the way paginatedquery is produced from the "normal" one through means of database
229: *
230: * @param queryFactory
231: * @param innerQuery
232: * @return Paginated Wrapper Query
233: */
234: Query getPaginatedWrapperQuery(QueryFactory queryFactory,
235: Query innerQuery);
236:
237: /**
238: * Like '_' in oracle
239: *
240: * @return Single Symbol Wild Card
241: */
242: Character getSingleSymbolWildCard();
243:
244: /**
245: * Like '%' in oracle
246: *
247: * @return Multi Symbol Wild Card
248: */
249: Character getMultiSymbolWildCard();
250:
251: /**
252: *
253: * @param expression
254: * @return sql fragment that uses database specific function to get Length in characters
255: */
256: String charLengthSql(String expression);
257:
258: /**
259: *
260: * @param expression
261: * @param pattern
262: * @param matches false in case of negation
263: * @return "regular expression like" sql fragment
264: */
265: String rlikeSql(String expression, String pattern, boolean matches);
266:
267: /**
268: *
269: * @param expression
270: * @param matches false in case of negation
271: * @return "regular expression like" sql fragment that uses placeholder "?" instead of pattern
272: */
273: String rlikeFunc(String expression, boolean matches);
274:
275: /**
276: *
277: * @return true if database supports subqueries
278: */
279: boolean supportsSubqueries();
280:
281: /**
282: *
283: * @return true if database supports limit clause
284: */
285: boolean supportsLimit();
286:
287: /**
288: *
289: * @return type that is used to replesent Reference Cursor
290: */
291: int getRefCursorJdbcType();
292:
293: boolean supportsSequences();
294:
295: boolean supportsAutoincrement();
296:
297: boolean supportsExplicitRecordLevelLocks();
298:
299: /**
300: * Returns true if driver supports ResultSet.getClob syntax
301: *
302: * @return true if driver supports ResultSet.getClob syntax
303: */
304: boolean supportsClob();
305:
306: /**
307: * Returns true if driver supports ResultSet.getBlob syntax
308: *
309: * @return true if driver supports ResultSet.getBlob syntax
310: */
311: boolean supportsBlob();
312:
313: /**
314: * Null implementation:
315: */
316: static class NullDatabasePolicy implements DatabasePolicy {
317: public String getLimitSql(int offset, int rowCount) {
318: return "";
319: }
320:
321: public String getLockHint(boolean lock, String tableName) {
322: return tableName;
323: }
324:
325: public String getLockString(long timeout, String forUpdateOf) {
326: return "";
327: }
328:
329: public boolean supportsSubqueries() {
330: return false;
331: }
332:
333: public boolean supportsSequences() {
334: return false;
335: }
336:
337: public int getLimitLocation() {
338: return 0;
339: }
340:
341: public boolean supportsLoHiLimit() {
342: return false;
343: }
344:
345: public String topSql() {
346: return "";
347: }
348:
349: public OutputStream getBinaryOutputStream(Blob lob)
350: throws SQLException {
351: return null;
352: }
353:
354: public boolean supportsDirectBlobInsert() {
355: return false;
356: }
357:
358: public boolean useTwoStepBinaryUpdate() {
359: return false;
360: }
361:
362: public boolean useClobOutputStream() {
363: return false;
364: }
365:
366: public String nextSequenceSql(String objectName) {
367: return null;
368: }
369:
370: public String getLockString() {
371: return "";
372: }
373:
374: public String getNoWaitLockString(String forUpdateOf) {
375: return "";
376: }
377:
378: public boolean isLocked(Exception e) {
379: return false;
380: }
381:
382: public boolean isDuplicate(Exception e) {
383: return false;
384: }
385:
386: public String connectionActiveSql() {
387: return null;
388: }
389:
390: public Writer getCharacterOutputStream(Clob lob)
391: throws SQLException {
392: return null;
393: }
394:
395: public OutputStream getAsciiOutputStream(Clob lob)
396: throws SQLException {
397: return null;
398: }
399:
400: public boolean useAnsiJoin() {
401: return true;
402: }
403:
404: public String proprietoryJoin(Join join) {
405: return "";
406: }
407:
408: public String getLimitSql(int max) {
409: return "";
410: }
411:
412: public boolean supportsLimit() {
413: return false;
414: }
415:
416: public void handlePostInsert(Transaction transaction,
417: Persistency persistency, Record record, Log logger)
418: throws SQLException {
419: }
420:
421: public Character getSingleSymbolWildCard() {
422: return new Character('?');
423: }
424:
425: public Character getMultiSymbolWildCard() {
426: return new Character('%');
427: }
428:
429: public String getName() {
430: return null;
431: }
432:
433: public Query getPaginatedWrapperQuery(
434: QueryFactory queryFactory, Query innerQuery) {
435: return innerQuery;
436: }
437:
438: public String dateSql(Date date) {
439: return null;
440: }
441:
442: public String toDateFunc() {
443: return null;
444: }
445:
446: public String toDateValue(Date date) {
447: return null;
448: }
449:
450: public String charLengthSql(String expression) {
451: return null;
452: }
453:
454: public String rlikeSql(String expression, String pattern,
455: boolean negate) {
456: return null;
457: }
458:
459: public String rlikeFunc(String expression, boolean matches) {
460: return null;
461: }
462:
463: public String nowSql() {
464: return null;
465: }
466:
467: public int getRefCursorJdbcType() {
468: return 0;
469: }
470:
471: public boolean supportsAutoincrement() {
472: return false;
473: }
474:
475: public boolean supportsExplicitRecordLevelLocks() {
476: return false;
477: }
478:
479: public boolean supportsClob() {
480: return false;
481: }
482:
483: public boolean supportsBlob() {
484: return false;
485: }
486: }
487: }
|