Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal error: use of unresolved type declaration #1477

Closed
demurgos opened this issue Oct 7, 2021 · 8 comments · Fixed by #1483
Closed

Internal error: use of unresolved type declaration #1477

demurgos opened this issue Oct 7, 2021 · 8 comments · Fixed by #1483

Comments

@demurgos
Copy link
Contributor

demurgos commented Oct 7, 2021

I am trying to use a Postgres composite type but get the following error:

internal error: entered unreachable code: (bug) use of unresolved type declaration [oid=27222609]

When querying pg_type manually, I can retrieve the type (it is my composite type). It means that there is an issue somewhere in the type resolver. I will further investigate the issue and send a PR to fix it.

@demurgos
Copy link
Contributor Author

demurgos commented Oct 8, 2021

I managed to reproduce the issue in the test suite. I am still working on the fix.

#[sqlx_macros::test]
async fn it_supports_composite_types_in_arrays() -> anyhow::Result<()> {
    // Only supported in Postgres 11+
    let mut conn = new::<Postgres>().await?;
    if matches!(conn.server_version_num(), Some(version) if version < 110000) {
        return Ok(());
    }

    conn.execute(
        r#"
DROP TABLE IF EXISTS pets;
DROP DOMAIN IF EXISTS pet_name_and_race_array;
DROP TYPE IF EXISTS PET_NAME_AND_RACE;

CREATE TYPE PET_NAME_AND_RACE AS (
  name TEXT,
  race TEXT
);
CREATE DOMAIN pet_name_and_race_array AS PET_NAME_AND_RACE[];
CREATE TABLE pets (
  owner TEXT NOT NULL,
  name TEXT NOT NULL,
  race TEXT NOT NULL,
  PRIMARY KEY (owner, name)
);
INSERT INTO pets(owner, name, race)
VALUES
  ('Alice', 'Foo', 'cat');
INSERT INTO pets(owner, name, race)
VALUES
  ('Alice', 'Bar', 'dog');
    "#,
    )
        .await?;

    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    struct PetNameAndRace {
        name: String,
        race: String,
    }

    impl sqlx::Type<Postgres> for PetNameAndRace {
        fn type_info() -> sqlx::postgres::PgTypeInfo {
            sqlx::postgres::PgTypeInfo::with_name("pet_name_and_race")
        }
    }

    impl<'r> sqlx::Decode<'r, Postgres> for PetNameAndRace {
        fn decode(
            value: sqlx::postgres::PgValueRef<'r>,
        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
            let mut decoder = sqlx::postgres::types::PgRecordDecoder::new(value)?;
            let name = decoder.try_decode::<String>()?;
            let race = decoder.try_decode::<String>()?;
            Ok(Self {name, race})
        }
    }

    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    struct PetNameAndRaceArray(Vec<PetNameAndRace>);

    impl sqlx::Type<Postgres> for PetNameAndRaceArray {
        fn type_info() -> sqlx::postgres::PgTypeInfo {
            // Array type name is the name of the element type prefixed with `_`
            sqlx::postgres::PgTypeInfo::with_name("_pet_name_and_race")
        }
    }

    impl<'r> sqlx::Decode<'r, Postgres> for PetNameAndRaceArray {
        fn decode(
            value: sqlx::postgres::PgValueRef<'r>,
        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
            Ok(Self(Vec::<PetNameAndRace>::decode(value)?))
        }
    }


    let mut conn = new::<Postgres>().await?;

    let row = sqlx::query("select owner, array_agg(row(name, race)::pet_name_and_race) as pets from pets group by owner")
        .fetch_one(&mut conn)
        .await?;

    let pets: PetNameAndRaceArray = row.get("pets");

    assert_eq!(pets.0.len(), 2);
    Ok(())
}

demurgos added a commit to demurgos/sqlx that referenced this issue Oct 8, 2021
This commit fixes the array decoder to support custom types. The core of the issue was that the array decoder did not use the type info retrieved from the database. It means that it only supported native types.

This commit fixes the issue by using the element type info fetched from the database. A new internal helper method is added to the `PgType` struct: it returns the type info for the inner array element, if available.

Closes launchbadge#1477
@demurgos
Copy link
Contributor Author

demurgos commented Oct 8, 2021

I sent a PR ( #1483 ) to fix the issue. The root cause was that the array decoder ignored the type info fetched from the DB, preventing it from supporting custom types.

demurgos added a commit to demurgos/sqlx that referenced this issue Oct 9, 2021
This commit fixes the array decoder to support custom types. The core of the issue was that the array decoder did not use the type info retrieved from the database. It means that it only supported native types.

This commit fixes the issue by using the element type info fetched from the database. A new internal helper method is added to the `PgType` struct: it returns the type info for the inner array element, if available.

Closes launchbadge#1477
@demurgos
Copy link
Contributor Author

@jplatte @abonander
I just noticed that besides the PR I send ( #1483 ) there is already is a similar PR: #1385

Could you comment on any of those PRs? This issue currently forces me to use my temporary fork of the lib, and I would much rather prefer to use the official version.

@jplatte
Copy link
Contributor

jplatte commented Nov 13, 2021

Actually, #1385 and #1483 are entirely orthogonal: My PR doesn't touch the encode / decode logic at all, it only affects the sqlx::Type trait.

I am not at all familiar with the postgres protocol and the Encode / Decode stuff, so can't comment on your PR.

@demurgos
Copy link
Contributor Author

I am not sure I understand your reply: both PRs are about improving support for arrays of custom types, and they don't touch the Postgres protocol.

The only change my PR does is that it reuses the type info already fetched from the DB to read arrays (so it is not restricted to built-in types).

@jplatte
Copy link
Contributor

jplatte commented Nov 13, 2021

The only change my PR does is that it reuses the type info already fetched from the DB to read arrays

My PR doesn't change the behavior of how things are read / written. It is simply an addition that allows users to declare (through the new PgHasArrayType trait) the type name of the corresponding array type for a given Rust type such that Vec<CustomType> implements sqlx::Type, the same way implementing the Type trait allows declaring the corresponding regular DB type.

@winston0410
Copy link

The PR of @demurgos has solved the issue perfectly! Can it be merged anytime soon?

@iupii
Copy link

iupii commented Dec 6, 2021

I have the same issue.

abonander pushed a commit that referenced this issue Dec 29, 2021
This commit fixes the array decoder to support custom types. The core of the issue was that the array decoder did not use the type info retrieved from the database. It means that it only supported native types.

This commit fixes the issue by using the element type info fetched from the database. A new internal helper method is added to the `PgType` struct: it returns the type info for the inner array element, if available.

Closes #1477
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants