diff options
author | Francisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com> | 2004-10-01 01:36:09 +0400 |
---|---|---|
committer | Francisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com> | 2004-10-01 01:36:09 +0400 |
commit | 0de8c14094bc7407ee47a3824cb321f21033438e (patch) | |
tree | 9f4ba661d57434af1fd97c5e1d50f81790355e31 /mcs/class/Npgsql/NpgsqlTypes | |
parent | 802e76ff671d1d8547b657c488e0d89a0fa2514e (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.cs | 486 | ||||
-rw-r--r-- | mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs | 135 | ||||
-rw-r--r-- | mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs | 263 | ||||
-rw-r--r-- | mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs | 209 |
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); + } + + } + +} |