1 /*
   2  * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.sql.rowset.serial;
  27 
  28 import java.sql.*;
  29 import javax.sql.*;
  30 import java.io.*;
  31 import java.math.*;
  32 import java.util.Map;
  33 
  34 /**
  35  * An input stream used for custom mapping user-defined types (UDTs).
  36  * An <code>SQLInputImpl</code> object is an input stream that contains a
  37  * stream of values that are the attributes of a UDT.
  38  * <p>
  39  * This class is used by the driver behind the scenes when the method
  40  * <code>getObject</code> is called on an SQL structured or distinct type
  41  * that has a custom mapping; a programmer never invokes
  42  * <code>SQLInputImpl</code> methods directly. They are provided here as a
  43  * convenience for those who write <code>RowSet</code> implementations.
  44  * <P>
  45  * The <code>SQLInputImpl</code> class provides a set of
  46  * reader methods analogous to the <code>ResultSet</code> getter
  47  * methods.  These methods make it possible to read the values in an
  48  * <code>SQLInputImpl</code> object.
  49  * <P>
  50  * The method <code>wasNull</code> is used to determine whether the
  51  * the last value read was SQL <code>NULL</code>.
  52  * <P>When the method <code>getObject</code> is called with an
  53  * object of a class implementing the interface <code>SQLData</code>,
  54  * the JDBC driver calls the method <code>SQLData.getSQLType</code>
  55  * to determine the SQL type of the UDT being custom mapped. The driver
  56  * creates an instance of <code>SQLInputImpl</code>, populating it with the
  57  * attributes of the UDT.  The driver then passes the input
  58  * stream to the method <code>SQLData.readSQL</code>, which in turn
  59  * calls the <code>SQLInputImpl</code> reader methods
  60  * to read the attributes from the input stream.
  61  * @see java.sql.SQLData
  62  */
  63 public class SQLInputImpl implements SQLInput {
  64 
  65     /**
  66      * <code>true</code> if the last value returned was <code>SQL NULL</code>;
  67      * <code>false</code> otherwise.
  68      */
  69     private boolean lastValueWasNull;
  70 
  71     /**
  72      * The current index into the array of SQL structured type attributes
  73      * that will be read from this <code>SQLInputImpl</code> object and
  74      * mapped to the fields of a class in the Java programming language.
  75      */
  76     private int idx;
  77 
  78     /**
  79      * The array of attributes to be read from this stream.  The order
  80      * of the attributes is the same as the order in which they were
  81      * listed in the SQL definition of the UDT.
  82      */
  83     private Object attrib[];
  84 
  85     /**
  86      * The type map to use when the method <code>readObject</code>
  87      * is invoked. This is a <code>java.util.Map</code> object in which
  88      * there may be zero or more entries.  Each entry consists of the
  89      * fully qualified name of a UDT (the value to be mapped) and the
  90      * <code>Class</code> object for a class that implements
  91      * <code>SQLData</code> (the Java class that defines how the UDT
  92      * will be mapped).
  93      */
  94     private Map map;
  95 
  96 
  97     /**
  98      * Creates an <code>SQLInputImpl</code> object initialized with the
  99      * given array of attributes and the given type map. If any of the
 100      * attributes is a UDT whose name is in an entry in the type map,
 101      * the attribute will be mapped according to the corresponding
 102      * <code>SQLData</code> implementation.
 103      *
 104      * @param attributes an array of <code>Object</code> instances in which
 105      *        each element is an attribute of a UDT. The order of the
 106      *        attributes in the array is the same order in which
 107      *        the attributes were defined in the UDT definition.
 108      * @param map a <code>java.util.Map</code> object containing zero or more
 109      *        entries, with each entry consisting of 1) a <code>String</code>
 110      *        giving the fully
 111      *        qualified name of the UDT and 2) the <code>Class</code> object
 112      *        for the <code>SQLData</code> implementation that defines how
 113      *        the UDT is to be mapped
 114      * @throws SQLException if the <code>attributes</code> or the <code>map</code>
 115      *        is a <code>null</code> value
 116      */
 117 
 118     public SQLInputImpl(Object[] attributes, Map<String,Class<?>> map)
 119         throws SQLException
 120     {
 121         if ((attributes == null) || (map == null)) {
 122             throw new SQLException("Cannot instantiate a SQLInputImpl " +
 123             "object with null parameters");
 124         }
 125         // assign our local reference to the attribute stream
 126         attrib = attributes;
 127         // init the index point before the head of the stream
 128         idx = -1;
 129         // set the map
 130         this.map = map;
 131     }
 132 
 133 
 134     /**
 135      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 136      * as an <code>Object</code> in the Java programming language.
 137      *
 138      * @return the next value in the input stream
 139      *         as an <code>Object</code> in the Java programming language
 140      * @throws SQLException if the read position is located at an invalid
 141      *         position or if there are no further values in the stream
 142      */
 143     private Object getNextAttribute() throws SQLException {
 144         if (++idx >= attrib.length) {
 145             throw new SQLException("SQLInputImpl exception: Invalid read " +
 146                                    "position");
 147         } else {
 148             return attrib[idx];
 149         }
 150     }
 151 
 152 
 153     //================================================================
 154     // Methods for reading attributes from the stream of SQL data.
 155     // These methods correspond to the column-accessor methods of
 156     // java.sql.ResultSet.
 157     //================================================================
 158 
 159     /**
 160      * Retrieves the next attribute in this <code>SQLInputImpl</code> object as
 161      * a <code>String</code> in the Java programming language.
 162      * <p>
 163      * This method does not perform type-safe checking to determine if the
 164      * returned type is the expected type; this responsibility is delegated
 165      * to the UDT mapping as defined by a <code>SQLData</code>
 166      * implementation.
 167      * <p>
 168      * @return the next attribute in this <code>SQLInputImpl</code> object;
 169      *     if the value is <code>SQL NULL</code>, return <code>null</code>
 170      * @throws SQLException if the read position is located at an invalid
 171      *     position or if there are no further values in the stream.
 172      */
 173     public String readString() throws SQLException {
 174 
 175         String attrib = (String)getNextAttribute();
 176 
 177         if (attrib == null) {
 178             lastValueWasNull = true;
 179             return null;
 180         } else {
 181             lastValueWasNull = false;
 182             return attrib;
 183         }
 184     }
 185 
 186     /**
 187      * Retrieves the next attribute in this <code>SQLInputImpl</code> object as
 188      * a <code>boolean</code> in the Java programming language.
 189      * <p>
 190      * This method does not perform type-safe checking to determine if the
 191      * returned type is the expected type; this responsibility is delegated
 192      * to the UDT mapping as defined by a <code>SQLData</code>
 193      * implementation.
 194      * <p>
 195      * @return the next attribute in this <code>SQLInputImpl</code> object;
 196      *     if the value is <code>SQL NULL</code>, return <code>null</code>
 197      * @throws SQLException if the read position is located at an invalid
 198      *     position or if there are no further values in the stream.
 199      */
 200     public boolean readBoolean() throws SQLException {
 201 
 202         Boolean attrib = (Boolean)getNextAttribute();
 203 
 204         if (attrib == null) {
 205             lastValueWasNull = true;
 206             return false;
 207         } else {
 208             lastValueWasNull = false;
 209             return attrib.booleanValue();
 210         }
 211     }
 212 
 213     /**
 214      * Retrieves the next attribute in this <code>SQLInputImpl</code> object as
 215      * a <code>byte</code> in the Java programming language.
 216      * <p>
 217      * This method does not perform type-safe checking to determine if the
 218      * returned type is the expected type; this responsibility is delegated
 219      * to the UDT mapping as defined by a <code>SQLData</code>
 220      * implementation.
 221      * <p>
 222      * @return the next attribute in this <code>SQLInputImpl</code> object;
 223      *     if the value is <code>SQL NULL</code>, return <code>null</code>
 224      * @throws SQLException if the read position is located at an invalid
 225      *     position or if there are no further values in the stream
 226      */
 227     public byte readByte() throws SQLException {
 228         Byte attrib = (Byte)getNextAttribute();
 229 
 230         if (attrib == null) {
 231             lastValueWasNull = true;
 232             return (byte)0;
 233         } else {
 234             lastValueWasNull = false;
 235             return attrib.byteValue();
 236         }
 237     }
 238 
 239     /**
 240      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 241      * as a <code>short</code> in the Java programming language.
 242      * <P>
 243      * This method does not perform type-safe checking to determine if the
 244      * returned type is the expected type; this responsibility is delegated
 245      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 246      * <P>
 247      * @return the next attribute in this <code>SQLInputImpl</code> object;
 248      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 249      * @throws SQLException if the read position is located at an invalid
 250      *       position or if there are no more values in the stream
 251      */
 252     public short readShort() throws SQLException {
 253         Short attrib = (Short)getNextAttribute();
 254 
 255         if (attrib == null) {
 256             lastValueWasNull = true;
 257             return (short)0;
 258         } else {
 259             lastValueWasNull = false;
 260             return attrib.shortValue();
 261         }
 262     }
 263 
 264     /**
 265      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 266      * as an <code>int</code> in the Java programming language.
 267      * <P>
 268      * This method does not perform type-safe checking to determine if the
 269      * returned type is the expected type; this responsibility is delegated
 270      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 271      * <P>
 272      * @return the next attribute in this <code>SQLInputImpl</code> object;
 273      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 274      * @throws SQLException if the read position is located at an invalid
 275      *       position or if there are no more values in the stream
 276      */
 277     public int readInt() throws SQLException {
 278         Integer attrib = (Integer)getNextAttribute();
 279 
 280         if (attrib == null) {
 281             lastValueWasNull = true;
 282             return (int)0;
 283         } else {
 284             lastValueWasNull = false;
 285             return attrib.intValue();
 286         }
 287     }
 288 
 289     /**
 290      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 291      * as a <code>long</code> in the Java programming language.
 292      * <P>
 293      * This method does not perform type-safe checking to determine if the
 294      * returned type is the expected type; this responsibility is delegated
 295      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 296      * <P>
 297      * @return the next attribute in this <code>SQLInputImpl</code> object;
 298      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 299      * @throws SQLException if the read position is located at an invalid
 300      *       position or if there are no more values in the stream
 301      */
 302     public long readLong() throws SQLException {
 303         Long attrib = (Long)getNextAttribute();
 304 
 305         if (attrib == null) {
 306             lastValueWasNull = true;
 307             return (long)0;
 308         } else {
 309             lastValueWasNull = false;
 310             return attrib.longValue();
 311         }
 312     }
 313 
 314     /**
 315      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 316      * as a <code>float</code> in the Java programming language.
 317      * <P>
 318      * This method does not perform type-safe checking to determine if the
 319      * returned type is the expected type; this responsibility is delegated
 320      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 321      * <P>
 322      * @return the next attribute in this <code>SQLInputImpl</code> object;
 323      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 324      * @throws SQLException if the read position is located at an invalid
 325      *       position or if there are no more values in the stream
 326      */
 327     public float readFloat() throws SQLException {
 328         Float attrib = (Float)getNextAttribute();
 329 
 330         if (attrib == null) {
 331             lastValueWasNull = true;
 332             return (float)0;
 333         } else {
 334             lastValueWasNull = false;
 335             return attrib.floatValue();
 336         }
 337     }
 338 
 339     /**
 340      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 341      * as a <code>double</code> in the Java programming language.
 342      * <P>
 343      * This method does not perform type-safe checking to determine if the
 344      * returned type is the expected type; this responsibility is delegated
 345      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 346      * <P>
 347      * @return the next attribute in this <code>SQLInputImpl</code> object;
 348      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 349      * @throws SQLException if the read position is located at an invalid
 350      *       position or if there are no more values in the stream
 351      */
 352     public double readDouble() throws SQLException {
 353         Double attrib = (Double)getNextAttribute();
 354 
 355         if (attrib == null) {
 356             lastValueWasNull = true;
 357             return (double)0;
 358         } else {
 359             lastValueWasNull = false;
 360             return attrib.doubleValue();
 361         }
 362     }
 363 
 364     /**
 365      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 366      * as a <code>java.math.BigDecimal</code>.
 367      * <P>
 368      * This method does not perform type-safe checking to determine if the
 369      * returned type is the expected type; this responsibility is delegated
 370      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 371      * <P>
 372      * @return the next attribute in this <code>SQLInputImpl</code> object;
 373      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 374      * @throws SQLException if the read position is located at an invalid
 375      *       position or if there are no more values in the stream
 376      */
 377     public java.math.BigDecimal readBigDecimal() throws SQLException {
 378         java.math.BigDecimal attrib = (java.math.BigDecimal)getNextAttribute();
 379 
 380         if (attrib == null) {
 381             lastValueWasNull = true;
 382             return null;
 383         } else {
 384             lastValueWasNull = false;
 385             return attrib;
 386         }
 387     }
 388 
 389     /**
 390      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 391      * as an array of bytes.
 392      * <p>
 393      * This method does not perform type-safe checking to determine if the
 394      * returned type is the expected type; this responsibility is delegated
 395      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 396      * <P>
 397      * @return the next attribute in this <code>SQLInputImpl</code> object;
 398      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 399      * @throws SQLException if the read position is located at an invalid
 400      *       position or if there are no more values in the stream
 401      */
 402     public byte[] readBytes() throws SQLException {
 403         byte[] attrib = (byte[])getNextAttribute();
 404 
 405         if (attrib == null) {
 406             lastValueWasNull = true;
 407             return null;
 408         } else {
 409             lastValueWasNull = false;
 410             return attrib;
 411         }
 412     }
 413 
 414     /**
 415      * Retrieves the next attribute in this <code>SQLInputImpl</code> as
 416      * a <code>java.sql.Date</code> object.
 417      * <P>
 418      * This method does not perform type-safe checking to determine if the
 419      * returned type is the expected type; this responsibility is delegated
 420      * to the UDT mapping as defined by a <code>SQLData</code> implementation.
 421      * <P>
 422      * @return the next attribute in this <code>SQLInputImpl</code> object;
 423      *       if the value is <code>SQL NULL</code>, return <code>null</code>
 424      * @throws SQLException if the read position is located at an invalid
 425      *       position or if there are no more values in the stream
 426      */
 427     public java.sql.Date readDate() throws SQLException {
 428         java.sql.Date attrib = (java.sql.Date)getNextAttribute();
 429 
 430         if (attrib == null) {
 431             lastValueWasNull = true;
 432             return null;
 433         } else {
 434             lastValueWasNull = false;
 435             return attrib;
 436         }
 437     }
 438 
 439     /**
 440      * Retrieves the next attribute in this <code>SQLInputImpl</code> object as
 441      * a <code>java.sql.Time</code> object.
 442      * <P>
 443      * This method does not perform type-safe checking to determine if the
 444      * returned type is the expected type as this responsibility is delegated
 445      * to the UDT mapping as implemented by a <code>SQLData</code>
 446      * implementation.
 447      *
 448      * @return the attribute; if the value is <code>SQL NULL</code>, return
 449      * <code>null</code>
 450      * @throws SQLException if the read position is located at an invalid
 451      * position; or if there are no further values in the stream.
 452      */
 453     public java.sql.Time readTime() throws SQLException {
 454         java.sql.Time attrib = (java.sql.Time)getNextAttribute();
 455 
 456         if (attrib == null) {
 457             lastValueWasNull = true;
 458             return null;
 459         } else {
 460             lastValueWasNull = false;
 461             return attrib;
 462         }
 463     }
 464 
 465     /**
 466      * Retrieves the next attribute in this <code>SQLInputImpl</code> object as
 467      * a <code>java.sql.Timestamp</code> object.
 468      *
 469      * @return the attribute; if the value is <code>SQL NULL</code>, return
 470      * <code>null</code>
 471      * @throws SQLException if the read position is located at an invalid
 472      * position; or if there are no further values in the stream.
 473      */
 474     public java.sql.Timestamp readTimestamp() throws SQLException {
 475         java.sql.Timestamp attrib = (java.sql.Timestamp)getNextAttribute();
 476 
 477         if (attrib == null) {
 478             lastValueWasNull = true;
 479             return null;
 480         } else {
 481             lastValueWasNull = false;
 482             return attrib;
 483         }
 484     }
 485 
 486     /**
 487      * Retrieves the next attribute in this <code>SQLInputImpl</code> object
 488      * as a stream of Unicode characters.
 489      * <P>
 490      * This method does not perform type-safe checking to determine if the
 491      * returned type is the expected type as this responsibility is delegated
 492      * to the UDT mapping as implemented by a <code>SQLData</code>
 493      * implementation.
 494      *
 495      * @return the attribute; if the value is <code>SQL NULL</code>, return <code>null</code>
 496      * @throws SQLException if the read position is located at an invalid
 497      * position; or if there are no further values in the stream.
 498      */
 499     public java.io.Reader readCharacterStream() throws SQLException {
 500         java.io.Reader attrib = (java.io.Reader)getNextAttribute();
 501 
 502         if (attrib == null) {
 503             lastValueWasNull = true;
 504             return null;
 505         } else {
 506             lastValueWasNull = false;
 507             return attrib;
 508         }
 509     }
 510 
 511     /**
 512      * Returns the next attribute in this <code>SQLInputImpl</code> object
 513      * as a stream of ASCII characters.
 514      * <P>
 515      * This method does not perform type-safe checking to determine if the
 516      * returned type is the expected type as this responsibility is delegated
 517      * to the UDT mapping as implemented by a <code>SQLData</code>
 518      * implementation.
 519      *
 520      * @return the attribute; if the value is <code>SQL NULL</code>,
 521      * return <code>null</code>
 522      * @throws SQLException if the read position is located at an invalid
 523      * position; or if there are no further values in the stream.
 524      */
 525     public java.io.InputStream readAsciiStream() throws SQLException {
 526         java.io.InputStream attrib = (java.io.InputStream)getNextAttribute();
 527 
 528         if (attrib == null) {
 529             lastValueWasNull = true;
 530             return null;
 531         } else {
 532             lastValueWasNull = false;
 533             return attrib;
 534         }
 535     }
 536 
 537     /**
 538      * Returns the next attribute in this <code>SQLInputImpl</code> object
 539      * as a stream of uninterpreted bytes.
 540      * <P>
 541      * This method does not perform type-safe checking to determine if the
 542      * returned type is the expected type as this responsibility is delegated
 543      * to the UDT mapping as implemented by a <code>SQLData</code>
 544      * implementation.
 545      *
 546      * @return the attribute; if the value is <code>SQL NULL</code>, return
 547      * <code>null</code>
 548      * @throws SQLException if the read position is located at an invalid
 549      * position; or if there are no further values in the stream.
 550      */
 551     public java.io.InputStream readBinaryStream() throws SQLException {
 552         java.io.InputStream attrib = (java.io.InputStream)getNextAttribute();
 553 
 554         if (attrib == null) {
 555             lastValueWasNull = true;
 556             return null;
 557         } else {
 558             lastValueWasNull = false;
 559             return attrib;
 560         }
 561     }
 562 
 563     //================================================================
 564     // Methods for reading items of SQL user-defined types from the stream.
 565     //================================================================
 566 
 567     /**
 568      * Retrieves the value at the head of this <code>SQLInputImpl</code>
 569      * object as an <code>Object</code> in the Java programming language.  The
 570      * actual type of the object returned is determined by the default
 571      * mapping of SQL types to types in the Java programming language unless
 572      * there is a custom mapping, in which case the type of the object
 573      * returned is determined by this stream's type map.
 574      * <P>
 575      * The JDBC technology-enabled driver registers a type map with the stream
 576      * before passing the stream to the application.
 577      * <P>
 578      * When the datum at the head of the stream is an SQL <code>NULL</code>,
 579      * this method returns <code>null</code>.  If the datum is an SQL
 580      * structured or distinct type with a custom mapping, this method
 581      * determines the SQL type of the datum at the head of the stream,
 582      * constructs an object of the appropriate class, and calls the method
 583      * <code>SQLData.readSQL</code> on that object. The <code>readSQL</code>
 584      * method then calls the appropriate <code>SQLInputImpl.readXXX</code>
 585      * methods to retrieve the attribute values from the stream.
 586      *
 587      * @return the value at the head of the stream as an <code>Object</code>
 588      *         in the Java programming language; <code>null</code> if
 589      *         the value is SQL <code>NULL</code>
 590      * @throws SQLException if the read position is located at an invalid
 591      * position; or if there are no further values in the stream.
 592      */
 593     public Object readObject() throws SQLException {
 594         Object attrib = (Object)getNextAttribute();
 595 
 596         if (attrib == null) {
 597             lastValueWasNull = true;
 598             return null;
 599         } else {
 600             lastValueWasNull = false;
 601             if (attrib instanceof Struct) {
 602                 Struct s = (Struct)attrib;
 603                 // look up the class in the map
 604                 Class c = (Class)map.get(s.getSQLTypeName());
 605                 if (c != null) {
 606                     // create new instance of the class
 607                     SQLData obj = null;
 608                     try {
 609                         obj = (SQLData)c.newInstance();
 610                     } catch (java.lang.InstantiationException ex) {
 611                         throw new SQLException("Unable to instantiate: " +
 612                                                ex.getMessage());
 613                     } catch (java.lang.IllegalAccessException ex) {
 614                         throw new SQLException("Unable to instantiate: " +
 615                                                ex.getMessage());
 616                     }
 617                     // get the attributes from the struct
 618                     Object attribs[] = s.getAttributes(map);
 619                     // create the SQLInput "stream"
 620                     SQLInputImpl sqlInput = new SQLInputImpl(attribs, map);
 621                     // read the values...
 622                     obj.readSQL(sqlInput, s.getSQLTypeName());
 623                     return (Object)obj;
 624                 }
 625             }
 626             return (Object)attrib;
 627         }
 628     }
 629 
 630     /**
 631      * Retrieves the value at the head of this <code>SQLInputImpl</code> object
 632      * as a <code>Ref</code> object in the Java programming language.
 633      *
 634      * @return a <code>Ref</code> object representing the SQL
 635      *         <code>REF</code> value at the head of the stream; if the value
 636      *         is <code>SQL NULL</code> return <code>null</code>
 637      * @throws SQLException if the read position is located at an invalid
 638      *         position; or if there are no further values in the stream.
 639      */
 640     public Ref readRef() throws SQLException {
 641         Ref attrib = (Ref)getNextAttribute();
 642 
 643         if (attrib == null) {
 644             lastValueWasNull = true;
 645             return null;
 646         } else {
 647             lastValueWasNull = false;
 648             return attrib;
 649         }
 650     }
 651 
 652     /**
 653      * Retrieves the <code>BLOB</code> value at the head of this
 654      * <code>SQLInputImpl</code> object as a <code>Blob</code> object
 655      * in the Java programming language.
 656      * <P>
 657      * This method does not perform type-safe checking to determine if the
 658      * returned type is the expected type as this responsibility is delegated
 659      * to the UDT mapping as implemented by a <code>SQLData</code>
 660      * implementation.
 661      *
 662      * @return a <code>Blob</code> object representing the SQL
 663      *         <code>BLOB</code> value at the head of this stream;
 664      *         if the value is <code>SQL NULL</code>, return
 665      *         <code>null</code>
 666      * @throws SQLException if the read position is located at an invalid
 667      * position; or if there are no further values in the stream.
 668      */
 669     public Blob readBlob() throws SQLException {
 670         Blob attrib = (Blob)getNextAttribute();
 671 
 672         if (attrib == null) {
 673             lastValueWasNull = true;
 674             return null;
 675         } else {
 676             lastValueWasNull = false;
 677             return attrib;
 678         }
 679     }
 680 
 681     /**
 682      * Retrieves the <code>CLOB</code> value at the head of this
 683      * <code>SQLInputImpl</code> object as a <code>Clob</code> object
 684      * in the Java programming language.
 685      * <P>
 686      * This method does not perform type-safe checking to determine if the
 687      * returned type is the expected type as this responsibility is delegated
 688      * to the UDT mapping as implemented by a <code>SQLData</code>
 689      * implementation.
 690      *
 691      * @return a <code>Clob</code> object representing the SQL
 692      *         <code>CLOB</code> value at the head of the stream;
 693      *         if the value is <code>SQL NULL</code>, return
 694      *         <code>null</code>
 695      * @throws SQLException if the read position is located at an invalid
 696      * position; or if there are no further values in the stream.
 697      */
 698     public Clob readClob() throws SQLException {
 699 
 700         Clob attrib = (Clob)getNextAttribute();
 701         if (attrib == null) {
 702             lastValueWasNull = true;
 703             return null;
 704         } else {
 705             lastValueWasNull = false;
 706             return attrib;
 707         }
 708     }
 709 
 710     /**
 711      * Reads an SQL <code>ARRAY</code> value from the stream and
 712      * returns it as an <code>Array</code> object in the Java programming
 713      * language.
 714      * <P>
 715      * This method does not perform type-safe checking to determine if the
 716      * returned type is the expected type as this responsibility is delegated
 717      * to the UDT mapping as implemented by a <code>SQLData</code>
 718      * implementation.
 719      *
 720      * @return an <code>Array</code> object representing the SQL
 721      *         <code>ARRAY</code> value at the head of the stream; *
 722      *         if the value is <code>SQL NULL</code>, return
 723      *         <code>null</code>
 724      * @throws SQLException if the read position is located at an invalid
 725      * position; or if there are no further values in the stream.
 726 
 727      */
 728     public Array readArray() throws SQLException {
 729         Array attrib = (Array)getNextAttribute();
 730 
 731         if (attrib == null) {
 732             lastValueWasNull = true;
 733             return null;
 734         } else {
 735             lastValueWasNull = false;
 736             return attrib;
 737         }
 738     }
 739 
 740     /**
 741      * Ascertains whether the last value read from this
 742      * <code>SQLInputImpl</code> object was <code>null</code>.
 743      *
 744      * @return <code>true</code> if the SQL value read most recently was
 745      *         <code>null</code>; otherwise, <code>false</code>; by default it
 746      *         will return false
 747      * @throws SQLException if an error occurs determining the last value
 748      *         read was a <code>null</code> value or not;
 749      */
 750     public boolean wasNull() throws SQLException {
 751         return lastValueWasNull;
 752     }
 753 
 754     /**
 755      * Reads an SQL <code>DATALINK</code> value from the stream and
 756      * returns it as an <code>URL</code> object in the Java programming
 757      * language.
 758      * <P>
 759      * This method does not perform type-safe checking to determine if the
 760      * returned type is the expected type as this responsibility is delegated
 761      * to the UDT mapping as implemented by a <code>SQLData</code>
 762      * implementation.
 763      *
 764      * @return an <code>URL</code> object representing the SQL
 765      *         <code>DATALINK</code> value at the head of the stream; *
 766      *         if the value is <code>SQL NULL</code>, return
 767      *         <code>null</code>
 768      * @throws SQLException if the read position is located at an invalid
 769      * position; or if there are no further values in the stream.
 770      */
 771     public java.net.URL readURL() throws SQLException {
 772         throw new SQLException("Operation not supported");
 773     }
 774 
 775     //---------------------------- JDBC 4.0 -------------------------
 776 
 777     /**
 778      * Reads an SQL <code>NCLOB</code> value from the stream and returns it as a
 779      * <code>Clob</code> object in the Java programming language.
 780      *
 781      * @return a <code>NClob</code> object representing data of the SQL <code>NCLOB</code> value
 782      * at the head of the stream; <code>null</code> if the value read is
 783      * SQL <code>NULL</code>
 784      * @exception SQLException if a database access error occurs
 785      */
 786      public NClob readNClob() throws SQLException {
 787         throw new UnsupportedOperationException("Operation not supported");
 788     }
 789 
 790     /**
 791      * Reads the next attribute in the stream and returns it as a <code>String</code>
 792      * in the Java programming language. It is intended for use when
 793      * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
 794      * and <code>LONGNVARCHAR</code> columns.
 795      *
 796      * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
 797      * @exception SQLException if a database access error occurs
 798      */
 799     public String readNString() throws SQLException {
 800         throw new UnsupportedOperationException("Operation not supported");
 801     }
 802 
 803     /**
 804      * Reads an SQL <code>XML</code> value from the stream and returns it as a
 805      * <code>SQLXML</code> object in the Java programming language.
 806      *
 807      * @return a <code>SQLXML</code> object representing data of the SQL <code>XML</code> value
 808      * at the head of the stream; <code>null</code> if the value read is
 809      * SQL <code>NULL</code>
 810      * @exception SQLException if a database access error occurs
 811      */
 812     public SQLXML readSQLXML() throws SQLException {
 813         throw new UnsupportedOperationException("Operation not supported");
 814     }
 815 
 816      /**
 817      * Reads an SQL <code>ROWID</code> value from the stream and returns it as a
 818      * <code>RowId</code> object in the Java programming language.
 819      *
 820      * @return a <code>RowId</code> object representing data of the SQL <code>ROWID</code> value
 821      * at the head of the stream; <code>null</code> if the value read is
 822      * SQL <code>NULL</code>
 823      * @exception SQLException if a database access error occurs
 824      */
 825     public RowId readRowId() throws SQLException {
 826         throw new UnsupportedOperationException("Operation not supported");
 827     }
 828 
 829 
 830 }