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
)
87 One
._Major
== TheOther
._Major
&&
88 One
._Minor
== TheOther
._Minor
&&
89 One
._Patch
== TheOther
._Patch
;
92 public static bool operator != (ServerVersion One
, ServerVersion TheOther
)
94 return ! (One
== TheOther
);
97 public static bool operator > (ServerVersion One
, ServerVersion TheOther
)
100 (One
._Major
> TheOther
._Major
) ||
101 (One
._Major
== TheOther
._Major
&& One
._Minor
> TheOther
._Minor
) ||
102 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
> TheOther
._Patch
);
105 public static bool operator >= (ServerVersion One
, ServerVersion TheOther
)
108 (One
._Major
> TheOther
._Major
) ||
109 (One
._Major
== TheOther
._Major
&& One
._Minor
> TheOther
._Minor
) ||
110 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
>= TheOther
._Patch
);
113 public static bool operator < (ServerVersion One
, ServerVersion TheOther
)
116 (One
._Major
< TheOther
._Major
) ||
117 (One
._Major
== TheOther
._Major
&& One
._Minor
< TheOther
._Minor
) ||
118 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
< TheOther
._Patch
);
121 public static bool operator <= (ServerVersion One
, ServerVersion TheOther
)
124 (One
._Major
< TheOther
._Major
) ||
125 (One
._Major
== TheOther
._Major
&& One
._Minor
< TheOther
._Minor
) ||
126 (One
._Major
== TheOther
._Major
&& One
._Minor
== TheOther
._Minor
&& One
._Patch
<= TheOther
._Patch
);
129 public override bool Equals(object O
)
131 return (O
.GetType() == this.GetType() && this == (ServerVersion
)O
);
134 public override int GetHashCode()
136 return _Major ^ _Minor ^ _Patch
;
140 /// Returns the string representation of this version in three place dot notation (Major.Minor.Patch).
142 public override String
ToString()
144 return string.Format("{0}.{1}.{2}", _Major
, _Minor
, _Patch
);
148 internal enum FormatCode
:
156 /// This class provides many util methods to handle
157 /// reading and writing of PostgreSQL protocol messages.
159 internal abstract class PGUtil
161 // Logging related values
162 private static readonly String CLASSNAME
= "PGUtil";
163 private static ResourceManager resman
= new ResourceManager(typeof(PGUtil
));
166 /// This method takes a ProtocolVersion and returns an integer
167 /// version number that the Postgres backend will recognize in a
170 public static Int32
ConvertProtocolVersion(ProtocolVersion Ver
)
173 case ProtocolVersion
.Version2
:
174 return ServerVersion
.ProtocolVersion2
;
176 case ProtocolVersion
.Version3
:
177 return ServerVersion
.ProtocolVersion3
;
187 /// This method takes a version string as returned by SELECT VERSION() and returns
188 /// a valid version string ("7.2.2" for example).
189 /// This is only needed when running protocol version 2.
190 /// This does not do any validity checks.
192 public static string ExtractServerVersion (string VersionString
)
194 Int32 Start
= 0, End
= 0;
196 // find the first digit and assume this is the start of the version number
197 for ( ; Start
< VersionString
.Length
&& ! char.IsDigit(VersionString
[Start
]) ; Start
++);
201 // read until hitting whitespace, which should terminate the version number
202 for ( ; End
< VersionString
.Length
&& ! char.IsWhiteSpace(VersionString
[End
]) ; End
++);
204 return VersionString
.Substring(Start
, End
- Start
+ 1);
208 /// This method takes a version string ("7.4.1" for example) and produces
209 /// the required integer version numbers (7, 4, and 1).
211 public static ServerVersion
ParseServerVersion (string VersionString
)
215 Parts
= VersionString
.Split('.');
217 if (Parts
.Length
< 2) {
218 throw new FormatException(String
.Format("Internal: Backend sent bad version string: {0}", VersionString
));
222 if (Parts
.Length
== 2) {
223 // Coerce it into a 3-part version.
224 return new ServerVersion(ConvertBeginToInt32(Parts
[0]), ConvertBeginToInt32(Parts
[1]), 0);
226 // If there are more than 3 parts, just ignore the extras, rather than rejecting it.
227 return new ServerVersion(ConvertBeginToInt32(Parts
[0]), ConvertBeginToInt32(Parts
[1]), ConvertBeginToInt32(Parts
[2]));
229 } catch (Exception E
) {
230 throw new FormatException(String
.Format("Internal: Backend sent bad version string: {0}", VersionString
), E
);
235 /// Convert the beginning numeric part of the given string to Int32.
237 /// Strings "12345ABCD" and "12345.54321" would both be converted to int 12345.
239 private static Int32
ConvertBeginToInt32(String Raw
)
242 for ( ; Length
< Raw
.Length
&& Char
.IsNumber(Raw
[Length
]) ; Length
++);
243 return Convert
.ToInt32(Raw
.Substring(0, Length
));
247 /// This method gets a C NULL terminated string from the network stream.
248 /// It keeps reading a byte in each time until a NULL byte is returned.
249 /// It returns the resultant string of bytes read.
250 /// This string is sent from backend.
252 public static String
ReadString(Stream network_stream
, Encoding encoding
)
254 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "ReadString");
256 ArrayList buffer
= new ArrayList();
260 // [FIXME] Is this cast always safe?
261 b
= (Byte
)network_stream
.ReadByte();
265 b
= (Byte
)network_stream
.ReadByte();
268 string_read
= encoding
.GetString((Byte
[])buffer
.ToArray(typeof(Byte
)));
269 NpgsqlEventLog
.LogMsg(resman
, "Log_StringRead", LogLevel
.Debug
, string_read
);
275 /// This method gets a length terminated string from a network stream.
276 /// It returns the resultant string of bytes read.
277 /// This string is sent from backend.
279 public static String
ReadString(Stream network_stream
, Encoding encoding
, Int32 length
)
281 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "ReadString");
283 ArrayList buffer
= new ArrayList();
287 for (int C
= 0 ; C
< length
; C
++)
289 // [FIXME] Is this cast always safe?
290 b
= (Byte
)network_stream
.ReadByte();
294 string_read
= encoding
.GetString((Byte
[])buffer
.ToArray(typeof(Byte
)));
295 NpgsqlEventLog
.LogMsg(resman
, "Log_StringRead", LogLevel
.Debug
, string_read
);
301 /// This method writes a C NULL terminated string to the network stream.
302 /// It appends a NULL terminator to the end of the String.
304 public static void WriteString(String the_string
, Stream network_stream
, Encoding encoding
)
306 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "WriteString");
308 network_stream
.Write(encoding
.GetBytes(the_string
+ '\x00') , 0, encoding
.GetByteCount(the_string
) + 1);
312 /// This method writes a C NULL terminated string limited in length to the
314 /// It pads the string with null bytes to the size specified.
316 public static void WriteLimString(String the_string
, Int32 n
, Stream network_stream
, Encoding encoding
)
318 NpgsqlEventLog
.LogMethodEnter(LogLevel
.Debug
, CLASSNAME
, "WriteLimString");
320 // [FIXME] Parameters should be validated. And what about strings
321 // larger than or equal to n?
323 // Pad the string to the specified value.
324 String string_padded
= the_string
.PadRight(n
, '\x00');
326 network_stream
.Write(encoding
.GetBytes(string_padded
), 0, n
);
329 public static void CheckedStreamRead(Stream stream
, Byte
[] buffer
, Int32 offset
, Int32 size
)
331 Int32 bytes_from_stream
= 0;
332 Int32 total_bytes_read
= 0;
336 bytes_from_stream
= stream
.Read(buffer
, offset
+ total_bytes_read
, size
);
337 total_bytes_read
+= bytes_from_stream
;
338 size
-= bytes_from_stream
;
345 /// Write a 32-bit integer to the given stream in the correct byte order.
347 public static void WriteInt32(Stream stream
, Int32
value)
349 stream
.Write(BitConverter
.GetBytes(IPAddress
.HostToNetworkOrder(value)), 0, 4);
353 /// Read a 32-bit integer from the given stream in the correct byte order.
355 public static Int32
ReadInt32(Stream stream
, Byte
[] buffer
)
357 CheckedStreamRead(stream
, buffer
, 0, 4);
358 return IPAddress
.NetworkToHostOrder(BitConverter
.ToInt32(buffer
, 0));
363 /// Write a 16-bit integer to the given stream in the correct byte order.
365 public static void WriteInt16(Stream stream
, Int16
value)
367 stream
.Write(BitConverter
.GetBytes(IPAddress
.HostToNetworkOrder(value)), 0, 2);
371 /// Read a 16-bit integer from the given stream in the correct byte order.
373 public static Int16
ReadInt16(Stream stream
, Byte
[] buffer
)
375 CheckedStreamRead(stream
, buffer
, 0, 2);
376 return IPAddress
.NetworkToHostOrder(BitConverter
.ToInt16(buffer
, 0));