--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.execute.NoPutResultSetImpl\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 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.io.FormatableBitSet;\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.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.execute.ExecIndexRow;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+import org.apache.derby.iapi.sql.execute.TargetResultSet;\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+import org.apache.derby.iapi.store.access.RowLocationRetRowSource;\r
+import org.apache.derby.iapi.store.access.RowSource;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.Orderable;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+\r
+/**\r
+ * Abstract ResultSet with built in Activation support for operations that\r
+ * return rows but do not allow the caller to put data on output pipes. This\r
+ * implementation of ResultSet is meant to be overridden by subtypes in the\r
+ * execution engine. Its primary users will be DML operations that do not put\r
+ * data on output pipes, but simply return it due to being result sets\r
+ * themselves.\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
+abstract class NoPutResultSetImpl\r
+extends BasicNoPutResultSetImpl\r
+{\r
+ /* Set in constructor and not modified */\r
+ public final int resultSetNumber;\r
+\r
+ /* fields used for formating run time statistics output */\r
+ protected String indent;\r
+ protected String subIndent;\r
+ protected int sourceDepth;\r
+\r
+ // fields used when being called as a RowSource\r
+ private boolean needsRowLocation;\r
+ protected ExecRow clonedExecRow;\r
+ GeneratedMethod checkGM;\r
+ long heapConglomerate;\r
+ protected TargetResultSet targetResultSet;\r
+\r
+ /* beetle 4464. compact flags into array of key column positions that we do check/skip nulls,\r
+ * so that we burn less cycles for each row, column.\r
+ */\r
+ protected int[] checkNullCols;\r
+ protected int cncLen;\r
+\r
+ /**\r
+ * Constructor\r
+ *\r
+ * @param activation The activation\r
+ * @param resultSetNumber The resultSetNumber\r
+ * @param optimizerEstimatedRowCount The optimizer's estimated number\r
+ * of rows.\r
+ * @param optimizerEstimatedCost The optimizer's estimated cost\r
+ */\r
+ NoPutResultSetImpl(Activation activation,\r
+ int resultSetNumber,\r
+ double optimizerEstimatedRowCount,\r
+ double optimizerEstimatedCost)\r
+ {\r
+ super(null,\r
+ activation,\r
+ optimizerEstimatedRowCount,\r
+ optimizerEstimatedCost);\r
+\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(activation!=null, "activation expected to be non-null");\r
+ SanityManager.ASSERT(resultSetNumber >= 0, "resultSetNumber expected to be >= 0");\r
+ }\r
+ this.resultSetNumber = resultSetNumber;\r
+ }\r
+\r
+ // NoPutResultSet interface\r
+\r
+ /**\r
+ * Returns the description of the table's rows\r
+ */\r
+ public ResultDescription getResultDescription() {\r
+ return activation.getResultDescription();\r
+ }\r
+\r
+ /**\r
+ Return my cursor name for JDBC. Can be null.\r
+ */\r
+ public String getCursorName() {\r
+\r
+ String cursorName = activation.getCursorName();\r
+ if ((cursorName == null) && isForUpdate()) {\r
+\r
+ activation.setCursorName(activation.getLanguageConnectionContext().getUniqueCursorName());\r
+\r
+ cursorName = activation.getCursorName();\r
+ }\r
+\r
+ return cursorName;\r
+ }\r
+\r
+ /** @see NoPutResultSet#resultSetNumber() */\r
+ public int resultSetNumber() {\r
+ return resultSetNumber;\r
+ }\r
+\r
+ /**\r
+ Close needs to invalidate any dependent statements, if this is a cursor.\r
+ Must be called by any subclasses that override close().\r
+ @exception StandardException on error\r
+ */\r
+ public void close() throws StandardException\r
+ {\r
+ if (!isOpen)\r
+ return;\r
+\r
+ /* If this is the top ResultSet then we must\r
+ * close all of the open subqueries for the\r
+ * entire query.\r
+ */\r
+ if (isTopResultSet)\r
+ {\r
+ /*\r
+ ** If run time statistics tracing is turned on, then now is the\r
+ ** time to dump out the information.\r
+ */\r
+ LanguageConnectionContext lcc = getLanguageConnectionContext();\r
+ if (lcc.getRunTimeStatisticsMode())\r
+ {\r
+ endExecutionTime = getCurrentTimeMillis();\r
+\r
+ lcc.setRunTimeStatisticsObject(\r
+ lcc.getExecutionContext().getResultSetStatisticsFactory().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
+\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
+\r
+ isOpen = false;\r
+\r
+ }\r
+\r
+ /** @see NoPutResultSet#setTargetResultSet */\r
+ public void setTargetResultSet(TargetResultSet trs)\r
+ {\r
+ targetResultSet = trs;\r
+ }\r
+\r
+ /** @see NoPutResultSet#setNeedsRowLocation */\r
+ public void setNeedsRowLocation(boolean needsRowLocation)\r
+ {\r
+ this.needsRowLocation = needsRowLocation;\r
+ }\r
+\r
+ // RowSource interface\r
+ \r
+ /** \r
+ * @see RowSource#getValidColumns\r
+ */\r
+ public FormatableBitSet getValidColumns()\r
+ {\r
+ // All columns are valid\r
+ return null;\r
+ }\r
+ \r
+ /** \r
+ * @see RowSource#getNextRowFromRowSource\r
+ * @exception StandardException on error\r
+ */\r
+ public DataValueDescriptor[] getNextRowFromRowSource()\r
+ throws StandardException\r
+ {\r
+ ExecRow execRow = getNextRowCore();\r
+ if (execRow != null)\r
+ {\r
+ /* Let the target preprocess the row. For now, this\r
+ * means doing an in place clone on any indexed columns\r
+ * to optimize cloning and so that we don't try to drain\r
+ * a stream multiple times. This is where we also\r
+ * enforce any check constraints.\r
+ */\r
+ clonedExecRow = targetResultSet.preprocessSourceRow(execRow);\r
+\r
+ return execRow.getRowArray();\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @see RowSource#needsToClone\r
+ */\r
+ public boolean needsToClone()\r
+ {\r
+ return(true);\r
+ }\r
+\r
+ /** \r
+ * @see RowSource#closeRowSource\r
+ */\r
+ public void closeRowSource()\r
+ {\r
+ // Do nothing here - actual work will be done in close()\r
+ }\r
+\r
+\r
+ // RowLocationRetRowSource interface\r
+\r
+ /**\r
+ * @see RowLocationRetRowSource#needsRowLocation\r
+ */\r
+ public boolean needsRowLocation()\r
+ {\r
+ return needsRowLocation;\r
+ }\r
+\r
+ /**\r
+ * @see RowLocationRetRowSource#rowLocation\r
+ * @exception StandardException on error\r
+ */\r
+ public void rowLocation(RowLocation rl)\r
+ throws StandardException\r
+ {\r
+ targetResultSet.changedRow(clonedExecRow, rl);\r
+ }\r
+\r
+\r
+ // class implementation\r
+\r
+ /**\r
+ * Clear the Orderable cache for each qualifier.\r
+ * (This should be done each time a scan/conglomerate with\r
+ * qualifiers is reopened.)\r
+ *\r
+ * @param qualifiers The Qualifiers to clear\r
+ */\r
+ protected void clearOrderableCache(Qualifier[][] qualifiers) throws StandardException\r
+ {\r
+ // Clear the Qualifiers's Orderable cache \r
+ if (qualifiers != null)\r
+ {\r
+ Qualifier qual;\r
+ for (int term = 0; term < qualifiers.length; term++)\r
+ {\r
+ for (int index = 0; index < qualifiers[term].length; index++)\r
+ {\r
+ qual = qualifiers[term][index];\r
+ qual.clearOrderableCache();\r
+ /* beetle 4880 performance enhancement and avoid deadlock while pushing\r
+ * down method call to store: pre-evaluate.\r
+ */\r
+ if (((GenericQualifier) qual).variantType != Qualifier.VARIANT)\r
+ qual.getOrderable(); // ignore return value\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Support methods for RowSource interface.\r
+ * These methods are used for enabling check constraint enforcement and\r
+ * replication logging for published tables when we are a RowSource.\r
+ */\r
+\r
+ /**\r
+ * Set the GeneratedMethod for enforcing check constraints\r
+ * \r
+ * @param checkGM The GeneratedMethod for enforcing any check constraints.\r
+ */\r
+ protected void setCheckConstraints(GeneratedMethod checkGM)\r
+ {\r
+ this.checkGM = checkGM;\r
+ }\r
+\r
+ /**\r
+ * Set the heap conglomerate number (used in enforcing check constraints)\r
+ * \r
+ * @param heapConglomerate The heap conglomerate number.\r
+ */\r
+ protected void setHeapConglomerate(long heapConglomerate)\r
+ {\r
+ this.heapConglomerate = heapConglomerate;\r
+ }\r
+\r
+ /**\r
+ * Set the current row to the row passed in.\r
+ *\r
+ * @param row the new current row\r
+ *\r
+ */\r
+ public final void setCurrentRow(ExecRow row)\r
+ {\r
+ activation.setCurrentRow(row, resultSetNumber);\r
+ currentRow = row;\r
+ }\r
+\r
+ /**\r
+ * Clear the current row\r
+ *\r
+ */\r
+ public final void clearCurrentRow()\r
+ {\r
+ currentRow = null;\r
+ activation.clearCurrentRow(resultSetNumber);\r
+ }\r
+\r
+ /**\r
+ * Is this ResultSet or it's source result set for update\r
+ * This method will be overriden in the inherited Classes\r
+ * if it is true\r
+ * @return Whether or not the result set is for update.\r
+ */\r
+ public boolean isForUpdate()\r
+ {\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Return true if we should skip the scan due to nulls in the start\r
+ * or stop position when the predicate on the column(s) in question\r
+ * do not implement ordered null semantics. beetle 4464, we also compact\r
+ * the areNullsOrdered flags into checkNullCols here.\r
+ *\r
+ * @param startPosition An index row for the start position\r
+ * @param stopPosition An index row for the stop position\r
+ *\r
+ * @return true means not to do the scan\r
+ */\r
+ protected boolean skipScan(ExecIndexRow startPosition, ExecIndexRow stopPosition)\r
+ throws StandardException\r
+ {\r
+ int nStartCols = (startPosition == null) ? 0 : startPosition.nColumns();\r
+ int nStopCols = (stopPosition == null) ? 0 : stopPosition.nColumns();\r
+\r
+ /* Two facts 1) for start and stop key column positions, one has to be the prefix\r
+ * of the other, 2) startPosition.areNullsOrdered(i) can't be different from\r
+ * stopPosition.areNullsOrdered(i) unless the case "c > null and c < 5", (where c is\r
+ * non-nullable), in which we skip the scan anyway.\r
+ * So we can just use the longer one to get checkNullCols.\r
+ */\r
+ boolean startKeyLonger = false;\r
+ int size = nStopCols;\r
+ if (nStartCols > nStopCols)\r
+ {\r
+ startKeyLonger = true;\r
+ size = nStartCols;\r
+ }\r
+ if (size == 0)\r
+ return false;\r
+ if ((checkNullCols == null) || (checkNullCols.length < size))\r
+ checkNullCols = new int[size];\r
+ cncLen = 0;\r
+\r
+ boolean returnValue = false;\r
+ for (int position = 0; position < nStartCols; position++)\r
+ {\r
+ if ( ! startPosition.areNullsOrdered(position))\r
+ {\r
+ if (startKeyLonger)\r
+ checkNullCols[cncLen++] = position + 1;\r
+ if (startPosition.getColumn(position + 1).isNull())\r
+ {\r
+ returnValue = true;\r
+ if (! startKeyLonger)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if (startKeyLonger && returnValue)\r
+ return true;\r
+ for (int position = 0; position < nStopCols; position++)\r
+ {\r
+ if ( ! stopPosition.areNullsOrdered(position))\r
+ {\r
+ if (! startKeyLonger)\r
+ checkNullCols[cncLen++] = position + 1;\r
+ if (returnValue)\r
+ continue;\r
+ if (stopPosition.getColumn(position + 1).isNull())\r
+ {\r
+ returnValue = true;\r
+ if (startKeyLonger)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return returnValue;\r
+ }\r
+\r
+ /**\r
+ * Return true if we should skip the scan due to nulls in the row\r
+ * when the start or stop positioners on the columns containing\r
+ * null do not implement ordered null semantics.\r
+ *\r
+ * @param row An index row\r
+ *\r
+ * @return true means skip the row because it has null\r
+ */\r
+ protected boolean skipRow(ExecRow row) throws StandardException\r
+ {\r
+ for (int i = 0; i < cncLen; i++)\r
+ {\r
+ if (row.getColumn(checkNullCols[i]).isNull())\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Return a 2-d array of Qualifiers as a String\r
+ */\r
+ public static String printQualifiers(Qualifier[][] qualifiers)\r
+ {\r
+ String idt = "";\r
+\r
+ String output = "";\r
+ if (qualifiers == null)\r
+ {\r
+ return idt + MessageService.getTextMessage(SQLState.LANG_NONE);\r
+ }\r
+\r
+ for (int term = 0; term < qualifiers.length; term++)\r
+ {\r
+ for (int i = 0; i < qualifiers[term].length; i++)\r
+ {\r
+ Qualifier qual = qualifiers[term][i];\r
+\r
+ output = idt + output +\r
+ MessageService.getTextMessage(\r
+ SQLState.LANG_COLUMN_ID_ARRAY,\r
+ String.valueOf(term), String.valueOf(i)) +\r
+ ": " + qual.getColumnId() + "\n";\r
+ \r
+ int operator = qual.getOperator();\r
+ String opString = null;\r
+ switch (operator)\r
+ {\r
+ case Orderable.ORDER_OP_EQUALS:\r
+ opString = "=";\r
+ break;\r
+\r
+ case Orderable.ORDER_OP_LESSOREQUALS:\r
+ opString = "<=";\r
+ break;\r
+\r
+ case Orderable.ORDER_OP_LESSTHAN:\r
+ opString = "<";\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT("Unknown operator " + operator);\r
+ }\r
+\r
+ // NOTE: This does not have to be internationalized, because\r
+ // this code should never be reached.\r
+ opString = "unknown value (" + operator + ")";\r
+ break;\r
+ }\r
+ output = output +\r
+ idt + MessageService.getTextMessage(SQLState.LANG_OPERATOR) +\r
+ ": " + opString + "\n" +\r
+ idt +\r
+ MessageService.getTextMessage(\r
+ SQLState.LANG_ORDERED_NULLS) +\r
+ ": " + qual.getOrderedNulls() + "\n" +\r
+ idt +\r
+ MessageService.getTextMessage(\r
+ SQLState.LANG_UNKNOWN_RETURN_VALUE) +\r
+ ": " + qual.getUnknownRV() + "\n" +\r
+ idt +\r
+ MessageService.getTextMessage(\r
+ SQLState.LANG_NEGATE_COMPARISON_RESULT) +\r
+ ": " + qual.negateCompareResult() + "\n";\r
+ }\r
+ }\r
+\r
+ return output;\r
+ }\r
+\r
+ /**\r
+ * @see NoPutResultSet#updateRow\r
+ *\r
+ * This method is result sets used for scroll insensitive updatable \r
+ * result sets for other result set it is a no-op.\r
+ */\r
+ public void updateRow(ExecRow row) throws StandardException {\r
+ // Only ResultSets of type Scroll Insensitive implement\r
+ // detectability, so for other result sets this method\r
+ // is a no-op\r
+ }\r
+\r
+ /**\r
+ * @see NoPutResultSet#markRowAsDeleted\r
+ *\r
+ * This method is result sets used for scroll insensitive updatable \r
+ * result sets for other result set it is a no-op.\r
+ */\r
+ public void markRowAsDeleted() throws StandardException {\r
+ // Only ResultSets of type Scroll Insensitive implement\r
+ // detectability, so for other result sets this method\r
+ // is a no-op\r
+ }\r
+\r
+ /**\r
+ * @see NoPutResultSet#positionScanAtRowLocation\r
+ *\r
+ * This method is result sets used for scroll insensitive updatable \r
+ * result sets for other result set it is a no-op.\r
+ */\r
+ public void positionScanAtRowLocation(RowLocation rl) \r
+ throws StandardException \r
+ {\r
+ // Only ResultSets of type Scroll Insensitive implement\r
+ // detectability, so for other result sets this method\r
+ // is a no-op\r
+ }\r
+\r
+\r
+}\r