001: package com.teamkonzept.db;
002:
003: import java.sql.*;
004: import java.io.StringReader;
005: import com.teamkonzept.lib.*;
006:
007: /** Abstrakte Klasse, zur Erstellung präparierter Queries.
008: * Eine solche Query zeichnet sich durch eine feste Anzahl von
009: * Query-Parametern und deren Reihenfolge aus.
010: *
011: * @see java.sql.PreparedStatement
012: * @author $Author: alex $
013: * @version $Revision: 1.20 $
014: */
015: public abstract class TKPrepQuery extends TKQuery implements
016: QueryConstants {
017:
018: /**
019: If true, queries are cached untill they are closeed.
020: This can be neccessary for teansactions.
021: It can cause "memory-leak" if queries are not closed.
022:
023: @see TKDBManager.closeNonsensitiveQueries(), to close all the cached queries.
024: */
025: public static boolean REGISTER_QUERY = false;
026:
027: /**
028: If true, queries are cached for reuse.
029: */
030: public static boolean REUSE_QUERY = false;
031:
032: /** Reihenfole der Queryparameter
033: */
034: protected String[] paramOrder;
035:
036: /** Name der Query Klasse, erleichtert die Wiederverwendung von PrepQueries ( wird nicht verwendet )
037: */
038: private Object queryID;
039:
040: /** Methode zur Initialisierung der Query.
041: * Diese Methode wird üblicherweise vom DB-Manager aufgerufen,
042: * um die Query zu initialisieren.
043: *
044: * @param tkConn - Verbindung zu der DB
045: * @param conv - Der der DB zugeordnete Typ-Konverter
046: * @param queryID Name der Query Klasse, erleichtert die Wiederverwendung des Objektes ( wird nicht verwendet )
047: *
048: * @see com.teamkonzept.db.TKDBManager
049: * @see com.teamkonzept.db.TKDBManager#newQuery
050: */
051: public void initQuery(final TKSQLTypeConverter conv,
052: final TKDBConnection tkConn, Object queryID) {
053: this .queryID = queryID;
054: this .aTKDBConnection = tkConn;
055: initQuery(tkConn.getConnection());
056: }
057:
058: /** Methode zur Initialisierung des Queryobjektes
059: *
060: * @param conn - Verbindung zur DB
061: * @param isPrepared - wird nicht mehr benötigt
062: * @param paramOrder - Liste mit Parameternamen, welche die
063: * Reihenfolge der Parameter im SQL-String
064: * angibt.
065: * @param paramTypes - Liste von Parametername, Parametertyp Paaren
066: * @param setRelevants - geordnete Liste, welche angibt, welche
067: * SQl(Teil)Queries relevante ResultSets liefern.
068: * @param sqlString - Dem der Query zugrundeliegende SQL-String.
069: *
070: */
071: public void initQuery(final Connection conn,
072: final boolean isPrepared, /* wird nicht mehr benˆtigt */
073: final String[] paramOrder, final Object[][] paramTypes,
074: final boolean[] setRelevants, final String sqlString) {
075: super .initQuery(conn, paramTypes, setRelevants);
076:
077: this .paramOrder = paramOrder;
078: this .sqlString = sqlString;
079:
080: if (sqlString == null) {
081: return;
082: }
083:
084: try {
085: stmt = conn.prepareStatement(sqlString);
086: } catch (SQLException sqle) {
087: printSqlException(sqle, "Create Statement");
088: }
089: }
090:
091: /** Methode, um die Query auszuführen
092: *
093: * @return true, falls die Query ein java.sql.ResultSet geliefert hat,
094: * false, falls das Resultat der Query ein "Update Count" ist
095: * oder leer ist.
096: *
097: * @exception com.teamkonzept.db.TKSQLError
098: */
099:
100: /**
101: * @return ob ResultSet vorhanden
102: */
103: public boolean execute() throws SQLException {
104: if (REGISTER_QUERY)
105: deregisterIndex = registerQuery();
106: final PreparedStatement pstmt = (PreparedStatement) stmt;
107: boolean isAuto = aTKDBConnection.isAutoCommit(); // (isAuto == true) <=> Multistatement Transaction
108:
109: if (CAT.isDebugEnabled()) {
110: CAT.debug("isaAuto Value during execute: " + isAuto);
111: CAT.debug("executing " + this );
112: CAT.debug("<BR>SQL:" + sqlString + "<BR>");
113: CAT.debug("PARAMS:" + queryParams + "<BR>");
114: CAT.debug("paramOrder" + paramOrder);
115: }
116:
117: try {
118: pstmt.clearParameters();
119: } catch (SQLException sqle) {
120: if (isAuto)
121: TKDBManager.closeConnection();
122: printSqlException(sqle, "clear Parameters");
123:
124: }
125:
126: try {
127: if (paramOrder != null) {
128: for (int i = 0; i < paramOrder.length; i++) {
129: final Object h = queryParams.get(paramOrder[i]);
130: if ((h == null) || (h instanceof TKNull)) {
131: int ht;
132: Object paramType = null;
133: if (paramTypes != null) {
134: paramType = paramTypes.get(paramOrder[i]);
135: }
136: if (paramType != null) {
137: ht = ((Integer) paramType).intValue();
138: } else {
139: ht = Types.INTEGER;
140: }
141: pstmt.setNull(i + 1, ht);
142: } else {
143: if (paramTypes != null) {
144: Integer type = (Integer) paramTypes
145: .get(paramOrder[i]);
146: if (type != null
147: && type.intValue() == Types.CLOB
148: && TKDBManager.getDBVendor() == QueryConstants.ORACLE) {
149: // wir setzen hier ein DUMMY Objekt !!!
150: // der CLOB MUSS spaeter manuell nachgepflegt werden !!!!!
151: // System.out.println("Setze CLOB ! Laenge : " + ((String)h).length());
152: pstmt.setObject(i + 1, " ");
153: } else
154: pstmt.setObject(i + 1, h);
155: } else
156: pstmt.setObject(i + 1, h);
157: }
158: }
159: }
160: } catch (SQLException sqle) {
161: if (isAuto)
162: TKDBManager.closeConnection();
163: printSqlException(sqle, "setObject");
164:
165: }
166:
167: try {
168: currIsResultSet = pstmt.execute();
169: } catch (SQLException sqle) {
170: if (isAuto)
171: TKDBManager.closeConnection();
172: printSqlException(sqle, "Execute Prepared Statement");
173: }
174: queryParams.clear();
175: currPos = 0;
176:
177: return currIsResultSet;
178: }
179:
180: /** Das PreparedStatement wird nicht geschlossen!
181: * Es werden lediglich die Results "abgeholt",
182: * damit das Statement vollst‰ndig abgearbeitet ist.
183: * Ausserdem wird das Objekt zum Wiederverwenden
184: * abgelegt.
185: *
186: * @exception java.sql.SQLException
187: */
188: public void specClose() throws SQLException {
189: if (REGISTER_QUERY)
190: deregisterQuery();
191:
192: if (stmt != null) {
193: throwawayResults();
194: }
195: if (REUSE_QUERY) {
196: aTKDBConnection.storePrepQuery(this , queryID);
197: } else // explicitly close statement
198: {
199: if (stmt != null) {
200: stmt.close();
201: }
202: }
203: }
204:
205: /**
206: for debugging
207: */
208: public Statement getStatement() {
209: return stmt;
210: }
211:
212: /**
213: @author marwan 14. 5. 01
214:
215: This is a hack!
216:
217: Calling this method assures two things:
218:
219: 1. All subsequently instantiated TKQuery objects of this Connection, will be cached until
220: TKDBConnection.closeNonsensitiveQueries() is called.
221: The call of closeNonsensitiveQueries() closes the Statement of each of these TKQueries,
222: and empties the cache.
223:
224: 2. These TKQuery objects will not be reused.
225:
226: It is a hack, as the caching mechanism was originally designed to keep track of queries
227: that are executed togeather in a transaction.
228:
229: */
230: public static void enableCleanup() {
231: REGISTER_QUERY = true;
232: REUSE_QUERY = true;
233:
234: }
235:
236: /**
237: @see enableCleanup(), disableCleanup()
238: */
239: public static void enableCleanup(boolean yes) {
240: if (yes) {
241: enableCleanup();
242: } else {
243: disableCleanup();
244: }
245: }
246:
247: /**
248: @see enableCleanup()
249:
250: Restores the default conditions after a call to enableCleanup()
251: (E.g. in the Webman Generation process, where no periodical calls to closeNonsensitiveQueries()
252: are possible)
253: */
254: public static void disableCleanup() {
255: REGISTER_QUERY = false;
256: REUSE_QUERY = true;
257:
258: }
259:
260: }
|