Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>2004-10-01 01:36:09 +0400
committerFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>2004-10-01 01:36:09 +0400
commit0de8c14094bc7407ee47a3824cb321f21033438e (patch)
tree9f4ba661d57434af1fd97c5e1d50f81790355e31 /mcs/class/Npgsql/NpgsqlTypes
parent802e76ff671d1d8547b657c488e0d89a0fa2514e (diff)
2004-09-30 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
* NpgsqlTypes/FastPath.cs, NpgsqlTypes/FastPathArg.cs, NpgsqlTypes/LargeObject.cs, NpgsqlTypes/LargeObjectManager.cs, Npgsql.dll.sources: Added large object support. Thanks Emiliano Necciari (e dot necciari at blogic dot it) for the patch. svn path=/trunk/mcs/; revision=34575
Diffstat (limited to 'mcs/class/Npgsql/NpgsqlTypes')
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/FastPath.cs486
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs135
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs263
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs209
4 files changed, 1093 insertions, 0 deletions
diff --git a/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs b/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs
new file mode 100644
index 00000000000..e6aa2d62b2d
--- /dev/null
+++ b/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs
@@ -0,0 +1,486 @@
+/*-------------------------------------------------------------------------
+
+ Fastpath.cs
+ This class is a port of the class Fastpath.java implemented by
+ PostgreSQL Global Development Group
+
+ Copyright (c) 2004, Emiliano Necciari
+ Original Code: Copyright (c) 2003, PostgreSQL Global Development Group
+
+ Note: (Francisco Figueiredo Jr.)
+ Changed case of method names to conform to .Net names standard.
+ Also changed type names to their true names. i.e. int -> Int32
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------
+*/
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Data;
+using Npgsql;
+
+namespace NpgsqlTypes
+{
+
+
+ /*
+ * This class implements the Fastpath api.
+ *
+ *
+ *
+ */
+ public class Fastpath
+ {
+ // This maps the functions names to their id's (possible unique just
+ // to a connection).
+ protected Hashtable func = new Hashtable();
+
+ protected NpgsqlConnection conn; // our connection
+ protected Stream stream; // the network stream
+
+ /*
+ * Initialises the fastpath system
+ *
+ * @param conn BaseConnection to attach to
+ * @param stream The network stream to the backend
+ */
+ public Fastpath(NpgsqlConnection conn, Stream stream)
+ {
+ this.conn = conn;
+ this.stream = stream;
+ }
+
+
+ /*
+ * Initialises the fastpath system
+ *
+ * @param conn BaseConnection to attach to
+ * @param stream The network stream to the backend
+ */
+ public Fastpath(NpgsqlConnection conn)
+ {
+ this.conn = conn;
+ // check if the connection is closed ?
+ this.stream = conn.Connector.Stream;
+ }
+
+ /*
+ * Send a function call to the PostgreSQL backend
+ *
+ * @param fnid Function id
+ * @param resulttype True if the result is an integer, false for other results
+ * @param args FastpathArguments to pass to fastpath
+ * @return null if no data, Integer if an integer result, or byte[] otherwise
+ * @exception SQLException if a database-access error occurs.
+ */
+ public Object FastpathCall(Int32 fnid, Boolean resulttype, FastpathArg[] args)
+ {
+ if (conn.BackendProtocolVersion == ProtocolVersion.Version3)
+ {
+ return FastpathV3(fnid, resulttype, args);
+ }
+ else
+ {
+ return FastpathV2(fnid, resulttype, args);
+ }
+ }
+
+ private Object FastpathV3(Int32 fnid, Boolean resulttype, FastpathArg[] args)
+ {
+ // give thread safety
+ lock (stream)
+ {
+ // send the function call
+ try
+ {
+ Int32 l_msgLen = 0;
+ l_msgLen += 16;
+ for (Int32 i=0;i < args.Length;i++)
+ l_msgLen += args[i].SendSize();
+
+ stream.WriteByte((Byte)'F');
+ PGUtil.WriteInt32(stream,l_msgLen);
+ PGUtil.WriteInt32(stream,fnid);
+ PGUtil.WriteInt16(stream,1);
+ PGUtil.WriteInt16(stream,1);
+ PGUtil.WriteInt16(stream,(short)args.Length);
+
+ for (Int32 i = 0;i < args.Length;i++)
+ args[i].Send(stream);
+
+ PGUtil.WriteInt16(stream,1);
+
+ // This is needed, otherwise data can be lost
+ stream.Flush();
+
+ }
+ catch (Exception ex)
+ {
+ throw new Exception(ex.ToString());
+ }
+
+ // Now handle the result
+
+ // Now loop, reading the results
+ Object result = null; // our result
+ Exception error = null;
+ Int32 c;
+ Boolean l_endQuery = false;
+ Byte[] input_buffer = new Byte[512];
+
+ while (!l_endQuery)
+ {
+ c = (Char)stream.ReadByte();
+
+ switch (c)
+ {
+ case 'A': // Asynchronous Notify
+ Int32 msglen = PGUtil.ReadInt32(stream,input_buffer);
+ Int32 pid = PGUtil.ReadInt32(stream,input_buffer);
+ String msg = PGUtil.ReadString(stream,conn.Connector.Encoding);
+ PGUtil.ReadString(stream,conn.Connector.Encoding);
+ String param = PGUtil.ReadString(stream,conn.Connector.Encoding);
+
+ conn.Connector.CheckErrorsAndNotifications();
+ break;
+ //------------------------------
+ // Error message returned
+ case 'E':
+ NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion);
+ e.ReadFromStream(stream,conn.Connector.Encoding);
+ throw new Exception(e.ToString());
+
+ //------------------------------
+ // Notice from backend
+ case 'N':
+ Int32 l_nlen = PGUtil.ReadInt32(stream,input_buffer);
+
+ NpgsqlError e1 = new NpgsqlError(conn.BackendProtocolVersion);
+ e1.ReadFromStream(stream,conn.Connector.Encoding);
+ conn.Connector.Mediator.Errors.Add(e1);
+
+ break;
+
+ case 'V':
+ Int32 l_msgLen = PGUtil.ReadInt32(stream,input_buffer);
+ Int32 l_valueLen = PGUtil.ReadInt32(stream,input_buffer);
+
+ if (l_valueLen == -1)
+ {
+ //null value
+ }
+ else if (l_valueLen == 0)
+ {
+ result = new Byte[0];
+ }
+ else
+ {
+ // Return an Integer if
+ if (resulttype)
+
+ result = PGUtil.ReadInt32(stream,input_buffer);
+ else
+ {
+ Byte[] buf = new Byte[l_valueLen];
+
+ Int32 bytes_from_stream = 0;
+ Int32 total_bytes_read = 0;
+ Int32 size = l_valueLen;
+ do
+ {
+ bytes_from_stream = stream.Read(buf, total_bytes_read, size);
+ total_bytes_read += bytes_from_stream;
+ size -= bytes_from_stream;
+ }
+ while(size > 0);
+
+ result = buf;
+ }
+ }
+ break;
+
+ case 'Z':
+ //TODO: use size better
+ if (PGUtil.ReadInt32(stream,input_buffer) != 5)
+ throw new Exception("Received Z" );
+ //TODO: handle transaction status
+ Char l_tStatus = (Char)stream.ReadByte();
+ l_endQuery = true;
+ break;
+
+ default:
+ throw new Exception("postgresql.fp.protocol received " + c.ToString());
+ }
+ }
+
+ if ( error != null )
+ throw error;
+
+ return result;
+ }
+ }
+
+ private Object FastpathV2(Int32 fnid, Boolean resulttype, FastpathArg[] args)
+ {
+ // added Oct 7 1998 to give us thread safety
+ lock (stream)
+ {
+ // send the function call
+ try
+ {
+ // 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
+ // that confuses the backend. The 0 terminates the command line.
+ stream.WriteByte((Byte)70);
+ stream.WriteByte((Byte)0);
+
+ PGUtil.WriteInt32(stream,fnid);
+ PGUtil.WriteInt32(stream,args.Length);
+
+
+ for (Int32 i = 0;i < args.Length;i++)
+ args[i].Send(stream);
+
+ // This is needed, otherwise data can be lost
+ stream.Flush();
+
+ }
+ catch (IOException ioe)
+ {
+ //Should be sending exception as second arg.
+ throw new Exception("postgresql.fp.send: " + ioe.ToString());
+ }
+
+ // Now handle the result
+
+ // Now loop, reading the results
+ Object result = null; // our result
+ String errorMessage = "";
+ Byte[] input_buffer = new Byte[512];
+ Int32 c;
+ Boolean l_endQuery = false;
+ while (!l_endQuery)
+ {
+ c = (Char)stream.ReadByte();
+
+ switch (c)
+ {
+ case 'A': // Asynchronous Notify
+ //TODO: do something with this
+ Int32 pid = PGUtil.ReadInt32(stream,input_buffer);
+ String msg = PGUtil.ReadString(stream,conn.Connector.Encoding);
+
+
+ conn.Connector.CheckErrorsAndNotifications();
+
+ break;
+
+ //------------------------------
+ // Error message returned
+ case 'E':
+ NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion);
+ e.ReadFromStream(stream,conn.Connector.Encoding);
+ errorMessage += e.Message;
+ break;
+
+ //------------------------------
+ // Notice from backend
+ case 'N':
+ NpgsqlError notice = new NpgsqlError(conn.BackendProtocolVersion);
+ notice.ReadFromStream(stream,conn.Connector.Encoding);
+ errorMessage += notice.Message;
+ break;
+
+ case 'V':
+ Char l_nextChar = (Char)stream.ReadByte();
+ if (l_nextChar == 'G')
+ {
+ Int32 sz = PGUtil.ReadInt32(stream,input_buffer);
+ // Return an Integer if
+ if (resulttype)
+ result = PGUtil.ReadInt32(stream,input_buffer);
+ else
+ {
+ Byte[] buf = new Byte[sz];
+
+ Int32 bytes_from_stream = 0;
+ Int32 total_bytes_read = 0;
+ Int32 size = sz;
+ do
+ {
+ bytes_from_stream = stream.Read(buf, total_bytes_read, size);
+ total_bytes_read += bytes_from_stream;
+ size -= bytes_from_stream;
+ }
+ while(size > 0);
+
+ result = buf;
+ }
+ //There should be a trailing '0'
+ Int32 l_endChar = (Char)stream.ReadByte();
+ }
+ else
+ {
+ //it must have been a '0', thus no results
+ }
+ break;
+
+ case 'Z':
+ l_endQuery = true;
+ break;
+
+ default:
+ throw new Exception("postgresql.fp.protocol " + c.ToString());
+ }
+ }
+
+ if ( errorMessage != null )
+ throw new Exception("postgresql.fp.error" + errorMessage);
+
+ return result;
+ }
+ }
+
+ /*
+ * Send a function call to the PostgreSQL backend by name.
+ *
+ * Note: the mapping for the procedure name to function id needs to exist,
+ * usually to an earlier call to addfunction().
+ *
+ * This is the prefered method to call, as function id's can/may change
+ * between versions of the backend.
+ *
+ * For an example of how this works, refer to org.postgresql.largeobject.LargeObject
+ *
+ * @param name Function name
+ * @param resulttype True if the result is an integer, false for other
+ * results
+ * @param args FastpathArguments to pass to fastpath
+ * @return null if no data, Integer if an integer result, or byte[] otherwise
+ * @exception SQLException if name is unknown or if a database-access error
+ * occurs.
+ * @see org.postgresql.largeobject.LargeObject
+ */
+ public Object FastpathCall(String name, Boolean resulttype, FastpathArg[] args)
+ {
+ return FastpathCall(GetID(name), resulttype, args);
+ }
+
+ /*
+ * This convenience method assumes that the return value is an Integer
+ * @param name Function name
+ * @param args Function arguments
+ * @return integer result
+ * @exception SQLException if a database-access error occurs or no result
+ */
+ public Int32 GetInteger(String name, FastpathArg[] args)
+ {
+ Int32 i = (Int32)FastpathCall(name, true, args);
+
+ return i;
+ }
+
+ /*
+ * This convenience method assumes that the return value is an Integer
+ * @param name Function name
+ * @param args Function arguments
+ * @return byte[] array containing result
+ * @exception SQLException if a database-access error occurs or no result
+ */
+ public Byte[] GetData(String name, FastpathArg[] args)
+ {
+ return (Byte[])FastpathCall(name, false, args);
+ }
+
+ /*
+ * This adds a function to our lookup table.
+ *
+ * <p>User code should use the addFunctions method, which is based upon a
+ * query, rather than hard coding the oid. The oid for a function is not
+ * guaranteed to remain static, even on different servers of the same
+ * version.
+ *
+ * @param name Function name
+ * @param fnid Function id
+ */
+ public void AddFunction(String name, Int32 fnid)
+ {
+ func.Add(name, fnid);
+ }
+
+ /*
+ * This takes a ResultSet containing two columns. Column 1 contains the
+ * function name, Column 2 the oid.
+ *
+ * <p>It reads the entire ResultSet, loading the values into the function
+ * table.
+ *
+ * <p><b>REMEMBER</b> to close() the resultset after calling this!!
+ *
+ * <p><b><em>Implementation note about function name lookups:</em></b>
+ *
+ * <p>PostgreSQL stores the function id's and their corresponding names in
+ * the pg_proc table. To speed things up locally, instead of querying each
+ * function from that table when required, a Hashtable is used. Also, only
+ * the function's required are entered into this table, keeping connection
+ * times as fast as possible.
+ *
+ * <p>The org.postgresql.largeobject.LargeObject class performs a query upon it's startup,
+ * and passes the returned ResultSet to the addFunctions() method here.
+ *
+ * <p>Once this has been done, the LargeObject api refers to the functions by
+ * name.
+ *
+ * <p>Dont think that manually converting them to the oid's will work. Ok,
+ * they will for now, but they can change during development (there was some
+ * discussion about this for V7.0), so this is implemented to prevent any
+ * unwarranted headaches in the future.
+ *
+ * @param rs ResultSet
+ * @exception SQLException if a database-access error occurs.
+ * @see org.postgresql.largeobject.LargeObjectManager
+ */
+ public void AddFunctions(IDataReader rs)
+ {
+ while (rs.Read())
+ {
+ String key = (String)rs[0];
+ if( !func.ContainsKey(key ) )
+ func.Add(key, Int32.Parse(rs[1].ToString()));
+ }
+ }
+
+ /*
+ * This returns the function id associated by its name
+ *
+ * <p>If addFunction() or addFunctions() have not been called for this name,
+ * then an SQLException is thrown.
+ *
+ * @param name Function name to lookup
+ * @return Function ID for fastpath call
+ * @exception SQLException is function is unknown.
+ */
+ public Int32 GetID(String name)
+ {
+ Int32 id = (Int32)func[name];
+
+
+
+ return id;
+ }
+ }
+
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs b/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs
new file mode 100644
index 00000000000..51277265987
--- /dev/null
+++ b/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs
@@ -0,0 +1,135 @@
+/*-------------------------------------------------------------------------
+
+ FastpathArg.cs
+ This class is a port of the class FastpathArg.java implemented by
+ PostgreSQL Global Development Group
+
+ Copyright (c) 2004, Emiliano Necciari
+ Original Code: Copyright (c) 2003, PostgreSQL Global Development Group
+
+ Note: (Francisco Figueiredo Jr.)
+ Changed case of method names to conform to .Net names standard.
+ Also changed type names to their true names. i.e. int -> Int32
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------
+*/
+
+using System;
+using System.IO;
+using Npgsql;
+
+namespace NpgsqlTypes
+{
+ public class FastpathArg
+ {
+ /*
+ * Type of argument, true=integer, false=byte[]
+ */
+ public Boolean type;
+
+ /*
+ * Integer value if type=true
+ */
+ public Int32 value;
+
+ /*
+ * Byte value if type=false;
+ */
+ public Byte[] bytes;
+
+ /*
+ * Constructs an argument that consists of an integer value
+ * @param value int value to set
+ */
+ public FastpathArg(Int32 value)
+ {
+ type = true;
+ this.value = value;
+ }
+
+ /*
+ * Constructs an argument that consists of an array of bytes
+ * @param bytes array to store
+ */
+ public FastpathArg(Byte[] bytes)
+ {
+ type = false;
+ this.bytes = bytes;
+ }
+
+ /*
+ * Constructs an argument that consists of part of a byte array
+ * @param buf source array
+ * @param off offset within array
+ * @param len length of data to include
+ */
+ public FastpathArg(Byte[] buf, Int32 off, Int32 len)
+ {
+ type = false;
+ bytes = new Byte[len];
+ //TODO:
+ bytes = buf;
+ }
+
+ /*
+ * Constructs an argument that consists of a String.
+ * @param s String to store
+ */
+ public FastpathArg(String s)
+ {
+ //this(s.ToCharArray());
+ }
+
+ /*
+ * This sends this argument down the network stream.
+ *
+ * <p>The stream sent consists of the length.int4 then the contents.
+ *
+ * <p><b>Note:</b> This is called from Fastpath, and cannot be called from
+ * client code.
+ *
+ * @param s output stream
+ * @exception IOException if something failed on the network stream
+ */
+ public void Send(Stream s)
+ {
+ if (type)
+ {
+ // argument is an integer
+ PGUtil.WriteInt32(s, 4);
+ PGUtil.WriteInt32(s, value); // integer value of argument
+ }
+ else
+ {
+ // argument is a byte array
+ PGUtil.WriteInt32(s, bytes.Length);
+ s.Write(bytes,0,bytes.Length);
+ }
+ }
+
+ public Int32 SendSize()
+ {
+ if (type)
+ {
+ return 8;
+ }
+ else
+ {
+ return 4+bytes.Length;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs b/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs
new file mode 100644
index 00000000000..b1090714f60
--- /dev/null
+++ b/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs
@@ -0,0 +1,263 @@
+/*-------------------------------------------------------------------------
+
+ LargeObject.cs
+ This class is a port of the class LargeObject.java implemented by
+ PostgreSQL Global Development Group
+
+ Copyright (c) 2004, Emiliano Necciari
+ Original Code: Copyright (c) 2003, PostgreSQL Global Development Group
+
+ Note: (Francisco Figueiredo Jr.)
+ Changed case of method names to conform to .Net names standard.
+ Also changed type names to their true names. i.e. int -> Int32
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------
+*/
+
+using System;
+using System.IO;
+using Npgsql;
+
+namespace NpgsqlTypes
+{
+
+ public class LargeObject
+ {
+ /*
+ * Indicates a seek from the begining of a file
+ */
+ public const Int32 SEEK_SET = 0;
+
+ /*
+ * Indicates a seek from the current position
+ */
+ public const Int32 SEEK_CUR = 1;
+
+ /*
+ * Indicates a seek from the end of a file
+ */
+ public const Int32 SEEK_END = 2;
+
+ private Fastpath fp; // Fastpath API to use
+ private Int32 oid; // OID of this object
+ private Int32 fd; // the descriptor of the open large object
+
+ private Boolean closed = false; // true when we are closed
+
+ /*
+ * 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 org.postgresql.largeobject.LargeObjectManager
+ */
+ public LargeObject(Fastpath fp, Int32 oid, Int32 mode)
+ {
+ 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 Int32 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()
+ {
+ if (!closed)
+ {
+
+ // finally close
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(fd);
+ fp.FastpathCall("lo_close", false, args); // true here as we dont care!!
+ closed = true;
+ }
+ }
+
+ /*
+ * 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.
+ */
+ public Byte[] Read(Int32 len)
+ {
+ // 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 Int32o 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;
+ //}
+ }
+
+ /*
+ * 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
+ * @return the number of bytes actually read
+ * @exception SQLException if a database-access error occurs.
+ */
+ public Int32 Read(Byte[] buf, Int32 off, Int32 len)
+ {
+ Byte[] b = Read(len);
+ if (b.Length < len)
+ len = b.Length;
+ Array.Copy(b,0,buf,off,len);
+ return 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)
+ {
+ FastpathArg[] args = new FastpathArg[2];
+ args[0] = new FastpathArg(fd);
+ args[1] = new FastpathArg(buf);
+ fp.FastpathCall("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, Int32 off, Int32 len)
+ {
+ Byte[] data = new Byte[len];
+
+ System.Array.Copy(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(Int32 pos, Int32 refi)
+ {
+ FastpathArg[] args = new FastpathArg[3];
+ args[0] = new FastpathArg(fd);
+ args[1] = new FastpathArg(pos);
+ args[2] = new FastpathArg(refi);
+ fp.FastpathCall("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(Int32 pos)
+ {
+ Seek(pos, SEEK_SET);
+ }
+
+ /*
+ * @return the current position within the object
+ * @exception SQLException if a database-access error occurs.
+ */
+ public Int32 Tell()
+ {
+ 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 Int32 Size()
+ {
+ Int32 cp = Tell();
+ Seek(0, SEEK_END);
+ Int32 sz = Tell();
+ Seek(cp, SEEK_SET);
+ return sz;
+ }
+
+ }
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs b/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs
new file mode 100644
index 00000000000..10e25323c76
--- /dev/null
+++ b/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs
@@ -0,0 +1,209 @@
+/*-------------------------------------------------------------------------
+
+ LargeObjectManager.cs
+ This class is a port of the class LargeObjectManager.java implemented by
+ PostgreSQL Global Development Group
+
+
+ Copyright (c) 2004, Emiliano Necciari
+ Original Code: Copyright (c) 2003, PostgreSQL Global Development Group
+
+ Note: (Francisco Figueiredo Jr.)
+ Changed case of method names to conform to .Net names standard.
+ Also changed type names to their true names. i.e. int -> Int32
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-------------------------------------------------------------------------
+*/
+
+using System;
+using System.Data;
+using Npgsql;
+
+namespace NpgsqlTypes
+{
+ /// <summary>
+ /// Summary description for LargeObjectManager.
+ /// </summary>
+ public class LargeObjectManager
+ {
+ // the fastpath api for this connection
+ private Fastpath fp;
+
+ /*
+ * This mode indicates we want to write to an object
+ */
+ public const Int32 WRITE = 0x00020000;
+
+ /*
+ * This mode indicates we want to read an object
+ */
+ public static Int32 READ = 0x00040000;
+
+ /*
+ * This mode is the default. It indicates we want read and write access to
+ * a large object
+ */
+ public static Int32 READWRITE = READ | WRITE;
+
+ /*
+ * This prevents us being created by mere mortals
+ */
+ private LargeObjectManager()
+ {}
+
+ /*
+ * Constructs the LargeObject API.
+ *
+ * <p><b>Important Notice</b>
+ * <br>This method should only be called by org.postgresql.Connection
+ *
+ * <p>There should only be one LargeObjectManager per Connection. The
+ * org.postgresql.Connection class keeps track of the various extension API's
+ * and it's advised you use those to gain access, and not going direct.
+ */
+ public LargeObjectManager(NpgsqlConnection conn)
+ {
+ // We need Fastpath to do anything
+ // Now get the function oid's for the api
+ //
+ // This is an example of Fastpath.addFunctions();
+ //
+ String sql;
+ if (conn.ServerVersion > new ServerVersion(7,3,0) )
+ {
+
+ sql = "SELECT p.proname,p.oid "+
+ " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "+
+ " WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND (";
+ }
+ else
+ {
+ sql = "SELECT proname,oid FROM pg_proc WHERE ";
+ }
+ sql += " proname = 'lo_open'" +
+ " or proname = 'lo_close'" +
+ " or proname = 'lo_creat'" +
+ " or proname = 'lo_unlink'" +
+ " or proname = 'lo_lseek'" +
+ " or proname = 'lo_tell'" +
+ " or proname = 'loread'" +
+ " or proname = 'lowrite'";
+
+ if (conn.ServerVersion > new ServerVersion(7,3,0) )
+ {
+ sql += ")";
+ }
+
+ IDbCommand cmd = new NpgsqlCommand(sql);
+ cmd.Connection = conn;
+
+ this.fp = new Fastpath(conn,conn.Connector.Stream);
+
+ IDataReader res = cmd.ExecuteReader(CommandBehavior.CloseConnection);
+
+
+ if (res == null)
+ throw new Exception("postgresql.lo.init");
+
+
+ fp.AddFunctions(res);
+ }
+
+ /*
+ * This opens an existing large object, based on its OID. This method
+ * assumes that READ and WRITE access is required (the default).
+ *
+ * @param oid of large object
+ * @return LargeObject instance providing access to the object
+ * @exception SQLException on error
+ */
+ public LargeObject Open(Int32 oid)
+ {
+ return new LargeObject(fp, oid, READWRITE);
+ }
+
+ /*
+ * This opens an existing large object, based on its OID
+ *
+ * @param oid of large object
+ * @param mode mode of open
+ * @return LargeObject instance providing access to the object
+ * @exception SQLException on error
+ */
+ public LargeObject Open(Int32 oid, Int32 mode)
+ {
+ return new LargeObject(fp, oid, mode);
+ }
+
+ /*
+ * This creates a large object, returning its OID.
+ *
+ * <p>It defaults to READWRITE for the new object's attributes.
+ *
+ * @return oid of new object
+ * @exception SQLException on error
+ */
+ public Int32 Create()
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(READWRITE);
+ return fp.GetInteger("lo_creat", args);
+ }
+
+ /*
+ * This creates a large object, returning its OID
+ *
+ * @param mode a bitmask describing different attributes of the new object
+ * @return oid of new object
+ * @exception SQLException on error
+ */
+ public Int32 Create(Int32 mode)
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(mode);
+ return fp.GetInteger("lo_creat", args);
+ }
+
+ /*
+ * This deletes a large object.
+ *
+ * @param oid describing object to delete
+ * @exception SQLException on error
+ */
+ public void Delete(Int32 oid)
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(oid);
+ fp.FastpathCall("lo_unlink", false, args);
+ }
+
+ /*
+ * This deletes a large object.
+ *
+ * <p>It is identical to the delete method, and is supplied as the C API uses
+ * unlink.
+ *
+ * @param oid describing object to delete
+ * @exception SQLException on error
+ */
+ public void Unlink(Int32 oid)
+ {
+ Delete(oid);
+ }
+
+ }
+
+}