001: /*
002: * Copyright 2004 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: OracleClobMapping.java,v 1.8 2004/02/01 18:22:42 jackknifebarber Exp $
009: */
010: package com.triactive.jdo.store;
011:
012: import com.triactive.jdo.PersistenceManager;
013: import com.triactive.jdo.StateManager;
014: import java.io.IOException;
015: import java.io.InputStreamReader;
016: import java.sql.Connection;
017: import java.sql.PreparedStatement;
018: import java.sql.ResultSet;
019: import java.sql.SQLException;
020: import java.sql.Types;
021: import javax.jdo.JDODataStoreException;
022: import oracle.sql.CLOB;
023: import org.apache.log4j.Category;
024:
025: public class OracleClobMapping extends StringMapping implements
026: PostInsertProcessing, PostUpdateProcessing {
027: private static final Category LOG = Category
028: .getInstance(OracleClobMapping.class);
029:
030: private final ClassBaseTable table;
031: private final int absoluteFieldNumber;
032: private ColumnMapping idMapping = null;
033: private String fetchStmt = null;
034:
035: public OracleClobMapping(ClassBaseTable table,
036: int relativeFieldNumber) {
037: super (table.newColumn(relativeFieldNumber));
038:
039: if (col.getLengthType() != Column.UNLIMITED_LENGTH)
040: throw new ColumnDefinitionException(
041: "Invalid length specified for CLOB column " + col
042: + ", must be 'unlimited'");
043:
044: this .table = table;
045: this .absoluteFieldNumber = relativeFieldNumber
046: + table.getClassMetaData().getInheritedFieldCount();
047: }
048:
049: private synchronized void initialize() {
050: if (idMapping == null) {
051: idMapping = table.getIDMapping();
052:
053: FetchStatement stmt = new FetchStatement(table);
054: stmt.select(getColumn());
055: stmt.andCondition(stmt.referenceColumn(idMapping
056: .getColumn())
057: + " = ?");
058:
059: fetchStmt = stmt.toString() + " FOR UPDATE";
060: }
061: }
062:
063: protected TypeInfo getTypeInfo() {
064: return dba.getTypeInfo(Types.CLOB);
065: }
066:
067: public String getSQLInsertionValue() {
068: return "EMPTY_CLOB()";
069: }
070:
071: public String getSQLUpdateValue() {
072: return "EMPTY_CLOB()";
073: }
074:
075: public void setString(PersistenceManager pm, PreparedStatement ps,
076: int param, String value) {
077: // No-op. Statement text includes "EMPTY_CLOB()" instead of "?"
078: }
079:
080: public String getString(PersistenceManager pm, ResultSet rs,
081: int param) {
082: String value = null;
083:
084: try {
085: char[] cbuf = null;
086: CLOB clob = (CLOB) rs.getClob(param);
087:
088: if (clob != null) {
089: // Note: Using clob.stringValue() results in StoreManagerTest
090: // exception: "java.sql.SQLException: Conversion to String failed"
091:
092: StringBuffer sbuf = new StringBuffer();
093: InputStreamReader reader = new InputStreamReader(clob
094: .asciiStreamValue());
095: long size = clob.length();
096:
097: try {
098: final int BUFF_SIZE = 4096;
099: cbuf = new char[BUFF_SIZE];
100: int charsRead = reader.read(cbuf);
101:
102: while (-1 != charsRead) {
103: sbuf.append(cbuf, 0, charsRead);
104:
105: java.util.Arrays.fill(cbuf, (char) 0);
106: charsRead = reader.read(cbuf);
107: }
108:
109: } catch (IOException e) {
110: throw new JDODataStoreException(
111: "Error reading Oracle CLOB object: param = "
112: + param, e);
113: }
114:
115: value = sbuf.toString();
116:
117: if (value.length() == 0)
118: value = null;
119: else if (value
120: .equals(OracleStringMapping.EMPTY_STRING_SURROGATE))
121: value = "";
122: }
123: } catch (SQLException e) {
124: throw dba.newDataStoreException(
125: "Can't get String result: param = " + param, e);
126: }
127:
128: return value;
129: }
130:
131: public void setObject(PersistenceManager pm, PreparedStatement ps,
132: int param, Object value) {
133: setString(pm, ps, param, (String) value);
134: }
135:
136: public Object getObject(PersistenceManager pm, ResultSet rs,
137: int param) {
138: return getString(pm, rs, param);
139: }
140:
141: public void postInsert(StateManager sm, Connection conn,
142: Object value) {
143: postUpdate(sm, conn, value);
144: }
145:
146: /**
147: * Retrieve the empty CLOB locator created by the insert statement
148: * and write out the current CLOB field value to the Oracle CLOB object
149: */
150: public void postUpdate(StateManager sm, Connection conn,
151: Object value) {
152: initialize();
153:
154: String strval = (String) value;
155:
156: if (strval == null)
157: strval = "";
158: else if (strval.length() == 0)
159: strval = OracleStringMapping.EMPTY_STRING_SURROGATE;
160:
161: PersistenceManager pm = sm.getPersistenceManager();
162:
163: try {
164: PreparedStatement ps = conn.prepareStatement(fetchStmt);
165:
166: try {
167: Object id = sm.getObjectId();
168: idMapping.setObject(pm, ps, 1, id);
169:
170: long startTime = System.currentTimeMillis();
171:
172: ResultSet rs = ps.executeQuery();
173:
174: try {
175: if (LOG.isDebugEnabled())
176: LOG
177: .debug("Time = "
178: + (System.currentTimeMillis() - startTime)
179: + " ms: " + fetchStmt);
180:
181: if (!rs.next())
182: throw new ObjectNotFoundException(
183: "No such database row", sm.getObject());
184:
185: CLOB clob = (CLOB) rs.getClob(1);
186:
187: clob.putString(1, strval);
188: } finally {
189: rs.close();
190: }
191: } finally {
192: ps.close();
193: }
194: } catch (SQLException e) {
195: throw dba.newDataStoreException("CLOB update failed: "
196: + fetchStmt, e);
197: }
198: }
199: }
|