001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.DMLWriteResultSet
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.execute;
023:
024: import org.apache.derby.iapi.types.DataValueDescriptor;
025: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
026: import org.apache.derby.iapi.services.io.StreamStorable;
027: import org.apache.derby.iapi.sql.execute.ExecRow;
028: import org.apache.derby.iapi.sql.execute.ConstantAction;
029: import org.apache.derby.iapi.error.StandardException;
030: import org.apache.derby.iapi.sql.Activation;
031: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
032:
033: import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
034: import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
035: import org.apache.derby.iapi.store.access.TransactionController;
036:
037: import org.apache.derby.catalog.UUID;
038: import org.apache.derby.iapi.services.io.FormatableBitSet;
039:
040: /**
041: * For INSERT/UPDATE/DELETE impls. Used to tag them.
042: */
043: abstract class DMLWriteResultSet extends NoRowsResultSetImpl {
044: protected WriteCursorConstantAction constantAction;
045: protected int[] baseRowReadMap;
046: protected int[] streamStorableHeapColIds;
047: protected ExecRow deferredSparseRow;
048: protected DynamicCompiledOpenConglomInfo heapDCOCI;
049: protected DynamicCompiledOpenConglomInfo[] indexDCOCIs;
050: private boolean needToObjectifyStream;
051:
052: public int rowCount;
053:
054: /**
055: * Constructor
056: *
057: * @param activation an activation
058: *
059: * @exception StandardException on error
060: */
061: DMLWriteResultSet(Activation activation) throws StandardException {
062: this (activation, activation.getConstantAction());
063: }
064:
065: DMLWriteResultSet(Activation activation,
066: ConstantAction constantAction) throws StandardException {
067: super (activation);
068:
069: this .constantAction = (WriteCursorConstantAction) constantAction;
070: baseRowReadMap = this .constantAction.getBaseRowReadMap();
071: streamStorableHeapColIds = this .constantAction
072: .getStreamStorableHeapColIds();
073:
074: TransactionController tc = activation
075: .getTransactionController();
076:
077: // Special handling for updatable VTIs
078: if (!(constantAction instanceof UpdatableVTIConstantAction)) {
079: heapDCOCI = tc
080: .getDynamicCompiledConglomInfo(this .constantAction.conglomId);
081: if (this .constantAction.indexCIDS.length != 0) {
082: indexDCOCIs = new DynamicCompiledOpenConglomInfo[this .constantAction.indexCIDS.length];
083: for (int index = 0; index < this .constantAction.indexCIDS.length; index++) {
084: indexDCOCIs[index] = tc
085: .getDynamicCompiledConglomInfo(this .constantAction.indexCIDS[index]);
086: }
087: }
088: }
089:
090: /* We only need to objectify the streams here if they are exposed to the users through the
091: * trigger context. For "before" trigger, we could just return the stream wrapped in
092: * RememberBytesInputStream to the user and reset it after usage, but this wouldn't work
093: * because the user may get the stream in trigger action and do something with it in parallel
094: * with the store doing insert. We could also delay the materializing until the stream is
095: * fetched in before trigger but that would complicate the code. For "after" trigger, we have
096: * to materialize it here because store only keeps a page's amount for each round. For other
097: * reasons of "deferred" operations we don't need to objectify here. Simply going through a
098: * temp table (either in memory part or spilled to disk) is fine for the stream, unless a
099: * same stream appears in two rows in the temp table, which could happen for an "update", in
100: * which case we do the objectifying in UpdateResultSet. Beetle 4896. Related bug entries:
101: * 2432, 3383.
102: */
103: needToObjectifyStream = (this .constantAction
104: .getTriggerInfo(activation
105: .getLanguageConnectionContext()
106: .getExecutionContext()) != null);
107: }
108:
109: public final int modifiedRowCount() {
110: return rowCount;
111: }
112:
113: /**
114: * Get next row from the source result set.
115: *
116: * @param source SourceResultSet
117: * Also look at Track#2432/change 12433
118: */
119: protected ExecRow getNextRowCore(NoPutResultSet source)
120: throws StandardException {
121: ExecRow row = source.getNextRowCore();
122: if (needToObjectifyStream) {
123: /*
124: See comments in the constructor. We also need to load the column
125: if it is part of an index on an insert but that is done in
126: insertResultSet#normalInsertCore or IRS#changedRow
127: */
128: objectifyStreams(row);
129: }
130: return row;
131: }
132:
133: private void objectifyStreams(ExecRow row) throws StandardException {
134: // if the column is a streamStorable, we need to materialize the object
135: // therefore, the object can be used to multiple rows.
136: if ((row != null) && (streamStorableHeapColIds != null)) {
137: for (int ix = 0; ix < streamStorableHeapColIds.length; ix++) {
138: int heapIx = streamStorableHeapColIds[ix];
139: int readIx = (baseRowReadMap == null) ? heapIx
140: : baseRowReadMap[heapIx];
141:
142: DataValueDescriptor col = row.getColumn(readIx + 1);
143: ((StreamStorable) col).loadStream();
144: }
145: }
146: }
147:
148: /**
149: * For deferred update, get a deferred sparse row based on the
150: * deferred non-sparse row. Share the underlying columns. If there
151: * is no column bit map, make them the same row.
152: *
153: * @exception StandardException Thrown on error
154: */
155: protected ExecRow makeDeferredSparseRow(ExecRow deferredBaseRow,
156: FormatableBitSet baseRowReadList,
157: LanguageConnectionContext lcc) throws StandardException {
158: ExecRow deferredSparseRow;
159:
160: if (baseRowReadList == null) {
161: /* No sparse row */
162: deferredSparseRow = deferredBaseRow;
163: } else {
164: /*
165: ** We need to do a fetch doing a partial row
166: ** read. We need to shift our 1-based bit
167: ** set to a zero based bit set like the store
168: ** expects.
169: */
170: deferredSparseRow = RowUtil.getEmptyValueRow(
171: baseRowReadList.getLength() - 1, lcc);
172: /*
173: ** getColumn(), setColumn(), and baseRowReadList are
174: ** one-based.
175: */
176: int fromPosition = 1;
177: for (int i = 1; i <= deferredSparseRow.nColumns(); i++) {
178: if (baseRowReadList.isSet(i)) {
179: deferredSparseRow.setColumn(i, deferredBaseRow
180: .getColumn(fromPosition++));
181: }
182: }
183: }
184:
185: return deferredSparseRow;
186: }
187:
188: /**
189: * get the index name given the conglomerate id of the index.
190: *
191: * @param indexCID conglomerate ID of the index.
192: *
193: * @return index name of given index.
194: */
195: String getIndexNameFromCID(long indexCID) {
196: return this.constantAction.getIndexNameFromCID(indexCID);
197: }
198: }
|