001: /*
002: * (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: * All rights reserved.
004: *
005: *
006: */
007:
008: package com.hp.hpl.jena.db.impl;
009:
010: import java.io.*;
011: import java.sql.PreparedStatement;
012: import java.sql.ResultSet;
013: import java.sql.SQLException;
014: import java.sql.Statement;
015: import java.util.Iterator;
016:
017: import com.hp.hpl.jena.db.IDBConnection;
018: import com.hp.hpl.jena.db.RDFRDBException;
019:
020: /* <---- TO WORK WITH ORACLE, PREFIX THIS LINE WITH "//" (I.E., TO EXPOSE IMPORT STATEMENTS) -------
021: import oracle.jdbc.OracleResultSet;
022: import oracle.sql.BLOB;
023: import oracle.jdbc.OracleDatabaseMetaData;
024:
025: /*--------------------------------------------------------------------*/
026:
027: /**
028: * @author hkuno based on code by Dave Reynolds
029: *
030: * Extends DriverRDB with Oracle-specific parameters.
031: * Note: To use this class with Oracle:
032: * 1. Uncomment the import statements above.
033: * 2. Comment out the interface stubs below.
034: * 3. Uncomment the try block in setConnection below.
035: *
036: */
037: public class Driver_Oracle_LOB extends DriverRDB {
038:
039: //* <----- TO WORK WITH ORACLE, PREFIX THIS LINE WITH "/*" (I.E., TO HIDE INTERFACE STUBS) ------
040:
041: public interface BLOB extends java.sql.Blob {
042: OutputStream getBinaryOutputStream();
043:
044: int getBufferSize();
045:
046: boolean isOpen();
047:
048: void close();
049: }
050:
051: private interface OracleResultSet extends ResultSet {
052: BLOB getBLOB(int i);
053: }
054:
055: /*--------------------------------------------------------------------*/
056:
057: /** The name of the database type this driver supports */
058:
059: /**
060: * Constructor
061: */
062: public Driver_Oracle_LOB() {
063: super ();
064:
065: String myPackageName = this .getClass().getPackage().getName();
066:
067: DATABASE_TYPE = "Oracle";
068: DRIVER_NAME = "oracle.jdbc.driver.OracleDriver";
069:
070: ID_SQL_TYPE = "INTEGER";
071: URI_COMPRESS = false;
072: LONG_OBJECT_LENGTH_MAX = INDEX_KEY_LENGTH_MAX = INDEX_KEY_LENGTH = 1000;
073: LONG_OBJECT_LENGTH = 250;
074: TABLE_NAME_LENGTH_MAX = 30;
075: /* 30 is a guesstimate. setConnection should be called
076: * immediately to get the correct value. */
077: IS_XACT_DB = true;
078: PRE_ALLOCATE_ID = true;
079: SKIP_DUPLICATE_CHECK = false;
080: SQL_FILE = "etc/oracle.sql";
081:
082: m_psetClassName = myPackageName + ".PSet_TripleStore_RDB";
083: m_psetReifierClassName = myPackageName + ".PSet_ReifStore_RDB";
084:
085: m_lsetClassName = myPackageName
086: + ".SpecializedGraph_TripleStore_RDB";
087: m_lsetReifierClassName = myPackageName
088: + ".SpecializedGraphReifier_RDB";
089:
090: QUOTE_CHAR = '\'';
091:
092: DB_NAMES_TO_UPPER = true;
093: setTableNames(TABLE_NAME_PREFIX);
094: }
095:
096: /**
097: * Set the database connection
098: */
099: public void setConnection(IDBConnection dbcon) {
100: m_dbcon = dbcon;
101: /* <---- TO WORK WITH ORACLE, PREFIX THIS LINE WITH "//" (I.E., TO EXPOSE TRY BLOCK) -------
102: try {
103: OracleDatabaseMetaData dmd = (OracleDatabaseMetaData)dbcon.getConnection().getMetaData();
104: if (dmd == null)
105: throw new RDFRDBException("Oracle database metadata not available.");
106: TABLE_NAME_LENGTH_MAX = dmd.getMaxTableNameLength();
107: setTableNames(TABLE_NAME_PREFIX); // need to recheck that table names are not too long
108: } catch ( SQLException e ) {
109: throw new RDFRDBException("Problem accessing Oracle database metadata.");
110: }
111: /*--------------------------------------------------------------------*/
112: try {
113: // Properties defaultSQL = SQLCache.loadSQLFile(DEFAULT_SQL_FILE, null, ID_SQL_TYPE);
114: // m_sql = new SQLCache(SQL_FILE, defaultSQL, dbcon, ID_SQL_TYPE);
115: m_sql = new SQLCache(SQL_FILE, null, dbcon, ID_SQL_TYPE);
116: } catch (Exception e) {
117: e.printStackTrace(System.err);
118: logger.error("Unable to set connection for Driver:", e);
119: }
120: }
121:
122: /**
123: * Allocate an identifier for a new graph.
124: *
125: */
126: public int graphIdAlloc(String graphName) {
127: int dbid = 0;
128: try {
129: String op = "insertGraph";
130: dbid = getInsertID(GRAPH_TABLE);
131: PreparedStatement ps = m_sql.getPreparedSQLStatement(op,
132: GRAPH_TABLE);
133: ps.setInt(1, dbid);
134: ps.setString(2, graphName);
135: ps.executeUpdate();
136: m_sql.returnPreparedSQLStatement(ps);
137: } catch (SQLException e) {
138: throw new RDFRDBException(
139: "Failed to get last inserted ID: " + e);
140: }
141: return dbid;
142: }
143:
144: /**
145: * Dellocate an identifier for a graph.
146: *
147: */
148: public void graphIdDealloc(int graphId) {
149: try {
150: String op = "deleteGraph";
151: PreparedStatement ps = m_sql.getPreparedSQLStatement(op,
152: GRAPH_TABLE);
153: ps.setInt(1, graphId);
154: ps.executeUpdate();
155: m_sql.returnPreparedSQLStatement(ps);
156: } catch (SQLException e) {
157: throw new RDFRDBException("Failed to delete graph ID: " + e);
158: }
159: return;
160: }
161:
162: // Now common code moved to DriverRDB - delete this anytime after Jena 2.5.2
163:
164: // public int getInsertID ( String tableName ) {
165: // DBIDInt result = null;
166: // try {
167: // String op = "getInsertID";
168: // PreparedStatement ps = m_sql.getPreparedSQLStatement(op,tableName);
169: // ResultSet rs = ps.executeQuery();
170: // if (rs.next()) {
171: // result = wrapDBID(rs.getObject(1));
172: // } else
173: // throw new RDFRDBException("No insert ID");
174: // m_sql.returnPreparedSQLStatement(ps);
175: // } catch (SQLException e) {
176: // throw new RDFRDBException("Failed to insert ID: " + e);
177: // }
178: // return result.getIntID();
179: // }
180:
181: /**
182: * Return the parameters for table creation.
183: * 1) column type for subj, prop, obj.
184: * 2) column type for head.
185: * 3) table and index name prefix.
186: * @param param array to hold table creation parameters.
187: */
188: protected void getTblParams(String[] param) {
189: String objColType;
190:
191: // length of varchar columns in statement tables
192: if (LONG_OBJECT_LENGTH > 4000)
193: throw new RDFRDBException("Long object length specified ("
194: + LONG_OBJECT_LENGTH
195: + ") exceeds maximum sane length of 4000.");
196: if (INDEX_KEY_LENGTH > 4000)
197: throw new RDFRDBException("Index key length specified ("
198: + INDEX_KEY_LENGTH
199: + ") exceeds maximum sane length of 4000.");
200:
201: objColType = "NVARCHAR2(" + LONG_OBJECT_LENGTH + ")";
202: STRINGS_TRIMMED = false;
203: param[0] = objColType;
204:
205: // length of head column in literal tables
206: String headColType = "NVARCHAR2(" + INDEX_KEY_LENGTH + ")";
207: param[1] = headColType;
208: param[2] = TABLE_NAME_PREFIX;
209: }
210:
211: /**
212: *
213: * Return the parameters for table creation.
214: * Generate the table name by counting the number of existing
215: * tables for the graph. This is not reliable if another client
216: * is concurrently trying to create a table so, if failure, we
217: * make several attempts to create the table.
218: */
219:
220: protected String[] getCreateTableParams(int graphId, boolean isReif) {
221: String[] parms = new String[3];
222: String[] res = new String[2];
223:
224: getTblParams(parms);
225: int tblCnt = getTableCount(graphId);
226: res[0] = genTableName(graphId, tblCnt, isReif);
227: res[1] = parms[0];
228: return res;
229: }
230:
231: /**
232: * Return the parameters for database initialization.
233: */
234: protected String[] getDbInitTablesParams() {
235: String[] res = new String[3];
236:
237: getTblParams(res);
238: EOS_LEN = EOS.length();
239:
240: return res;
241: }
242:
243: /**
244: * Insert a long object into the database.
245: * This assumes the object is not already in the database.
246: * @return the db index of the added literal
247: */
248: public DBIDInt addRDBLongObject(RDBLongObject lobj, String table)
249: throws RDFRDBException {
250: DBIDInt longObjID = null;
251: try {
252: int argi = 1;
253: boolean save = m_dbcon.getConnection().getAutoCommit();
254:
255: // Change in Jena 2.5 - insertLongObjectNoTail (was insertLongObject)
256: // Remove these comments after testing and release of 2.5.
257: // THIS DRIVER IS NOT THE REAL Oracle driver and is not untested.
258: String opname = (lobj.tail.length() > 0) ? "insertLongObjectEmptyTail"
259: : "insertLongObjectNoTail";
260: PreparedStatement ps = m_sql.getPreparedSQLStatement(
261: opname, table);
262: int dbid = 0; // init only needed to satisfy java compiler
263: if (PRE_ALLOCATE_ID) {
264: dbid = getInsertID(table);
265: ps.setInt(argi++, dbid);
266: longObjID = wrapDBID(new Integer(dbid));
267: }
268: ps.setString(argi++, lobj.head);
269: if (lobj.tail.length() > 0) {
270: ps.setLong(argi++, lobj.hash);
271: } else {
272: ps.setNull(argi++, java.sql.Types.BIGINT);
273: }
274: ps.executeUpdate();
275: m_sql.returnPreparedSQLStatement(ps);
276:
277: if (lobj.tail.length() > 0) {
278: if (!xactOp(xactIsActive)) {
279: m_dbcon.getConnection().setAutoCommit(false);
280: }
281: opname = "getEmptyBLOB";
282: String cmd = m_sql.getSQLStatement(opname, table,
283: longObjID.getID().toString());
284: Statement lobStmt = m_sql.getConnection()
285: .createStatement();
286: ResultSet lrs = lobStmt.executeQuery(cmd);
287: lrs.next();
288:
289: BLOB blob = ((OracleResultSet) lrs).getBLOB(1);
290: OutputStream outstream = blob.getBinaryOutputStream();
291: int size = blob.getBufferSize();
292:
293: int length = -1;
294: //InputStream instream = new StringBufferInputStream(lobj.tail);
295: InputStream instream = new ByteArrayInputStream(
296: lobj.tail.getBytes("UTF-8"));
297:
298: // Buffer to hold chunks of data to being written to the Blob.
299: byte[] buffer = new byte[size];
300:
301: while ((length = instream.read(buffer)) != -1)
302: outstream.write(buffer, 0, length);
303:
304: if (blob.isOpen())
305: blob.close();
306: instream.close();
307: outstream.close();
308: lobStmt.close();
309: if (!xactOp(xactIsActive)) {
310: m_dbcon.getConnection().setAutoCommit(save);
311: }
312: }
313:
314: if (!PRE_ALLOCATE_ID) {
315: dbid = getInsertID(table);
316: longObjID = wrapDBID(new Integer(dbid));
317: }
318: } catch (Exception e1) {
319: /* DEBUG */System.out.println("Problem on long object (l="
320: + lobj.head + ") " + e1);
321: // System.out.println("ID is: " + id);
322: throw new RDFRDBException("Failed to add long object ", e1);
323: }
324: return longObjID;
325: }
326:
327: /**
328: * Retrieve LongObject from database.
329: */
330: protected RDBLongObject IDtoLongObject(int dbid, String table) {
331: RDBLongObject res = null;
332: try {
333: String opName = "getLongObject";
334: PreparedStatement ps = m_sql.getPreparedSQLStatement(
335: opName, table);
336: ps.setInt(1, dbid);
337: OracleResultSet rs = (OracleResultSet) ps.executeQuery();
338: if (rs.next()) {
339: res = new RDBLongObject();
340: res.head = rs.getString(1);
341: BLOB blob = rs.getBLOB(2);
342:
343: if (blob != null) {
344: int len = (int) blob.length();
345: byte[] data = blob.getBytes(1, len);
346: res.tail = new String(data, "UTF-8");
347: } else {
348: res.tail = "";
349: }
350: }
351: rs.close();
352: m_sql.returnPreparedSQLStatement(ps);
353:
354: } catch (SQLException e1) {
355: // /* DEBUG */ System.out.println("Literal truncation (" + l.toString().length() + ") " + l.toString().substring(0, 150));
356: throw new RDFRDBException(
357: "Failed to retrieve long object (SQL Exception): ",
358: e1);
359: } catch (UnsupportedEncodingException e2) {
360: throw new RDFRDBException(
361: "Failed to retrieve long object (UnsupportedEncoding): ",
362: e2);
363: }
364: return res;
365: }
366:
367: /**
368: * Drop all Jena-related sequences from database, if necessary.
369: * Override in subclass if sequences must be explicitly deleted.
370: */
371: public void clearSequences() {
372: Iterator seqIt = getSequences().iterator();
373: while (seqIt.hasNext()) {
374: removeSequence((String) seqIt.next());
375: }
376: }
377:
378: public String genSQLStringMatchLHS_IC(String var) {
379: return "UPPER(" + var + ")";
380: }
381:
382: public String genSQLStringMatchRHS_IC(String strToMatch) {
383: return "UPPER(" + strToMatch + ")";
384: }
385:
386: public String stringMatchEscapeChar() {
387: return "\\";
388: }
389:
390: public String genSQLStringMatchEscape() {
391: return " " + genSQLEscapeKW() + " '" + stringMatchEscapeChar()
392: + "'";
393: }
394:
395: }
396:
397: /*
398: * (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
399: * All rights reserved.
400: *
401: * Redistribution and use in source and binary forms, with or without
402: * modification, are permitted provided that the following conditions
403: * are met:
404: * 1. Redistributions of source code must retain the above copyright
405: * notice, this list of conditions and the following disclaimer.
406: * 2. Redistributions in binary form must reproduce the above copyright
407: * notice, this list of conditions and the following disclaimer in the
408: * documentation and/or other materials provided with the distribution.
409: * 3. The name of the author may not be used to endorse or promote products
410: * derived from this software without specific prior written permission.
411:
412: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
413: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
414: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
415: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
416: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
417: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
418: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
419: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
420: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
421: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
422: */
|