001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.JavaValueNode
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.sql.compile.CompilerContext;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027:
028: import org.apache.derby.iapi.services.context.ContextManager;
029:
030: import org.apache.derby.iapi.types.DataTypeDescriptor;
031:
032: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
033:
034: import org.apache.derby.iapi.types.TypeId;
035:
036: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
037: import org.apache.derby.iapi.error.StandardException;
038: import org.apache.derby.iapi.services.i18n.MessageService;
039: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
040: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
041:
042: import org.apache.derby.iapi.types.JSQLType;
043:
044: import org.apache.derby.iapi.services.compiler.LocalField;
045: import org.apache.derby.iapi.services.compiler.MethodBuilder;
046:
047: import org.apache.derby.iapi.services.loader.ClassInspector;
048:
049: import org.apache.derby.iapi.store.access.Qualifier;
050:
051: import org.apache.derby.iapi.util.JBitSet;
052:
053: import org.apache.derby.iapi.reference.SQLState;
054:
055: import java.lang.reflect.Modifier;
056:
057: import java.util.Vector;
058:
059: /**
060: * This abstract node class represents a data value in the Java domain.
061: */
062:
063: abstract class JavaValueNode extends QueryTreeNode {
064: private boolean mustCastToPrimitive;
065:
066: protected boolean forCallStatement;
067: private boolean valueReturnedToSQLDomain;
068: private boolean returnValueDiscarded;
069:
070: protected JSQLType jsqlType;
071:
072: /* Name of field holding receiver value, if any */
073: private LocalField receiverField;
074:
075: public boolean isPrimitiveType() throws StandardException {
076: JSQLType myType = getJSQLType();
077:
078: if (myType == null) {
079: return false;
080: } else {
081: return (myType.getCategory() == JSQLType.JAVA_PRIMITIVE);
082: }
083: }
084:
085: public String getJavaTypeName() throws StandardException {
086: JSQLType myType = getJSQLType();
087:
088: if (myType == null) {
089: return "";
090: }
091:
092: switch (myType.getCategory()) {
093: case JSQLType.JAVA_CLASS:
094: return myType.getJavaClassName();
095:
096: case JSQLType.JAVA_PRIMITIVE:
097: return JSQLType.primitiveNames[myType.getPrimitiveKind()];
098:
099: default:
100:
101: if (SanityManager.DEBUG) {
102: SanityManager.THROWASSERT("Inappropriate JSQLType: "
103: + myType);
104: }
105: }
106:
107: return "";
108: }
109:
110: public void setJavaTypeName(String javaTypeName) {
111: jsqlType = new JSQLType(javaTypeName);
112: }
113:
114: public String getPrimitiveTypeName() throws StandardException {
115: JSQLType myType = getJSQLType();
116:
117: if (myType == null) {
118: return "";
119: }
120:
121: switch (myType.getCategory()) {
122: case JSQLType.JAVA_PRIMITIVE:
123: return JSQLType.primitiveNames[myType.getPrimitiveKind()];
124:
125: default:
126:
127: if (SanityManager.DEBUG) {
128: SanityManager.THROWASSERT("Inappropriate JSQLType: "
129: + myType);
130: }
131: }
132:
133: return "";
134: }
135:
136: /**
137: * Toggles whether the code generator should add a cast to extract a primitive
138: * value from an object.
139: *
140: * @param booleanValue true if we want the code generator to add a cast
141: * false otherwise
142: */
143: public void castToPrimitive(boolean booleanValue) {
144: mustCastToPrimitive = booleanValue;
145: }
146:
147: /**
148: * Reports whether the code generator should add a cast to extract a primitive
149: * value from an object.
150: *
151: * @return true if we want the code generator to add a cast
152: * false otherwise
153: */
154: public boolean mustCastToPrimitive() {
155: return mustCastToPrimitive;
156: }
157:
158: /**
159: * Get the JSQLType that corresponds to this node. Could be a SQLTYPE,
160: * a Java primitive, or a Java class.
161: *
162: * @return the corresponding JSQLType
163: *
164: */
165: public JSQLType getJSQLType() throws StandardException {
166: return jsqlType;
167: }
168:
169: /**
170: * Map a JSQLType to a compilation type id.
171: *
172: * @param jsqlType the universal type to map
173: *
174: * @return the corresponding compilation type id
175: *
176: */
177: public TypeId mapToTypeID(JSQLType jsqlType) {
178: DataTypeDescriptor dts = jsqlType.getSQLType();
179:
180: if (dts == null) {
181: return null;
182: }
183:
184: return dts.getTypeId();
185: }
186:
187: /**
188: * Set the clause that this node appears in.
189: *
190: * @param clause The clause that this node appears in.
191: */
192: public void setClause(int clause) {
193: clause = clause;
194: }
195:
196: /**
197: * Mark this node as being for a CALL Statement.
198: * (void methods are only okay for CALL Statements)
199: */
200: public void markForCallStatement() {
201: forCallStatement = true;
202: }
203:
204: /**
205: * @see ValueNode#remapColumnReferencesToExpressions
206: *
207: * @exception StandardException Thrown on error
208: */
209: abstract public JavaValueNode remapColumnReferencesToExpressions()
210: throws StandardException;
211:
212: /**
213: * @see ValueNode#categorize
214: *
215: * @exception StandardException Thrown on error
216: */
217: abstract public boolean categorize(JBitSet referencedTabs,
218: boolean simplePredsOnly) throws StandardException;
219:
220: /**
221: * @see ValueNode#bindExpression
222: *
223: * @return the new node, usually this
224: *
225: * @exception StandardException Thrown on error
226: */
227: abstract JavaValueNode bindExpression(FromList fromList,
228: SubqueryList subqueryList, Vector aggregateVector)
229: throws StandardException;
230:
231: /**
232: * @see ValueNode#preprocess
233: *
234: * @exception StandardException Thrown on error
235: */
236: abstract public void preprocess(int numTables,
237: FromList outerFromList, SubqueryList outerSubqueryList,
238: PredicateList outerPredicateList) throws StandardException;
239:
240: /** @see ValueNode#getConstantValueAsObject
241: *
242: * @exception StandardException Thrown on error
243: */
244: Object getConstantValueAsObject() throws StandardException {
245: return null;
246: }
247:
248: /**
249: * Do the code generation for this node. Call the more general
250: * routine that generates expressions.
251: *
252: * @param acb The ActivationClassBuilder for the class being built
253: * @param mb the method the expression will go into
254: *
255: * @exception StandardException Thrown on error
256: */
257:
258: protected final void generate(ActivationClassBuilder acb,
259: MethodBuilder mb) throws StandardException {
260: generateExpression(acb, mb);
261: }
262:
263: /**
264: * Generate the expression that evaluates to the receiver. This is
265: * for the case where a java expression is being returned to the SQL
266: * domain, and we need to check whether the receiver is null (if so,
267: * the SQL value should be set to null, and this Java expression
268: * not evaluated). Instance method calls and field references have
269: * receivers, while class method calls and calls to constructors do
270: * not. If this Java expression does not have a receiver, this method
271: * returns null.
272: *
273: * The implementation of this method should only generate the receiver
274: * once and cache it in a field. This is because there will be two
275: * references to the receiver, and we want to evaluate it only once.
276: *
277: *
278: * @param acb The ExpressionClassBuilder for the class being built
279: * @param mb the method the expression will go into
280: *
281: * @return True if has compiled receiver.
282: *
283: * @exception StandardException Thrown on error
284: */
285: protected boolean generateReceiver(ExpressionClassBuilder acb,
286: MethodBuilder mb) throws StandardException {
287: return false;
288: }
289:
290: /**
291: * Return the variant type for the underlying expression.
292: * The variant type can be:
293: * VARIANT - variant within a scan
294: * (method calls and non-static field access)
295: * SCAN_INVARIANT - invariant within a scan
296: * (column references from outer tables)
297: * QUERY_INVARIANT - invariant within the life of a query
298: * (constant expressions)
299: *
300: * @return The variant type for the underlying expression.
301: */
302: protected int getOrderableVariantType() throws StandardException {
303: // The default is VARIANT
304: return Qualifier.VARIANT;
305: //return Qualifier.SCAN_INVARIANT;
306: }
307:
308: /**
309: * General logic shared by Core compilation and by the Replication Filter
310: * compiler. Every child of ValueNode must implement one of these methods.
311: *
312: * @param acb The ExpressionClassBuilder for the class being built
313: * @param mb the method the expression will go into
314: *
315: * @exception StandardException Thrown on error
316: */
317:
318: protected abstract void generateExpression(
319: ExpressionClassBuilder acb, MethodBuilder mb)
320: throws StandardException;
321:
322: /**
323: * Generate the expression that evaluates to the receiver. This is
324: * for the case where a java expression is being returned to the SQL
325: * domain, and we need to check whether the receiver is null (if so,
326: * the SQL value should be set to null, and this Java expression
327: * not evaluated). Instance method calls and field references have
328: * receivers, while class method calls and calls to constructors do
329: * not. If this Java expression does not have a receiver, this method
330: * returns null.
331: *
332: * This also covers the case where a java expression is being returned
333: * to the Java domain. In this case, we need to check whether the
334: * receiver is null only if the value returned by the Java expression
335: * is an object (not a primitive type). We don't want to generate the
336: * expression here if we are returning a primitive type to the Java
337: * domain, because there's no point in checking whether the receiver
338: * is null in this case (we can't make the expression return a null
339: * value).
340: *
341: * Only generate the receiver once and cache it in a field. This is
342: * because there will be two references to the receiver, and we want
343: * to evaluate it only once.
344: *
345: *
346: * @param acb The ActivationClassBuilder for the class being built
347: * @param mb the method the expression will go into
348: * @param receiver The query tree form of the receiver expression
349: *
350: * @return The compiled receiver, if any.
351: *
352: * @exception StandardException Thrown on error
353: */
354: protected final boolean generateReceiver(
355: ExpressionClassBuilder acb, MethodBuilder mb,
356: JavaValueNode receiver) throws StandardException {
357: ClassInspector classInspector = getClassFactory()
358: .getClassInspector();
359:
360: /*
361: ** Don't generate the expression now if it returns a primitive
362: ** type to the Java domain.
363: */
364: if ((!valueReturnedToSQLDomain())
365: && classInspector.primitiveType(getJavaTypeName())) {
366: return false;
367: }
368:
369: /*
370: ** Generate the following:
371: **
372: ** <receiver class> <field name>;
373: ** <field name> = <receiver>;
374: **
375: ** for non-static calls.
376: */
377:
378: String receiverClassName = receiver.getJavaTypeName();
379: receiverField = acb.newFieldDeclaration(Modifier.PRIVATE,
380: receiverClassName);
381:
382: receiver.generateExpression(acb, mb);
383: mb.putField(receiverField);
384: return true;
385: }
386:
387: /**
388: * Get an expression that has the value of the receiver. If a field
389: * holding the receiver value was already generated, use that. If not,
390: * generate the receiver value.
391: *
392: * @param acb The ExpressionClassBuilder for the class we're generating
393: * @param mb the method the expression will go into
394: * @param receiver The query tree form of the receiver expression
395: *
396: *
397: * @exception StandardException Thrown on error
398: */
399: protected final void getReceiverExpression(
400: ExpressionClassBuilder acb, MethodBuilder mb,
401: JavaValueNode receiver) throws StandardException {
402: if (receiverField != null) {
403: mb.getField(receiverField);
404: } else {
405: receiver.generateExpression(acb, mb);
406: }
407: }
408:
409: /** Inform this node that it returns its value to the SQL domain */
410: protected void returnValueToSQLDomain() {
411: valueReturnedToSQLDomain = true;
412: }
413:
414: /** Tell whether this node returns its value to the SQL domain */
415: protected boolean valueReturnedToSQLDomain() {
416: return valueReturnedToSQLDomain;
417: }
418:
419: /** Tell this node that nothing is done with the returned value */
420: protected void markReturnValueDiscarded() {
421: returnValueDiscarded = true;
422: }
423:
424: /** Tell whether the return value from this node is discarded */
425: protected boolean returnValueDiscarded() {
426: return returnValueDiscarded;
427: }
428:
429: /**
430: Check the reliability type of this java value.
431:
432: @exception StandardException Thrown on error
433:
434: @see org.apache.derby.iapi.sql.compile.CompilerContext
435: */
436: public void checkReliability(ValueNode sqlNode)
437: throws StandardException {
438: sqlNode.checkReliability(CompilerContext.FUNCTION_CALL_ILLEGAL,
439: SQLState.LANG_JAVA_METHOD_CALL_OR_FIELD_REF);
440: }
441: }
|