disable broken tests on net_4_0
[mcs.git] / class / Npgsql / NpgsqlTypes / NpgsqlTypesHelper.cs
blob3c25d5d4670dbc867096cbd21bbf59a0622510f3
1 // NpgsqlTypes.NpgsqlTypesHelper.cs
2 //
3 // Author:
4 // Francisco Jr. (fxjrlists@yahoo.com.br)
5 //
6 // Copyright (C) 2002 The Npgsql Development Team
7 // npgsql-general@gborg.postgresql.org
8 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 using System;
25 using System.Collections;
26 using System.Globalization;
27 using System.Data;
28 using System.Net;
29 using System.Text;
30 using System.Resources;
31 using Npgsql;
34 namespace NpgsqlTypes
36 /// <summary>
37 /// This class contains helper methods for type conversion between
38 /// the .Net type system and postgresql.
39 /// </summary>
40 internal abstract class NpgsqlTypesHelper
42 // Logging related values
43 private static readonly String CLASSNAME = "NpgsqlTypesHelper";
44 private static ResourceManager resman = new ResourceManager(typeof(NpgsqlTypesHelper));
46 /// <summary>
47 /// A cache of basic datatype mappings keyed by server version. This way we don't
48 /// have to load the basic type mappings for every connection.
49 /// </summary>
50 private static Hashtable BackendTypeMappingCache = new Hashtable();
51 private static NpgsqlNativeTypeMapping NativeTypeMapping = null;
54 /// <summary>
55 /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
56 /// of the given NpgsqlDbType.
57 /// </summary>
58 public static NpgsqlNativeTypeInfo GetNativeTypeInfo(NpgsqlDbType NpgsqlDbType)
60 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBackendTypeNameFromNpgsqlDbType");
62 VerifyDefaultTypesMap();
63 return NativeTypeMapping[NpgsqlDbType];
66 /// <summary>
67 /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
68 /// of the given DbType.
69 /// </summary>
70 public static NpgsqlNativeTypeInfo GetNativeTypeInfo(DbType DbType)
72 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBackendTypeNameFromNpgsqlDbType");
74 VerifyDefaultTypesMap();
75 return NativeTypeMapping[DbType];
80 /// <summary>
81 /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
82 /// of the given System.Type.
83 /// </summary>
84 public static NpgsqlNativeTypeInfo GetNativeTypeInfo(Type Type)
86 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBackendTypeNameFromNpgsqlDbType");
88 VerifyDefaultTypesMap();
89 return NativeTypeMapping[Type];
92 // CHECKME
93 // Not sure what to do with this one. I don't believe we ever ask for a binary
94 // formatting, so this shouldn't even be used right now.
95 // At some point this will need to be merged into the type converter system somehow?
96 public static Object ConvertBackendBytesToSystemType(NpgsqlBackendTypeInfo TypeInfo, Byte[] data, Encoding encoding, Int32 fieldValueSize, Int32 typeModifier)
98 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertBackendBytesToStytemType");
101 // We are never guaranteed to know about every possible data type the server can send us.
102 // When we encounter an unknown type, we punt and return the data without modification.
103 if (TypeInfo == null)
104 return data;
106 switch (TypeInfo.NpgsqlDbType)
108 case NpgsqlDbType.Bytea:
109 return data;
110 /*case NpgsqlDbType.Boolean:
111 return BitConverter.ToBoolean(data, 0);
112 case NpgsqlDbType.DateTime:
113 return DateTime.MinValue.AddTicks(IPAddress.NetworkToHostOrder(BitConverter.ToInt64(data, 0)));
115 case NpgsqlDbType.Int16:
116 return IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 0));
117 case NpgsqlDbType.Int32:
118 return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 0));
119 case NpgsqlDbType.Int64:
120 return IPAddress.NetworkToHostOrder(BitConverter.ToInt64(data, 0));
121 case NpgsqlDbType.String:
122 case NpgsqlDbType.AnsiString:
123 case NpgsqlDbType.StringFixedLength:
124 return encoding.GetString(data, 0, fieldValueSize);*/
125 default:
126 throw new InvalidCastException("Type not supported in binary format");
129 return null;
132 ///<summary>
133 /// This method is responsible to convert the string received from the backend
134 /// to the corresponding NpgsqlType.
135 /// The given TypeInfo is called upon to do the conversion.
136 /// If no TypeInfo object is provided, no conversion is performed.
137 /// </summary>
138 public static Object ConvertBackendStringToSystemType(NpgsqlBackendTypeInfo TypeInfo, String data, Int16 typeSize, Int32 typeModifier)
140 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertBackendStringToSystemType");
142 if (TypeInfo != null) {
143 return TypeInfo.ConvertToNative(data, typeSize, typeModifier);
144 } else {
145 return data;
149 /// <summary>
150 /// Create the one and only native to backend type map.
151 /// This map is used when formatting native data
152 /// types to backend representations.
153 /// </summary>
154 private static void VerifyDefaultTypesMap()
156 lock(CLASSNAME) {
157 if (NativeTypeMapping != null) {
158 return;
161 NativeTypeMapping = new NpgsqlNativeTypeMapping();
164 // Conflicting types should have mapped first the non default mappings.
165 // For example, char, varchar and text map to DbType.String. As the most
166 // common is to use text with string, it has to be the last mapped, in order
167 // to type mapping has the last entry, in this case, text, as the map value
168 // for DbType.String.
170 NativeTypeMapping.AddType("refcursor", NpgsqlDbType.Refcursor, DbType.String, true, null);
172 NativeTypeMapping.AddType("char", NpgsqlDbType.Char, DbType.String, true, null);
174 NativeTypeMapping.AddType("varchar", NpgsqlDbType.Varchar, DbType.String, true, null);
176 NativeTypeMapping.AddType("text", NpgsqlDbType.Text, DbType.String, true, null);
178 NativeTypeMapping.AddDbTypeAlias("text", DbType.StringFixedLength);
179 NativeTypeMapping.AddDbTypeAlias("text", DbType.AnsiString);
180 NativeTypeMapping.AddDbTypeAlias("text", DbType.AnsiStringFixedLength);
181 NativeTypeMapping.AddTypeAlias("text", typeof(String));
184 NativeTypeMapping.AddType("bytea", NpgsqlDbType.Bytea, DbType.Binary, true,
185 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBinary));
187 NativeTypeMapping.AddTypeAlias("bytea", typeof(Byte[]));
189 NativeTypeMapping.AddType("bit", NpgsqlDbType.Bit, DbType.Boolean, true,
190 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBit));
192 NativeTypeMapping.AddType("bool", NpgsqlDbType.Boolean, DbType.Boolean, false,
193 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBoolean));
195 NativeTypeMapping.AddTypeAlias("bool", typeof(Boolean));
197 NativeTypeMapping.AddType("int2", NpgsqlDbType.Smallint, DbType.Int16, false,
198 null);
200 NativeTypeMapping.AddTypeAlias("int2", typeof(Int16));
202 NativeTypeMapping.AddDbTypeAlias("int2", DbType.Byte);
204 NativeTypeMapping.AddTypeAlias("int2", typeof(Byte));
206 NativeTypeMapping.AddType("int4", NpgsqlDbType.Integer, DbType.Int32, false,
207 null);
209 NativeTypeMapping.AddTypeAlias("int4", typeof(Int32));
211 NativeTypeMapping.AddType("int8", NpgsqlDbType.Bigint, DbType.Int64, false,
212 null);
214 NativeTypeMapping.AddTypeAlias("int8", typeof(Int64));
216 NativeTypeMapping.AddType("float4", NpgsqlDbType.Real, DbType.Single, true,
217 null);
219 NativeTypeMapping.AddTypeAlias("float4", typeof(Single));
221 NativeTypeMapping.AddType("float8", NpgsqlDbType.Double, DbType.Double, true,
222 null);
224 NativeTypeMapping.AddTypeAlias("float8", typeof(Double));
226 NativeTypeMapping.AddType("numeric", NpgsqlDbType.Numeric, DbType.Decimal, false,
227 null);
229 NativeTypeMapping.AddTypeAlias("numeric", typeof(Decimal));
231 NativeTypeMapping.AddType("currency", NpgsqlDbType.Money, DbType.Currency, true,
232 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToMoney));
234 NativeTypeMapping.AddType("date", NpgsqlDbType.Date, DbType.Date, true,
235 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDate));
237 NativeTypeMapping.AddType("time", NpgsqlDbType.Time, DbType.Time, true,
238 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToTime));
240 NativeTypeMapping.AddType("timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, true,
241 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDateTime));
243 NativeTypeMapping.AddTypeAlias("timestamp", typeof(DateTime));
245 NativeTypeMapping.AddType("timestamptz", NpgsqlDbType.TimestampTZ, DbType.DateTime, true,
246 new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDateTime));
248 NativeTypeMapping.AddType("point", NpgsqlDbType.Point, DbType.Object, true,
249 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPoint));
251 NativeTypeMapping.AddTypeAlias("point", typeof(NpgsqlPoint));
253 NativeTypeMapping.AddType("box", NpgsqlDbType.Box, DbType.Object, true,
254 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToBox));
256 NativeTypeMapping.AddTypeAlias("box", typeof(NpgsqlBox));
258 NativeTypeMapping.AddType("lseg", NpgsqlDbType.LSeg, DbType.Object, true,
259 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToLSeg));
261 NativeTypeMapping.AddTypeAlias("lseg", typeof(NpgsqlLSeg));
263 NativeTypeMapping.AddType("path", NpgsqlDbType.Path, DbType.Object, true,
264 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPath));
266 NativeTypeMapping.AddTypeAlias("path", typeof(NpgsqlPath));
268 NativeTypeMapping.AddType("polygon", NpgsqlDbType.Polygon, DbType.Object, true,
269 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPolygon));
271 NativeTypeMapping.AddTypeAlias("polygon", typeof(NpgsqlPolygon));
273 NativeTypeMapping.AddType("circle", NpgsqlDbType.Circle, DbType.Object, true,
274 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToCircle));
276 NativeTypeMapping.AddTypeAlias("circle", typeof(NpgsqlCircle));
278 NativeTypeMapping.AddType("inet", NpgsqlDbType.Inet, DbType.Object, true,
279 new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToIPAddress));
281 NativeTypeMapping.AddTypeAlias("inet", typeof(IPAddress));
282 NativeTypeMapping.AddTypeAlias("inet", typeof(NpgsqlInet));
286 ///<summary>
287 /// This method creates (or retrieves from cache) a mapping between type and OID
288 /// of all natively supported postgresql data types.
289 /// This is needed as from one version to another, this mapping can be changed and
290 /// so we avoid hardcoding them.
291 /// </summary>
292 /// <returns>NpgsqlTypeMapping containing all known data types. The mapping must be
293 /// cloned before it is modified because it is cached; changes made by one connection may
294 /// effect another connection.</returns>
295 public static NpgsqlBackendTypeMapping CreateAndLoadInitialTypesMapping(NpgsqlConnector conn)
297 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "LoadTypesMapping");
299 // [TODO] Verify another way to get higher concurrency.
300 lock(CLASSNAME)
302 // Check the cache for an initial types map.
303 NpgsqlBackendTypeMapping oidToNameMapping = (NpgsqlBackendTypeMapping) BackendTypeMappingCache[conn.ServerVersion];
305 if (oidToNameMapping != null)
307 return oidToNameMapping;
310 // Not in cache, create a new one.
311 oidToNameMapping = new NpgsqlBackendTypeMapping();
313 // Create a list of all natively supported postgresql data types.
314 NpgsqlBackendTypeInfo[] TypeInfoList = new NpgsqlBackendTypeInfo[]
316 new NpgsqlBackendTypeInfo(0, "unknown", NpgsqlDbType.Text, DbType.String, typeof(String),
317 null),
319 new NpgsqlBackendTypeInfo(0, "refcursor", NpgsqlDbType.Refcursor, DbType.String, typeof(String),
320 null),
322 new NpgsqlBackendTypeInfo(0, "char", NpgsqlDbType.Char, DbType.String, typeof(String),
323 null),
325 new NpgsqlBackendTypeInfo(0, "bpchar", NpgsqlDbType.Text, DbType.String, typeof(String),
326 null),
328 new NpgsqlBackendTypeInfo(0, "varchar", NpgsqlDbType.Varchar, DbType.String, typeof(String),
329 null),
331 new NpgsqlBackendTypeInfo(0, "text", NpgsqlDbType.Text, DbType.String, typeof(String),
332 null),
334 new NpgsqlBackendTypeInfo(0, "name", NpgsqlDbType.Text, DbType.String, typeof(String),
335 null),
337 new NpgsqlBackendTypeInfo(0, "bytea", NpgsqlDbType.Bytea, DbType.Binary, typeof(Byte[]),
338 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBinary)),
340 new NpgsqlBackendTypeInfo(0, "bit", NpgsqlDbType.Bit, DbType.Boolean, typeof(Boolean),
341 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBit)),
343 new NpgsqlBackendTypeInfo(0, "bool", NpgsqlDbType.Boolean, DbType.Boolean, typeof(Boolean),
344 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBoolean)),
347 new NpgsqlBackendTypeInfo(0, "int2", NpgsqlDbType.Smallint, DbType.Int16, typeof(Int16),
348 null),
350 new NpgsqlBackendTypeInfo(0, "int4", NpgsqlDbType.Integer, DbType.Int32, typeof(Int32),
351 null),
353 new NpgsqlBackendTypeInfo(0, "int8", NpgsqlDbType.Bigint, DbType.Int64, typeof(Int64),
354 null),
356 new NpgsqlBackendTypeInfo(0, "oid", NpgsqlDbType.Bigint, DbType.Int64, typeof(Int64),
357 null),
360 new NpgsqlBackendTypeInfo(0, "float4", NpgsqlDbType.Real, DbType.Single, typeof(Single),
361 null),
363 new NpgsqlBackendTypeInfo(0, "float8", NpgsqlDbType.Double, DbType.Double, typeof(Double),
364 null),
366 new NpgsqlBackendTypeInfo(0, "numeric", NpgsqlDbType.Numeric, DbType.Decimal, typeof(Decimal),
367 null),
369 new NpgsqlBackendTypeInfo(0, "inet", NpgsqlDbType.Inet, DbType.Object, typeof(NpgsqlInet), new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToInet)),
371 new NpgsqlBackendTypeInfo(0, "money", NpgsqlDbType.Money, DbType.Decimal, typeof(Decimal),
372 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToMoney)),
375 new NpgsqlBackendTypeInfo(0, "date", NpgsqlDbType.Date, DbType.Date, typeof(DateTime),
376 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDate)),
378 new NpgsqlBackendTypeInfo(0, "time", NpgsqlDbType.Time, DbType.Time, typeof(DateTime),
379 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToTime)),
381 new NpgsqlBackendTypeInfo(0, "timetz", NpgsqlDbType.Time, DbType.Time, typeof(DateTime),
382 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToTime)),
384 new NpgsqlBackendTypeInfo(0, "timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, typeof(DateTime),
385 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDateTime)),
387 new NpgsqlBackendTypeInfo(0, "timestamptz", NpgsqlDbType.Timestamp, DbType.DateTime, typeof(DateTime),
388 new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDateTime)),
391 new NpgsqlBackendTypeInfo(0, "point", NpgsqlDbType.Point, DbType.Object, typeof(NpgsqlPoint),
392 new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPoint)),
394 new NpgsqlBackendTypeInfo(0, "lseg", NpgsqlDbType.LSeg, DbType.Object, typeof(NpgsqlLSeg),
395 new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToLSeg)),
397 new NpgsqlBackendTypeInfo(0, "path", NpgsqlDbType.Path, DbType.Object, typeof(NpgsqlPath),
398 new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPath)),
400 new NpgsqlBackendTypeInfo(0, "box", NpgsqlDbType.Box, DbType.Object, typeof(NpgsqlBox),
401 new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToBox)),
403 new NpgsqlBackendTypeInfo(0, "circle", NpgsqlDbType.Circle, DbType.Object, typeof(NpgsqlCircle),
404 new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToCircle)),
406 new NpgsqlBackendTypeInfo(0, "polygon", NpgsqlDbType.Polygon, DbType.Object, typeof(NpgsqlPolygon),
407 new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPolygon)),
410 // Attempt to map each type info in the list to an OID on the backend and
411 // add each mapped type to the new type mapping object.
412 LoadTypesMappings(conn, oidToNameMapping, TypeInfoList);
414 // Add this mapping to the per-server-version cache so we don't have to
415 // do these expensive queries on every connection startup.
416 BackendTypeMappingCache.Add(conn.ServerVersion, oidToNameMapping);
418 return oidToNameMapping;
424 /// <summary>
425 /// Attempt to map types by issuing a query against pg_type.
426 /// This function takes a list of NpgsqlTypeInfo and attempts to resolve the OID field
427 /// of each by querying pg_type. If the mapping is found, the type info object is
428 /// updated (OID) and added to the provided NpgsqlTypeMapping object.
429 /// </summary>
430 /// <param name="conn">NpgsqlConnector to send query through.</param>
431 /// <param name="TypeMappings">Mapping object to add types too.</param>
432 /// <param name="TypeInfoList">List of types that need to have OID's mapped.</param>
433 public static void LoadTypesMappings(NpgsqlConnector conn, NpgsqlBackendTypeMapping TypeMappings, IList TypeInfoList)
435 StringBuilder InList = new StringBuilder();
436 Hashtable NameIndex = new Hashtable();
438 // Build a clause for the SELECT statement.
439 // Build a name->typeinfo mapping so we can match the results of the query
440 /// with the list of type objects efficiently.
441 foreach (NpgsqlBackendTypeInfo TypeInfo in TypeInfoList) {
442 NameIndex.Add(TypeInfo.Name, TypeInfo);
443 InList.AppendFormat("{0}'{1}'", ((InList.Length > 0) ? ", " : ""), TypeInfo.Name);
446 if (InList.Length == 0) {
447 return;
450 NpgsqlCommand command = new NpgsqlCommand("SELECT oid, typname FROM pg_type WHERE typname IN (" + InList.ToString() + ")", conn);
451 NpgsqlDataReader dr = command.ExecuteReader();
453 while (dr.Read()) {
454 NpgsqlBackendTypeInfo TypeInfo = (NpgsqlBackendTypeInfo)NameIndex[dr[1].ToString()];
456 TypeInfo._OID = Convert.ToInt32(dr[0]);
458 TypeMappings.AddType(TypeInfo);
463 /// <summary>
464 /// Delegate called to convert the given backend data to its native representation.
465 /// </summary>
466 internal delegate Object ConvertBackendToNativeHandler(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier);
467 /// <summary>
468 /// Delegate called to convert the given native data to its backand representation.
469 /// </summary>
470 internal delegate String ConvertNativeToBackendHandler(NpgsqlNativeTypeInfo TypeInfo, Object NativeData);
472 /// <summary>
473 /// Represents a backend data type.
474 /// This class can be called upon to convert a backend field representation to a native object.
475 /// </summary>
476 internal class NpgsqlBackendTypeInfo
478 private ConvertBackendToNativeHandler _ConvertBackendToNative;
480 internal Int32 _OID;
481 private String _Name;
482 private NpgsqlDbType _NpgsqlDbType;
483 private DbType _DbType;
484 private Type _Type;
486 /// <summary>
487 /// Construct a new NpgsqlTypeInfo with the given attributes and conversion handlers.
488 /// </summary>
489 /// <param name="OID">Type OID provided by the backend server.</param>
490 /// <param name="Name">Type name provided by the backend server.</param>
491 /// <param name="NpgsqlDbType">NpgsqlDbType</param>
492 /// <param name="Type">System type to convert fields of this type to.</param>
493 /// <param name="ConvertBackendToNative">Data conversion handler.</param>
494 public NpgsqlBackendTypeInfo(Int32 OID, String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Type Type, ConvertBackendToNativeHandler ConvertBackendToNative)
496 _OID = OID;
497 _Name = Name;
498 _NpgsqlDbType = NpgsqlDbType;
499 _DbType = DbType;
500 _Type = Type;
501 _ConvertBackendToNative = ConvertBackendToNative;
504 /// <summary>
505 /// Type OID provided by the backend server.
506 /// </summary>
507 public Int32 OID
509 get { return _OID; }
512 /// <summary>
513 /// Type name provided by the backend server.
514 /// </summary>
515 public String Name
516 { get { return _Name; } }
518 /// <summary>
519 /// NpgsqlDbType.
520 /// </summary>
521 public NpgsqlDbType NpgsqlDbType
522 { get { return _NpgsqlDbType; } }
524 /// <summary>
525 /// NpgsqlDbType.
526 /// </summary>
527 public DbType DbType
528 { get { return _DbType; } }
530 /// <summary>
531 /// System type to convert fields of this type to.
532 /// </summary>
533 public Type Type
534 { get { return _Type; } }
536 /// <summary>
537 /// Perform a data conversion from a backend representation to
538 /// a native object.
539 /// </summary>
540 /// <param name="BackendData">Data sent from the backend.</param>
541 /// <param name="TypeModifier">Type modifier field sent from the backend.</param>
542 public Object ConvertToNative(String BackendData, Int16 TypeSize, Int32 TypeModifier)
544 if (_ConvertBackendToNative != null) {
545 return _ConvertBackendToNative(this, BackendData, TypeSize, TypeModifier);
546 } else {
547 try {
548 return Convert.ChangeType(BackendData, Type, CultureInfo.InvariantCulture);
549 } catch {
550 return BackendData;
556 /// <summary>
557 /// Represents a backend data type.
558 /// This class can be called upon to convert a native object to its backend field representation,
559 /// </summary>
560 internal class NpgsqlNativeTypeInfo
562 private static NumberFormatInfo ni;
564 private ConvertNativeToBackendHandler _ConvertNativeToBackend;
566 private String _Name;
567 private NpgsqlDbType _NpgsqlDbType;
568 private DbType _DbType;
569 private Boolean _Quote;
570 private Boolean _UseSize;
572 static NpgsqlNativeTypeInfo()
574 ni = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone();
575 ni.NumberDecimalDigits = 15;
578 /// <summary>
579 /// Construct a new NpgsqlTypeInfo with the given attributes and conversion handlers.
580 /// </summary>
581 /// <param name="OID">Type OID provided by the backend server.</param>
582 /// <param name="Name">Type name provided by the backend server.</param>
583 /// <param name="NpgsqlDbType">NpgsqlDbType</param>
584 /// <param name="Type">System type to convert fields of this type to.</param>
585 /// <param name="ConvertBackendToNative">Data conversion handler.</param>
586 /// <param name="ConvertNativeToBackend">Data conversion handler.</param>
587 public NpgsqlNativeTypeInfo(String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Boolean Quote, ConvertNativeToBackendHandler ConvertNativeToBackend)
589 _Name = Name;
590 _NpgsqlDbType = NpgsqlDbType;
591 _DbType = DbType;
592 _Quote = Quote;
593 _ConvertNativeToBackend = ConvertNativeToBackend;
596 // The only parameters types which use length currently supported are char and varchar. Check for them.
598 if ( (NpgsqlDbType == NpgsqlDbType.Char)
599 || (NpgsqlDbType == NpgsqlDbType.Varchar))
601 _UseSize = true;
602 else
603 _UseSize = false;
606 /// <summary>
607 /// Type name provided by the backend server.
608 /// </summary>
609 public String Name
610 { get { return _Name; } }
612 /// <summary>
613 /// NpgsqlDbType.
614 /// </summary>
615 public NpgsqlDbType NpgsqlDbType
616 { get { return _NpgsqlDbType; } }
618 /// <summary>
619 /// DbType.
620 /// </summary>
621 public DbType DbType
622 { get { return _DbType; } }
625 /// <summary>
626 /// Apply quoting.
627 /// </summary>
628 public Boolean Quote
629 { get { return _Quote; } }
631 /// <summary>
632 /// Use parameter size information.
633 /// </summary>
634 public Boolean UseSize
635 { get { return _UseSize; } }
638 /// <summary>
639 /// Perform a data conversion from a native object to
640 /// a backend representation.
641 /// DBNull and null values are handled differently depending if a plain query is used
642 /// When
643 /// </summary>
644 /// <param name="NativeData">Native .NET object to be converted.</param>
645 /// <param name="ForExtendedQuery">Flag indicating if the conversion has to be done for
646 /// plain queries or extended queries</param>
647 public String ConvertToBackend(Object NativeData, Boolean ForExtendedQuery)
649 if (ForExtendedQuery)
650 return ConvertToBackendExtendedQuery(NativeData);
651 else
652 return ConvertToBackendPlainQuery(NativeData);
656 private String ConvertToBackendPlainQuery(Object NativeData)
658 if ((NativeData == DBNull.Value) || (NativeData == null))
659 return "NULL"; // Plain queries exptects null values as string NULL.
661 if (_ConvertNativeToBackend != null)
662 return (this.Quote ? QuoteString(_ConvertNativeToBackend(this, NativeData)) : _ConvertNativeToBackend(this, NativeData));
663 else
667 if (NativeData is System.Enum)
669 // Do a special handling of Enum values.
670 // Translate enum value to its underlying type.
671 return QuoteString((String)Convert.ChangeType(Enum.Format(NativeData.GetType(), NativeData, "d"), typeof(String), CultureInfo.InvariantCulture));
673 else if (NativeData is IFormattable)
675 return (this.Quote ? QuoteString(((IFormattable) NativeData).ToString(null, ni).Replace("'", "''").Replace("\\", "\\\\")) :
676 ((IFormattable) NativeData).ToString(null, ni).Replace("'", "''").Replace("\\", "\\\\"));
680 // Do special handling of strings when in simple query. Escape quotes and backslashes.
681 return (this.Quote ? QuoteString(NativeData.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace("\0", "\\0")) :
682 NativeData.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace("\0", "\\0"));
688 private String ConvertToBackendExtendedQuery(Object NativeData)
690 if ((NativeData == DBNull.Value) || (NativeData == null))
691 return null; // Extended query expects null values be represented as null.
693 if (_ConvertNativeToBackend != null)
694 return _ConvertNativeToBackend(this, NativeData);
695 else
697 if (NativeData is System.Enum)
699 // Do a special handling of Enum values.
700 // Translate enum value to its underlying type.
701 return (String)Convert.ChangeType(Enum.Format(NativeData.GetType(), NativeData, "d"), typeof(String), CultureInfo.InvariantCulture);
703 else if (NativeData is IFormattable)
705 return ((IFormattable)NativeData).ToString(null, ni);
709 return NativeData.ToString();
715 private static String QuoteString(String S)
717 return String.Format("E'{0}'", S);
722 /// <summary>
723 /// Provide mapping between type OID, type name, and a NpgsqlBackendTypeInfo object that represents it.
724 /// </summary>
725 internal class NpgsqlBackendTypeMapping
727 private Hashtable OIDIndex;
728 private Hashtable NameIndex;
730 /// <summary>
731 /// Construct an empty mapping.
732 /// </summary>
733 public NpgsqlBackendTypeMapping()
735 OIDIndex = new Hashtable();
736 NameIndex = new Hashtable();
739 /// <summary>
740 /// Copy constuctor.
741 /// </summary>
742 private NpgsqlBackendTypeMapping(NpgsqlBackendTypeMapping Other)
744 OIDIndex = (Hashtable)Other.OIDIndex.Clone();
745 NameIndex = (Hashtable)Other.NameIndex.Clone();
748 /// <summary>
749 /// Add the given NpgsqlBackendTypeInfo to this mapping.
750 /// </summary>
751 public void AddType(NpgsqlBackendTypeInfo T)
753 if (OIDIndex.Contains(T.OID)) {
754 throw new Exception("Type already mapped");
757 OIDIndex[T.OID] = T;
758 NameIndex[T.Name] = T;
761 /// <summary>
762 /// Add a new NpgsqlBackendTypeInfo with the given attributes and conversion handlers to this mapping.
763 /// </summary>
764 /// <param name="OID">Type OID provided by the backend server.</param>
765 /// <param name="Name">Type name provided by the backend server.</param>
766 /// <param name="NpgsqlDbType">NpgsqlDbType</param>
767 /// <param name="Type">System type to convert fields of this type to.</param>
768 /// <param name="ConvertBackendToNative">Data conversion handler.</param>
769 public void AddType(Int32 OID, String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Type Type,
770 ConvertBackendToNativeHandler BackendConvert)
772 AddType(new NpgsqlBackendTypeInfo(OID, Name, NpgsqlDbType, DbType, Type, BackendConvert));
775 /// <summary>
776 /// Get the number of type infos held.
777 /// </summary>
778 public Int32 Count
779 { get { return NameIndex.Count; } }
781 /// <summary>
782 /// Retrieve the NpgsqlBackendTypeInfo with the given backend type OID, or null if none found.
783 /// </summary>
784 public NpgsqlBackendTypeInfo this [Int32 OID]
788 return (NpgsqlBackendTypeInfo)OIDIndex[OID];
792 /// <summary>
793 /// Retrieve the NpgsqlBackendTypeInfo with the given backend type name, or null if none found.
794 /// </summary>
795 public NpgsqlBackendTypeInfo this [String Name]
799 return (NpgsqlBackendTypeInfo)NameIndex[Name];
803 /// <summary>
804 /// Make a shallow copy of this type mapping.
805 /// </summary>
806 public NpgsqlBackendTypeMapping Clone()
808 return new NpgsqlBackendTypeMapping(this);
811 /// <summary>
812 /// Determine if a NpgsqlBackendTypeInfo with the given backend type OID exists in this mapping.
813 /// </summary>
814 public Boolean ContainsOID(Int32 OID)
816 return OIDIndex.ContainsKey(OID);
819 /// <summary>
820 /// Determine if a NpgsqlBackendTypeInfo with the given backend type name exists in this mapping.
821 /// </summary>
822 public Boolean ContainsName(String Name)
824 return NameIndex.ContainsKey(Name);
830 /// <summary>
831 /// Provide mapping between type Type, NpgsqlDbType and a NpgsqlNativeTypeInfo object that represents it.
832 /// </summary>
833 internal class NpgsqlNativeTypeMapping
835 private Hashtable NameIndex;
836 private Hashtable NpgsqlDbTypeIndex;
837 private Hashtable DbTypeIndex;
838 private Hashtable TypeIndex;
840 /// <summary>
841 /// Construct an empty mapping.
842 /// </summary>
843 public NpgsqlNativeTypeMapping()
845 NameIndex = new Hashtable();
846 NpgsqlDbTypeIndex = new Hashtable();
847 DbTypeIndex = new Hashtable();
848 TypeIndex = new Hashtable();
851 /// <summary>
852 /// Add the given NpgsqlNativeTypeInfo to this mapping.
853 /// </summary>
854 public void AddType(NpgsqlNativeTypeInfo T)
856 if (NameIndex.Contains(T.Name)) {
857 throw new Exception("Type already mapped");
860 NameIndex[T.Name] = T;
861 NpgsqlDbTypeIndex[T.NpgsqlDbType] = T;
862 DbTypeIndex[T.DbType] = T;
865 /// <summary>
866 /// Add a new NpgsqlNativeTypeInfo with the given attributes and conversion handlers to this mapping.
867 /// </summary>
868 /// <param name="OID">Type OID provided by the backend server.</param>
869 /// <param name="Name">Type name provided by the backend server.</param>
870 /// <param name="NpgsqlDbType">NpgsqlDbType</param>
871 /// <param name="ConvertBackendToNative">Data conversion handler.</param>
872 /// <param name="ConvertNativeToBackend">Data conversion handler.</param>
873 public void AddType(String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Boolean Quote,
874 ConvertNativeToBackendHandler NativeConvert)
876 AddType(new NpgsqlNativeTypeInfo(Name, NpgsqlDbType, DbType, Quote, NativeConvert));
879 public void AddNpgsqlDbTypeAlias(String Name, NpgsqlDbType NpgsqlDbType)
881 if (NpgsqlDbTypeIndex.Contains(NpgsqlDbType)) {
882 throw new Exception("NpgsqlDbType already aliased");
885 NpgsqlDbTypeIndex[NpgsqlDbType] = NameIndex[Name];
888 public void AddDbTypeAlias(String Name, DbType DbType)
890 if (DbTypeIndex.Contains(DbType)) {
891 throw new Exception("NpgsqlDbType already aliased");
894 DbTypeIndex[DbType] = NameIndex[Name];
897 public void AddTypeAlias(String Name, Type Type)
899 if (TypeIndex.Contains(Type)) {
900 throw new Exception("Type already aliased");
903 TypeIndex[Type] = NameIndex[Name];
906 /// <summary>
907 /// Get the number of type infos held.
908 /// </summary>
909 public Int32 Count
910 { get { return NameIndex.Count; } }
912 /// <summary>
913 /// Retrieve the NpgsqlNativeTypeInfo with the given backend type name, or null if none found.
914 /// </summary>
915 public NpgsqlNativeTypeInfo this [String Name]
919 return (NpgsqlNativeTypeInfo)NameIndex[Name];
923 /// <summary>
924 /// Retrieve the NpgsqlNativeTypeInfo with the given NpgsqlDbType, or null if none found.
925 /// </summary>
926 public NpgsqlNativeTypeInfo this [NpgsqlDbType NpgsqlDbType]
930 return (NpgsqlNativeTypeInfo)NpgsqlDbTypeIndex[NpgsqlDbType];
934 /// <summary>
935 /// Retrieve the NpgsqlNativeTypeInfo with the given DbType, or null if none found.
936 /// </summary>
937 public NpgsqlNativeTypeInfo this [DbType DbType]
941 return (NpgsqlNativeTypeInfo)DbTypeIndex[DbType];
947 /// <summary>
948 /// Retrieve the NpgsqlNativeTypeInfo with the given Type, or null if none found.
949 /// </summary>
950 public NpgsqlNativeTypeInfo this [Type Type]
954 return (NpgsqlNativeTypeInfo)TypeIndex[Type];
958 /// <summary>
959 /// Determine if a NpgsqlNativeTypeInfo with the given backend type name exists in this mapping.
960 /// </summary>
961 public Boolean ContainsName(String Name)
963 return NameIndex.ContainsKey(Name);
966 /// <summary>
967 /// Determine if a NpgsqlNativeTypeInfo with the given NpgsqlDbType exists in this mapping.
968 /// </summary>
969 public Boolean ContainsNpgsqlDbType(NpgsqlDbType NpgsqlDbType)
971 return NpgsqlDbTypeIndex.ContainsKey(NpgsqlDbType);
974 /// <summary>
975 /// Determine if a NpgsqlNativeTypeInfo with the given Type name exists in this mapping.
976 /// </summary>
977 public Boolean ContainsType(Type Type)
979 return TypeIndex.ContainsKey(Type);