001: /*
002:
003: Derby - Class org.apache.derby.client.am.SectionManager
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.client.am;
023:
024: import org.apache.derby.shared.common.reference.JDBC30Translation;
025:
026: import org.apache.derby.shared.common.reference.SQLState;
027:
028: public class SectionManager {
029: String collection_;
030: Agent agent_;
031:
032: // Cursor holdability attributes used as package cluster indices.
033: // Not defined in PackageBindOptions because this attribute is part of the
034: // declare cursor [with hold] sql string based on section binds.
035: // By convention, we bind all sections in the same package with
036: // the same holdability.
037: final static int HOLD = 0;
038: final static int NO_HOLD = 1;
039:
040: // The following stack of available sections is
041: // for pooling and recycling previously used sections.
042: // For performance, the section objects themselves are pooled,
043: // rather than just keeping track of free section numbers;
044: // this way, we don't have to new-up a section if one is available in the pool.
045: java.util.Stack freeSectionsNonHold_ = null;
046: java.util.Stack freeSectionsHold_ = null;
047:
048: int nextAvailableSectionNumber_ = 1;
049:
050: // store package consistency token information and initialized in
051: // setPKGNAMCBytes
052: // holdPKGNAMCBytes stores PKGNAMCBytes when holdability is hold
053: // noHoldPKGNAMCBytes stores PKGNAMCBytes when holdability is no hold
054: public static byte[] holdPKGNAMCBytes = null;
055: public static byte[] noHoldPKGNAMCBytes = null;
056:
057: final static String packageNameWithHold__ = "SYSLH000";
058: final static String packageNameWithNoHold__ = "SYSLN000";
059:
060: final static String cursorNamePrefixWithHold__ = "SQL_CURLH000C";
061: final static String cursorNamePrefixWithNoHold__ = "SQL_CURLN000C";
062:
063: // Jdbc 1 positioned updates are implemented via
064: // sql scan for "...where current of <users-cursor-name>",
065: // the addition of mappings from cursor names to query sections,
066: // and the subtitution of <users-cursor-name> with <canned-cursor-name> in the pass-thru sql string
067: // "...where current of <canned-cursor-name>" when user-defined cursor names are used.
068: // Both "canned" cursor names (from our jdbc package set) and user-defined cursor names are mapped.
069: // Statement.cursorName_ is initialized to null until the cursor name is requested or set.
070: // When set (s.setCursorName()) with a user-defined name, then it is added to the cursor map at that time;
071: // When requested (rs.getCursorName()), if the cursor name is still null,
072: // then is given the canned cursor name as defined by our jdbc package set and added to the cursor map.
073: // Still need to consider how positioned updates should interact with multiple result sets from a stored.
074: private java.util.Hashtable positionedUpdateCursorNameToQuerySection_ = new java.util.Hashtable();
075:
076: // Cursor name to ResultSet mapping is needed for positioned updates to check whether
077: // a ResultSet is scrollable. If so, exception is thrown.
078: private java.util.Hashtable positionedUpdateCursorNameToResultSet_ = new java.util.Hashtable();
079:
080: String databaseName;
081:
082: int maxNumSections_ = 32768;
083:
084: public SectionManager(String collection, Agent agent,
085: String databaseName) {
086: collection_ = collection;
087: agent_ = agent;
088: this .databaseName = databaseName;
089: freeSectionsNonHold_ = new java.util.Stack();
090: freeSectionsHold_ = new java.util.Stack();
091: }
092:
093: /**
094: * Store the Packagename and consistency token information This is called from Section.setPKGNAMCBytes
095: *
096: * @param b bytearray that has the PKGNAMC information to be stored
097: * @param resultSetHoldability depending on the holdability store it in the correct byte array packagename and
098: * consistency token information for when holdability is set to HOLD_CURSORS_OVER_COMMIT
099: * is stored in holdPKGNAMCBytes and in noHoldPKGNAMCBytes when holdability is set to
100: * CLOSE_CURSORS_AT_COMMIT
101: */
102: public void setPKGNAMCBytes(byte[] b, int resultSetHoldability) {
103: if (resultSetHoldability == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
104: agent_.sectionManager_.holdPKGNAMCBytes = b;
105: } else if (resultSetHoldability == JDBC30Translation.CLOSE_CURSORS_AT_COMMIT) {
106: agent_.sectionManager_.noHoldPKGNAMCBytes = b;
107: }
108: }
109:
110: //------------------------entry points----------------------------------------
111:
112: // Get a section for either a jdbc update or query statement.
113: public Section getDynamicSection(int resultSetHoldability)
114: throws SqlException {
115: int cursorHoldIndex;
116: if (resultSetHoldability == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
117: return getSection(freeSectionsHold_, packageNameWithHold__,
118: cursorNamePrefixWithHold__, resultSetHoldability);
119: } else if (resultSetHoldability == JDBC30Translation.CLOSE_CURSORS_AT_COMMIT) {
120: return getSection(freeSectionsNonHold_,
121: packageNameWithNoHold__,
122: cursorNamePrefixWithNoHold__, resultSetHoldability);
123: } else {
124: throw new SqlException(agent_.logWriter_,
125: new ClientMessageId(
126: SQLState.UNSUPPORTED_HOLDABILITY_PROPERTY),
127: new Integer(resultSetHoldability));
128: }
129: }
130:
131: protected Section getSection(java.util.Stack freeSections,
132: String packageName, String cursorNamePrefix,
133: int resultSetHoldability) throws SqlException {
134: if (!freeSections.empty()) {
135: return (Section) freeSections.pop();
136: } else if (nextAvailableSectionNumber_ < (maxNumSections_ - 1)) {
137: String cursorName = cursorNamePrefix
138: + nextAvailableSectionNumber_;
139: Section section = new Section(agent_, packageName,
140: nextAvailableSectionNumber_, cursorName,
141: resultSetHoldability);
142: nextAvailableSectionNumber_++;
143: return section;
144: } else
145: // unfortunately we have run out of sections
146: {
147: throw new SqlException(
148: agent_.logWriter_,
149: new ClientMessageId(SQLState.EXCEEDED_MAX_SECTIONS),
150: "32k");
151: }
152: }
153:
154: public void freeSection(Section section, int resultSetHoldability) {
155: if (resultSetHoldability == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {
156: this .freeSectionsHold_.push(section);
157: } else if (resultSetHoldability == JDBC30Translation.CLOSE_CURSORS_AT_COMMIT) {
158: this .freeSectionsNonHold_.push(section);
159: }
160: }
161:
162: // Get a section for a jdbc 2 positioned update/delete for the corresponding query.
163: // A positioned update section must come from the same package as its query section.
164: Section getPositionedUpdateSection(Section querySection)
165: throws SqlException {
166: Connection connection = agent_.connection_;
167: return getDynamicSection(connection.holdability());
168: }
169:
170: // Get a section for a jdbc 1 positioned update/delete for the corresponding query.
171: // A positioned update section must come from the same package as its query section.
172: Section getPositionedUpdateSection(String cursorName,
173: boolean useExecuteImmediateSection) throws SqlException {
174: Section querySection = (Section) positionedUpdateCursorNameToQuerySection_
175: .get(cursorName);
176:
177: // If querySection is null, then the user must have provided a bad cursor name.
178: // Otherwise, get a new section and save the client's cursor name and the server's
179: // cursor name to the new section.
180: if (querySection != null) {
181: Section section = getPositionedUpdateSection(querySection);
182: // getPositionedUpdateSection gets the next available section from the query
183: // package, and it has a different cursor name associated with the section.
184: // We need to save the client's cursor name and server's cursor name to the
185: // new section.
186: section.setClientCursorName(querySection
187: .getClientCursorName());
188: section.serverCursorNameForPositionedUpdate_ = querySection
189: .getServerCursorName();
190: return section;
191: } else {
192: return null;
193: }
194: }
195:
196: void mapCursorNameToQuerySection(String cursorName, Section section) {
197: positionedUpdateCursorNameToQuerySection_.put(cursorName,
198: section);
199: }
200:
201: void mapCursorNameToResultSet(String cursorName, ResultSet resultSet) {
202: positionedUpdateCursorNameToResultSet_.put(cursorName,
203: resultSet);
204: }
205:
206: ResultSet getPositionedUpdateResultSet(String cursorName)
207: throws SqlException {
208: ResultSet rs = (ResultSet) positionedUpdateCursorNameToResultSet_
209: .get(cursorName);
210: if (rs == null) {
211: throw new SqlException(agent_.logWriter_,
212: new ClientMessageId(
213: SQLState.CLIENT_RESULT_SET_NOT_OPEN));
214: }
215: return (rs.resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) ? null
216: : rs;
217: }
218:
219: void removeCursorNameToResultSetMapping(String clientCursorName,
220: String serverCursorName) {
221: if (clientCursorName != null) {
222: positionedUpdateCursorNameToResultSet_
223: .remove(clientCursorName);
224: }
225: if (serverCursorName != null) {
226: positionedUpdateCursorNameToResultSet_
227: .remove(serverCursorName);
228: }
229: }
230:
231: void removeCursorNameToQuerySectionMapping(String clientCursorName,
232: String serverCursorName) {
233: if (clientCursorName != null) {
234: positionedUpdateCursorNameToQuerySection_
235: .remove(clientCursorName);
236: }
237: if (serverCursorName != null) {
238: positionedUpdateCursorNameToQuerySection_
239: .remove(serverCursorName);
240: }
241: }
242:
243: }
|