internal async Task <List <PostgresType> > LoadBackendTypes(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async) { var commandTimeout = 0; // Default to infinity if (timeout.IsSet) { commandTimeout = (int)timeout.TimeLeft.TotalSeconds; if (commandTimeout <= 0) { throw new TimeoutException(); } } var typeLoadingQuery = GenerateTypesQuery(SupportsRangeTypes, SupportsEnumTypes, conn.Settings.LoadTableComposites); using (var command = new NpgsqlCommand(typeLoadingQuery, conn)) { command.CommandTimeout = commandTimeout; command.AllResultTypesAreUnknown = true; using (var reader = async ? await command.ExecuteReaderAsync() : command.ExecuteReader()) { var byOID = new Dictionary <uint, PostgresType>(); // First load the types themselves while (async ? await reader.ReadAsync() : reader.Read()) { timeout.Check(); var ns = reader.GetString(reader.GetOrdinal("nspname")); var internalName = reader.GetString(reader.GetOrdinal("typname")); var oid = Convert.ToUInt32(reader[reader.GetOrdinal("oid")]); Debug.Assert(internalName != null); Debug.Assert(oid != 0); var typeChar = reader.GetString(reader.GetOrdinal("type"))[0]; switch (typeChar) { case 'b': // Normal base type var baseType = new PostgresBaseType(ns, internalName, oid); byOID[baseType.OID] = baseType; continue; case 'a': // Array { var elementOID = Convert.ToUInt32(reader[reader.GetOrdinal("elemoid")]); Debug.Assert(elementOID > 0); if (!byOID.TryGetValue(elementOID, out var elementPostgresType)) { Log.Trace($"Array type '{internalName}' refers to unknown element with OID {elementOID}, skipping", conn.ProcessID); continue; } var arrayType = new PostgresArrayType(ns, internalName, oid, elementPostgresType); byOID[arrayType.OID] = arrayType; continue; } case 'r': // Range { var elementOID = Convert.ToUInt32(reader[reader.GetOrdinal("elemoid")]); Debug.Assert(elementOID > 0); if (!byOID.TryGetValue(elementOID, out var subtypePostgresType)) { Log.Trace($"Range type '{internalName}' refers to unknown subtype with OID {elementOID}, skipping", conn.ProcessID); continue; } var rangeType = new PostgresRangeType(ns, internalName, oid, subtypePostgresType); byOID[rangeType.OID] = rangeType; continue; } case 'e': // Enum var enumType = new PostgresEnumType(ns, internalName, oid); byOID[enumType.OID] = enumType; continue; case 'c': // Composite // Unlike other types, we don't var compositeType = new PostgresCompositeType(ns, internalName, oid); byOID[compositeType.OID] = compositeType; continue; case 'd': // Domain var baseTypeOID = Convert.ToUInt32(reader[reader.GetOrdinal("typbasetype")]); Debug.Assert(baseTypeOID > 0); if (!byOID.TryGetValue(baseTypeOID, out var basePostgresType)) { Log.Trace($"Domain type '{internalName}' refers to unknown base type with OID {baseTypeOID}, skipping", conn.ProcessID); continue; } var domainType = new PostgresDomainType(ns, internalName, oid, basePostgresType); byOID[domainType.OID] = domainType; continue; case 'p': // pseudo-type (record, void) // Hack this as a base type goto case 'b'; default: throw new ArgumentOutOfRangeException($"Unknown typtype for type '{internalName}' in pg_type: {typeChar}"); } } if (async) { await reader.NextResultAsync(); } else { reader.NextResult(); } LoadCompositeFields(reader, byOID); if (SupportsEnumTypes) { if (async) { await reader.NextResultAsync(); } else { reader.NextResult(); } LoadEnumLabels(reader, byOID); } return(byOID.Values.ToList()); } } }
void LoadBackendType(DbDataReader reader, NpgsqlConnector connector) { var ns = reader.GetString(reader.GetOrdinal("nspname")); var name = reader.GetString(reader.GetOrdinal("typname")); var oid = Convert.ToUInt32(reader[reader.GetOrdinal("oid")]); Debug.Assert(name != null); Debug.Assert(oid != 0); var typeChar = reader.GetString(reader.GetOrdinal("type"))[0]; switch (typeChar) { case 'b': // Normal base type var baseType = new PostgresBaseType(ns, name, oid); Add(baseType); BaseTypes.Add(baseType); return; case 'a': // Array { var elementOID = Convert.ToUInt32(reader[reader.GetOrdinal("elemoid")]); Debug.Assert(elementOID > 0); if (!ByOID.TryGetValue(elementOID, out var elementPostgresType)) { Log.Trace($"Array type '{name}' refers to unknown element with OID {elementOID}, skipping", connector.Id); return; } var arrayType = new PostgresArrayType(ns, name, oid, elementPostgresType); Add(arrayType); ArrayTypes.Add(arrayType); return; } case 'r': // Range { var elementOID = Convert.ToUInt32(reader[reader.GetOrdinal("elemoid")]); Debug.Assert(elementOID > 0); if (!ByOID.TryGetValue(elementOID, out var subtypePostgresType)) { Log.Trace($"Range type '{name}' refers to unknown subtype with OID {elementOID}, skipping", connector.Id); return; } var rangeType = new PostgresRangeType(ns, name, oid, subtypePostgresType); Add(rangeType); RangeTypes.Add(rangeType); return; } case 'e': // Enum var enumType = new PostgresEnumType(ns, name, oid); Add(enumType); EnumTypes.Add(enumType); return; case 'c': // Composite var compositeType = new PostgresCompositeType(ns, name, oid); Add(compositeType); CompositeTypes.Add(compositeType); return; case 'd': // Domain var baseTypeOID = Convert.ToUInt32(reader[reader.GetOrdinal("typbasetype")]); Debug.Assert(baseTypeOID > 0); if (!ByOID.TryGetValue(baseTypeOID, out var basePostgresType)) { Log.Trace($"Domain type '{name}' refers to unknown base type with OID {baseTypeOID}, skipping", connector.Id); return; } var domainType = new PostgresDomainType(ns, name, oid, basePostgresType); Add(domainType); DomainTypes.Add(domainType); return; case 'p': // pseudo-type (record, void) // Hack this as a base type goto case 'b'; default: throw new ArgumentOutOfRangeException($"Unknown typtype for type '{name}' in pg_type: {typeChar}"); } }