001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.ExecSPSNode
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.compile;
023:
024: import org.apache.derby.iapi.services.sanity.SanityManager;
025:
026: import org.apache.derby.iapi.services.loader.GeneratedClass;
027:
028: import org.apache.derby.iapi.error.StandardException;
029:
030: import org.apache.derby.iapi.sql.compile.CompilerContext;
031:
032: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
033: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
034: import org.apache.derby.iapi.sql.dictionary.SPSDescriptor;
035:
036: import org.apache.derby.iapi.sql.depend.DependencyManager;
037:
038: import org.apache.derby.iapi.reference.SQLState;
039:
040: import org.apache.derby.iapi.sql.execute.ConstantAction;
041: import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
042:
043: import org.apache.derby.iapi.types.DataTypeDescriptor;
044: import org.apache.derby.iapi.sql.PreparedStatement;
045: import org.apache.derby.iapi.sql.ResultDescription;
046:
047: import org.apache.derby.impl.sql.CursorInfo;
048:
049: import org.apache.derby.iapi.util.ByteArray;
050:
051: import java.util.Enumeration;
052:
053: /**
054: * A ExecSPSNode is the root of a QueryTree
055: * that represents an EXECUTE STATEMENT
056: * statement. It is a tad abnormal. Duringa
057: * bind, it locates and retrieves the SPSDescriptor
058: * for the particular statement. At generate time,
059: * it generates the prepared statement for the
060: * stored prepared statement and returns it (i.e.
061: * it effectively replaces itself with the appropriate
062: * prepared statement).
063: *
064: * @author jamie
065: */
066:
067: public class ExecSPSNode extends StatementNode {
068: private TableName name;
069: private SPSDescriptor spsd;
070: private ExecPreparedStatement ps;
071:
072: /**
073: * Initializer for a ExecSPSNode
074: *
075: * @param newObjectName The name of the table to be created
076: *
077: * @exception StandardException Thrown on error
078: */
079:
080: public void init(Object newObjectName) {
081: this .name = (TableName) newObjectName;
082: }
083:
084: /**
085: * Bind this ExecSPSNode. This means doing any static error
086: * checking that can be done before actually creating the table.
087: * For example, verifying that the ResultColumnList does not
088: * contain any duplicate column names.
089: *
090: * @return The bound query tree
091: *
092: * @exception StandardException Thrown on error
093: */
094: public QueryTreeNode bind() throws StandardException {
095: /*
096: ** Grab the compiler context each time we bind just
097: ** to make sure we have the write one (even though
098: ** we are caching it).
099: */
100: DataDictionary dd = getDataDictionary();
101:
102: String schemaName = name.getSchemaName();
103: SchemaDescriptor sd = getSchemaDescriptor(name.getSchemaName());
104: if (schemaName == null)
105: name.setSchemaName(sd.getSchemaName());
106:
107: if (sd.getUUID() != null)
108: spsd = dd.getSPSDescriptor(name.getTableName(), sd);
109:
110: if (spsd == null) {
111: throw StandardException.newException(
112: SQLState.LANG_OBJECT_NOT_FOUND, "STATEMENT", name);
113: }
114:
115: if (spsd.getType() == spsd.SPS_TYPE_TRIGGER) {
116: throw StandardException.newException(
117: SQLState.LANG_TRIGGER_SPS_CANNOT_BE_EXECED, name);
118: }
119:
120: /*
121: ** This execute statement is dependent on the
122: ** stored prepared statement. If for any reason
123: ** the underlying statement is invalidated by
124: ** the time we get to execution, the 'execute statement'
125: ** will get invalidated when the underlying statement
126: ** is invalidated.
127: */
128: getCompilerContext().createDependency(spsd);
129:
130: return this ;
131: }
132:
133: /**
134: * SPSes are atomic if its underlying statement is
135: * atomic.
136: *
137: * @return true if the statement is atomic
138: */
139: public boolean isAtomic() {
140:
141: if (SanityManager.DEBUG) {
142: SanityManager
143: .ASSERT(ps != null,
144: "statement expected to be bound before calling isAtomic()");
145: }
146:
147: return ps.isAtomic();
148: }
149:
150: /**
151: * Do code generation for this statement. Overrides
152: * the normal generation path in StatementNode.
153: *
154: * @param ignored - ignored (he he)
155: *
156: * @return A GeneratedClass for this statement
157: *
158: * @exception StandardException Thrown on error
159: */
160: public GeneratedClass generate(ByteArray ignored)
161: throws StandardException {
162: //Bug 4821 - commiting the nested transaction will release any bind time locks
163: //This way we won't get lock time out errors while trying to update sysstatement
164: //table during stale sps recompilation later in the getPreparedstatement() call.
165: if (spsd.isValid() == false) {
166: getLanguageConnectionContext().commitNestedTransaction();
167: getLanguageConnectionContext().beginNestedTransaction(true);
168: }
169:
170: /*
171: ** The following does a prepare on the underlying
172: ** statement if necessary. The returned statement
173: ** is valid and its class is loaded up.
174: */
175: ps = spsd.getPreparedStatement();
176:
177: /*
178: ** Set the saved constants from the prepared statement.
179: ** Put them in the compilation context -- this is where
180: ** they are expected.
181: */
182: getCompilerContext().setSavedObjects(ps.getSavedObjects());
183: getCompilerContext().setCursorInfo(ps.getCursorInfo());
184: GeneratedClass gc = ps.getActivationClass();
185:
186: return gc;
187: }
188:
189: /**
190: * Make the result description. Really, we are just
191: * copying it from the stored prepared statement.
192: *
193: * @return the description
194: */
195: public ResultDescription makeResultDescription() {
196: return ps.getResultDescription();
197: }
198:
199: /**
200: * Get information about this cursor. For sps,
201: * this is info saved off of the original query
202: * tree (the one for the underlying query).
203: *
204: * @return the cursor info
205: */
206: public Object getCursorInfo() {
207: return ps.getCursorInfo();
208: }
209:
210: /**
211: * Return a description of the ? parameters for the statement
212: * represented by this query tree. Just return the params
213: * stored with the prepared statement.
214: *
215: * @return An array of DataTypeDescriptors describing the
216: * ? parameters for this statement. It returns null
217: * if there are no parameters.
218: *
219: * @exception StandardException on error
220: */
221: public DataTypeDescriptor[] getParameterTypes()
222: throws StandardException {
223: return spsd.getParams();
224: }
225:
226: /**
227: * Create the Constant information that will drive the guts of Execution.
228: * This is assumed to be the first action on this node.
229: *
230: */
231: public ConstantAction makeConstantAction() {
232: return ps.getConstantAction();
233: }
234:
235: /**
236: * We need a savepoint if we will do transactional work.
237: * We'll ask the underlying statement if it needs
238: * a savepoint and pass that back. We have to do this
239: * after generation because getting the PS now might
240: * cause us to basically do DDL (for a stmt recompilation)
241: * which is explicitly banned during binding. So the
242: * caller can only call this after generate() has retrieved
243: * the target PS.
244: *
245: * @return boolean always true.
246: */
247: public boolean needsSavepoint() {
248: if (SanityManager.DEBUG) {
249: SanityManager
250: .ASSERT(ps != null,
251: "statement expected to be bound before calling needsSavepoint()");
252: }
253:
254: return ps.needsSavepoint();
255: }
256:
257: /** @see QueryTreeNode#executeStatementName */
258: public String executeStatementName() {
259: return name.getTableName();
260: }
261:
262: /** @see QueryTreeNode#executeSchemaName */
263: public String executeSchemaName() {
264: return name.getSchemaName();
265: }
266:
267: /**
268: * Get the name of the SPS that is used
269: * to execute this statement. Only relevant
270: * for an ExecSPSNode -- otherwise, returns null.
271: *
272: * @return the name of the underlying sps
273: */
274: public String getSPSName() {
275: return spsd.getQualifiedName();
276: }
277:
278: /*
279: * Shouldn't be called
280: */
281: int activationKind() {
282: if (SanityManager.DEBUG) {
283: SanityManager.THROWASSERT("activationKind not expected "
284: + "to be called for a stored prepared statement");
285: }
286: return StatementNode.NEED_PARAM_ACTIVATION;
287: }
288:
289: /////////////////////////////////////////////////////////////////////
290: //
291: // PRIVATE
292: //
293: /////////////////////////////////////////////////////////////////////
294:
295: /////////////////////////////////////////////////////////////////////
296: //
297: // MISC
298: //
299: /////////////////////////////////////////////////////////////////////
300: public String statementToString() {
301: return "EXECUTE STATEMENT";
302: }
303:
304: // called after bind only
305: private final SPSDescriptor getSPSDescriptor() {
306: return spsd;
307: }
308: }
|