KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > NumericTypeCompiler


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.NumericTypeCompiler
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
25
26 import org.apache.derby.iapi.services.context.ContextService;
27
28 import org.apache.derby.iapi.services.loader.ClassFactory;
29
30 import org.apache.derby.iapi.services.sanity.SanityManager;
31
32 import org.apache.derby.iapi.services.info.JVMInfo;
33 import org.apache.derby.iapi.services.io.StoredFormatIds;
34
35 import org.apache.derby.iapi.error.StandardException;
36
37 import org.apache.derby.iapi.types.DataTypeDescriptor;
38 import org.apache.derby.iapi.types.DataTypeDescriptor;
39 import org.apache.derby.iapi.types.DataValueFactory;
40 import org.apache.derby.iapi.types.NumberDataValue;
41 import org.apache.derby.iapi.types.TypeId;
42
43 import org.apache.derby.iapi.sql.compile.TypeCompiler;
44
45 import org.apache.derby.iapi.reference.ClassName;
46 import org.apache.derby.iapi.reference.Limits;
47 import org.apache.derby.iapi.reference.SQLState;
48 import org.apache.derby.iapi.services.compiler.LocalField;
49 import org.apache.derby.iapi.services.compiler.MethodBuilder;
50
51 /**
52  * This class implements TypeId for the SQL numeric datatype.
53  *
54  * @author Jeff Lichtman
55  */

56
57 public final class NumericTypeCompiler extends BaseTypeCompiler
58 {
59     /** @see TypeCompiler#interfaceName */
60     public String JavaDoc interfaceName()
61     {
62         return ClassName.NumberDataValue;
63     }
64
65     /**
66      * @see TypeCompiler#getCorrespondingPrimitiveTypeName
67      */

68
69     public String JavaDoc getCorrespondingPrimitiveTypeName()
70     {
71         /* Only numerics and booleans get mapped to Java primitives */
72         int formatId = getStoredFormatIdFromTypeId();
73         switch (formatId)
74         {
75             case StoredFormatIds.DOUBLE_TYPE_ID:
76                 return "double";
77
78             case StoredFormatIds.INT_TYPE_ID:
79                 return "int";
80
81             case StoredFormatIds.LONGINT_TYPE_ID:
82                 return "long";
83
84             case StoredFormatIds.REAL_TYPE_ID:
85                 return "float";
86
87             case StoredFormatIds.SMALLINT_TYPE_ID:
88                 return "short";
89
90             case StoredFormatIds.TINYINT_TYPE_ID:
91                 return "byte";
92
93             case StoredFormatIds.DECIMAL_TYPE_ID:
94             default:
95                 if (SanityManager.DEBUG)
96                 {
97                     SanityManager.THROWASSERT(
98                         "unexpected formatId in getCorrespondingPrimitiveTypeName() - " + formatId);
99                 }
100                 return null;
101         }
102     }
103
104     /**
105      * Get the method name for getting out the corresponding primitive
106      * Java type.
107      *
108      * @return String The method call name for getting the
109      * corresponding primitive Java type.
110      */

111     public String JavaDoc getPrimitiveMethodName()
112     {
113         int formatId = getStoredFormatIdFromTypeId();
114         switch (formatId)
115         {
116             case StoredFormatIds.DOUBLE_TYPE_ID:
117                 return "getDouble";
118
119             case StoredFormatIds.INT_TYPE_ID:
120                 return "getInt";
121
122             case StoredFormatIds.LONGINT_TYPE_ID:
123                 return "getLong";
124
125             case StoredFormatIds.REAL_TYPE_ID:
126                 return "getFloat";
127
128             case StoredFormatIds.SMALLINT_TYPE_ID:
129                 return "getShort";
130
131             case StoredFormatIds.TINYINT_TYPE_ID:
132                 return "getByte";
133
134             case StoredFormatIds.DECIMAL_TYPE_ID:
135             default:
136                 if (SanityManager.DEBUG)
137                 {
138                     SanityManager.THROWASSERT(
139                         "unexpected formatId in getPrimitiveMethodName() - " + formatId);
140                 }
141                 return null;
142         }
143     }
144
145     /**
146      * @see TypeCompiler#getCastToCharWidth
147      */

148     public int getCastToCharWidth(DataTypeDescriptor dts)
149     {
150         int formatId = getStoredFormatIdFromTypeId();
151         switch (formatId)
152         {
153             case StoredFormatIds.DECIMAL_TYPE_ID:
154                 // Need to have space for '-' and decimal point.
155
return dts.getPrecision() + 2;
156
157             case StoredFormatIds.DOUBLE_TYPE_ID:
158                 return TypeCompiler.DOUBLE_MAXWIDTH_AS_CHAR;
159
160             case StoredFormatIds.INT_TYPE_ID:
161                 return TypeCompiler.INT_MAXWIDTH_AS_CHAR;
162
163             case StoredFormatIds.LONGINT_TYPE_ID:
164                 return TypeCompiler.LONGINT_MAXWIDTH_AS_CHAR;
165
166             case StoredFormatIds.REAL_TYPE_ID:
167                 return TypeCompiler.REAL_MAXWIDTH_AS_CHAR;
168
169             case StoredFormatIds.SMALLINT_TYPE_ID:
170                 return TypeCompiler.SMALLINT_MAXWIDTH_AS_CHAR;
171
172             case StoredFormatIds.TINYINT_TYPE_ID:
173                 return TypeCompiler.TINYINT_MAXWIDTH_AS_CHAR;
174
175             default:
176                 if (SanityManager.DEBUG)
177                 {
178                     SanityManager.THROWASSERT(
179                         "unexpected formatId in getCastToCharWidth() - " + formatId);
180                 }
181                 return 0;
182         }
183     }
184
185     /**
186      * @see TypeCompiler#resolveArithmeticOperation
187      *
188      * @exception StandardException Thrown on error
189      */

190     public DataTypeDescriptor
191     resolveArithmeticOperation(DataTypeDescriptor leftType,
192                                 DataTypeDescriptor rightType,
193                                 String JavaDoc operator)
194                             throws StandardException
195     {
196         NumericTypeCompiler higherTC;
197         DataTypeDescriptor higherType;
198         boolean nullable;
199         int precision, scale, maximumWidth;
200
201         /*
202         ** Check the right type to be sure it's a number. By convention,
203         ** we call this method off the TypeId of the left operand, so if
204         ** we get here, we know the left operand is a number.
205         */

206         if (SanityManager.DEBUG)
207             SanityManager.ASSERT(leftType.getTypeId().isNumericTypeId(),
208                 "The left type is supposed to be a number because we're resolving an arithmetic operator");
209
210         TypeId leftTypeId = leftType.getTypeId();
211         TypeId rightTypeId = rightType.getTypeId();
212
213         boolean supported = true;
214
215         if ( ! (rightTypeId.isNumericTypeId()) )
216         {
217             supported = false;
218         }
219
220         if (TypeCompiler.MOD_OP.equals(operator)) {
221             switch (leftTypeId.getJDBCTypeId()) {
222             case java.sql.Types.TINYINT:
223             case java.sql.Types.SMALLINT:
224             case java.sql.Types.INTEGER:
225             case java.sql.Types.BIGINT:
226                 break;
227             default:
228                 supported = false;
229                 break;
230             }
231             switch (rightTypeId.getJDBCTypeId()) {
232             case java.sql.Types.TINYINT:
233             case java.sql.Types.SMALLINT:
234             case java.sql.Types.INTEGER:
235             case java.sql.Types.BIGINT:
236                 break;
237             default:
238                 supported = false;
239                 break;
240             }
241
242         }
243
244         if (!supported) {
245             throw StandardException.newException(SQLState.LANG_BINARY_OPERATOR_NOT_SUPPORTED,
246                     operator,
247                     leftType.getTypeId().getSQLTypeName(),
248                     rightType.getTypeId().getSQLTypeName()
249                     );
250         }
251
252         /*
253         ** Take left as the higher precedence if equal
254         */

255         if (rightTypeId.typePrecedence() > leftTypeId.typePrecedence())
256         {
257             higherType = rightType;
258             higherTC = (NumericTypeCompiler) getTypeCompiler(rightTypeId);
259         }
260         else
261         {
262             higherType = leftType;
263             higherTC = (NumericTypeCompiler) getTypeCompiler(leftTypeId);
264         }
265
266         /* The calculation of precision and scale should be based upon
267          * the type with higher precedence, which is going to be the result
268          * type, this is also to be consistent with maximumWidth. Beetle 3906.
269          */

270         precision = higherTC.getPrecision(operator, leftType, rightType);
271         scale = higherTC.getScale(operator, leftType, rightType);
272
273         if (higherType.getTypeId().isDecimalTypeId())
274         {
275             maximumWidth = (scale > 0) ? precision + 3 : precision + 1;
276
277             /*
278             ** Be careful not to overflow
279             */

280             if (maximumWidth < precision)
281             {
282                 maximumWidth = Integer.MAX_VALUE;
283             }
284         }
285         else
286         {
287             maximumWidth = higherType.getMaximumWidth();
288         }
289         
290         /* The result is nullable if either side is nullable */
291         nullable = leftType.isNullable() || rightType.isNullable();
292
293         /*
294         ** The higher type does not have the right nullability. Create a
295         ** new DataTypeDescriptor that has the correct type and nullability.
296         **
297         ** It's OK to call the implementation of the DataTypeDescriptorFactory
298         ** here, because we're in the same package.
299         */

300         return new DataTypeDescriptor(
301                     higherType.getTypeId(),
302                     precision,
303                     scale,
304                     nullable,
305                     maximumWidth
306                 );
307     }
308     /** @see TypeCompiler#comparable */
309     public boolean comparable(TypeId otherType,
310                               boolean forEquals,
311                               ClassFactory cf)
312     {
313         return numberComparable(otherType, forEquals, cf);
314     }
315
316
317     /** @see TypeCompiler#convertible */
318     public boolean convertible(TypeId otherType, boolean forDataTypeFunction)
319     {
320         return (numberConvertible(otherType, forDataTypeFunction));
321
322     }
323
324         /**
325          * Tell whether this type (numeric) is compatible with the given type.
326          *
327          * @param otherType The TypeId of the other type.
328          */

329     public boolean compatible(TypeId otherType)
330     {
331         // Numbers can only be compatible with other numbers.
332
return (otherType.isNumericTypeId());
333     }
334
335     /** @see TypeCompiler#storable */
336     public boolean storable(TypeId otherType, ClassFactory cf)
337     {
338         return numberStorable(getTypeId(), otherType, cf);
339     }
340
341     /**
342         Return the method name to get a Derby DataValueDescriptor
343         object of the correct type. This implementation returns "getDataValue".
344     */

345     protected String JavaDoc dataValueMethodName()
346     {
347         if (getStoredFormatIdFromTypeId() == StoredFormatIds.DECIMAL_TYPE_ID)
348             return "getDecimalDataValue";
349         else
350             return super.dataValueMethodName();
351     }
352
353     protected String JavaDoc nullMethodName()
354     {
355         int formatId = getStoredFormatIdFromTypeId();
356         switch (formatId)
357         {
358             case StoredFormatIds.DECIMAL_TYPE_ID:
359                 return "getNullDecimal";
360
361             case StoredFormatIds.DOUBLE_TYPE_ID:
362                 return "getNullDouble";
363
364             case StoredFormatIds.INT_TYPE_ID:
365                 return "getNullInteger";
366
367             case StoredFormatIds.LONGINT_TYPE_ID:
368                 return "getNullLong";
369
370             case StoredFormatIds.REAL_TYPE_ID:
371                 return "getNullFloat";
372
373             case StoredFormatIds.SMALLINT_TYPE_ID:
374                 return "getNullShort";
375
376             case StoredFormatIds.TINYINT_TYPE_ID:
377                 return "getNullByte";
378
379             default:
380                 if (SanityManager.DEBUG)
381                 {
382                     SanityManager.THROWASSERT(
383                         "unexpected formatId in nullMethodName() - " + formatId);
384                 }
385                 return null;
386         }
387     }
388
389     /**
390      * Get the precision of the operation involving
391      * two of the same types. Only meaningful for
392      * decimals, which override this.
393      *
394      * @param operator a string representing the operator,
395      * null means no operator, just a type merge
396      * @param leftType the left type
397      * @param rightType the left type
398      *
399      * @return the resultant precision
400      */

401     private int getPrecision(String JavaDoc operator,
402                             DataTypeDescriptor leftType,
403                             DataTypeDescriptor rightType)
404     {
405         // Only meaningful for decimal
406
if (getStoredFormatIdFromTypeId() != StoredFormatIds.DECIMAL_TYPE_ID)
407         {
408             return leftType.getPrecision();
409         }
410
411         long lscale = (long)leftType.getScale();
412         long rscale = (long)rightType.getScale();
413         long lprec = (long)leftType.getPrecision();
414         long rprec = (long)rightType.getPrecision();
415         long val;
416
417         /*
418         ** Null means datatype merge. Take the maximum
419         ** left of decimal digits plus the scale.
420         */

421         if (operator == null)
422         {
423             val = this.getScale(operator, leftType, rightType) +
424                     Math.max(lprec - lscale, rprec - rscale);
425         }
426         else if (operator.equals(TypeCompiler.TIMES_OP))
427         {
428             val = lprec + rprec;
429         }
430         else if (operator.equals(TypeCompiler.SUM_OP))
431         {
432             val = lprec - lscale + rprec - rscale +
433                         this.getScale(operator, leftType, rightType);
434         }
435         else if (operator.equals(TypeCompiler.DIVIDE_OP))
436         {
437             val = Math.min(NumberDataValue.MAX_DECIMAL_PRECISION_SCALE,
438                            this.getScale(operator, leftType, rightType) + lprec - lscale + rprec);
439         }
440         /*
441         ** AVG, -, +
442         */

443         else
444         {
445             /*
446             ** Take max scale and max left of decimal
447             ** plus one.
448             */

449             val = this.getScale(operator, leftType, rightType) +
450                     Math.max(lprec - lscale, rprec - rscale) + 1;
451
452             if (val > Limits.DB2_MAX_DECIMAL_PRECISION_SCALE)
453             // then, like DB2, just set it to the max possible.
454
val = Limits.DB2_MAX_DECIMAL_PRECISION_SCALE;
455         }
456
457         if (val > Integer.MAX_VALUE)
458         {
459             val = Integer.MAX_VALUE;
460         }
461         val = Math.min(NumberDataValue.MAX_DECIMAL_PRECISION_SCALE, val);
462         return (int)val;
463     }
464
465     /**
466      * Get the scale of the operation involving
467      * two of the same types. Since we don't really
468      * have a good way to pass the resultant scale
469      * and precision around at execution time, we
470      * will model that BigDecimal does by default.
471      * This is good in most cases, though we would
472      * probably like to use something more sophisticated
473      * for division.
474      *
475      * @param operator a string representing the operator,
476      * null means no operator, just a type merge
477      * @param leftType the left type
478      * @param rightType the left type
479      *
480      * @return the resultant precision
481      */

482     private int getScale(String JavaDoc operator,
483                             DataTypeDescriptor leftType,
484                             DataTypeDescriptor rightType)
485     {
486         // Only meaningful for decimal
487
if (getStoredFormatIdFromTypeId() != StoredFormatIds.DECIMAL_TYPE_ID)
488         {
489             return leftType.getScale();
490         }
491
492         long val;
493
494         long lscale = (long)leftType.getScale();
495         long rscale = (long)rightType.getScale();
496         long lprec = (long)leftType.getPrecision();
497         long rprec = (long)rightType.getPrecision();
498
499         /*
500         ** Retain greatest scale, take sum of left
501         ** of decimal
502         */

503         if (TypeCompiler.TIMES_OP.equals(operator))
504         {
505             val = lscale + rscale;
506         }
507         else if (TypeCompiler.DIVIDE_OP.equals(operator))
508         {
509             /*
510             ** Take max left scale + right precision - right scale + 1,
511             ** or 4, whichever is biggest
512             */

513             LanguageConnectionContext lcc = (LanguageConnectionContext)
514                 (ContextService.getContext(LanguageConnectionContext.CONTEXT_ID));
515
516             // Scale: 31 - left precision + left scale - right scale
517
val = Math.max(NumberDataValue.MAX_DECIMAL_PRECISION_SCALE - lprec + lscale - rscale, 0);
518
519         }
520         else if (TypeCompiler.AVG_OP.equals(operator))
521         {
522             val = Math.max(Math.max(lscale, rscale),
523                         NumberDataValue.MIN_DECIMAL_DIVIDE_SCALE);
524         }
525         /*
526         ** SUM, -, + all take max(lscale,rscale)
527         */

528         else
529         {
530             val = Math.max(lscale, rscale);
531         }
532
533         if (val > Integer.MAX_VALUE)
534         {
535             val = Integer.MAX_VALUE;
536         }
537         val = Math.min(NumberDataValue.MAX_DECIMAL_PRECISION_SCALE, val);
538         return (int)val;
539     }
540
541
542     public void generateDataValue(MethodBuilder mb,
543                                         LocalField field)
544     {
545         if (!JVMInfo.J2ME && getTypeId().isDecimalTypeId())
546         {
547             // cast the value to a Number (from BigDecimal) for method resolution
548
// For J2ME there is no implementation of Number for DECIMAL
549
// so values are handled as thier original type, which is just
550
// a String for DECIMAL constants from the parser.
551
mb.upCast("java.lang.Number");
552         }
553
554         super.generateDataValue(mb, field);
555     }
556
557 }
558
Popular Tags