--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.execute.CallStatementResultSet\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.execute;\r
+\r
+import java.sql.ResultSet;\r
+import java.sql.SQLException;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.jdbc.ConnectionContext;\r
+import org.apache.derby.iapi.services.loader.GeneratedMethod;\r
+import org.apache.derby.iapi.sql.Activation;\r
+\r
+/**\r
+ * Call a Java procedure. This calls a generated method in the\r
+ * activation which sets up the parameters and then calls the\r
+ * Java method that the procedure resolved to.\r
+ * <P>\r
+ * Valid dynamic results returned by the procedure will be closed\r
+ * as inaccessible when this is closed (e.g. a CALL within a trigger).\r
+ * \r
+ * <BR>\r
+ * Any code that requires the dynamic results to be accessible\r
+ * (such as the JDBC Statement object executing the CALL) must\r
+ * obtain the dynamic results from Activation.getDynamicResults()\r
+ * and remove each ResultSet it will be handling by clearing the\r
+ * reference in the object returned.\r
+ * \r
+ * @see Activation#getDynamicResults()\r
+ */\r
+class CallStatementResultSet extends NoRowsResultSetImpl\r
+{\r
+\r
+ private final GeneratedMethod methodCall;\r
+\r
+ /*\r
+ * class interface\r
+ *\r
+ */\r
+ CallStatementResultSet(\r
+ GeneratedMethod methodCall,\r
+ Activation a) \r
+ throws StandardException\r
+ {\r
+ super(a);\r
+ this.methodCall = methodCall;\r
+ }\r
+\r
+ /**\r
+ * Just invoke the method.\r
+ @exception StandardException Standard Derby error policy\r
+ */\r
+ public void open() throws StandardException\r
+ {\r
+ setup();\r
+ methodCall.invoke(activation);\r
+ }\r
+ \r
+ /**\r
+ * Need to explicitly close any dynamic result sets.\r
+ * <BR>\r
+ * If the dynamic results are not accessible then they\r
+ * need to be destroyed (ie. closed) according the the\r
+ * SQL Standard.\r
+ * <BR>\r
+ * An execution of a CALL statement through JDBC makes the\r
+ * dynamic results accessible, in this case the closing\r
+ * of the dynamic result sets is handled by the JDBC\r
+ * statement object (EmbedStatement) that executed the CALL.\r
+ * We cannot unify the closing of dynamic result sets to\r
+ * this close, as in accessible case it is called during\r
+ * the Statement.execute call, thus it would close the\r
+ * dynamic results before the application has a change\r
+ * to use them.\r
+ * \r
+ * <BR>\r
+ * With an execution of a CALL\r
+ * statement as a trigger's action statement the dynamic\r
+ * result sets are not accessible. In this case this close\r
+ * method is called after the execution of the trigger's\r
+ * action statement.\r
+ * <BR>\r
+ * <BR>\r
+ * Section 4.27.5 of the TECHNICAL CORRIGENDUM 1 to the SQL 2003\r
+ * Standard details what happens to dynamic result sets in detail,\r
+ * the SQL 2003 foundation document is missing these details.\r
+ */\r
+ public void close() throws StandardException\r
+ {\r
+ super.close();\r
+ \r
+ \r
+ \r
+ ResultSet[][] dynamicResults = getActivation().getDynamicResults();\r
+ if (dynamicResults != null)\r
+ {\r
+ // Need to ensure all the result sets opened by this\r
+ // CALL statement for this connection are closed.\r
+ // If any close() results in an exception we need to keep going,\r
+ // save any exceptions and then throw them once we are complete.\r
+ StandardException errorOnClose = null;\r
+ \r
+ ConnectionContext jdbcContext = null;\r
+ \r
+ for (int i = 0; i < dynamicResults.length; i++)\r
+ {\r
+ ResultSet[] param = dynamicResults[i];\r
+ ResultSet drs = param[0];\r
+ \r
+ // Can be null if the procedure never set this parameter\r
+ // or if the dynamic results were processed by JDBC (EmbedStatement).\r
+ if (drs == null)\r
+ continue;\r
+ \r
+ if (jdbcContext == null)\r
+ jdbcContext = (ConnectionContext)\r
+ lcc.getContextManager().getContext(ConnectionContext.CONTEXT_ID);\r
+ \r
+ try {\r
+ \r
+ // Is this a valid, open dynamic result set for this connection?\r
+ if (!jdbcContext.processInaccessibleDynamicResult(drs))\r
+ {\r
+ // If not just ignore it, not Derby's problem.\r
+ continue;\r
+ }\r
+ \r
+ drs.close();\r
+ \r
+ } catch (SQLException e) {\r
+ \r
+ // Just report the first error\r
+ if (errorOnClose == null)\r
+ {\r
+ StandardException se = StandardException.plainWrapException(e);\r
+ errorOnClose = se;\r
+ }\r
+ }\r
+ finally {\r
+ // Remove any reference to the ResultSet to allow\r
+ // it and any associated resources to be garbage collected.\r
+ param[0] = null;\r
+ }\r
+ }\r
+ \r
+ if (errorOnClose != null)\r
+ throw errorOnClose;\r
+ } \r
+ }\r
+\r
+ /**\r
+ * @see org.apache.derby.iapi.sql.ResultSet#cleanUp\r
+ */\r
+ public void cleanUp() throws StandardException\r
+ {\r
+ close();\r
+ }\r
+}\r