**** Merged from MCS ****
[mono-project.git] / mcs / class / Npgsql / Npgsql / PGUtil.cs
blob2faad1bdd0c815ce5a7231eb2c84f5e28a2b4c04
1 // created on 1/6/2002 at 22:27
3 // Npgsql.PGUtil.cs
4 //
5 // Author:
6 // Francisco Jr. (fxjrlists@yahoo.com.br)
7 //
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
27 using System;
28 using System.Collections;
29 using System.IO;
30 using System.Text;
31 using System.Net.Sockets;
32 using System.Net;
33 using System.Resources;
35 namespace Npgsql
37 /// <summary>
38 /// Represent the frontend/backend protocol version.
39 /// </summary>
40 public enum ProtocolVersion
42 Unknown,
43 Version2,
44 Version3
47 /// <summary>
48 /// Represent the backend server version.
49 /// </summary>
50 public sealed class ServerVersion
52 public static readonly Int32 ProtocolVersion2 = 2 << 16; // 131072
53 public static readonly Int32 ProtocolVersion3 = 3 << 16; // 196608
55 private Int32 _Major;
56 private Int32 _Minor;
57 private Int32 _Patch;
59 internal ServerVersion(Int32 Major, Int32 Minor, Int32 Patch)
61 _Major = Major;
62 _Minor = Minor;
63 _Patch = Patch;
66 /// <summary>
67 /// Server version major number.
68 /// </summary>
69 public Int32 Major
70 { get { return _Major; } }
72 /// <summary>
73 /// Server version minor number.
74 /// </summary>
75 public Int32 Minor
76 { get { return _Minor; } }
78 /// <summary>
79 /// Server version patch level number.
80 /// </summary>
81 public Int32 Patch
82 { get { return _Patch; } }
84 public static bool operator == (ServerVersion One, ServerVersion TheOther)
86 return
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)
99 return
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)
107 return
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)
115 return
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)
123 return
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;
139 /// <summary>
140 /// Returns the string representation of this version in three place dot notation (Major.Minor.Patch).
141 /// </summary>
142 public override String ToString()
144 return string.Format("{0}.{1}.{2}", _Major, _Minor, _Patch);
148 internal enum FormatCode:
149 short
151 Text = 0,
152 Binary = 1
155 ///<summary>
156 /// This class provides many util methods to handle
157 /// reading and writing of PostgreSQL protocol messages.
158 /// </summary>
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));
165 ///<summary>
166 /// This method takes a ProtocolVersion and returns an integer
167 /// version number that the Postgres backend will recognize in a
168 /// startup packet.
169 /// </summary>
170 public static Int32 ConvertProtocolVersion(ProtocolVersion Ver)
172 switch (Ver) {
173 case ProtocolVersion.Version2 :
174 return ServerVersion.ProtocolVersion2;
176 case ProtocolVersion.Version3 :
177 return ServerVersion.ProtocolVersion3;
181 // CHECKME
182 // should we throw?
183 return 0;
186 /// <summary>
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.
191 /// </summary>
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++);
199 End = 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);
207 /// <summary>
208 /// This method takes a version string ("7.4.1" for example) and produces
209 /// the required integer version numbers (7, 4, and 1).
210 /// </summary>
211 public static ServerVersion ParseServerVersion (string VersionString)
213 String[] Parts;
215 Parts = VersionString.Split('.');
217 if (Parts.Length < 2) {
218 throw new FormatException(String.Format("Internal: Backend sent bad version string: {0}", VersionString));
221 try {
222 if (Parts.Length == 2) {
223 // Coerce it into a 3-part version.
224 return new ServerVersion(ConvertBeginToInt32(Parts[0]), ConvertBeginToInt32(Parts[1]), 0);
225 } else {
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);
234 /// <summary>
235 /// Convert the beginning numeric part of the given string to Int32.
236 /// For example:
237 /// Strings "12345ABCD" and "12345.54321" would both be converted to int 12345.
238 /// </summary>
239 private static Int32 ConvertBeginToInt32(String Raw)
241 Int32 Length = 0;
242 for ( ; Length < Raw.Length && Char.IsNumber(Raw[Length]) ; Length++);
243 return Convert.ToInt32(Raw.Substring(0, Length));
246 ///<summary>
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.
251 /// </summary>
252 public static String ReadString(Stream network_stream, Encoding encoding)
254 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadString");
256 ArrayList buffer = new ArrayList();
257 Byte b;
258 String string_read;
260 // [FIXME] Is this cast always safe?
261 b = (Byte)network_stream.ReadByte();
262 while(b != 0)
264 buffer.Add(b);
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);
271 return string_read;
274 ///<summary>
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.
278 /// </summary>
279 public static String ReadString(Stream network_stream, Encoding encoding, Int32 length)
281 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadString");
283 ArrayList buffer = new ArrayList();
284 Byte b;
285 String string_read;
287 for (int C = 0 ; C < length ; C++)
289 // [FIXME] Is this cast always safe?
290 b = (Byte)network_stream.ReadByte();
291 buffer.Add(b);
294 string_read = encoding.GetString((Byte[])buffer.ToArray(typeof(Byte)));
295 NpgsqlEventLog.LogMsg(resman, "Log_StringRead", LogLevel.Debug, string_read);
297 return string_read;
300 ///<summary>
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.
303 /// </summary>
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);
311 ///<summary>
312 /// This method writes a C NULL terminated string limited in length to the
313 /// backend server.
314 /// It pads the string with null bytes to the size specified.
315 /// </summary>
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;
340 while(size > 0);
344 /// <summary>
345 /// Write a 32-bit integer to the given stream in the correct byte order.
346 /// </summary>
347 public static void WriteInt32(Stream stream, Int32 value)
349 stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), 0, 4);
352 /// <summary>
353 /// Read a 32-bit integer from the given stream in the correct byte order.
354 /// </summary>
355 public static Int32 ReadInt32(Stream stream, Byte[] buffer)
357 CheckedStreamRead(stream, buffer, 0, 4);
358 return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, 0));
362 /// <summary>
363 /// Write a 16-bit integer to the given stream in the correct byte order.
364 /// </summary>
365 public static void WriteInt16(Stream stream, Int16 value)
367 stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), 0, 2);
370 /// <summary>
371 /// Read a 16-bit integer from the given stream in the correct byte order.
372 /// </summary>
373 public static Int16 ReadInt16(Stream stream, Byte[] buffer)
375 CheckedStreamRead(stream, buffer, 0, 2);
376 return IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 0));