1 // created on 1/6/2002 at 22:27
6 // Francisco Jr. (fxjrlists@yahoo.com.br)
8 // Copyright (C) 2002 The Npgsql Development Team
9 // npgsql-general@gborg.postgresql.org
10 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 using System
.Collections
;
31 using System
.Net
.Sockets
;
33 using System
.Resources
;
38 /// Represent the frontend/backend protocol version.
40 public enum ProtocolVersion
48 /// Represent the backend server version.
50 public sealed class ServerVersion
52 public static readonly Int32 ProtocolVersion2
= 2 << 16; // 131072
53 public static readonly Int32 ProtocolVersion3
= 3 << 16; // 196608
59 internal ServerVersion(Int32 Major
, Int32 Minor
, Int32 Patch
)
67 /// Server version major number.
70 { get { return _Major; }
}
73 /// Server version minor number.
76 { get { return _Minor; }
}
79 /// Server version patch level number.
82 { get { return _Patch; }
}
84 public static bool operator == (ServerVersion One
, ServerVersion TheOther
)
86 if (((Object
)One
== null) || ((Object
)TheOther
== null))
89 One
._Major
== TheOther
._Major
&&
90 One
._Minor
== TheOther
._Minor
&&
91 One
._Patch
== TheOther
._Patch
;
94 public static bool operator != (ServerVersion One
, ServerVersion TheOther
)
96 if (((Object
)One
== null) || ((Object
)TheOther
== null))
99 return ! (One
== TheOther
);
102 public static bool operator > (ServerVersion One
, ServerVersion TheOther
)
105 (One
._Major
> TheOther
._Major
) ||
106 (One
._Major
== TheOther
._Major
&& One
._Minor
> TheOther
._Minor
) ||
107 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
> TheOther
._Patch
);
110 public static bool operator >= (ServerVersion One
, ServerVersion TheOther
)
113 (One
._Major
> TheOther
._Major
) ||
114 (One
._Major
== TheOther
._Major
&& One
._Minor
> TheOther
._Minor
) ||
115 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
>= TheOther
._Patch
);
118 public static bool operator < (ServerVersion One
, ServerVersion TheOther
)
121 (One
._Major
< TheOther
._Major
) ||
122 (One
._Major
== TheOther
._Major
&& One
._Minor
< TheOther
._Minor
) ||
123 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
< TheOther
._Patch
);
126 public static bool operator <= (ServerVersion One
, ServerVersion TheOther
)
129 (One
._Major
< TheOther
._Major
) ||
130 (One
._Major
== TheOther
._Major
&& One
._Minor
< TheOther
._Minor
) ||
131 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
<= TheOther
._Patch
);
134 public override bool Equals(object O
)
139 return (O
.GetType() == this.GetType() && this == (ServerVersion
)O
);
142 public override int GetHashCode()
144 return _Major ^ _Minor ^ _Patch
;
148 /// Returns the string representation of this version in three place dot notation (Major.Minor.Patch).
150 public override String
ToString()
152 return string.Format("{0}.{1}.{2}", _Major
, _Minor
, _Patch
);
156 internal enum FormatCode
:
164 /// This class provides many util methods to handle
165 /// reading and writing of PostgreSQL protocol messages.
167 internal abstract class PGUtil
169 // Logging related values
170 private static readonly String CLASSNAME
= "PGUtil";
171 private static ResourceManager resman
= new ResourceManager(typeof(PGUtil
));
174 /// This method takes a ProtocolVersion and returns an integer
175 /// version number that the Postgres backend will recognize in a
178 public static Int32
ConvertProtocolVersion(ProtocolVersion Ver
)
181 case ProtocolVersion
.Version2
:
182 return ServerVersion
.ProtocolVersion2
;
184 case ProtocolVersion
.Version3
:
185 return ServerVersion
.ProtocolVersion3
;
195 /// This method takes a version string as returned by SELECT VERSION() and returns
196 /// a valid version string ("7.2.2" for example).
197 /// This is only needed when running protocol version 2.
198 /// This does not do any validity checks.
200 public static string ExtractServerVersion (string VersionString
)
202 Int32 Start
= 0, End
= 0;
204 // find the first digit and assume this is the start of the version number
205 for ( ; Start
< VersionString
.Length
&& ! char.IsDigit(VersionString
[Start
]) ; Start
++);
209 // read until hitting whitespace, which should terminate the version number
210 for ( ; End
< VersionString
.Length
&& ! char.IsWhiteSpace(VersionString
[End
]) ; End
++);
212 return VersionString
.Substring(Start
, End
- Start
+ 1);
216 /// This method takes a version string ("7.4.1" for example) and produces
217 /// the required integer version numbers (7, 4, and 1).
219 public static ServerVersion
ParseServerVersion (string VersionString
)
223 Parts
= VersionString
.Split('.');
225 if (Parts
.Length
< 2) {
226 throw new FormatException(String
.Format("Internal: Backend sent bad version string: {0}", VersionString
));
230 if (Parts
.Length
== 2) {
231 // Coerce it into a 3-part version.
232 return new ServerVersion(ConvertBeginToInt32(Parts
[0]), ConvertBeginToInt32(Parts
[1]), 0);
234 // If there are more than 3 parts, just ignore the extras, rather than rejecting it.
235 return new ServerVersion(ConvertBeginToInt32(Parts
[0]), ConvertBeginToInt32(Parts
[1]), ConvertBeginToInt32(Parts
[2]));
237 } catch (Exception E
) {
238 throw new FormatException(String
.Format("Internal: Backend sent bad version string: {0}", VersionString
), E
);
243 /// Convert the beginning numeric part of the given string to Int32.
245 /// Strings "12345ABCD" and "12345.54321" would both be converted to int 12345.
247 private static Int32
ConvertBeginToInt32(String Raw
)
250 for ( ; Length
< Raw
.Length
&& Char
.IsNumber(Raw
[Length
]) ; Length
++);
251 return Convert
.ToInt32(Raw
.Substring(0, Length
));
255 /// This method gets a C NULL terminated string from the network stream.
256 /// It keeps reading a byte in each time until a NULL byte is returned.
257 /// It returns the resultant string of bytes read.
258 /// This string is sent from backend.
260 public static String
ReadString(Stream network_stream
, Encoding encoding
)
262 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "ReadString");
264 ArrayList buffer
= new ArrayList();
268 // [FIXME] Is this cast always safe?
269 b
= (Byte
)network_stream
.ReadByte();
273 b
= (Byte
)network_stream
.ReadByte();
276 string_read
= encoding
.GetString((Byte
[])buffer
.ToArray(typeof(Byte
)));
277 NpgsqlEventLog
.LogMsg(resman
, "Log_StringRead", LogLevel
.Debug
, string_read
);
283 /// This method gets a length terminated string from a network stream.
284 /// It returns the resultant string of bytes read.
285 /// This string is sent from backend.
287 public static String
ReadString(Stream network_stream
, Encoding encoding
, Int32 length
)
289 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "ReadString");
291 ArrayList buffer
= new ArrayList();
295 for (int C
= 0 ; C
< length
; C
++)
297 // [FIXME] Is this cast always safe?
298 b
= (Byte
)network_stream
.ReadByte();
302 string_read
= encoding
.GetString((Byte
[])buffer
.ToArray(typeof(Byte
)));
303 NpgsqlEventLog
.LogMsg(resman
, "Log_StringRead", LogLevel
.Debug
, string_read
);
309 /// This method writes a C NULL terminated string to the network stream.
310 /// It appends a NULL terminator to the end of the String.
312 public static void WriteString(String the_string
, Stream network_stream
, Encoding encoding
)
314 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "WriteString");
316 NpgsqlEventLog
.LogMsg(resman
, "Log_StringWritten", LogLevel
.Debug
, the_string
);
318 network_stream
.Write(encoding
.GetBytes(the_string
+ '\x00') , 0, encoding
.GetByteCount(the_string
) + 1);
322 /// This method writes a C NULL terminated string limited in length to the
324 /// It pads the string with null bytes to the size specified.
326 public static void WriteLimString(String the_string
, Int32 n
, Stream network_stream
, Encoding encoding
)
328 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "WriteLimString");
330 // [FIXME] Parameters should be validated. And what about strings
331 // larger than or equal to n?
333 // Pad the string to the specified value.
334 String string_padded
= the_string
.PadRight(n
, '\x00');
336 network_stream
.Write(encoding
.GetBytes(string_padded
), 0, n
);
339 public static void CheckedStreamRead(Stream stream
, Byte
[] buffer
, Int32 offset
, Int32 size
)
341 Int32 bytes_from_stream
= 0;
342 Int32 total_bytes_read
= 0;
346 bytes_from_stream
= stream
.Read(buffer
, offset
+ total_bytes_read
, size
);
347 total_bytes_read
+= bytes_from_stream
;
348 size
-= bytes_from_stream
;
355 /// Write a 32-bit integer to the given stream in the correct byte order.
357 public static void WriteInt32(Stream stream
, Int32
value)
359 stream
.Write(BitConverter
.GetBytes(IPAddress
.HostToNetworkOrder(value)), 0, 4);
363 /// Read a 32-bit integer from the given stream in the correct byte order.
365 public static Int32
ReadInt32(Stream stream
, Byte
[] buffer
)
367 CheckedStreamRead(stream
, buffer
, 0, 4);
368 return IPAddress
.NetworkToHostOrder(BitConverter
.ToInt32(buffer
, 0));
373 /// Write a 16-bit integer to the given stream in the correct byte order.
375 public static void WriteInt16(Stream stream
, Int16
value)
377 stream
.Write(BitConverter
.GetBytes(IPAddress
.HostToNetworkOrder(value)), 0, 2);
381 /// Read a 16-bit integer from the given stream in the correct byte order.
383 public static Int16
ReadInt16(Stream stream
, Byte
[] buffer
)
385 CheckedStreamRead(stream
, buffer
, 0, 2);
386 return IPAddress
.NetworkToHostOrder(BitConverter
.ToInt16(buffer
, 0));