All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.SimpleInputStream Maven / Gradle / Ivy

There is a newer version: 12.8.1.jre11
Show newest version
//---------------------------------------------------------------------------------------------------------------------------------
// File: SimpleInputStream.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 

package com.microsoft.sqlserver.jdbc;

import java.io.*;

/**
* SimpleInputStream is an InputStream implementation that reads from TDS.
* 
* This class is to support adaptive streaming of non plp aka simple byte types char, byte etc.
*   
*/
abstract class BaseInputStream extends InputStream
{
    abstract byte[] getBytes() throws SQLServerException;

    // Flag indicating whether the stream conforms to adaptive response buffering API restrictions
    final boolean isAdaptive;

    // Flag indicating whether the stream consumes and discards data as it reads it
    final boolean isStreaming;

    /** Generate the  logging ID */
    private String parentLoggingInfo = "";
    private static int lastLoggingID = 0;
    private synchronized static int nextLoggingID() { return ++lastLoggingID; }
    static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.InputStream");;
    private String traceID;
    final public String toString() 
    { 
        if(traceID== null)
            traceID = getClass().getName() + "ID:" + nextLoggingID();     
        return traceID; 
   }
    final void setLoggingInfo( String info)
    { 
        parentLoggingInfo = info;
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString());
    }

    
    int streamPos  = 0;
    int markedStreamPos=0;        
    TDSReaderMark currentMark;
    private ServerDTVImpl dtv;
    TDSReader tdsReader;
    int readLimit=0;
    boolean isReadLimitSet = false;

    BaseInputStream(TDSReader tdsReader, boolean isAdaptive, boolean isStreaming, ServerDTVImpl dtv)
    {
        this.tdsReader = tdsReader;
        this.isAdaptive = isAdaptive;
        this.isStreaming = isStreaming;

        if(isAdaptive)
            clearCurrentMark();
        else
            currentMark = tdsReader.mark();
        this.dtv = dtv;
    }
    
    final void clearCurrentMark()
    {
        currentMark = null;
        isReadLimitSet = false;
        if (isAdaptive && isStreaming)
            tdsReader.stream();
    }

    void closeHelper() throws IOException
    {
        if(isAdaptive && null !=dtv )
        {
            if(logger.isLoggable(java.util.logging.Level.FINER))
                logger.finer(toString() +" closing the adaptive stream.");    
            dtv.setPositionAfterStreamed(tdsReader);
         }
        currentMark = null;
        tdsReader = null;
        dtv=null;
    }

    /**
    * Verifies stream is open and throws IOException if otherwise.
    */		
    final void checkClosed() throws IOException
    {
        if (null==tdsReader)
            throw new IOException(SQLServerException.getErrString("R_streamIsClosed"));
    }

    /**
    *  Tests if this input stream supports the mark and reset methods.
    * @return true if mark and reset are supported.
    */	
    public boolean markSupported() 
    {
        return true;
    }

    void setReadLimit(int readLimit)
    {
        // we buffer the whole stream in the full case so readlimit is meaningless.
        // spec does not say what to do with -ve values.
        if(isAdaptive && readLimit>0)
        {
            this.readLimit =readLimit;
            isReadLimitSet = true;
        }
    }
    /**
    * Resets stream to saved mark position. 
    * @exception IOException if an I/O error occurs.
    */	
    void resetHelper() throws IOException
    {	
        checkClosed();
        // if no mark set already throw
        if(null == currentMark)
            throw new IOException(SQLServerException.getErrString("R_streamWasNotMarkedBefore"));
        tdsReader.reset(currentMark);   
    }
}


final class SimpleInputStream extends BaseInputStream 
{

    // Stated length of the  payload
    private final int payloadLength;

    /**
    * Initializes the input stream.
    */	
    SimpleInputStream(TDSReader tdsReader, int payLoadLength, InputStreamGetterArgs getterArgs, ServerDTVImpl dtv) throws SQLServerException
    {
        super(tdsReader, getterArgs.isAdaptive, getterArgs.isStreaming, dtv);
        setLoggingInfo(getterArgs.logContext);
        this.payloadLength = payLoadLength;
    }

    
    /**
    * Closes the stream releasing all resources held.
    */	
    public  void close() throws IOException
    {
        if(null == tdsReader)
            return;
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() +"Enter Closing SimpleInputStream.");
        
        // Discard the remainder of the stream, positioning the TDSReader
        // at the next item in the TDS response.  Once the stream is closed,
        // it can no longer access the discarded response data.
        skip(payloadLength - streamPos);

        closeHelper();
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() +"Exit Closing SimpleInputStream.");
    }
    
    /**
    * Checks if we have EOS state.
    */
    private final  boolean isEOS() throws IOException
    {
        assert streamPos<=payloadLength;
        return (streamPos==payloadLength);
    }

    // java.io.InputStream interface methods.

    /**
     * Skips over and discards n bytes of data from this input stream.
     * @param n the number of bytes to be skipped. 
     * @return the actual number of bytes skipped. 
     * @exception IOException if an I/O error occurs.
     */
    public long skip(long n) throws IOException
    {
        checkClosed();
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() +" Skipping :" + n);
        if (n < 0) return 0L;
        if (isEOS()) return 0;

        int skipAmount;  
        if (streamPos+n > payloadLength)
        {
            skipAmount = payloadLength-streamPos;
        }
        else
        {
            skipAmount = (int) n;
        }
        try
        {
            tdsReader.skip(skipAmount);
        }
        catch (SQLServerException e)
        {
            throw new IOException(e.getMessage());
        }
        streamPos+=skipAmount;
        if(isReadLimitSet && ((streamPos - markedStreamPos) > readLimit))
            clearCurrentMark();

        return skipAmount;

    }
    /**
    * Returns the number of bytes that can be read (or skipped over) from this 
    * input stream without blocking by the next caller of a method for 
    * this input stream.
    * @return the actual number of bytes available. 
    * @exception IOException if an I/O error occurs.
    */	
    public int available() throws IOException 
    {
        checkClosed();
        assert streamPos<=payloadLength;

        int available = payloadLength-streamPos;
        if (tdsReader.available()< available)
            available = tdsReader.available();
        return available;
    }

    private byte [] bSingleByte;
    /**
    * Reads the next byte of data from the input stream.
    * @return the byte read or -1 meaning no more bytes. 
    * @exception IOException if an I/O error occurs.
    */	
    public int read() throws IOException 
    {
        checkClosed();
        if(null == bSingleByte)
            bSingleByte = new byte[1];
        if (isEOS()) return -1;
        int bytesRead = read(bSingleByte,0,1);
        return (0==bytesRead) ? -1 : (bSingleByte[0]&0xFF);
    }

    /**
    * Reads available data into supplied byte array.
    * @param b array of bytes to fill.
    * @return the number of bytes read or -1 meaning no bytes read. 
    * @exception IOException if an I/O error occurs.
    */
    public int read(byte[] b) throws IOException
    {
        checkClosed();
        return read(b,0,b.length);
    }

    /**
    * Reads available data into supplied byte array.
    * @param b array of bytes to fill.
    * @param offset the offset into array b where to start writing.
    * @param maxBytes the max number of bytes to write into b.
    * @return the number of bytes read or -1 meaning no bytes read. 
    * @exception IOException if an I/O error occurs.
    */
    public int read(byte b[], int offset, int maxBytes) throws IOException
    {	
        checkClosed();
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() +" Reading " + maxBytes + " from stream offset " + streamPos + " payload length " + payloadLength);

        if (offset < 0 || maxBytes < 0 || offset + maxBytes > b.length)
            throw new IndexOutOfBoundsException();

        if (0 == maxBytes ) return 0;
        if (isEOS()) return -1;
                
        int readAmount=0;
        if (streamPos+maxBytes> payloadLength)
        {
            readAmount = payloadLength-streamPos;
        }
        else
        {
            readAmount = maxBytes;
        }

        try
        {
            tdsReader.readBytes(b, offset, readAmount);
        }
        catch (SQLServerException e)
        {
            throw new IOException(e.getMessage());
        }
        streamPos += readAmount;
        
        if(isReadLimitSet && ((streamPos - markedStreamPos) > readLimit))
            clearCurrentMark();

        return readAmount;
    }

    /**
    * Marks the current position in this input stream.
    * @param readLimit the number of bytes to hold
    */	
    public void mark(int readLimit) 
    {
        if(null != tdsReader && readLimit >0)
        {
            currentMark = tdsReader.mark();
            markedStreamPos = streamPos;
            setReadLimit(readLimit);
        }
    }
    
    /**
    * Resets stream to saved mark position. 
    * @exception IOException if an I/O error occurs.
    */	
    public void reset() throws IOException
    {	
        resetHelper();
        streamPos = markedStreamPos;
    }

    /**
    * Helper function to convert the entire PLP stream into a contiguous byte array.
    * This call is inefficient (in terms of memory usage and run time) for
    * very large PLPs.  Use it only if a contiguous byte array is required.
    */
    final byte[] getBytes() throws SQLServerException
    {
        // We should always retrieve the entire stream, and only once.
        assert 0 == streamPos;

        byte[] value = new byte[payloadLength];
        try 
        {
            read(value);
            close();
        }
        catch (IOException e)
        {
            SQLServerException.makeFromDriverError(
                null,
                null, 
                e.getMessage(),
                null,
                true);
        }

        
        return value;
    }


}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy