KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > helper > LOBValueWriter


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.helper;
23
24 import java.sql.*;
25 import java.util.*;
26 import oracle.toplink.essentials.internal.expressions.SQLSelectStatement;
27 import oracle.toplink.essentials.internal.expressions.ForUpdateClause;
28 import oracle.toplink.essentials.queryframework.*;
29 import oracle.toplink.essentials.expressions.Expression;
30 import oracle.toplink.essentials.internal.sessions.AbstractSession;
31 import oracle.toplink.essentials.internal.databaseaccess.DatabaseCall;
32 import oracle.toplink.essentials.internal.databaseaccess.Accessor;
33
34 /**
35  * INTERNAL:
36  * <p><b>Purpose</b>:LOBValueWriter is used to write a large size of object into an Oracle
37  * CLOB/BLOB column through Oracle LOB Locator. It's a work-around object for the well-known 4k write
38  * limits on an Oracle thin driver.
39  *
40  * <p><b>Responsibilities</b>:<ul>
41  * <li> Build the Oracle empty lob method call string for the insert call.
42  * <li> Build the minimial SELECT call to retrieve the locator.
43  * <li> Write the lob value through the locator.
44  * <li> Resolve the multiple table INSERT/SELECT orders.
45  * <li> Resolve the nested unit of work commit issue.
46  * </ul>
47  *
48  * @author: King Wang
49  * @since TopLink/Java 5.0. July 2002.
50  */

51 public class LOBValueWriter {
52     //DatabaseCalls still to be processed
53
private Collection calls = null;
54     private Accessor accessor;
55
56     /**
57      * This is the default constructor for the class.
58      *
59      * Bug 2804663 - Each DatabaseAccessor will now hold on to its own instance
60      * of this class, hence a singleton pattern is not applicable.
61      */

62     public LOBValueWriter(Accessor accessor) {
63         this.accessor = accessor;
64     }
65
66     protected void buildAndExecuteCall(DatabaseCall dbCall, AbstractSession session) {
67         DatabaseQuery query = dbCall.getQuery();
68         if (!query.isWriteObjectQuery()) {
69             //if not writequery, should not go through the locator writing..
70
return;
71         }
72         WriteObjectQuery writeQuery = (WriteObjectQuery)query;
73         writeQuery.setAccessor(accessor);
74         //build a select statement form the query
75
SQLSelectStatement selectStatement = buildSelectStatementForLocator(writeQuery, dbCall, session);
76
77         //then build a call from the statement
78
DatabaseCall call = buildCallFromSelectStatementForLocator(selectStatement, writeQuery, dbCall, session);
79
80         accessor.executeCall(call, call.getQuery().getTranslationRow(), session);
81     }
82
83     /**
84     * Fetch the locator(s) from the result set and write LOB value to the table
85     */

86     public void fetchLocatorAndWriteValue(DatabaseCall dbCall, Object JavaDoc resultSet) throws SQLException {
87         Enumeration enumFields = dbCall.getContexts().getFields().elements();
88         Enumeration enumValues = dbCall.getContexts().getValues().elements();
89         AbstractSession executionSession = dbCall.getQuery().getSession().getExecutionSession(dbCall.getQuery());
90         while (enumFields.hasMoreElements()) {
91             DatabaseField field = (DatabaseField)enumFields.nextElement();
92             Object JavaDoc value = enumValues.nextElement();
93
94             //write the value through the locator
95
executionSession.getPlatform().writeLOB(field, value, (ResultSet)resultSet, executionSession);
96         }
97     }
98
99     /**
100     * Build the select statement for selecting the locator
101     */

102     private SQLSelectStatement buildSelectStatementForLocator(WriteObjectQuery writeQuery, DatabaseCall call, AbstractSession session) {
103         SQLSelectStatement selectStatement = new SQLSelectStatement();
104         Vector tables = writeQuery.getDescriptor().getTables();
105         selectStatement.setTables(tables);
106         //rather than get ALL fields from the descriptor, only use the LOB-related fields to build the minimal SELECT statement.
107
selectStatement.setFields(call.getContexts().getFields());
108         //the where clause setting here is sufficient if the object does not map to multiple tables.
109
selectStatement.setWhereClause(writeQuery.getDescriptor().getObjectBuilder().buildPrimaryKeyExpressionFromObject(writeQuery.getObject(), session));
110         //need pessimistic locking for the locator select
111
selectStatement.setLockingClause(ForUpdateClause.newInstance(ObjectBuildingQuery.LOCK));
112
113         if (tables.size() > 1) {
114             //the primary key expression from the primary table
115
Expression expression = selectStatement.getWhereClause();
116
117             //additioanl join from the non-primary tables
118
Expression additionalJoin = (Expression)writeQuery.getDescriptor().getQueryManager().getAdditionalJoinExpression();
119             if (additionalJoin != null) {
120                 expression = expression.and(additionalJoin);
121             }
122
123             //where clause now contains extra joins across all tables
124
selectStatement.setWhereClause(expression);
125         }
126
127         //normalize the statement at the end, such as assign alias to all tables, and build sorting statement
128
selectStatement.normalize(session, writeQuery.getDescriptor());
129         return selectStatement;
130     }
131
132     /**
133     * Build the sql call from the select statement for selecting the locator
134     */

135     private DatabaseCall buildCallFromSelectStatementForLocator(SQLSelectStatement selectStatement, WriteObjectQuery writeQuery, DatabaseCall dbCall, AbstractSession session) {
136         DatabaseCall call = selectStatement.buildCall(session);
137
138         //the LOB context must be passed into the new call object
139
call.setContexts(dbCall.getContexts());
140         //need to explictly define one rwo return, otherwise, TL assumes multiple rows return and confuses the accessor
141
call.returnOneRow();
142         //the query object has to be set in order to access to the platform and login objects
143
call.setQuery(writeQuery);
144         // prepare it
145
call.prepare(session);
146         //finally do the translation
147
call.translate(writeQuery.getTranslationRow(), writeQuery.getModifyRow(), session);
148         return call;
149     }
150
151     // Building of SELECT statements is no longer done in DatabaseAccessor.basicExecuteCall
152
// for updates because DatabaseCall.isUpdateCall() can't recognize update in case
153
// StoredProcedureCall is used. Therefore in all cases: insert(single or multiple tables)
154
// and update the original (insert and update) calls are saved
155
// and both building and executing of SELECT statements postponed until
156
// buildAndExecuteSelectCalls method is called.
157

158     /**
159     * Add original (insert or update) call to the collection
160     */

161     public void addCall(Call call) {
162         if (calls == null) {
163             //use lazy initialization
164
calls = new ArrayList(2);
165         }
166         calls.add(call);
167     }
168
169     // Bug 3110860: RETURNINGPOLICY-OBTAINED PK CAUSES LOB TO BE INSERTED INCORRECTLY
170
// The deferred locator SELECT calls should be generated and executed after ReturningPolicy
171
// merges PK obtained from the db into the object held by the query.
172
// That's why original (insert or update) calls are saved,
173
// and both building and executing of SELECT statements postponed until
174
// this method is called.
175

176     /**
177     * Build and execute the deferred select calls.
178     */

179     public void buildAndExecuteSelectCalls(AbstractSession session) {
180         if ((calls == null) || calls.isEmpty()) {
181             //no deferred select calls (it means no locator is required)
182
return;
183         }
184
185         //all INSERTs have been executed, time to execute the SELECTs
186
try {
187             for (Iterator callIt = calls.iterator(); callIt.hasNext();) {
188                 DatabaseCall dbCall = (DatabaseCall)callIt.next();
189                 buildAndExecuteCall(dbCall, session);
190             }
191         } finally {
192             //after executing all select calls, need to empty the collection.
193
//this is neccessary in the nested unit of work cases.
194
calls.clear();
195         }
196     }
197 }
198
Popular Tags