--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.execute.NoRowsResultSetImpl\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.Timestamp;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.iapi.services.loader.GeneratedMethod;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.stream.HeaderPrintWriter;\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.ResultDescription;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.Row;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.conn.StatementContext;\r
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.ExecutionContext;\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+import org.apache.derby.iapi.sql.execute.ResultSetStatisticsFactory;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+/**\r
+ * This implementation of ResultSet\r
+ * is meant to be overridden by subtypes\r
+ * in the execution engine. Its primary users\r
+ * will be DDL, which only need to define a\r
+ * constructor to create the DDL object being\r
+ * defined. All other ResultSet operations will\r
+ * be handled by this superclass -- i.e., nothing\r
+ * is allowed to be done to a DDL Result Set, since\r
+ * it has no rows to provide.\r
+ * <p>\r
+ * This abstract class does not define the entire ResultSet\r
+ * interface, but leaves the 'get' half of the interface\r
+ * for subtypes to implement. It is package-visible only,\r
+ * with its methods being public for exposure by its subtypes.\r
+ * <p>\r
+ *\r
+ */\r
+abstract class NoRowsResultSetImpl implements ResultSet\r
+{\r
+ final Activation activation;\r
+ private boolean dumpedStats;\r
+ NoPutResultSet[] subqueryTrackingArray;\r
+\r
+ private final boolean statisticsTimingOn;\r
+ /** True if the result set has been opened, and not yet closed. */\r
+ private boolean isOpen;\r
+\r
+ /* fields used for formating run time statistics output */\r
+ protected String indent;\r
+ protected String subIndent;\r
+ protected int sourceDepth;\r
+\r
+ /* Run time statistics variables */\r
+ final LanguageConnectionContext lcc;\r
+ protected long beginTime;\r
+ protected long endTime;\r
+ protected long beginExecutionTime;\r
+ protected long endExecutionTime;\r
+\r
+ NoRowsResultSetImpl(Activation activation)\r
+ throws StandardException\r
+ {\r
+ this.activation = activation;\r
+\r
+ if (SanityManager.DEBUG) {\r
+ if (activation == null)\r
+ SanityManager.THROWASSERT("activation is null in result set " + getClass());\r
+ }\r
+\r
+ lcc = activation.getLanguageConnectionContext();\r
+ statisticsTimingOn = lcc.getStatisticsTiming();\r
+\r
+ /* NOTE - We can't get the current time until after setting up the\r
+ * activation, as we end up using the activation to get the \r
+ * LanguageConnectionContext.\r
+ */\r
+ beginTime = getCurrentTimeMillis();\r
+ beginExecutionTime = beginTime;\r
+\r
+ StatementContext sc = lcc.getStatementContext();\r
+ sc.setTopResultSet(this, (NoPutResultSet[]) null);\r
+\r
+ // Pick up any materialized subqueries\r
+ if (subqueryTrackingArray == null)\r
+ {\r
+ subqueryTrackingArray = sc.getSubqueryTrackingArray();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set up the result set for use. Should always be called from\r
+ * <code>open()</code>.\r
+ *\r
+ * @exception StandardException thrown on error\r
+ */\r
+ void setup() throws StandardException {\r
+ isOpen = true;\r
+ }\r
+\r
+ /**\r
+ * Returns FALSE\r
+ */\r
+ public final boolean returnsRows() { return false; }\r
+\r
+ /**\r
+ * Returns zero.\r
+ */\r
+ public int modifiedRowCount() { return 0; }\r
+\r
+ /**\r
+ * Returns null.\r
+ */\r
+ public ResultDescription getResultDescription()\r
+ {\r
+ return (ResultDescription)null;\r
+ }\r
+ \r
+ public final Activation getActivation()\r
+ {\r
+ return activation;\r
+ }\r
+\r
+ /**\r
+ * Returns the row at the absolute position from the query, \r
+ * and returns NULL when there is no such position.\r
+ * (Negative position means from the end of the result set.)\r
+ * Moving the cursor to an invalid position leaves the cursor\r
+ * positioned either before the first row (negative position)\r
+ * or after the last row (positive position).\r
+ * NOTE: An exception will be thrown on 0.\r
+ *\r
+ * @param row The position.\r
+ * @return The row at the absolute position, or NULL if no such position.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow getAbsoluteRow(int row) throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "absolute");\r
+ }\r
+\r
+ /**\r
+ * Returns the row at the relative position from the current\r
+ * cursor position, and returns NULL when there is no such position.\r
+ * (Negative position means toward the beginning of the result set.)\r
+ * Moving the cursor to an invalid position leaves the cursor\r
+ * positioned either before the first row (negative position)\r
+ * or after the last row (positive position).\r
+ * NOTE: 0 is valid.\r
+ * NOTE: An exception is thrown if the cursor is not currently\r
+ * positioned on a row.\r
+ *\r
+ * @param row The position.\r
+ * @return The row at the relative position, or NULL if no such position.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow getRelativeRow(int row) throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "relative");\r
+ }\r
+\r
+ /**\r
+ * Sets the current position to before the first row and returns NULL\r
+ * because there is no current row.\r
+ *\r
+ * @return NULL.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow setBeforeFirstRow() \r
+ throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "beforeFirst");\r
+ }\r
+\r
+ /**\r
+ * Returns the first row from the query, and returns NULL when there\r
+ * are no rows.\r
+ *\r
+ * @return The first row, or NULL if no rows.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow getFirstRow() \r
+ throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "first");\r
+ }\r
+\r
+ /**\r
+ * No rows to return, so throw an exception.\r
+ *\r
+ * @exception StandardException Always throws a\r
+ * StandardException to indicate\r
+ * that this method is not intended to\r
+ * be used.\r
+ */\r
+ public ExecRow getNextRow() throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "next");\r
+ }\r
+\r
+ /**\r
+ * Returns the previous row from the query, and returns NULL when there\r
+ * are no more previous rows.\r
+ *\r
+ * @return The previous row, or NULL if no more previous rows.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow getPreviousRow() \r
+ throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "previous");\r
+ }\r
+\r
+ /**\r
+ * Returns the last row from the query, and returns NULL when there\r
+ * are no rows.\r
+ *\r
+ * @return The last row, or NULL if no rows.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow getLastRow()\r
+ throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "last");\r
+ }\r
+\r
+ /**\r
+ * Sets the current position to after the last row and returns NULL\r
+ * because there is no current row.\r
+ *\r
+ * @return NULL.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ * @see Row\r
+ */\r
+ public ExecRow setAfterLastRow() \r
+ throws StandardException\r
+ {\r
+ /*\r
+ The JDBC use of this class will never call here.\r
+ Only the DB API used directly can get this exception.\r
+ */\r
+ throw StandardException.newException(SQLState.LANG_DOES_NOT_RETURN_ROWS, "afterLast");\r
+ }\r
+\r
+ /**\r
+ * Clear the current row. This is done after a commit on holdable\r
+ * result sets.\r
+ * This is a no-op on result set which do not provide rows.\r
+ */\r
+ public final void clearCurrentRow() \r
+ {\r
+ \r
+ }\r
+\r
+ /**\r
+ * Determine if the cursor is before the first row in the result \r
+ * set. \r
+ *\r
+ * @return true if before the first row, false otherwise. Returns\r
+ * false when the result set contains no rows.\r
+ */\r
+ public boolean checkRowPosition(int isType)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns the row number of the current row. Row\r
+ * numbers start from 1 and go to 'n'. Corresponds\r
+ * to row numbering used to position current row\r
+ * in the result set (as per JDBC).\r
+ *\r
+ * @return the row number, or 0 if not on a row\r
+ *\r
+ */\r
+ public int getRowNumber()\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ /**\r
+ * Dump the stat if not already done so. Close all of the open subqueries.\r
+ *\r
+ * @exception StandardException thrown on error\r
+ */\r
+ public void close() throws StandardException\r
+ { \r
+ if (!isOpen)\r
+ return;\r
+\r
+ if (! dumpedStats)\r
+ {\r
+ /*\r
+ ** If run time statistics tracing is turned on, then now is the\r
+ ** time to dump out the information.\r
+ ** NOTE - We make a special exception for commit. If autocommit\r
+ ** is on, then the run time statistics from the autocommit is the\r
+ ** only one that the user would ever see. So, we don't overwrite\r
+ ** the run time statistics object for a commit.\r
+ */\r
+ if (lcc.getRunTimeStatisticsMode() &&\r
+ ! doesCommit())\r
+ {\r
+ endExecutionTime = getCurrentTimeMillis();\r
+\r
+ ExecutionContext ec = lcc.getExecutionContext();\r
+ ResultSetStatisticsFactory rssf;\r
+ rssf = ec.getResultSetStatisticsFactory();\r
+\r
+ lcc.setRunTimeStatisticsObject(\r
+ rssf.getRunTimeStatistics(activation, this, subqueryTrackingArray));\r
+\r
+ HeaderPrintWriter istream = lcc.getLogQueryPlan() ? Monitor.getStream() : null;\r
+ if (istream != null)\r
+ {\r
+ istream.printlnWithHeader(LanguageConnectionContext.xidStr + \r
+ lcc.getTransactionExecute().getTransactionIdString() +\r
+ "), " +\r
+ LanguageConnectionContext.lccStr +\r
+ lcc.getInstanceNumber() +\r
+ "), " +\r
+ lcc.getRunTimeStatisticsObject().getStatementText() + " ******* " +\r
+ lcc.getRunTimeStatisticsObject().getStatementExecutionPlanText());\r
+ }\r
+ }\r
+ dumpedStats = true;\r
+ }\r
+\r
+ /* This is the top ResultSet, \r
+ * close all of the open subqueries.\r
+ */\r
+ int staLength = (subqueryTrackingArray == null) ? 0 :\r
+ subqueryTrackingArray.length;\r
+\r
+ for (int index = 0; index < staLength; index++)\r
+ {\r
+ if (subqueryTrackingArray[index] == null)\r
+ {\r
+ continue;\r
+ }\r
+ if (subqueryTrackingArray[index].isClosed())\r
+ {\r
+ continue;\r
+ }\r
+ subqueryTrackingArray[index].close();\r
+ }\r
+\r
+ isOpen = false;\r
+\r
+ if (activation.isSingleExecution())\r
+ activation.close();\r
+ }\r
+\r
+ /**\r
+ * Find out if the <code>ResultSet</code> is closed.\r
+ *\r
+ * @return <code>true</code> if closed, <code>false</code> otherwise\r
+ */\r
+ public boolean isClosed() {\r
+ return !isOpen;\r
+ }\r
+\r
+ public void finish() throws StandardException\r
+ {\r
+ }\r
+\r
+ /**\r
+ * Get the execution time in milliseconds.\r
+ *\r
+ * @return long The execution time in milliseconds.\r
+ */\r
+ public long getExecuteTime()\r
+ {\r
+ return endTime - beginTime;\r
+ }\r
+\r
+ /**\r
+ * Get the Timestamp for the beginning of execution.\r
+ *\r
+ * @return Timestamp The Timestamp for the beginning of execution.\r
+ */\r
+ public Timestamp getBeginExecutionTimestamp()\r
+ {\r
+ if (beginExecutionTime == 0)\r
+ {\r
+ return null;\r
+ }\r
+ else\r
+ {\r
+ return new Timestamp(beginExecutionTime);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the Timestamp for the end of execution.\r
+ *\r
+ * @return Timestamp The Timestamp for the end of execution.\r
+ */\r
+ public Timestamp getEndExecutionTimestamp()\r
+ {\r
+ if (endExecutionTime == 0)\r
+ {\r
+ return null;\r
+ }\r
+ else\r
+ {\r
+ return new Timestamp(endExecutionTime);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * RESOLVE - This method will go away once it is overloaded in all subclasses.\r
+ * Return the query plan as a String.\r
+ *\r
+ * @param depth Indentation level.\r
+ *\r
+ * @return String The query plan as a String.\r
+ */\r
+ public String getQueryPlanText(int depth)\r
+ {\r
+ return MessageService.getTextMessage(\r
+ SQLState.LANG_GQPT_NOT_SUPPORTED,\r
+ getClass().getName());\r
+ }\r
+\r
+ /**\r
+ * Return the total amount of time spent in this ResultSet\r
+ *\r
+ * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet\r
+ * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below.\r
+ *\r
+ * @return long The total amount of time spent (in milliseconds).\r
+ */\r
+ public long getTimeSpent(int type)\r
+ {\r
+ /* RESOLVE - this should be overloaded in all subclasses */\r
+ return 0;\r
+ }\r
+\r
+ /**\r
+ * @see ResultSet#getSubqueryTrackingArray\r
+ */\r
+ public final NoPutResultSet[] getSubqueryTrackingArray(int numSubqueries)\r
+ {\r
+ if (subqueryTrackingArray == null)\r
+ {\r
+ subqueryTrackingArray = new NoPutResultSet[numSubqueries];\r
+ }\r
+\r
+ return subqueryTrackingArray;\r
+ }\r
+\r
+ /**\r
+ * @see ResultSet#getAutoGeneratedKeysResultset\r
+ */\r
+ public ResultSet getAutoGeneratedKeysResultset()\r
+ {\r
+ //A non-null resultset would be returned only for an insert statement \r
+ return (ResultSet)null;\r
+ }\r
+\r
+ /**\r
+ Return the cursor name, null in this case.\r
+\r
+ @see ResultSet#getCursorName\r
+ */\r
+ public String getCursorName() {\r
+ return null;\r
+ }\r
+\r
+ // class implementation\r
+\r
+ /**\r
+ * Return the current time in milliseconds, if DEBUG and RunTimeStats is\r
+ * on, else return 0. (Only pay price of system call if need to.)\r
+ *\r
+ * @return long Current time in milliseconds.\r
+ */\r
+ protected final long getCurrentTimeMillis()\r
+ {\r
+ if (statisticsTimingOn)\r
+ {\r
+ return System.currentTimeMillis();\r
+ }\r
+ else\r
+ {\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Run a check constraint against the current row. Raise an error if\r
+ * the check constraint is violated.\r
+ *\r
+ * @param checkGM Generated code to run the check constraint.\r
+ * @param checkName Name of the constraint to check.\r
+ * @param heapConglom Number of heap conglomerate.\r
+ * @param activation Class in which checkGM lives.\r
+ *\r
+ * @exception StandardException thrown on error\r
+ */\r
+ public static void evaluateACheckConstraint\r
+ (\r
+ GeneratedMethod checkGM,\r
+ String checkName,\r
+ long heapConglom,\r
+ Activation activation\r
+ )\r
+ throws StandardException\r
+ {\r
+ if (checkGM != null)\r
+ {\r
+ DataValueDescriptor checkBoolean;\r
+\r
+ checkBoolean = (DataValueDescriptor) checkGM.invoke(activation);\r
+\r
+ /* Throw exception if check constraint is violated.\r
+ * (Only if check constraint evaluates to false.)\r
+ */ \r
+ if ((checkBoolean != null) &&\r
+ (! checkBoolean.isNull()) &&\r
+ (! checkBoolean.getBoolean()))\r
+ {\r
+ /* Now we have a lot of painful work to get the\r
+ * table name for the error message. All we have \r
+ * is the conglomerate number to work with.\r
+ */\r
+ DataDictionary dd = activation.getLanguageConnectionContext().getDataDictionary();\r
+ ConglomerateDescriptor cd = dd.getConglomerateDescriptor( heapConglom );\r
+ TableDescriptor td = dd.getTableDescriptor(cd.getTableID());\r
+\r
+ StandardException se = StandardException.newException(SQLState.LANG_CHECK_CONSTRAINT_VIOLATED, \r
+ td.getQualifiedName(), checkName);\r
+\r
+ throw se;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * Run check constraints against the current row. Raise an error if\r
+ * a check constraint is violated.\r
+ *\r
+ * @param checkGM Generated code to run the check constraint.\r
+ * @param activation Class in which checkGM lives.\r
+ *\r
+ * @exception StandardException thrown on error\r
+ */\r
+ public static void evaluateCheckConstraints\r
+ (\r
+ GeneratedMethod checkGM,\r
+ Activation activation\r
+ )\r
+ throws StandardException\r
+ {\r
+ if (checkGM != null)\r
+ {\r
+ // Evaluate the expression containing the check constraints.\r
+ // This expression will throw an exception if there is a\r
+ // violation, so there is no need to check the result.\r
+ checkGM.invoke(activation);\r
+ }\r
+\r
+ }\r
+ \r
+ /**\r
+ * Does this ResultSet cause a commit or rollback.\r
+ *\r
+ * @return Whether or not this ResultSet cause a commit or rollback.\r
+ */\r
+ public boolean doesCommit()\r
+ {\r
+ return false;\r
+ }\r
+\r
+ public java.sql.SQLWarning getWarnings() {\r
+ return null;\r
+ }\r
+\r
+}\r