001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.UserTypeConstantNode
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.error.StandardException;
025:
026: import org.apache.derby.iapi.types.TypeId;
027: import org.apache.derby.iapi.types.UserDataValue;
028:
029: import org.apache.derby.iapi.sql.compile.TypeCompiler;
030:
031: import org.apache.derby.iapi.services.compiler.MethodBuilder;
032: import org.apache.derby.iapi.services.compiler.LocalField;
033: import org.apache.derby.iapi.services.io.StoredFormatIds;
034:
035: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
036:
037: import org.apache.derby.iapi.types.DataValueFactory;
038:
039: import org.apache.derby.iapi.types.TypeId;
040:
041: import org.apache.derby.iapi.types.TypeId;
042:
043: import org.apache.derby.iapi.types.DataValueDescriptor;
044:
045: import org.apache.derby.iapi.services.sanity.SanityManager;
046: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
047:
048: import org.apache.derby.iapi.reference.ClassName;
049:
050: import org.apache.derby.catalog.TypeDescriptor;
051:
052: import org.apache.derby.iapi.util.ReuseFactory;
053: import org.apache.derby.iapi.services.classfile.VMOpcode;
054: import org.apache.derby.iapi.types.*;
055:
056: import java.lang.reflect.Modifier;
057: import java.sql.Date;
058: import java.sql.Time;
059: import java.sql.Timestamp;
060: import java.sql.Types;
061:
062: /**
063: User type constants. These are created by built-in types
064: that use user types as their implementation. This could also
065: potentially be used by an optimizer that wanted to store plans
066: for frequently-used parameter values.
067:
068: This is also used to represent nulls in user types, which occurs
069: when NULL is inserted into or supplied as the update value for
070: a usertype column.
071:
072: @author ames
073: */
074: public class UserTypeConstantNode extends ConstantNode {
075: /*
076: ** This value field hides the value in the super-type. It is here
077: ** Because user-type constants work differently from built-in constants.
078: ** User-type constant values are stored as Objects, while built-in
079: ** constants are stored as StorableDataValues.
080: **
081: ** RESOLVE: This is a bit of a mess, and should be fixed. All constants
082: ** should be represented the same way.
083: */
084: Object value;
085:
086: /**
087: * Initializer for a typed null node
088: * or a date, time, or timestamp value. Parameters may be:
089: *
090: * <ul>
091: * <li>arg1 The TypeId for the type of the node</li>
092: * <li>arg2 The factory to get the TypeId and DataTypeServices factories from.</li>
093: * </ul>
094: *
095: * <p>
096: * - OR -
097: * </p>
098: *
099: * <ul>
100: * <li>arg1 the date, time, or timestamp value</li>
101: * </ul>
102: *
103: * @exception StandardException thrown on failure
104: */
105: public void init(Object arg1) throws StandardException {
106: DataValueDescriptor dvd = null;
107:
108: if (arg1 instanceof TypeId) {
109: super .init(arg1, Boolean.TRUE, ReuseFactory
110: .getInteger(TypeDescriptor.MAXIMUM_WIDTH_UNKNOWN));
111: } else {
112: Integer maxWidth = null;
113: TypeId typeId = null;
114:
115: if (arg1 instanceof DataValueDescriptor)
116: dvd = (DataValueDescriptor) arg1;
117: if (arg1 instanceof Date
118: || (dvd != null && dvd.getTypeFormatId() == StoredFormatIds.SQL_DATE_ID)) {
119: maxWidth = ReuseFactory
120: .getInteger(TypeId.DATE_MAXWIDTH);
121: typeId = TypeId.getBuiltInTypeId(Types.DATE);
122: } else if (arg1 instanceof Time
123: || (dvd != null && dvd.getTypeFormatId() == StoredFormatIds.SQL_TIME_ID)) {
124: maxWidth = ReuseFactory
125: .getInteger(TypeId.TIME_MAXWIDTH);
126: typeId = TypeId.getBuiltInTypeId(Types.TIME);
127: } else if (arg1 instanceof Timestamp
128: || (dvd != null && dvd.getTypeFormatId() == StoredFormatIds.SQL_TIMESTAMP_ID)) {
129: maxWidth = ReuseFactory
130: .getInteger(TypeId.TIMESTAMP_MAXWIDTH);
131: typeId = TypeId.getBuiltInTypeId(Types.TIMESTAMP);
132: } else {
133: if (SanityManager.DEBUG) {
134: SanityManager.THROWASSERT("Unexpected class "
135: + arg1.getClass().getName());
136: }
137: }
138:
139: super .init(typeId, (arg1 == null) ? Boolean.TRUE
140: : Boolean.FALSE, maxWidth);
141:
142: if (dvd != null)
143: setValue(dvd);
144: else if (arg1 instanceof Date) {
145: setValue(getDataValueFactory()
146: .getDataValue((Date) arg1));
147: } else if (arg1 instanceof Time) {
148: setValue(getDataValueFactory()
149: .getDataValue((Time) arg1));
150: } else if (arg1 instanceof Timestamp) {
151: setValue(getDataValueFactory().getDataValue(
152: (Timestamp) arg1));
153: }
154:
155: value = arg1;
156: }
157: }
158:
159: /**
160: * Return the object value of this user defined type.
161: *
162: * @return the value of this constant. can't use getValue() for this.
163: * getValue() returns the DataValueDescriptor for the built-in
164: * types that are implemented as user types (date, time, timestamp)
165: */
166: public Object getObjectValue() {
167: return value;
168: }
169:
170: /**
171: * Return whether or not this node represents a typed null constant.
172: *
173: */
174: public boolean isNull() {
175: return (value == null);
176: }
177:
178: /**
179: * Return the value of this user defined type as a Storable
180: *
181: * @return the value of this constant as a UserType
182: * @exception StandardException thrown on failure
183: */
184: public DataValueDescriptor getStorableValue()
185: throws StandardException {
186: if (value instanceof DataValueDescriptor)
187: return ((DataValueDescriptor) value).getClone();
188:
189: DataValueFactory dvf = getDataValueFactory();
190: TypeId typeID = getTypeId();
191: String typeName = typeID.getSQLTypeName();
192:
193: if (typeName.equals(TypeId.DATE_NAME)) {
194: return new SQLDate((Date) value);
195: } else if (typeName.equals(TypeId.TIME_NAME)) {
196: return new SQLTime((Time) value);
197: } else if (typeName.equals(TypeId.TIMESTAMP_NAME)) {
198: return new SQLTimestamp((Timestamp) value);
199: } else {
200: return dvf.getDataValue(value, (UserDataValue) null);
201: }
202: }
203:
204: /**
205: * Sets the object value of this user defined type
206: *
207: * @param newValue the value of this constant. can't use setValue() for this.
208: */
209: public void setObjectValue(Object newValue) {
210: value = newValue;
211: }
212:
213: /**
214: * Return the length
215: *
216: * @return The length of the value this node represents
217: *
218: * @exception StandardException Thrown on error
219: */
220: //public int getLength() throws StandardException {
221: // return TypeDescriptor.MAXIMUM_WIDTH_UNKNOWN;
222: //}
223: /**
224: * Return an Object representing the bind time value of this
225: * expression tree. If the expression tree does not evaluate to
226: * a constant at bind time then we return null.
227: * This is useful for bind time resolution of VTIs.
228: * RESOLVE: What do we do for primitives?
229: *
230: * @return An Object representing the bind time value of this expression tree.
231: * (null if not a bind time constant.)
232: *
233: */
234: public Object getConstantValueAsObject() {
235: return value;
236: }
237:
238: /**
239: * For a UserTypeConstantNode, we have to store away the object somewhere
240: * and have a way to get it back at runtime.
241: * These objects are serializable. This gives us at least two options:
242: * 1) serialize it out into a byte array field, and serialize
243: * it back in when needed, from the field.
244: * 2) have an array of objects in the prepared statement and a #,
245: * to find the object directly. Because it is serializable, it
246: * will store with the rest of the executable just fine.
247: * Choice 2 gives better performance -- the ser/deser cost is paid
248: * on database access for the statement, not for each execution of it.
249: * However, it requires some infrastructure support from prepared
250: * statements. For now, we take choice 3, and make some assumptions
251: * about available methods on the user type. This choice has the
252: * shortcoming that it will not work for arbitrary user types.
253: * REVISIT and implement choice 2 when a general solution is needed.
254: * <p>
255: * A null is generated as a Null value cast to the type of
256: * the constant node.
257: *
258: * @param acb The ExpressionClassBuilder for the class being built
259: * @param mb The method the expression will go into
260: *
261: *
262: * @exception StandardException Thrown on error
263: */
264: public void generateExpression(ExpressionClassBuilder acb,
265: MethodBuilder mb) throws StandardException {
266:
267: TypeCompiler tc = getTypeCompiler();
268: String fieldType = tc.interfaceName();
269:
270: /*
271: ** NOTE: DO NOT CALL THE CONSTRUCTOR TO GENERATE ANYTHING. IT HAS
272: ** A DIFFERENT value FIELD.
273: */
274:
275: /* Are we generating a SQL null value? */
276: if (value == null) {
277: acb.generateNull(mb, tc);
278: }
279: // The code generated here is invoked when the generated class is constructed. However the prepared statement
280: // is not set into the activation class when it is constructed, but later. So we cannot use the getSavedObject
281: // method to retrieve the value.
282: // else if( value instanceof DataValueDescriptor)
283: // {
284: // acb.pushThisAsActivation( mb);
285: // mb.callMethod( VMOpcode.INVOKEINTERFACE,
286: // null,
287: // "getPreparedStatement",
288: // ClassName.ExecPreparedStatement,
289: // 0);
290: // mb.push( acb.addItem( value));
291: // mb.callMethod( VMOpcode.INVOKEINTERFACE,
292: // null,
293: // "getSavedObject",
294: // "java.lang.Object",
295: // 1);
296: // mb.cast( fieldType);
297: // }
298: else {
299: /*
300: The generated java is the expression:
301: <java type name>.valueOf("<value.toString>")
302:
303: super.generateValue will wrap this expression in
304: the appropriate column constructor.
305:
306: If the type doesn't have a valueOf method, then we will
307: give an error. We have to assume that valueOf will
308: reconstruct the object from a String literal. If this is
309: a false assumption, some other object may be constructed,
310: or a runtime error may result due to valueOf failing.
311: */
312: String typeName = getTypeId()
313: .getCorrespondingJavaTypeName();
314:
315: mb.push(value.toString());
316: mb.callMethod(VMOpcode.INVOKESTATIC, typeName, "valueOf",
317: typeName, 1);
318:
319: LocalField field = acb.newFieldDeclaration(
320: Modifier.PRIVATE, fieldType);
321:
322: acb.generateDataValue(mb, tc, field);
323: }
324: }
325:
326: /**
327: * Should never be called for UserTypeConstantNode because
328: * we have our own generateExpression().
329: *
330: * @param acb The ExpressionClassBuilder for the class being built
331: * @param mb The method the expression will go into
332: *
333: * @exception StandardException Thrown on error
334: */
335: void generateConstant(ExpressionClassBuilder acb, MethodBuilder mb)
336: throws StandardException {
337: if (SanityManager.DEBUG) {
338: SanityManager
339: .THROWASSERT("geneateConstant() not expected to be called for UserTypeConstantNode because we have implemented our own generateExpression().");
340: }
341: }
342: }
|