LargeObject.java 7.82 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
package postgresql.largeobject;

import java.io.*;
import java.lang.*;
import java.net.*;
import java.util.*;
import java.sql.*;

import postgresql.fastpath.*;

/**
 * This class implements the large object interface to postgresql.
 *
 * <p>It provides the basic methods required to run the interface, plus
 * a pair of methods that provide InputStream and OutputStream classes
 * for this object.
 *
 * <p>Normally, client code would use the getAsciiStream, getBinaryStream,
 * or getUnicodeStream methods in ResultSet, or setAsciiStream, 
 * setBinaryStream, or setUnicodeStream methods in PreparedStatement to
 * access Large Objects.
 *
 * <p>However, sometimes lower level access to Large Objects are required,
 * that are not supported by the JDBC specification.
 *
 * <p>Refer to postgresql.largeobject.LargeObjectManager on how to gain access
 * to a Large Object, or how to create one.
 *
 * @see postgresql.largeobject.LargeObjectManager
 * @see postgresql.ResultSet#getAsciiStream
 * @see postgresql.ResultSet#getBinaryStream
 * @see postgresql.ResultSet#getUnicodeStream
 * @see postgresql.PreparedStatement#setAsciiStream
 * @see postgresql.PreparedStatement#setBinaryStream
 * @see postgresql.PreparedStatement#setUnicodeStream
 * @see java.sql.ResultSet#getAsciiStream
 * @see java.sql.ResultSet#getBinaryStream
 * @see java.sql.ResultSet#getUnicodeStream
 * @see java.sql.PreparedStatement#setAsciiStream
 * @see java.sql.PreparedStatement#setBinaryStream
 * @see java.sql.PreparedStatement#setUnicodeStream
 *
 */
public class LargeObject
{
  /**
   * Indicates a seek from the begining of a file
   */
  public static final int SEEK_SET = 0;
  
  /**
   * Indicates a seek from the current position
   */
  public static final int SEEK_CUR = 1;
  
  /**
   * Indicates a seek from the end of a file
   */
  public static final int SEEK_END = 2;
  
  private Fastpath	fp;	// Fastpath API to use
  private int		oid;	// OID of this object
  private int		fd;	// the descriptor of the open large object
  
  /**
   * This opens a large object.
   *
   * <p>If the object does not exist, then an SQLException is thrown.
   *
   * @param fp FastPath API for the connection to use
   * @param oid of the Large Object to open
   * @param mode Mode of opening the large object
   * (defined in LargeObjectManager)
   * @exception SQLException if a database-access error occurs.
   * @see postgresql.largeobject.LargeObjectManager
   */
  protected LargeObject(Fastpath fp,int oid,int mode) throws SQLException
  {
    this.fp = fp;
    this.oid = oid;
    
    FastpathArg args[] = new FastpathArg[2];
    args[0] = new FastpathArg(oid);
    args[1] = new FastpathArg(mode);
    this.fd = fp.getInteger("lo_open",args);
  }
  
  /**
   * @return the OID of this LargeObject
   */
  public int getOID()
  {
    return oid;
  }
  
  /**
   * This method closes the object. You must not call methods in this
   * object after this is called.
   * @exception SQLException if a database-access error occurs.
   */
  public void close() throws SQLException
  {
    FastpathArg args[] = new FastpathArg[1];
    args[0] = new FastpathArg(fd);
    fp.fastpath("lo_close",false,args); // true here as we dont care!!
  }
  
  /**
   * Reads some data from the object, and return as a byte[] array
   *
   * @param len number of bytes to read
   * @return byte[] array containing data read
   * @exception SQLException if a database-access error occurs.
   */
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    public byte[] read(int len) throws SQLException
    {
	// This is the original method, where the entire block (len bytes)
	// is retrieved in one go.
	FastpathArg args[] = new FastpathArg[2];
	args[0] = new FastpathArg(fd);
	args[1] = new FastpathArg(len);
	return fp.getData("loread",args);
	
	// This version allows us to break this down into 4k blocks
	//if(len<=4048) {
	//// handle as before, return the whole block in one go
	//FastpathArg args[] = new FastpathArg[2];
	//args[0] = new FastpathArg(fd);
	//args[1] = new FastpathArg(len);
	//return fp.getData("loread",args);
	//} else {
	//// return in 4k blocks
	//byte[] buf=new byte[len];
	//int off=0;
	//while(len>0) {
	//int bs=4048;
	//len-=bs;
	//if(len<0) {
	//bs+=len;
	//len=0;
	//}
	//read(buf,off,bs);
	//off+=bs;
	//}
	//return buf;
	//}
    }
    
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
  /**
   * Reads some data from the object into an existing array
   *
   * @param buf destination array
   * @param off offset within array
   * @param len number of bytes to read
   * @exception SQLException if a database-access error occurs.
   */
  public void read(byte buf[],int off,int len) throws SQLException
  {
    System.arraycopy(read(len),0,buf,off,len);
  }
  
  /**
   * Writes an array to the object
   *
   * @param buf array to write
   * @exception SQLException if a database-access error occurs.
   */
  public void write(byte buf[]) throws SQLException
  {
    FastpathArg args[] = new FastpathArg[2];
    args[0] = new FastpathArg(fd);
    args[1] = new FastpathArg(buf);
    fp.fastpath("lowrite",false,args);
  }
  
  /**
   * Writes some data from an array to the object
   *
   * @param buf destination array
   * @param off offset within array
   * @param len number of bytes to write
   * @exception SQLException if a database-access error occurs.
   */
  public void write(byte buf[],int off,int len) throws SQLException
  {
    byte data[] = new byte[len];
    System.arraycopy(buf,off,data,0,len);
    write(data);
  }
  
  /**
   * Sets the current position within the object.
   *
   * <p>This is similar to the fseek() call in the standard C library. It
   * allows you to have random access to the large object.
   *
   * @param pos position within object
   * @param ref Either SEEK_SET, SEEK_CUR or SEEK_END
   * @exception SQLException if a database-access error occurs.
   */
  public void seek(int pos,int ref) throws SQLException
  {
    FastpathArg args[] = new FastpathArg[3];
    args[0] = new FastpathArg(fd);
    args[1] = new FastpathArg(pos);
    args[2] = new FastpathArg(ref);
    fp.fastpath("lo_lseek",false,args);
  }
  
  /**
   * Sets the current position within the object.
   *
   * <p>This is similar to the fseek() call in the standard C library. It
   * allows you to have random access to the large object.
   *
   * @param pos position within object from begining
   * @exception SQLException if a database-access error occurs.
   */
  public void seek(int pos) throws SQLException
  {
    seek(pos,SEEK_SET);
  }
  
  /**
   * @return the current position within the object
   * @exception SQLException if a database-access error occurs.
   */
  public int tell() throws SQLException
  {
    FastpathArg args[] = new FastpathArg[1];
    args[0] = new FastpathArg(fd);
    return fp.getInteger("lo_tell",args);
  }
  
  /**
   * This method is inefficient, as the only way to find out the size of
   * the object is to seek to the end, record the current position, then
   * return to the original position.
   *
   * <p>A better method will be found in the future.
   *
   * @return the size of the large object
   * @exception SQLException if a database-access error occurs.
   */
  public int size() throws SQLException
  {
    int cp = tell();
    seek(0,SEEK_END);
    int sz = tell();
    seek(cp,SEEK_SET);
    return sz;
  }
  
  /**
   * Returns an InputStream from this object.
   *
   * <p>This InputStream can then be used in any method that requires an
   * InputStream.
   *
   * @exception SQLException if a database-access error occurs.
   */
  public InputStream getInputStream() throws SQLException
  {
    throw new SQLException("LargeObject:getInputStream not implemented");
  }
  
  /**
   * Returns an OutputStream to this object
   *
   * <p>This OutputStream can then be used in any method that requires an
   * OutputStream.
   *
   * @exception SQLException if a database-access error occurs.
   */
  public OutputStream getOutputStream() throws SQLException
  {
    throw new SQLException("LargeObject:getOutputStream not implemented");
  }
}