/* * Copyright (C) 2000 - 2011 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://www.openbluedragon.org/ * * $Id: cfStoredProcData.java 2374 2013-06-10 22:14:24Z alan $ */ package com.naryx.tagfusion.cfm.sql; /** * Works exclusively with the cfSTOREDPROC and cfPROCPARAM class. */ import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.naryx.tagfusion.cfm.engine.catchDataFactory; import com.naryx.tagfusion.cfm.engine.cfQueryResultData; import com.naryx.tagfusion.cfm.engine.cfSession; import com.naryx.tagfusion.cfm.engine.cfmRunTimeException; public class cfStoredProcData extends Object { private Connection con; List<preparedData> params; List<resultSetHolder> results; int maxRows = -1; public cfStoredProcData(Connection con) { this.con = con; params = new ArrayList<preparedData>(); results = new ArrayList<resultSetHolder>(); } public boolean resultsExpected() { return (results.size() > 0); } public Iterator<preparedData> iterator() { return params.iterator(); } public List<preparedData> getParams() { return params; } public List<resultSetHolder> getResults() { return results; } public void addPreparedData(preparedData _data) { // If it's an Oracle cursor output parameter then check if we need to also // register it as a result set if ((_data.isOUT()) && (_data.getCfSqlType() == preparedData.CF_SQL_REFCURSOR)) { // With the JDBC-ODBC bridge the result set is returned as a result set // instead of as an output parameter so we need to register it as a result set too. // NOTE: We still need to register it as a parameter too so the stored procedure will be // passed the correct number of parameters and in the correct order. // NOTE: This check needs to check a value that will also work when a J2EE data source is used. // That's why the DBMD.getDriverName() method is being used. String driverName = null; try { driverName = con.getMetaData().getDriverName(); } catch (SQLException e) { // ignore } if ((driverName != null) && driverName.startsWith("JDBC-ODBC Bridge")) { // Need to also add it as a result set results.add(new resultSetHolder(_data.getOutVariable(), results.size() + 1, -1)); // Now change the name of the output parameter so it won't conflict with the result set _data.setOutVariable(_data.getOutVariable() + "_dummy_out_param"); } } params.add(_data); } public void setResultSet(String name, int index, int maxRows) { results.add(new resultSetHolder(name, index, maxRows)); } public String getQueryString() { String paramString = ""; if (params.size() > 0) { paramString = "("; for (int i = 0; i < params.size(); i++) { if (i < params.size() - 1) paramString += "?,"; else paramString += "?"; } paramString += ")"; } else { try { String driverName = con.getMetaData().getDriverName(); if (driverName.equals("MySQL-AB JDBC Driver")) paramString += "()"; } catch (SQLException sqlExc) { } } return paramString; } public boolean setUseNamedParameters() { // If there are no parameters then just return false if (params.size() == 0) return false; // Check if all of the parameters contain a paramName (ie. DBVARNAME) boolean useNamedParameters = true; for (int i = 0; i < params.size(); i++) { preparedData pData = params.get(i); if (pData.paramName == null) { useNamedParameters = false; break; } } // if all of the parameters contain a paramName (ie. DBVARNAME) // then check if the driver supports named parameters if (useNamedParameters) useNamedParameters = preparedData.supportsNamedParameters(con); // Set the useNamedParameters flag in each preparedData object for (int i = 0; i < params.size(); i++) { preparedData pData = params.get(i); pData.setUseNamedParameters(useNamedParameters); } return useNamedParameters; } // ----------------------------------------- public void retrieveAndStoreResultSets(cfSession Session, String datasourceName, CallableStatement call) throws cfmRunTimeException { // the Oracle 10g JDBC driver has a bug: call.getUpdateCount() always // returns a positive number, instead of -1 when there are no more // results; this bug puts the following code into an infinite loop; // just return because Oracle returns result sets as output parameters // anyway (there are never any result sets returned here) if (call.getClass().getName().equals("oracle.jdbc.driver.T4CCallableStatement")) return; try { int currentResultSet = 1; do { // there may be multiple result sets and/or update counts ResultSet rs = call.getResultSet(); if (rs != null) { resultSetHolder rsh = getResultSetHolder(currentResultSet); if (rsh != null) { Session.setData(rsh.name, new cfQueryResultData(rs, "Stored Procedure", rsh.maxRows)); } currentResultSet++; // moved this out of the above 'if' clause to fix bug #2376 rs.close(); } } while (call.getMoreResults() || (call.getUpdateCount() >= 0)); } catch (SQLException e) { throw new cfmRunTimeException(catchDataFactory.databaseException(datasourceName, "sql.storedProcedureResult", null, "", e)); } } // -------------------------------------------------------------- private resultSetHolder getResultSetHolder(int indx) { Iterator<resultSetHolder> iter = results.iterator(); resultSetHolder rsh; while (iter.hasNext()) { rsh = iter.next(); if (rsh.resultIndex == indx) return rsh; } return null; } }