KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > mapping > MappingTypeInfo


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 XQuark Group.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.mapper.mapping;
24
25 import java.io.*;
26 import java.math.BigDecimal JavaDoc;
27 import java.sql.*;
28 import java.util.Arrays JavaDoc;
29 import java.util.Iterator JavaDoc;
30
31 import org.xml.sax.SAXException JavaDoc;
32 import org.xquark.jdbc.typing.*;
33 import org.xquark.mapper.RepositoryException;
34 import org.xquark.mapper.dbms.AbstractConnection;
35 import org.xquark.schema.Declaration;
36 import org.xquark.schema.SimpleType;
37 import org.xquark.schema.datatypes.ByteArray;
38 import org.xquark.schema.datatypes.DateTime;
39 import org.xquark.schema.datatypes.PrimitiveType;
40 import org.xquark.schema.validation.ValidationContextProvider;
41 import org.xquark.xml.xdbc.XMLDBCException;
42 import org.xquark.xml.xdbc.XMLErrorHandler;
43
44 /**
45  * @author sr
46  *
47  * To change the template for this generated type comment go to
48  * Window - Preferences - Java - Code Generation - Code and Comments
49  */

50 public class MappingTypeInfo extends org.xquark.jdbc.typing.MappingInfo {
51
52     /** Conversion authorized by setObject */
53     public static int AUTHORIZED_CONVERSIONS[][] = new int[13][];
54     
55     static
56     {
57         // Conversion authorized by setObject ("getting Started" of JDBC user guide)
58
AUTHORIZED_CONVERSIONS[JAVA_STRING] = new int[]
59         {
60             Types.TINYINT, Types.SMALLINT, Types.INTEGER, Types.BIGINT,
61             Types.REAL, Types.FLOAT, Types.DOUBLE, Types.DECIMAL, Types.NUMERIC,
62             Types.BIT, Types.CHAR, Types.VARCHAR, Types.LONGVARCHAR,
63             Types.BINARY, Types.VARBINARY, Types.LONGVARBINARY, Types.DATE,
64             Types.TIME, Types.TIMESTAMP
65         };
66         Arrays.sort(AUTHORIZED_CONVERSIONS[JAVA_STRING]); // for binary search
67
// Note: this sort could be avoided but is safer if arrays are modified later
68
// further more is precompiled-data
69

70         AUTHORIZED_CONVERSIONS[JAVA_BIG_DECIMAL] =
71         AUTHORIZED_CONVERSIONS[JAVA_BOOLEAN] =
72         AUTHORIZED_CONVERSIONS[JAVA_FLOAT] =
73         AUTHORIZED_CONVERSIONS[JAVA_DOUBLE] = new int[]
74         {
75             Types.TINYINT, Types.SMALLINT,
76             Types.INTEGER, Types.BIGINT, Types.REAL, Types.FLOAT, Types.DOUBLE,
77             Types.DECIMAL, Types.NUMERIC, Types.BIT, Types.CHAR, Types.VARCHAR,
78             Types.LONGVARCHAR
79         };
80         Arrays.sort(AUTHORIZED_CONVERSIONS[JAVA_DOUBLE]); // for binary search
81

82         AUTHORIZED_CONVERSIONS[SCHEMA_BYTE_ARRAY] = new int[]
83         {
84             Types.BINARY,
85             Types.VARBINARY, Types.LONGVARBINARY
86         };
87         Arrays.sort(AUTHORIZED_CONVERSIONS[SCHEMA_BYTE_ARRAY]); // for binary search
88

89         AUTHORIZED_CONVERSIONS[SCHEMA_DATETIME] = new int[]
90         {
91             Types.CHAR,
92             Types.VARCHAR, Types.LONGVARCHAR, Types.DATE, Types.TIME,
93             Types.TIMESTAMP
94         };
95         Arrays.sort(AUTHORIZED_CONVERSIONS[SCHEMA_DATETIME]); // for binary search
96
}
97
98     /**
99      * @param XMLType
100      */

101     public MappingTypeInfo(SimpleType XMLType) {
102         super(XMLType);
103     }
104
105     /**
106      * @param XMLType
107      * @throws SAXException
108      */

109     public MappingTypeInfo(String JavaDoc XMLType) {
110         super(XMLType);
111     }
112
113     public MappingTypeInfo(String JavaDoc XMLType, boolean useStringDelimitor)
114     {
115         super(XMLType);
116         this.useStringDelimitor = useStringDelimitor;
117     }
118     
119     /* Used for value generators */
120     public MappingTypeInfo(SimpleType XMLType, boolean useStringDelimitor)
121     {
122         super(XMLType);
123         this.useStringDelimitor = useStringDelimitor;
124     }
125     
126     void checkTargetType(ColumnMetaData cmeta) throws SAXException JavaDoc {
127         checkTargetType(cmeta, null);
128     }
129
130     void checkTargetType(ColumnMetaData cmeta, XMLErrorHandler messageHandler)
131     throws SAXException JavaDoc {
132         setDBType(cmeta.getType());
133         
134         if (!cmeta.getSqlType().isStorage())
135             throw new SAXException JavaDoc("Storage is not supported for the "
136                     + cmeta.getTypeName() + " data type.");
137         
138     
139         if (sType.getPrimitive().getType() == PrimitiveType.UNION) // UNION
140
{
141             Iterator JavaDoc it = sType.getMemberTypes().iterator();
142             PrimitiveType wType = null;
143             
144             while (it.hasNext())
145             {
146                 conversion = IMPOSSIBLE; // other flags do not use default value
147
wType = ((SimpleType)it.next()).getPrimitive();
148                 checkTargetType(wType, JAVA_TYPE_BINDINGS[wType.getType()],
149                                     messageHandler);
150                 // TO IMPROVE : do global flags have to be consistent for every type of Union ? What if not ? The last are kept ?
151
}
152         }
153         else
154             checkTargetType(sType.getPrimitive(), javaType, messageHandler);
155     }
156
157     /** Schema conversion is supposed to be done
158      * @param useEmptyStringAlias
159      */

160     public void setParameter(PreparedStatement pStmt, int i, Object JavaDoc value, AbstractConnection connection, boolean useEmptyStringAlias, XMLErrorHandler messageHandler) throws SQLException, XMLDBCException {
161         if (value == null) // for Oracle : because setObjet(i, null) leads to an exception
162
pStmt.setNull(i, dbType.getJDBCType());
163         else
164         {
165             if (conversion == AUTOMATIC)
166                 storeConvertedToSQL(pStmt, i , adaptSchemaObjectToJDBC(value));
167             else if (useJDBCStringMethods())
168             {
169                 String JavaDoc str = (String JavaDoc)value;
170     
171                 if (targetIsString)
172                 {
173                     if (useStringDelimitor)
174                         str += STRING_DELIMITOR;
175                 
176                     if (useEmptyStringAlias && (str.length() == 0))
177                         pStmt.setString(i, STRING_DELIMITOR);
178                     else if (str.length() > dbType.getLength())
179                         throw new RepositoryException(RepositoryException.DATA_LOSS, "Value is too large for column.");
180                     else
181                     {
182                         if (useStreams)
183                             pStmt.setCharacterStream(i, new StringReader(str), str.length());
184                         else
185                             pStmt.setString(i, str);
186                     }
187                 }
188                 else
189                     pStmt.setString(i, str);
190             }
191             else // object other than string (converted)
192
{
193                 checkDataLoss(value, messageHandler);
194                 value = adaptSchemaObjectToJDBC(value);
195                 if (useStreams && (javaType == SCHEMA_BYTE_ARRAY))
196                 {
197                     byte[] bytes = (byte[])value;
198                     pStmt.setBinaryStream(i, new ByteArrayInputStream(bytes), bytes.length);
199                 }
200                 else
201                     connection.setObject(pStmt, i, value, javaType, dbType);
202             }
203         }
204     }
205
206     private Object JavaDoc adaptSchemaObjectToJDBC(Object JavaDoc value) {
207         
208         switch (javaType) {
209             case SCHEMA_DURATION:
210             case SCHEMA_URI:
211             case SCHEMA_QNAME:
212                 value = value.toString();
213                 break;
214                 
215             case SCHEMA_DATETIME:
216                 if (value instanceof java.util.Date JavaDoc)
217                     value = new Timestamp(((java.util.Date JavaDoc)value).getTime());
218                 // NOTE: Use the base date type for schema API and JDBC
219
// in order to allow user generators to use the JDBC java.sql.Date type.
220
break;
221             
222             case SCHEMA_BYTE_ARRAY:
223                 if (value instanceof ByteArray) // user generator could pass a byte array.
224
value = ((ByteArray)value).getData();
225                 break;
226                 
227             case JAVA_LIST:
228                 value = sType.toXMLString(value);
229                 break;
230     
231             default :
232                 break;
233         }
234         return value;
235     }
236
237     private void storeConvertedToSQL(PreparedStatement pStmt, int i, Object JavaDoc o) throws SQLException, XMLDBCException {
238         
239         // no check is performed on JDBC types because control has been performed
240
// before: conversion is authorized and AUTOMATIC
241
switch (javaType) {
242             case SCHEMA_DURATION: // Java types that use strings for JDBC
243
case SCHEMA_URI:
244             case SCHEMA_QNAME:
245             case JAVA_STRING:
246             case JAVA_LIST:
247                 try {
248                     pStmt.setBytes(i, ((String JavaDoc) o).getBytes("UTF-8"));
249                     // The default XML one
250
}
251                 catch (UnsupportedEncodingException e) {
252                     throw new RuntimeException JavaDoc("UTF-8 encoding is not supported by the current JRE. Mapping from string to binary is impossible");
253                 }
254                 break;
255     
256             case SCHEMA_DATETIME :
257                 DateTime dt = (DateTime)o;
258                 int n = 0;
259                 switch (sType.getPrimitive().getType()) {
260                     case PrimitiveType.GYEAR :
261                         n = dt.getYear();
262                         break;
263                     case PrimitiveType.GMONTH :
264                         n = dt.getMonth() + 1;
265                         break;
266                     case PrimitiveType.GDAY :
267                         n = dt.getDate();
268                         break;
269                     default :
270                         }
271                 pStmt.setInt(i, n);
272                 break;
273     
274             default :
275                 throw new RepositoryException(
276                     RepositoryException.INTERNAL_ERROR,
277                     "This automatic conversion is not currently supported (javaType: "
278                     + javaType + ", JDBCtype: " + dbType.getJDBCType() + ')');
279         }
280     }
281
282     private void checkDataLoss(Object JavaDoc o, XMLErrorHandler messageHandler) throws XMLDBCException {
283         switch(javaType)
284         {
285             case JAVA_BIG_DECIMAL:
286                 if (o instanceof BigDecimal JavaDoc && messageHandler != null && dbType.getLength() > 0) // system generators (Long, Integer) are not controlled
287
{
288                     BigDecimal JavaDoc bd = (BigDecimal JavaDoc)o;
289                     int precision = (int)Math.ceil(Math.log(bd.unscaledValue().doubleValue())/Math.log(10d));
290                     if (precision > dbType.getLength() ||
291                         (dbType.getScale() >= 0 && bd.scale() > dbType.getScale()))
292                         messageHandler.warning(new RepositoryException(RepositoryException.DATA_LOSS, "Precision loss."));
293                 }
294                 break;
295             case SCHEMA_BYTE_ARRAY:
296                 if (((ByteArray)o).getLength() > dbType.getLength())
297                     throw new RepositoryException(RepositoryException.DATA_LOSS, "Value is too large for column.");
298                 break;
299             default:
300         }
301     }
302
303     public String JavaDoc getTypedNullValue() throws RepositoryException {
304         switch (dbType.getJDBCType())
305         {
306             case Types.BIT: case Types.TINYINT: case Types.SMALLINT:
307             case Types.INTEGER: case Types.BIGINT: case Types.FLOAT:
308             case Types.REAL: case Types.DOUBLE: case Types.NUMERIC:
309             case Types.DECIMAL:
310                 return "TO_NUMBER(null)";
311             case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR:
312             case Types.CLOB:
313                 return "''";
314             case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY:
315             case Types.BLOB:
316                 return "0";
317             case Types.DATE: case Types.TIME: case Types.TIMESTAMP:
318                 return "TO_DATE(null)";
319             default:
320                 throw new RepositoryException(RepositoryException.NOT_IMPLEMENTED,
321                 "Such query cannot be handled because of the column " + dbType.getJDBCType()
322                 + " SQL type");
323         }
324     }
325
326     /* Should be set in the RDBMS portability layer in AbstractStatement (to ADD) */
327     public String JavaDoc getParameter(ResultSet rs, int i, Declaration decl, ValidationContextProvider nsContext)
328     throws SQLException
329     {
330         String JavaDoc ret = null;
331         SimpleType type = null;
332         
333         if (decl == null) // for Text nodes or generic mapping
334
type = sType;
335         else // if no type, take the pseudo type from the table definition
336
type = decl.getType().getValueType();
337         
338         if (useJDBCStringMethods() && (conversion != AUTOMATIC))
339         {
340             if (useStreams) // use getCharacterStream because Oracle does not tolerate getString for CLOBs
341
{
342                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
343                 Reader reader = rs.getCharacterStream(i);
344                 char[] buffer = new char[256];
345                 int len = 0;
346                 try
347                 {
348                     while ((len = reader.read(buffer)) > 0)
349                         sb.append(buffer, 0, len);
350                 }
351                 catch (IOException e)
352                 {
353                     throw new SQLException("IOException while using read() on a Reader object obtained by getCharacterStream().");
354                 }
355                 ret = sb.toString();
356             }
357             else
358             {
359                 ret = rs.getString(i);
360                 if (targetIsString)
361                 {
362                     if (useStringDelimitor)
363                         ret = ret.substring(0, ret.length() - STRING_DELIMITOR_LENGTH);
364                     else if ((ret != null) && ret.equals(STRING_DELIMITOR))
365                         ret = "";
366                 }
367                 if (!storeCanonicalString()) // data is not stored converted : canonize now
368
ret = type.toXMLString(ret, nsContext);
369             }
370         }
371         else
372         {
373             Object JavaDoc o;
374             if (conversion == AUTOMATIC)
375                 o = convertToXML(rs, i);
376             else if (useStreams) // BLOB or LONGVARBINARY
377
{
378                 ByteArrayOutputStream out = new ByteArrayOutputStream(256);
379                 InputStream in = rs.getBinaryStream(i);
380                 byte[] buffer = new byte[256];
381                 int len = 0;
382                 try
383                 {
384                     while ((len = in.read(buffer)) > 0)
385                         out.write(buffer, 0, len);
386                 }
387                 catch (IOException e)
388                 {
389                     throw new SQLException("IOException while using read() on a Reader object obtained by getCharacterStream().");
390                 }
391                 o = out.toByteArray();
392             }
393             else
394                 o = rs.getObject(i); // because first index starts at 0 and OID belongs to columns
395

396             if (o != null)
397                 ret = type.toXMLString(o, nsContext);
398         }
399
400         return ret;
401     }
402     
403     /* generated object type must be insensitive to a setObject-getObject U-turn */
404     private Object JavaDoc convertToXML(ResultSet rs, int i)
405     throws SQLException
406     {
407         switch (dbType.getJDBCType()) {
408             case Types.VARBINARY :
409
410                 try {
411                     return new String JavaDoc(rs.getBytes(i), "UTF-8");
412                 }
413                 catch (UnsupportedEncodingException e) {
414                     throw new RuntimeException JavaDoc("UTF-8 encoding is not supported by the current JRE. Mapping from string to binary is impossible");
415                 }
416             case Types.BIGINT :
417             case Types.DECIMAL :
418             case Types.DOUBLE :
419             case Types.FLOAT :
420             case Types.INTEGER :
421             case Types.NUMERIC :
422             case Types.REAL :
423             case Types.SMALLINT :
424             case Types.TINYINT :
425
426                 Timestamp ts = null;
427                 int n = rs.getInt(i);
428                 switch (sType.getPrimitive().getType()) {
429                     case PrimitiveType.GYEAR :
430                         ts = new Timestamp(n, 0, 0, 0, 0, 0, 0);
431                         break;
432                     case PrimitiveType.GMONTH :
433                         ts = new Timestamp(0, n, 0, 0, 0, 0, 0);
434                         break;
435                     case PrimitiveType.GDAY :
436                         ts = new Timestamp(0, 0, n, 0, 0, 0, 0);
437                         break;
438                     default :
439                         }
440                 return ts;
441
442             default :
443                 throw new RuntimeException JavaDoc("This automatic conversion is not currently supported (javaType: "
444                         + javaType
445                         + ", JDBCtype: "
446                         + dbType.getJDBCType()
447                         + ')');
448         }
449     }
450     
451     public String JavaDoc getTypeCreationString(AbstractConnection connection) {
452         PrimitiveType pType = sType.getPrimitive();
453         int JDBCType = ABSTRACT_SCHEMA_JDBC_MAPPING[pType.getType()];
454         
455         int optimumJDBCType = optimize(
456                 JDBCType,
457                 connection.getTypeMap(),
458                 pType.getMaxLength(),
459                 pType.getTotalDigits(),
460                 pType.getFractionDigits(),
461                 (Number JavaDoc)pType.getMinValue(),
462                 (Number JavaDoc)pType.getMaxValue()
463                 );
464         
465         return ColumnMetaDataImpl.getTypeCreationString(
466                 optimumJDBCType,
467                 connection.getTypeMap(),
468                 pType.getMaxLength(),
469                 pType.getTotalDigits(),
470                 pType.getFractionDigits()
471                 );
472     }
473
474     private void checkTargetType(PrimitiveType pType, int localJavaType, XMLErrorHandler messageHandler)
475     throws SAXException JavaDoc {
476         int targetJDBCType = getAbstractJDBCType(dbType.getJDBCType());
477         
478         // First verify that setObject is authorized (redundant ?)
479
if (localJavaType < JAVA_LIST
480                 && (Arrays.binarySearch(AUTHORIZED_CONVERSIONS[localJavaType], (int)targetJDBCType) < 0) // Warning getDataType returns a short
481
&& !isJDBCStringIOAllowed)
482             throw new SAXException JavaDoc(sType + " XML data type cannot be mapped on "
483             + dbType + " with SQL type " + dbType.getNativeType() + ".");
484         
485         // Verify that the XML and SQL type fit
486

487         // 1. Classify the XML type in a basic (JDBC) type within (VARCHAR,
488
// VARBINARY, DECIMAL, FLOAT, DOUBLE, TIMESTAMP)
489
int abstractBaseJDBCType = ABSTRACT_SCHEMA_JDBC_MAPPING[pType.getType()];
490     
491        // conversion type flag setting
492
if (abstractBaseJDBCType == targetJDBCType)
493            conversion = NONE;
494        else
495        {
496            switch (targetJDBCType)
497            {
498                case Types.VARCHAR:
499                    conversion = IMPLICIT;
500                    break;
501                    
502                case Types.VARBINARY:
503                    if (abstractBaseJDBCType == Types.VARCHAR)
504                        conversion = AUTOMATIC;
505                    break;
506                    
507                case Types.DECIMAL:
508                    if (abstractBaseJDBCType == Types.REAL
509                     || abstractBaseJDBCType == Types.FLOAT
510                     || abstractBaseJDBCType == Types.DOUBLE)
511                        conversion = IMPLICIT;
512                    else if (pType.getType() == PrimitiveType.GYEAR
513                     || pType.getType() == PrimitiveType.GMONTH
514                     || pType.getType() == PrimitiveType.GDAY)
515                        conversion = AUTOMATIC;
516                    break;
517                    
518                case Types.REAL:
519                    if (abstractBaseJDBCType == Types.DECIMAL
520                     || abstractBaseJDBCType == Types.FLOAT
521                     || abstractBaseJDBCType == Types.DOUBLE)
522                        conversion = IMPLICIT;
523                    break;
524                    
525                case Types.DOUBLE:
526                    if (abstractBaseJDBCType == Types.DECIMAL
527                     || abstractBaseJDBCType == Types.FLOAT
528                     || abstractBaseJDBCType == Types.REAL)
529                        conversion = IMPLICIT;
530                    break;
531                    
532                default:
533            }
534            
535            if (conversion == IMPOSSIBLE)
536                throw new SAXException JavaDoc(sType + " XML data type cannot be mapped on column with SQL type "
537                        + dbType.getNativeType() + ".");
538        }
539     
540        // pseudo facet setting (could be performed only if the target type requires it)
541
int maxLen = pType.getMaxLength(),
542             precision = pType.getTotalDigits(),
543             scale = pType.getFractionDigits(); // if -1, no need to check
544

545        switch (pType.getType())
546        {
547            case PrimitiveType.BOOLEAN:
548                maxLen = 5;
549                break;
550            case PrimitiveType.DECIMAL:
551                // maxlen calculation for writing in VARCHAR SQL type
552
if (precision > 0) // use absolute limits if any
553
maxLen = precision + (scale > 0?2:1); // sign and dot
554
else if (scale >= 0) // if no scale and no precision no prediction on string size can be performed
555
{
556                    if ((pType.getMinValue() != null) && (pType.getMaxValue() != null)) // bounded
557
{
558                        double maxAbs = Math.max(
559                                         Math.abs(((Number JavaDoc)pType.getMinValue()).doubleValue()),
560                                         Math.abs(((Number JavaDoc)pType.getMaxValue()).doubleValue())
561                                         );
562                        maxLen = (int)Math.ceil(Math.log(maxAbs)/Math.log(10d));
563                        if (scale > 0)
564                            maxLen += scale + 2;
565                        else
566                            maxLen += scale + 1;
567                    }
568                }
569                break;
570                
571            case PrimitiveType.DATE_TIME:
572                maxLen = 19; // this is the minimum value for a date string using schema syntax
573
break;
574            case PrimitiveType.TIME:
575                maxLen = 8; // this is the minimum value for a date string using schema syntax
576
break;
577            case PrimitiveType.DATE:
578                maxLen = 10; // this is the minimum value for a date string using schema syntax
579
break;
580            case PrimitiveType.GYEAR_MONTH:
581                maxLen = 7; // this is the minimum value for a date string using schema syntax
582
break;
583            case PrimitiveType.GYEAR:
584                maxLen = 4; // this is the minimum value for a date string using schema syntax
585
precision = 4;
586                scale = 0;
587                break;
588            case PrimitiveType.GMONTH_DAY:
589                maxLen = 7; // this is the minimum value for a date string using schema syntax
590
break;
591            case PrimitiveType.GDAY:
592                maxLen = 5; // this is the minimum value for a date string using schema syntax
593
precision = 2;
594                scale = 0;
595                break;
596            case PrimitiveType.GMONTH:
597                maxLen = 6; // this is the minimum value for a date string using schema syntax
598
precision = 2;
599                scale = 0;
600                break;
601        }
602     
603        // check capacity fit
604
try
605        {
606            switch (targetJDBCType)
607            {
608                case Types.VARCHAR:
609                case Types.VARBINARY:
610                    
611                    if (maxLen < 0)
612                    {
613                        if (messageHandler != null)
614                            messageHandler.warning(new XMLDBCException("XML data may overflow in " + dbType));
615                    }
616                    else if (maxLen > dbType.getLength())
617                        throw new SAXException JavaDoc("XML data type length is larger than " + dbType);
618                    break;
619                    
620                case Types.DECIMAL:
621                    if (precision < 0)
622                    {
623                        if (messageHandler != null)
624                            messageHandler.warning(new XMLDBCException("XML data may overflow in " + dbType));
625                    }
626                    else if (precision > dbType.getLength())
627                        throw new SAXException JavaDoc("XML data type precision is larger than " + dbType);
628                    else if ((scale >= 0) && (scale > dbType.getScale()))
629                        throw new SAXException JavaDoc("XML data type scale is larger than " + dbType);
630                    break;
631                    
632                default:
633            }
634        }
635        catch (XMLDBCException e)
636        {
637            throw new SAXException JavaDoc("Operation aborted by user application.", e);
638        }
639     }
640
641     /**
642      * <B>JDBC Types returned by the driver must be substituted to match one
643      * of the following basic types : VARCHAR, VARBINARY, DECIMAL, REAL,
644      * DOUBLE, TIMESTAMP</B>
645      *
646      * @return
647      */

648     private int getAbstractJDBCType(int targetType) throws SAXException JavaDoc {
649         switch (targetType) {
650             case Types.BIGINT : case Types.BIT : case Types.TINYINT :
651             case Types.SMALLINT : case Types.DECIMAL : case Types.NUMERIC :
652             case Types.INTEGER : case DbType.BOOLEAN : case DbType.ORACLE_ROWID:
653                 return Types.DECIMAL;
654                 
655             case Types.CHAR : case Types.CLOB :
656             case Types.LONGVARCHAR : case Types.VARCHAR :
657                 return Types.VARCHAR;
658                 
659             case Types.DOUBLE :
660                return Types.DOUBLE;
661                 
662             case Types.FLOAT : case Types.REAL :
663                return Types.REAL;
664                 
665             case Types.DATE : case Types.TIME : case Types.TIMESTAMP :
666                 return Types.TIMESTAMP;
667                 
668             case Types.LONGVARBINARY :case Types.BLOB :
669             case Types.VARBINARY : case Types.BINARY :
670                 return Types.VARBINARY;
671
672             case Types.NULL :
673                 throw new SAXException JavaDoc("The JDBC NULL type is not currently supported.");
674             case Types.OTHER :
675                 throw new SAXException JavaDoc("The JDBC OTHER type is not currently supported.");
676             case Types.REF :
677                 throw new SAXException JavaDoc("The JDBC REF type is not currently supported.");
678             case Types.JAVA_OBJECT :
679                 throw new SAXException JavaDoc("The JDBC JAVA_OBJECT type is not currently supported.");
680             case Types.STRUCT :
681                 throw new SAXException JavaDoc("The JDBC STRUCT type is not currently supported.");
682             case Types.DISTINCT :
683                 throw new SAXException JavaDoc("The JDBC CLOB type is not currently supported.");
684             case Types.ARRAY :
685                 throw new SAXException JavaDoc("The JDBC ARRAY type is not currently supported.");
686             default:
687                 return targetType;
688         }
689     }
690
691     private int optimize(int dataType, TypeMap typeMap, long maxLength, int precision, int scale, Number JavaDoc min, Number JavaDoc max) {
692         int optimum = dataType;
693         
694         switch (dataType) // switch according to "base" target JDBC type
695
{ // and try to analyse facets(restrictions) to find a 'smaller one'
696
case Types.VARCHAR :
697                 if (maxLength <= typeMap.getSize(Types.VARCHAR))
698                     optimum = Types.VARCHAR;
699                 else
700                     optimum = Types.LONGVARCHAR;
701                 break;
702             case Types.DOUBLE : case Types.FLOAT : // 15 digits mantissa
703
if (precision <= 7)
704                     optimum = Types.REAL;
705                 break;
706             case Types.NUMERIC : case Types.DECIMAL : // 15 digits of precision and scale at least
707
if (scale == 0) // integers
708
{
709                     int smallest = getSmallestInteger(precision,
710                     min == null ? Double.MIN_VALUE : min.doubleValue(),
711                     max == null ? Double.MAX_VALUE : max.doubleValue());
712                     if (smallest != 0)
713                         optimum = smallest;
714                 }
715                 // else use scale and precision coming from XML schema type
716
break;
717             case Types.VARBINARY :
718                 if (maxLength <= typeMap.getSize(Types.VARBINARY))
719                     optimum = Types.VARBINARY;
720                 else
721                     optimum = Types.LONGVARBINARY;
722                 break;
723             default : // Nothing to do with VARCHAR, TIMESTAMP, REAL
724
}
725         return optimum;
726     }
727
728     /** Calculate the most adapted JDBC integer type basing on the precision & max value given.
729      * @return The calculated JDBC-SQL type from java.sql.Types
730      * @param precision
731      * @param min
732      * @param max
733      */

734     private int getSmallestInteger(int precision, double min, double max) {
735         int ret = 0;
736         int prec = 0;
737         
738         /* downsizing with boundaries */
739         prec = (int)Math.ceil(Math.log(Math.max(Math.abs(min), Math.abs(max)))/Math.log(10d));
740         
741         if (precision > 0)
742             prec = Math.min(precision, prec);
743         
744         /* downsizing with precision */
745         if (prec <= 3)
746             ret = Types.TINYINT;
747         else if (prec <= 5)
748             ret = Types.SMALLINT;
749         else if (prec <= 10)
750             ret = Types.INTEGER;
751         else if (prec <= 19)
752             ret = Types.BIGINT;
753         
754         return ret;
755     }
756
757 }
758
Popular Tags