/** * Copyright (C) 2010 Orbeon, Inc. * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; either version * 2.1 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.processor.sql; import oracle.jdbc.*; import oracle.sql.*; import oracle.xdb.XMLType; import org.orbeon.oxf.common.OXFException; import org.orbeon.oxf.util.NetUtils; import org.orbeon.oxf.xml.XMLParsing; import org.w3c.dom.Document; import org.w3c.dom.Node; import java.io.*; import java.sql.*; /** * Base class for Oracle delegates. * * NOTE: Check whether this works with WebLogic 8.1 and the thin driver, or if for example * weblogic.jdbc.vendor.oracle.OracleThinBlob must be used. Would this work with createTemporary() * anyway? */ public abstract class SQLProcessorOracleDelegateBase implements DatabaseDelegate { // public SQLProcessorOracleTomcat4Delegate() { // // Load the Oracle JDBC driver // try { // DriverManager.registerDriver // (new oracle.jdbc.driver.OracleDriver()); // Connection conn = DriverManager.getConnection("jdbc:oracle:oci:@rosaura","scott","tiger"); // // // Create Oracle DatabaseMetaData object // DatabaseMetaData meta = conn.getMetaData(); // // // gets driver info: // System.out.println("JDBC driver version is " + meta.getDriverVersion()); // System.out.println("JDBC driver nameis " + meta.getDriverName()); // } catch (SQLException e) { // e.printStackTrace(); // } // } public void setClob(PreparedStatement stmt, int index, String value) throws SQLException { // Get an OraclePreparedStatement final OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt); // Get an OracleConnection to prevent ClassCastException in oracle.sql.CLOB // - see this post from 2004 https://forums.oracle.com/thread/281238 // - this still seems to be the case with Oracle 12c Release 1 (12.1.0.1) ojdbc6_g.jar // - we only observed OraclePreparedStatement.getConnection() returning a wrapped // connection when getting the OraclePreparedStatement through JDBC 4, so // unwrapping the connection with JDBC 4's unwrap should be fine final Connection connection = oracleStmt.getConnection(); final OracleConnection oracleConnection = connection instanceof OracleConnection ? (OracleConnection) connection : connection.unwrap(OracleConnection.class); // Create a temporary CLOB final CLOB clob = CLOB.createTemporary(oracleConnection, true, CLOB.DURATION_SESSION); // Write to the CLOB final Writer writer = clob.getCharacterOutputStream(); try { NetUtils.copyStream(new StringReader(value), writer); writer.flush(); } catch (IOException e) { throw new OXFException(e); } // Set the CLOB on the statement oracleStmt.setClob(index, clob); } public void setBlob(PreparedStatement stmt, int index, byte[] value) throws SQLException { final OutputStream os = getBlobOutputStream(stmt, index); try { NetUtils.copyStream(new ByteArrayInputStream(value), os); os.close(); } catch (IOException e) { throw new OXFException(e); } } public OutputStream getBlobOutputStream(PreparedStatement stmt, final int index) throws SQLException { // Get an OraclePreparedStatement final OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt); // Create a temporary BLOB final BLOB blob = BLOB.createTemporary(oracleStmt.getConnection(), true, BLOB.DURATION_SESSION); // Get the output stream final OutputStream os = blob.getBinaryOutputStream(); // Return a special OutputStream that will *have* to be closed for anything to happen return new BufferedOutputStream(new OutputStream() { private boolean closed = false; public void close() throws IOException { if (!closed) { os.flush(); os.close(); // Set the BLOB on the statement try { oracleStmt.setBlob(index, blob); } catch (SQLException e) { throw new OXFException(e); } closed = true; } } public void flush() throws IOException { os.flush(); } public void write(byte b[]) throws IOException { os.write(b); } public void write(byte b[], int off, int len) throws IOException { os.write(b, off, len); } public void write(int b) throws IOException { os.write(b); } }); } public boolean isXMLType(int columnType, String columnTypeName) throws SQLException { // This according to Oracle documentation return columnTypeName != null && OracleTypes.OPAQUE == columnType && columnTypeName.compareTo("SYS.XMLTYPE") == 0; } public Node getDOM(ResultSet resultSet, String columnName) throws SQLException { final OracleResultSet oracleResultSet = getOracleResultSet(resultSet); // XMLType xmlType = (XMLType) oracleResultSet.getObject(columnName); final OPAQUE opaque = oracleResultSet.getOPAQUE(columnName); final XMLType xmlType = XMLType.createXML(opaque); final Node doc; if(false && xmlType.isFragment()) { // TODO: Handle XML fragment correctly // doc = XMLUtils.parseDocumentFragment(xmlType.getStringVal()); doc = null; } else { // FIXME: Xerces throws when walking the tree if we return the DOM directly!!! // doc = xmlType.getDOM(); doc = XMLParsing.stringToDOM(xmlType.getStringVal()); } return doc; } public void setDOM(PreparedStatement stmt, int index, String document) throws SQLException { // Get an OraclePreparedStatement final OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt); final XMLType xmlType = XMLType.createXML(oracleStmt.getConnection(), document); oracleStmt.setObject(index, xmlType); } public void setDOM(PreparedStatement stmt, int index, Document document) throws SQLException { // Get an OraclePreparedStatement OraclePreparedStatement oracleStmt = getOraclePreparedStatement(stmt); // FIXME: XMLType.createXML(oracleStmt.getConnection(), doc) returns null!!! XMLType xmlType = XMLType.createXML(oracleStmt.getConnection(), document); oracleStmt.setObject(index, xmlType); } /** * Derived classes must implement this to return a native OraclePreparedStatement. */ protected abstract OraclePreparedStatement getOraclePreparedStatement(PreparedStatement stmt); /** * Derived classes must implement this to return a native OracleResultSet. */ protected abstract OracleResultSet getOracleResultSet(ResultSet resultSet); }