NpgsqlDbColumn LoadColumnDefinition(NpgsqlDataReader reader, DatabaseInfo databaseInfo) { // Note: we don't set ColumnName and BaseColumnName. These should always contain the // column alias rather than the table column name (i.e. in case of "SELECT foo AS foo_alias"). // It will be set later. var column = new NpgsqlDbColumn { AllowDBNull = !reader.GetBoolean(reader.GetOrdinal("attnotnull")), BaseCatalogName = _connection.Database, BaseSchemaName = reader.GetString(reader.GetOrdinal("nspname")), BaseServerName = _connection.Host, BaseTableName = reader.GetString(reader.GetOrdinal("relname")), ColumnOrdinal = reader.GetInt32(reader.GetOrdinal("attnum")) - 1, ColumnAttributeNumber = (short)(reader.GetInt16(reader.GetOrdinal("attnum")) - 1), IsKey = reader.GetBoolean(reader.GetOrdinal("isprimarykey")), IsReadOnly = !reader.GetBoolean(reader.GetOrdinal("is_updatable")), IsUnique = reader.GetBoolean(reader.GetOrdinal("isunique")), DataTypeName = reader.GetString(reader.GetOrdinal("typname")), TableOID = reader.GetFieldValue<uint>(reader.GetOrdinal("attrelid")), TypeOID = reader.GetFieldValue<uint>(reader.GetOrdinal("typoid")) }; column.PostgresType = databaseInfo.ByOID[column.TypeOID]; var defaultValueOrdinal = reader.GetOrdinal("default"); column.DefaultValue = reader.IsDBNull(defaultValueOrdinal) ? null : reader.GetString(defaultValueOrdinal); column.IsAutoIncrement = column.DefaultValue != null && column.DefaultValue.StartsWith("nextval("); ColumnPostConfig(column, reader.GetInt32(reader.GetOrdinal("typmod"))); return column; }
/// <summary> /// Performs some post-setup configuration that's common to both table columns and non-columns. /// </summary> void ColumnPostConfig(NpgsqlDbColumn column, int typeModifier) { var typeMapper = _connection.Connector.TypeMapper; if (typeMapper.Mappings.TryGetValue(column.DataTypeName, out var mapping)) column.NpgsqlDbType = mapping.NpgsqlDbType; else if ( column.DataTypeName.Contains(".") && typeMapper.Mappings.TryGetValue(column.DataTypeName.Split('.')[1], out mapping) ) { column.NpgsqlDbType = mapping.NpgsqlDbType; } column.DataType = typeMapper.TryGetByOID(column.TypeOID, out var handler) ? handler.GetFieldType() : null; if (column.DataType != null) { column.IsLong = handler is ByteaHandler; if (handler is IMappedCompositeHandler) column.UdtAssemblyQualifiedName = column.DataType.AssemblyQualifiedName; } if (typeModifier == -1) return; // If the column's type is a domain, use its base data type to interpret the typmod var dataTypeName = column.PostgresType is PostgresDomainType ? ((PostgresDomainType)column.PostgresType).BaseType.Name : column.DataTypeName; switch (dataTypeName) { case "bpchar": case "char": case "varchar": column.ColumnSize = typeModifier - 4; break; case "numeric": case "decimal": // See http://stackoverflow.com/questions/3350148/where-are-numeric-precision-and-scale-for-a-field-found-in-the-pg-catalog-tables column.NumericPrecision = ((typeModifier - 4) >> 16) & 65535; column.NumericScale = (typeModifier - 4) & 65535; break; } }
NpgsqlDbColumn SetUpNonColumnField(FieldDescription field) { // ColumnName and BaseColumnName will be set later var column = new NpgsqlDbColumn { BaseCatalogName = _connection.Database, BaseServerName = _connection.Host, IsReadOnly = true, DataTypeName = field.PostgresType.DisplayName, TypeOID = field.TypeOID, TableOID = field.TableOID, ColumnAttributeNumber = field.ColumnAttributeNumber, PostgresType = field.PostgresType }; ColumnPostConfig(column, field.TypeModifier); return column; }