private NativeToBackendTypeConverterOptions(bool Immutable, bool useConformantStrings, bool supports_E_StringPrefix, bool supportsHexByteFormat, NpgsqlBackendTypeMapping oidToNameMapping) { this.IsImmutable = Immutable; this._UseConformantStrings = useConformantStrings; this._Supports_E_StringPrefix = supports_E_StringPrefix; this._SupportsHexByteFormat = supportsHexByteFormat; this._oidToNameMapping = oidToNameMapping; }
///<summary> /// This method creates (or retrieves from cache) a mapping between type and OID /// of all natively supported postgresql data types. /// This is needed as from one version to another, this mapping can be changed and /// so we avoid hardcoding them. /// </summary> /// <returns>NpgsqlTypeMapping containing all known data types. The mapping must be /// cloned before it is modified because it is cached; changes made by one connection may /// effect another connection. /// </returns> public static NpgsqlBackendTypeMapping CreateAndLoadInitialTypesMapping(NpgsqlConnector conn) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "LoadTypesMapping"); MappingKey key = new MappingKey(conn); // Check the cache for an initial types map. NpgsqlBackendTypeMapping oidToNameMapping = null; if (BackendTypeMappingCache.TryGetValue(key, out oidToNameMapping)) { return(oidToNameMapping); } // Not in cache, create a new one. oidToNameMapping = new NpgsqlBackendTypeMapping(); // Create a list of all natively supported postgresql data types. // Attempt to map each type info in the list to an OID on the backend and // add each mapped type to the new type mapping object. LoadTypesMappings(conn, oidToNameMapping, TypeInfoList(conn.UseExtendedTypes, conn.CompatVersion)); //We hold the lock for the least time possible on the least scope possible. //We must lock on BackendTypeMappingCache because it will be updated by this operation, //and we must not just add to it, but also check that another thread hasn't updated it //in the meantime. Strictly just doing : //return BackendTypeMappingCache[key] = oidToNameMapping; //as the only call within the locked section should be safe and correct, but we'll assume //there's some subtle problem with temporarily having two copies of the same mapping and //ensure only one is called. //It is of course wasteful that multiple threads could be creating mappings when only one //will be used, but we aim for better overall concurrency at the risk of causing some //threads the extra work. NpgsqlBackendTypeMapping mappingCheck = null; //First check without acquiring the lock; don't lock if we don't have to. if (BackendTypeMappingCache.TryGetValue(key, out mappingCheck))//Another thread built the mapping in the meantime. { return(mappingCheck); } lock (BackendTypeMappingCache) { //Final check. We have the lock now so if this fails it'll continue to fail. if (BackendTypeMappingCache.TryGetValue(key, out mappingCheck))//Another thread built the mapping in the meantime. { return(mappingCheck); } // Add this mapping to the per-server-version cache so we don't have to // do these expensive queries on every connection startup. BackendTypeMappingCache.Add(key, oidToNameMapping); } return(oidToNameMapping); }
/// <summary> /// Attempt to map types by issuing a query against pg_type. /// This function takes a list of NpgsqlTypeInfo and attempts to resolve the OID field /// of each by querying pg_type. If the mapping is found, the type info object is /// updated (OID) and added to the provided NpgsqlTypeMapping object. /// </summary> /// <param name="conn">NpgsqlConnector to send query through.</param> /// <param name="TypeMappings">Mapping object to add types too.</param> /// <param name="TypeInfoList">List of types that need to have OID's mapped.</param> public static void LoadTypesMappings(NpgsqlConnector conn, NpgsqlBackendTypeMapping TypeMappings, IEnumerable <NpgsqlBackendTypeInfo> TypeInfoList) { StringBuilder InList = new StringBuilder(); Dictionary <string, NpgsqlBackendTypeInfo> NameIndex = new Dictionary <string, NpgsqlBackendTypeInfo>(); // Build a clause for the SELECT statement. // Build a name->typeinfo mapping so we can match the results of the query // with the list of type objects efficiently. foreach (NpgsqlBackendTypeInfo TypeInfo in TypeInfoList) { NameIndex.Add(TypeInfo.Name, TypeInfo); InList.AppendFormat("{0}'{1}'", ((InList.Length > 0) ? ", " : ""), TypeInfo.Name); //do the same for the equivalent array type. NameIndex.Add("_" + TypeInfo.Name, ArrayTypeInfo(TypeInfo)); InList.Append(", '_").Append(TypeInfo.Name).Append('\''); } if (InList.Length == 0) { return; } using ( NpgsqlCommand command = new NpgsqlCommand(string.Format("SELECT typname, oid FROM pg_type WHERE typname IN ({0})", InList), conn)) { using (NpgsqlDataReader dr = command.GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { while (dr.Read()) { NpgsqlBackendTypeInfo TypeInfo = NameIndex[dr[0].ToString()]; TypeInfo._OID = Convert.ToInt32(dr[1]); TypeMappings.AddType(TypeInfo); } } } }
/// <summary> /// Copy constuctor. /// </summary> private NpgsqlBackendTypeMapping(NpgsqlBackendTypeMapping Other) { OIDIndex = new Dictionary <int, NpgsqlBackendTypeInfo>(Other.OIDIndex); NameIndex = new Dictionary <string, NpgsqlBackendTypeInfo>(Other.NameIndex); }
/// <summary> /// Clone the current object with a different OID/Name mapping. /// </summary> /// <param name="oidToNameMapping">OID/Name mapping object to use in the new instance.</param> /// <returns>A new NativeToBackendTypeConverterOptions object.</returns> internal NativeToBackendTypeConverterOptions Clone(NpgsqlBackendTypeMapping oidToNameMapping = null) { return(new NativeToBackendTypeConverterOptions(_UseConformantStrings, _Supports_E_StringPrefix, _SupportsHexByteFormat, oidToNameMapping)); }
internal NativeToBackendTypeConverterOptions(bool useConformantStrings, bool supports_E_StringPrefix, bool supportsHexByteFormat, NpgsqlBackendTypeMapping oidToNameMapping) : this(false, useConformantStrings, supports_E_StringPrefix, supportsHexByteFormat, oidToNameMapping) { }