001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.JavaToSQLValueNode
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.dictionary.DataDictionary;
025: import org.apache.derby.iapi.types.DataTypeDescriptor;
026: import org.apache.derby.iapi.types.TypeId;
027: import org.apache.derby.iapi.sql.compile.TypeCompiler;
028: import org.apache.derby.iapi.reference.SQLState;
029:
030: import org.apache.derby.iapi.services.compiler.MethodBuilder;
031: import org.apache.derby.iapi.services.compiler.LocalField;
032:
033: import org.apache.derby.iapi.error.StandardException;
034:
035: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
036:
037: import org.apache.derby.iapi.sql.compile.Visitable;
038: import org.apache.derby.iapi.sql.compile.Visitor;
039:
040: import org.apache.derby.iapi.services.sanity.SanityManager;
041:
042: import java.lang.reflect.Modifier;
043:
044: import org.apache.derby.iapi.util.JBitSet;
045:
046: import java.util.Vector;
047:
048: /**
049: * This node type converts a value from the Java domain to the SQL domain.
050: */
051:
052: public class JavaToSQLValueNode extends ValueNode {
053: JavaValueNode javaNode;
054:
055: /**
056: * Initializer for a JavaToSQLValueNode
057: *
058: * @param value The Java value to convert to the SQL domain
059: */
060: public void init(Object value) {
061: this .javaNode = (JavaValueNode) value;
062: }
063:
064: /**
065: * Set the clause that this node appears in.
066: *
067: * @param clause The clause that this node appears in.
068: */
069: public void setClause(int clause) {
070: super .setClause(clause);
071: javaNode.setClause(clause);
072: }
073:
074: /**
075: * Preprocess an expression tree. We do a number of transformations
076: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
077: * subquery flattening.
078: * NOTE: This is done before the outer ResultSetNode is preprocessed.
079: *
080: * @param numTables Number of tables in the DML Statement
081: * @param outerFromList FromList from outer query block
082: * @param outerSubqueryList SubqueryList from outer query block
083: * @param outerPredicateList PredicateList from outer query block
084: *
085: * @return The modified expression
086: *
087: * @exception StandardException Thrown on error
088: */
089: public ValueNode preprocess(int numTables, FromList outerFromList,
090: SubqueryList outerSubqueryList,
091: PredicateList outerPredicateList) throws StandardException {
092: javaNode.preprocess(numTables, outerFromList,
093: outerSubqueryList, outerPredicateList);
094:
095: return this ;
096: }
097:
098: /**
099: * Do code generation for this conversion of a value from the Java to
100: * the SQL domain.
101: *
102: * @param acb The ExpressionClassBuilder for the class we're generating
103: * @param mb the method the expression will go into
104: *
105: * @exception StandardException Thrown on error
106: */
107:
108: public void generateExpression(ExpressionClassBuilder acb,
109: MethodBuilder mb) throws StandardException {
110: TypeId resultType;
111: String resultTypeName;
112:
113: /*
114: ** Tell the Java node that it's value is being returned to the
115: ** SQL domain. This way, it knows whether the checking for a null
116: ** receiver is to be done at the Java level or the SQL level.
117: */
118: javaNode.returnValueToSQLDomain();
119:
120: /* Generate the receiver, if any. */
121: boolean hasReceiver = javaNode.generateReceiver(acb, mb);
122:
123: /*
124: ** If the java expression has a receiver, we want to check whether
125: ** it's null before evaluating the whole expression (to avoid
126: ** a NullPointerException.
127: */
128: if (hasReceiver) {
129: /*
130: ** There is a receiver. Generate a null SQL value to return
131: ** in case the receiver is null. First, create a field to hold
132: ** the null SQL value.
133: */
134: String nullValueClass = getTypeCompiler().interfaceName();
135: LocalField nullValueField = acb.newFieldDeclaration(
136: Modifier.PRIVATE, nullValueClass);
137: /*
138: ** There is a receiver. Generate the following to test
139: ** for null:
140: **
141: ** (receiverExpression == null) ?
142: */
143:
144: mb.conditionalIfNull();
145: mb.getField(nullValueField);
146: acb.generateNullWithExpress(mb, getTypeCompiler());
147:
148: /*
149: ** We have now generated the expression to test, and the
150: ** "true" side of the ?: operator. Finish the "true" side
151: ** so we can generate the "false" side.
152: */
153: mb.startElseCode();
154: }
155:
156: resultType = getTypeId();
157: TypeCompiler tc = getTypeCompiler();
158:
159: resultTypeName = tc.interfaceName();
160:
161: /* Allocate an object for re-use to hold the result of the conversion */
162: LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE,
163: resultTypeName);
164:
165: /* Generate the expression for the Java value under us */
166: javaNode.generateExpression(acb, mb);
167:
168: /* Generate the SQL value, which is always nullable */
169: acb.generateDataValue(mb, tc, field);
170:
171: /*
172: ** If there was a receiver, the return value will be the result
173: ** of the ?: operator.
174: */
175: if (hasReceiver) {
176: mb.completeConditional();
177: }
178: }
179:
180: /**
181: * Prints the sub-nodes of this object. See QueryTreeNode for
182: * how tree printing is supposed to work.
183: *
184: * @param depth The depth of this node in the tree
185: */
186:
187: public void printSubNodes(int depth) {
188: if (SanityManager.DEBUG) {
189: super .printSubNodes(depth);
190:
191: printLabel(depth, "javaNode: ");
192: javaNode.treePrint(depth + 1);
193: }
194: }
195:
196: /**
197: * Get the JavaValueNode that lives under this JavaToSQLValueNode.
198: *
199: * @return The JavaValueNode that lives under this node.
200: */
201:
202: public JavaValueNode getJavaValueNode() {
203: return javaNode;
204: }
205:
206: /**
207: * @see QueryTreeNode#disablePrivilegeCollection
208: */
209: public void disablePrivilegeCollection() {
210: super .disablePrivilegeCollection();
211: if (javaNode != null)
212: javaNode.disablePrivilegeCollection();
213: }
214:
215: /**
216: * Bind this expression. This means binding the sub-expressions,
217: * as well as figuring out what the return type is for this expression.
218: *
219: * @param fromList The FROM list for the query this
220: * expression is in, for binding columns.
221: * @param subqueryList The subquery list being built as we find
222: * SubqueryNodes
223: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
224: *
225: * @return The new top of the expression tree.
226: *
227: * @exception StandardException Thrown on error
228: */
229:
230: public ValueNode bindExpression(FromList fromList,
231: SubqueryList subqueryList, Vector aggregateVector)
232: throws StandardException {
233: // method invocations are not allowed in ADD TABLE clauses.
234: // And neither are field references.
235: javaNode.checkReliability(this );
236:
237: /* Bind the expression under us */
238: javaNode = javaNode.bindExpression(fromList, subqueryList,
239: aggregateVector);
240:
241: DataTypeDescriptor dts = DataTypeDescriptor
242: .getSQLDataTypeDescriptor(javaNode.getJavaTypeName());
243: if (dts == null) {
244: throw StandardException.newException(
245: SQLState.LANG_NO_CORRESPONDING_S_Q_L_TYPE, javaNode
246: .getJavaTypeName());
247: }
248:
249: setType(dts);
250:
251: return this ;
252: }
253:
254: /**
255: * Remap all ColumnReferences in this tree to be clones of the
256: * underlying expression.
257: *
258: * @return ValueNode The remapped expression tree.
259: *
260: * @exception StandardException Thrown on error
261: */
262: public ValueNode remapColumnReferencesToExpressions()
263: throws StandardException {
264: javaNode = javaNode.remapColumnReferencesToExpressions();
265: return this ;
266: }
267:
268: /**
269: * Categorize this predicate. Initially, this means
270: * building a bit map of the referenced tables for each predicate.
271: * If the source of this ColumnReference (at the next underlying level)
272: * is not a ColumnReference or a VirtualColumnNode then this predicate
273: * will not be pushed down.
274: *
275: * For example, in:
276: * select * from (select 1 from s) a (x) where x = 1
277: * we will not push down x = 1.
278: * NOTE: It would be easy to handle the case of a constant, but if the
279: * inner SELECT returns an arbitrary expression, then we would have to copy
280: * that tree into the pushed predicate, and that tree could contain
281: * subqueries and method calls.
282: *
283: * @param referencedTabs JBitSet with bit map of referenced FromTables
284: * @param simplePredsOnly Whether or not to consider method
285: * calls, field references and conditional nodes
286: * when building bit map
287: *
288: * @return boolean Whether or not source.expression is a ColumnReference
289: * or a VirtualColumnNode.
290: *
291: * @exception StandardException Thrown on error
292: */
293: public boolean categorize(JBitSet referencedTabs,
294: boolean simplePredsOnly) throws StandardException {
295: return javaNode.categorize(referencedTabs, simplePredsOnly);
296: }
297:
298: /**
299: * Return the variant type for the underlying expression.
300: * The variant type can be:
301: * VARIANT - variant within a scan
302: * (method calls and non-static field access)
303: * SCAN_INVARIANT - invariant within a scan
304: * (column references from outer tables)
305: * QUERY_INVARIANT - invariant within the life of a query
306: * (constant expressions)
307: *
308: * @return The variant type for the underlying expression.
309: * @exception StandardException thrown on error
310: */
311: protected int getOrderableVariantType() throws StandardException {
312: return javaNode.getOrderableVariantType();
313: }
314:
315: /**
316: * Accept a visitor, and call v.visit()
317: * on child nodes as necessary.
318: *
319: * @param v the visitor
320: *
321: * @exception StandardException on error
322: */
323: public Visitable accept(Visitor v) throws StandardException {
324: Visitable returnNode = v.visit(this );
325:
326: if (v.skipChildren(this )) {
327: return returnNode;
328: }
329:
330: if (javaNode != null && !v.stopTraversal()) {
331: javaNode = (JavaValueNode) javaNode.accept(v);
332: }
333:
334: return returnNode;
335: }
336:
337: /**
338: * {@inheritDoc}
339: */
340: protected boolean isEquivalent(ValueNode o) {
341: // anything in the java domain is not equiavlent.
342: return false;
343: }
344: }
|