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;
        }