Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/mysql/jdbc/Field.java


1   /*
2    Copyright (C) 2002-2004 MySQL AB
3   
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of version 2 of the GNU General Public License as
6    published by the Free Software Foundation.
7    
8   
9    There are special exceptions to the terms and conditions of the GPL 
10   as it is applied to this software. View the full text of the 
11   exception exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
12   software distribution.
13  
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18  
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  
23   */
24  package com.mysql.jdbc;
25  
26  import java.io.UnsupportedEncodingException;
27  import java.sql.SQLException;
28  import java.sql.Types;
29  
30  
31  /**
32   * Field is a class used to describe fields in a
33   * ResultSet
34   *
35   * @author Mark Matthews
36   * @version $Id: Field.java,v 1.15.2.15 2004/10/21 19:31:03 mmatthew Exp $
37   */
38  public class Field {
39      //~ Static fields/initializers ---------------------------------------------
40  
41      private static final int AUTO_INCREMENT_FLAG = 512;
42      private Connection connection = null;
43      private String charsetName = null;
44      private String databaseName = null;
45      private String defaultValue = null;
46      private String fullName = null;
47      private String fullNameWithDatabase = null;
48      private String fullOriginalName = null;
49      private String fullOriginalNameWithDatabase = null;
50      private String name; // The Field name
51      private String originalColumnName = null;
52      private String originalTableName = null;
53      private String tableName; // The Name of the Table
54      private byte[] buffer;
55      private int charsetIndex = 0;
56      private int colDecimals;
57      private int databaseNameLength = -1;
58  
59      // database name info
60      private int databaseNameStart = -1;
61      private int defaultValueLength = -1;
62  
63      // default value info - from COM_LIST_FIELDS execution
64      private int defaultValueStart = -1;
65      private long length; // Internal length of the field;
66      private int mysqlType = -1; // the MySQL type
67      private int nameLength;
68      private int nameStart;
69      private int originalColumnNameLength = -1;
70  
71      // column name info (before aliasing)
72      private int originalColumnNameStart = -1;
73      private int originalTableNameLength = -1;
74  
75      // table name info (before aliasing)
76      private int originalTableNameStart = -1;
77      private int precisionAdjustFactor = 0;
78      private int sqlType = -1; // the java.sql.Type
79      private int tableNameLength;
80      private int tableNameStart;
81      private short colFlag;
82  
83      //~ Constructors -----------------------------------------------------------
84  
85      /**
86      * Constructor used by DatabaseMetaData methods.
87      */
88      Field(String tableName, String columnName, int jdbcType, long length) {
89          this.tableName = tableName;
90          this.name = columnName;
91          this.length = length;
92          sqlType = jdbcType;
93          colFlag = 0;
94          colDecimals = 0;
95      }
96  
97      /**
98       * Constructor used when communicating with pre 4.1 servers
99       */
100     Field(Connection conn, byte[] buffer, int nameStart, int nameLength,
101         int tableNameStart, int tableNameLength, long length, int mysqlType,
102         short colFlag, int colDecimals) throws SQLException {
103         this(conn, buffer, -1, -1, tableNameStart, tableNameLength, -1, -1,
104             nameStart, nameLength, -1, -1, length, mysqlType, colFlag,
105             colDecimals, -1, -1, MysqlDefs.NO_CHARSET_INFO);
106     }
107 
108     /**
109      * Constructor used when communicating with 4.1 and newer
110      * servers
111      */
112     Field(Connection conn, byte[] buffer, int databaseNameStart,
113         int databaseNameLength, int tableNameStart, int tableNameLength,
114         int originalTableNameStart, int originalTableNameLength, int nameStart,
115         int nameLength, int originalColumnNameStart,
116         int originalColumnNameLength, long length, int mysqlType, short colFlag,
117         int colDecimals, int defaultValueStart, int defaultValueLength,
118         int charsetIndex) throws SQLException {
119         this.connection = conn;
120         this.buffer = buffer;
121         this.nameStart = nameStart;
122         this.nameLength = nameLength;
123         this.tableNameStart = tableNameStart;
124         this.tableNameLength = tableNameLength;
125         this.length = length;
126         this.colFlag = colFlag;
127         this.colDecimals = colDecimals;
128         this.mysqlType = mysqlType;
129 
130         // 4.1 field info...
131         this.databaseNameStart = databaseNameStart;
132         this.databaseNameLength = databaseNameLength;
133 
134         this.originalTableNameStart = originalTableNameStart;
135         this.originalTableNameLength = originalTableNameLength;
136 
137         this.originalColumnNameStart = originalColumnNameStart;
138         this.originalColumnNameLength = originalColumnNameLength;
139 
140         this.defaultValueStart = defaultValueStart;
141         this.defaultValueLength = defaultValueLength;
142         
143         // Re-map to 'real' blob type, if we're a BLOB
144 
145         if (this.mysqlType == MysqlDefs.FIELD_TYPE_BLOB) {
146           setBlobTypeBasedOnLength();
147         }
148         
149         // Map MySqlTypes to java.sql Types
150         this.sqlType = MysqlDefs.mysqlToJavaType(this.mysqlType);
151 
152         if (this.sqlType == Types.TINYINT && this.length == 1 
153             && (this.connection != null && this.connection.getTinyint1isBit())) {
154           this.sqlType = Types.BIT;
155         }
156         
157         // If we're not running 4.1 or newer, use the connection's
158         // charset
159         this.charsetIndex = charsetIndex;
160         
161         this.charsetName = this.connection.getCharsetNameForIndex(this.charsetIndex);
162         
163         boolean isBinary = isBinary();
164 
165         //
166         // Handle TEXT type (special case), Fix proposed by Peter McKeown
167         //
168         if ((sqlType == java.sql.Types.LONGVARBINARY) && !isBinary) {
169             sqlType = java.sql.Types.LONGVARCHAR;
170         } else if ((sqlType == java.sql.Types.VARBINARY) && !isBinary) {
171             sqlType = java.sql.Types.VARCHAR;
172         }
173 
174         //
175         // Handle odd values for 'M' for floating point/decimal numbers
176         //
177         if (!isUnsigned()) {
178             switch (this.mysqlType) {
179             case MysqlDefs.FIELD_TYPE_DECIMAL:
180                 this.precisionAdjustFactor = -1;
181 
182                 break;
183 
184             case MysqlDefs.FIELD_TYPE_DOUBLE:
185             case MysqlDefs.FIELD_TYPE_FLOAT:
186                 this.precisionAdjustFactor = 1;
187 
188                 break;
189             }
190         } else {
191             switch (this.mysqlType) {
192             case MysqlDefs.FIELD_TYPE_DOUBLE:
193             case MysqlDefs.FIELD_TYPE_FLOAT:
194                 this.precisionAdjustFactor = 1;
195 
196                 break;
197             }
198         }
199     }
200 
201     //~ Methods ----------------------------------------------------------------
202 
203     /**
204      * DOCUMENT ME!
205      *
206      * @return DOCUMENT ME!
207      */
208     public boolean isAutoIncrement() {
209         return ((colFlag & AUTO_INCREMENT_FLAG) > 0);
210     }
211 
212     /**
213      * DOCUMENT ME!
214      *
215      * @return DOCUMENT ME!
216      */
217     public boolean isBinary() {
218         return ((colFlag & 128) > 0);
219     }
220 
221     /**
222      * DOCUMENT ME!
223      *
224      * @return DOCUMENT ME!
225      */
226     public boolean isBlob() {
227         return ((colFlag & 16) > 0);
228     }
229 
230     /**
231      * Returns the character set (if known) for this
232      * field.
233      *
234      * @return the character set
235      */
236     public String getCharacterSet() {
237         return this.charsetName;
238     }
239 
240     /**
241      * DOCUMENT ME!
242      *
243      * @param conn DOCUMENT ME!
244      */
245     public void setConnection(Connection conn) {
246         this.connection = conn;
247         
248     this.charsetName = this.connection.getEncoding();
249     }
250 
251     /**
252      * DOCUMENT ME!
253      *
254      * @return DOCUMENT ME!
255      */
256     public String getDatabaseName() {
257         if ((this.databaseName == null) && (this.databaseNameStart != -1)
258                 && (this.databaseNameLength != -1)) {
259             this.databaseName = getStringFromBytes(this.databaseNameStart,
260                     this.databaseNameLength);
261         }
262 
263         return this.databaseName;
264     }
265 
266     /**
267      * DOCUMENT ME!
268      *
269      * @return DOCUMENT ME!
270      */
271     public String getFullName() {
272         if (fullName == null) {
273             StringBuffer fullNameBuf = new StringBuffer(getTableName().length()
274                     + 1 + getName().length());
275             fullNameBuf.append(tableName);
276 
277             // much faster to append a char than a String
278             fullNameBuf.append('.');
279             fullNameBuf.append(name);
280             fullName = fullNameBuf.toString();
281             fullNameBuf = null;
282         }
283 
284         return fullName;
285     }
286 
287     /**
288      * DOCUMENT ME!
289      *
290      * @return DOCUMENT ME!
291      */
292     public String getFullOriginalName() {
293         getOriginalName();
294 
295         if (this.originalColumnName == null) {
296             return null; // we don't have this information
297         }
298 
299         if (fullName == null) {
300             StringBuffer fullOriginalNameBuf = new StringBuffer(getOriginalTableName()
301                                                                     .length()
302                     + 1 + getOriginalName().length());
303             fullOriginalNameBuf.append(this.originalTableName);
304 
305             // much faster to append a char than a String
306             fullOriginalNameBuf.append('.');
307             fullOriginalNameBuf.append(this.originalColumnName);
308             this.fullOriginalName = fullOriginalNameBuf.toString();
309             fullOriginalNameBuf = null;
310         }
311 
312         return this.fullOriginalName;
313     }
314 
315     /**
316      * DOCUMENT ME!
317      *
318      * @return DOCUMENT ME!
319      */
320     public long getLength() {
321         return length;
322     }
323 
324     /**
325      * DOCUMENT ME!
326      *
327      * @return DOCUMENT ME!
328      */
329     public boolean isMultipleKey() {
330         return ((colFlag & 8) > 0);
331     }
332 
333     /**
334      * DOCUMENT ME!
335      *
336      * @return DOCUMENT ME!
337      */
338     public int getMysqlType() {
339         return mysqlType;
340     }
341 
342     /**
343      * DOCUMENT ME!
344      *
345      * @return DOCUMENT ME!
346      */
347     public String getName() {
348         if (this.name == null) {
349             this.name = getStringFromBytes(this.nameStart, this.nameLength);
350         }
351 
352         return name;
353     }
354 
355     /**
356      * DOCUMENT ME!
357      *
358      * @return DOCUMENT ME!
359      */
360     public String getOriginalName() {
361         if ((this.originalColumnName == null)
362                 && (this.originalColumnNameStart != -1)
363                 && (this.originalColumnNameLength != -1)) {
364             this.originalColumnName = getStringFromBytes(this.originalColumnNameStart,
365                     this.originalColumnNameLength);
366         }
367 
368         return this.originalColumnName;
369     }
370 
371     /**
372      * DOCUMENT ME!
373      *
374      * @return DOCUMENT ME!
375      */
376     public String getOriginalTableName() {
377         if ((this.originalTableName == null)
378                 && (this.originalTableNameStart != -1)
379                 && (this.originalTableNameLength != -1)) {
380             this.originalTableName = getStringFromBytes(this.originalTableNameStart,
381                     this.originalTableNameLength);
382         }
383 
384         return this.originalTableName;
385     }
386 
387     /**
388      * Returns amount of correction that
389      * should be applied to the precision value.
390      *
391      * Different versions of MySQL report different
392      * precision values.
393      *
394      * @return the amount to adjust precision value by.
395      */
396     public int getPrecisionAdjustFactor() {
397         return this.precisionAdjustFactor;
398     }
399 
400     /**
401      * DOCUMENT ME!
402      *
403      * @return DOCUMENT ME!
404      */
405     public boolean isPrimaryKey() {
406         return ((colFlag & 2) > 0);
407     }
408 
409     /**
410      * DOCUMENT ME!
411      *
412      * @return DOCUMENT ME!
413      */
414     public int getSQLType() {
415         return sqlType;
416     }
417 
418     /**
419      * DOCUMENT ME!
420      *
421      * @return DOCUMENT ME!
422      */
423     public String getTable() {
424         return getTableName();
425     }
426 
427     /**
428      * DOCUMENT ME!
429      *
430      * @return DOCUMENT ME!
431      */
432     public String getTableName() {
433         if (tableName == null) {
434             tableName = getStringFromBytes(tableNameStart, tableNameLength);
435         }
436 
437         return tableName;
438     }
439 
440     /**
441      * DOCUMENT ME!
442      *
443      * @return DOCUMENT ME!
444      */
445     public boolean isUniqueKey() {
446         return ((colFlag & 4) > 0);
447     }
448 
449     /**
450      * DOCUMENT ME!
451      *
452      * @return DOCUMENT ME!
453      */
454     public boolean isUnsigned() {
455         return ((colFlag & 32) > 0);
456     }
457 
458     /**
459      * DOCUMENT ME!
460      *
461      * @return DOCUMENT ME!
462      */
463     public boolean isZeroFill() {
464         return ((colFlag & 64) > 0);
465     }
466 
467     /**
468      * DOCUMENT ME!
469      *
470      * @return DOCUMENT ME!
471      */
472     public String toString() {
473       return this.getDatabaseName() + " . " +  this.getTableName() + "(" + this.getOriginalTableName() + ") . " + this.getName() + "(" + this.getOriginalName() + ")";
474        
475     }
476 
477     int getDecimals() {
478         return colDecimals;
479     }
480 
481     boolean isNotNull() {
482         return ((colFlag & 1) > 0);
483     }
484 
485     /**
486      * Is this field _definitely_ not writable?
487      * 
488      * @return true if this field can not be written to in an INSERT/UPDATE
489      * statement.
490      */
491     boolean isReadOnly() throws SQLException {
492       if (this.connection.getIO().versionMeetsMinimum(4, 1, 0)) {
493         String orgColumnName = getOriginalName();
494         String orgTableName = getOriginalTableName();
495         
496         return !(orgColumnName != null && orgColumnName.length() > 0 &&
497             orgTableName != null && orgTableName.length() > 0);
498       } else {
499         return false;
500       }
501     }
502     
503     /**
504      * Create a string with the correct charset encoding from the
505      * byte-buffer that contains the data for this field
506      */
507     private String getStringFromBytes(int stringStart, int stringLength) {
508         if ((stringStart == -1) || (stringLength == -1)) {
509             return null;
510         }
511 
512         String stringVal = null;
513 
514         if (connection != null) {
515             if (connection.useUnicode()) {
516               
517                 String encoding = this.connection.getCharacterSetMetadata();
518                 
519                 if (encoding == null) {
520                   encoding = connection.getEncoding();
521                 }
522                 
523                 if (encoding != null) {
524                    
525           SingleByteCharsetConverter converter = null;
526           
527           if (this.connection != null) {
528             converter = this.connection.getCharsetConverter(encoding);
529           }
530                     
531                     if (converter != null) { // we have a converter
532                         stringVal = converter.toString(buffer, stringStart,
533                                 stringLength);
534                     } else {
535                         // we have no converter, use JVM converter 
536                         byte[] stringBytes = new byte[stringLength];
537 
538                         int endIndex = stringStart + stringLength;
539                         int pos = 0;
540 
541                         for (int i = stringStart; i < endIndex; i++) {
542                             stringBytes[pos++] = buffer[i];
543                         }
544 
545                         try {
546                             stringVal = new String(stringBytes, encoding);
547                         } catch (UnsupportedEncodingException ue) {
548                             throw new RuntimeException(
549                                 "Unsupported character encoding '" + encoding
550                                 + "'");
551                         }
552                     }
553                 } else {
554                     // we have no encoding, use JVM standard charset
555                     stringVal = StringUtils.toAsciiString(buffer, stringStart,
556                             stringLength);
557                 }
558             } else {
559                 // we are not using unicode, so use JVM standard charset 
560                 stringVal = StringUtils.toAsciiString(buffer, stringStart,
561                         stringLength);
562             }
563         } else {
564             // we don't have a connection, so punt 
565             stringVal = StringUtils.toAsciiString(buffer, stringStart,
566                     stringLength);
567         }
568 
569         return stringVal;
570     }
571     
572     //
573     // MySQL only has one protocol-level BLOB type that it exposes
574     // which is FIELD_TYPE_BLOB, although we can divine what the
575     // actual type is by the length reported ...
576     //
577     private void setBlobTypeBasedOnLength() {
578        if (this.length == MysqlDefs.LENGTH_TINYBLOB) {
579          this.mysqlType = MysqlDefs.FIELD_TYPE_TINY_BLOB;
580        } else if (this.length == MysqlDefs.LENGTH_BLOB) {
581          this.mysqlType = MysqlDefs.FIELD_TYPE_BLOB;
582        } else if (this.length == MysqlDefs.LENGTH_MEDIUMBLOB) {
583          this.mysqlType = MysqlDefs.FIELD_TYPE_MEDIUM_BLOB;
584        } else if (this.length == MysqlDefs.LENGTH_LONGBLOB) {
585          this.mysqlType = MysqlDefs.FIELD_TYPE_LONG_BLOB;
586        }
587     }
588 }