001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.IsNullNode
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.reference.ClassName;
025:
026: import org.apache.derby.iapi.services.compiler.MethodBuilder;
027: import org.apache.derby.iapi.services.sanity.SanityManager;
028:
029: import org.apache.derby.iapi.error.StandardException;
030:
031: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
032: import org.apache.derby.iapi.sql.compile.Optimizable;
033:
034: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
035:
036: import org.apache.derby.iapi.store.access.ScanController;
037:
038: import org.apache.derby.iapi.types.DataTypeDescriptor;
039: import org.apache.derby.iapi.types.DataValueDescriptor;
040: import org.apache.derby.iapi.types.DataValueFactory;
041: import org.apache.derby.iapi.types.TypeId;
042:
043: import org.apache.derby.iapi.types.Orderable;
044:
045: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
046:
047: import java.sql.Types;
048:
049: /**
050: * This node represents either a unary
051: * IS NULL or IS NOT NULL comparison operator
052: *
053: * @author Jerry Brenner
054: */
055:
056: public final class IsNullNode extends UnaryComparisonOperatorNode
057: implements RelationalOperator {
058:
059: Object nullValue = null;
060:
061: public void setNodeType(int nodeType) {
062: String operator;
063: String methodName;
064:
065: if (nodeType == C_NodeTypes.IS_NULL_NODE) {
066: /* By convention, the method name for the is null operator is "isNull" */
067: operator = "is null";
068: methodName = "isNullOp";
069: } else {
070: if (SanityManager.DEBUG) {
071: if (nodeType != C_NodeTypes.IS_NOT_NULL_NODE) {
072: SanityManager.THROWASSERT("Unexpected nodeType = "
073: + nodeType);
074: }
075: }
076: /* By convention, the method name for the is not null operator is
077: * "isNotNull"
078: */
079: operator = "is not null";
080: methodName = "isNotNull";
081: }
082: setOperator(operator);
083: setMethodName(methodName);
084: super .setNodeType(nodeType);
085: }
086:
087: /**
088: * Negate the comparison.
089: *
090: * @param operand The operand of the operator
091: *
092: * @return UnaryOperatorNode The negated expression
093: *
094: * @exception StandardException Thrown on error
095: */
096: UnaryOperatorNode getNegation(ValueNode operand)
097: throws StandardException {
098: UnaryOperatorNode negation;
099:
100: if (SanityManager.DEBUG) {
101: SanityManager.ASSERT(dataTypeServices != null,
102: "dataTypeServices is expected to be non-null");
103: }
104:
105: if (isNullNode()) {
106: setNodeType(C_NodeTypes.IS_NOT_NULL_NODE);
107: } else {
108: if (SanityManager.DEBUG) {
109: if (!isNotNullNode()) {
110: SanityManager.THROWASSERT("Unexpected nodeType = "
111: + getNodeType());
112: }
113: }
114: setNodeType(C_NodeTypes.IS_NULL_NODE);
115: }
116: return this ;
117: }
118:
119: /**
120: * Bind a ? parameter operand of the IS [NOT] NULL predicate.
121: *
122: * @exception StandardException Thrown on error
123: */
124:
125: void bindParameter() throws StandardException {
126: /*
127: ** If IS [NOT] NULL has a ? operand, we assume
128: ** its type is varchar with the implementation-defined maximum length
129: ** for a varchar.
130: */
131:
132: operand.setType(new DataTypeDescriptor(TypeId
133: .getBuiltInTypeId(Types.VARCHAR), true));
134: }
135:
136: /* RelationalOperator interface */
137:
138: /** @see RelationalOperator#usefulStartKey */
139: public boolean usefulStartKey(Optimizable optTable) {
140: // IS NULL is start/stop key, IS NOT NULL is not
141: return (isNullNode());
142: }
143:
144: /** @see RelationalOperator#usefulStopKey */
145: public boolean usefulStopKey(Optimizable optTable) {
146: // IS NULL is start/stop key, IS NOT NULL is not
147: return (isNullNode());
148: }
149:
150: /** @see RelationalOperator#getStartOperator */
151: public int getStartOperator(Optimizable optTable) {
152: if (SanityManager.DEBUG) {
153: if (!isNullNode()) {
154: SanityManager
155: .THROWASSERT("getNodeType() not expected to return "
156: + getNodeType());
157: }
158: }
159: return ScanController.GE;
160: }
161:
162: /** @see RelationalOperator#getStopOperator */
163: public int getStopOperator(Optimizable optTable) {
164: if (SanityManager.DEBUG) {
165: if (!isNullNode()) {
166: SanityManager
167: .THROWASSERT("getNodeType() not expected to return "
168: + getNodeType());
169: }
170: }
171: return ScanController.GT;
172: }
173:
174: /** @see RelationalOperator#generateOperator */
175: public void generateOperator(MethodBuilder mb, Optimizable optTable) {
176: mb.push(Orderable.ORDER_OP_EQUALS);
177: }
178:
179: /** @see RelationalOperator#generateNegate */
180: public void generateNegate(MethodBuilder mb, Optimizable optTable) {
181: mb.push(isNotNullNode());
182: }
183:
184: /** @see RelationalOperator#getOperator */
185: public int getOperator() {
186: int operator;
187: if (isNullNode()) {
188: operator = IS_NULL_RELOP;
189: } else {
190: if (SanityManager.DEBUG) {
191: if (!isNotNullNode()) {
192: SanityManager.THROWASSERT("Unexpected nodeType = "
193: + getNodeType());
194: }
195: }
196: operator = IS_NOT_NULL_RELOP;
197: }
198:
199: return operator;
200: }
201:
202: /** @see RelationalOperator#compareWithKnownConstant */
203: public boolean compareWithKnownConstant(Optimizable optTable,
204: boolean considerParameters) {
205: return true;
206: }
207:
208: /**
209: * @see RelationalOperator#getCompareValue
210: *
211: * @exception StandardException Thrown on error
212: */
213: public DataValueDescriptor getCompareValue(Optimizable optTable)
214: throws StandardException {
215: if (nullValue == null) {
216: nullValue = operand.getTypeId().getNull();
217: }
218:
219: return (DataValueDescriptor) nullValue;
220: }
221:
222: /** @see RelationalOperator#equalsComparisonWithConstantExpression */
223: public boolean equalsComparisonWithConstantExpression(
224: Optimizable optTable) {
225: boolean retval = false;
226:
227: // Always return false for NOT NULL
228: if (isNotNullNode()) {
229: return false;
230: }
231:
232: /*
233: ** Is the operand a column in the given table?
234: */
235: if (operand instanceof ColumnReference) {
236: int tabNum = ((ColumnReference) operand).getTableNumber();
237: if (optTable.hasTableNumber()
238: && (optTable.getTableNumber() == tabNum)) {
239: retval = true;
240: }
241: }
242:
243: return retval;
244: }
245:
246: /**
247: * @see RelationalOperator#getTransitiveSearchClause
248: *
249: * @exception StandardException thrown on error
250: */
251: public RelationalOperator getTransitiveSearchClause(
252: ColumnReference otherCR) throws StandardException {
253: return (RelationalOperator) getNodeFactory().getNode(
254: getNodeType(), otherCR, getContextManager());
255: }
256:
257: /**
258: * null operators are defined on DataValueDescriptor.
259: * Overrides method in UnaryOperatorNode for code generation purposes.
260: */
261: public String getReceiverInterfaceName() {
262: return ClassName.DataValueDescriptor;
263: }
264:
265: /** IS NULL is like =, so should have the same selectivity */
266: public double selectivity(Optimizable optTable) {
267: if (isNullNode()) {
268: return 0.1d;
269: } else {
270: if (SanityManager.DEBUG) {
271: if (!isNotNullNode()) {
272: SanityManager.THROWASSERT("Unexpected nodeType = "
273: + getNodeType());
274: }
275: }
276: /* IS NOT NULL is like <>, so should have same selectivity */
277: return 0.9d;
278: }
279: }
280:
281: private boolean isNullNode() {
282: return getNodeType() == C_NodeTypes.IS_NULL_NODE;
283: }
284:
285: private boolean isNotNullNode() {
286: return getNodeType() == C_NodeTypes.IS_NOT_NULL_NODE;
287: }
288:
289: /** @see ValueNode#isRelationalOperator */
290: public boolean isRelationalOperator() {
291: return true;
292: }
293:
294: /** @see ValueNode#optimizableEqualityNode */
295: public boolean optimizableEqualityNode(Optimizable optTable,
296: int columnNumber, boolean isNullOkay) {
297: if (!isNullNode() || !isNullOkay)
298: return false;
299:
300: ColumnReference cr = getColumnOperand(optTable, columnNumber);
301: if (cr == null) {
302: return false;
303: }
304:
305: return true;
306: }
307:
308: }
|