-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Can't decode PostgreSQL arrays of custom types #1672
Comments
Any update on this? |
Anyone who could point into the correct direction on how to fix this? We really need this feature. |
Try adding |
Thank you for helping @abonander. I added the attribute, but it didn't help unfortunately. I looked up the oid and it's sqlx/tests/postgres/postgres.rs Lines 1423 to 1425 in 32f1273
|
@abonander I guess I have the same issue. I described it on the forum: https://users.rust-lang.org/t/how-should-one-use-sqlx-with-newtype-pattern/73172. Is it a bug or a feature? |
Hi, I've hit this bug in my own code last week and started working on a patch. I believe that the best solution to fix it is to refactor how SQLx handles types. Even if refactoring type resolution does not land immediately, I think it should help locating the source of the bug. I will do my best to provide a fix in a timely manner. |
A quick update on this bug. Over the last weeks, I was working on refactoring Postgres types. The linked PR is pretty exploratory and will need a lot of work before it can be in a state where it could get merged, however it was pretty helpful: it turned this runtime panic into a compilation error. The essence of the issue is that custom types must be resolved from the DB, and then decoders must get access to their metadata. However, decoders can't pass arbitrary state and context gets lost. When context gets lost, the decoders fallback to using Using A quick solution would be to maintain context in a thread local or other similar ambient store, similarly to how async runtime or logger sinks are passed down implicitly. I prefer serde's style of using explicit deserializers, but this a larger change. I'll continue work on my experimental branch to fix the issue, but full support for the Postgres type system (including custom types) will need deeper changes to SQLx. This means that the fix may take a long time before it's merged. In the meantime, I can at least replace panics with regular errors. |
Postgres arrays and records do not fully support custom types. When encountering an unknown OID, they currently default to using `PgTypeInfo::with_oid`. This is invalid as it breaks the invariant that decoding only uses resolved types, leading to panics. This commit returns an error instead of panicking. This is merely a mitigation: a proper fix would actually add full support for custom Postgres types. Full support involves more work, so it may still be useful to fix this immediate issue. Related issues: - launchbadge#1672 - launchbadge#1797
Postgres arrays and records do not fully support custom types. When encountering an unknown OID, they currently default to using `PgTypeInfo::with_oid`. This is invalid as it breaks the invariant that decoding only uses resolved types, leading to panics. This commit returns an error instead of panicking. This is merely a mitigation: a proper fix would actually add full support for custom Postgres types. Full support involves more work, so it may still be useful to fix this immediate issue. Related issues: - launchbadge#1672 - launchbadge#1797
I have a good news: I have a branch where I am able to decode anonymous records and arrays of custom types. The bad news is that it requires quite a few changes. I'll write a message going more into details but here are the main points:
My plan is to fix Clippy issues / make sure CI passes, and then discuss how to implement the various changes required to support this feature. |
Postgres arrays and records do not fully support custom types. When encountering an unknown OID, they currently default to using `PgTypeInfo::with_oid`. This is invalid as it breaks the invariant that decoding only uses resolved types, leading to panics. This commit returns an error instead of panicking. This is merely a mitigation: a proper fix would actually add full support for custom Postgres types. Full support involves more work, so it may still be useful to fix this immediate issue. Related issues: - #1672 - #1797
I could really use this. I don't care that the failure will occur at decode time, having some way have mapping anonymous records and arrays of anon records is better than no way. My first attempt at this was similar to the following: #[derive(Clone, Debug)]
pub struct Data {
pub sub_data: Vec<SubData>,
pub some_bool: bool,
}
// This just has scalar fields so derive `FromRow` works
// but this type _does not_ exist in the database, it's just for
// data returned by a query I'm running.
#[derive(Clone, Debug, sqlx::Decode, sqlx::FromRow)]
pub struct SubData { ...stuff... }
impl<'r> sqlx::FromRow<'r, PgRow> for Data {
fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
// The column with array of records in my returned data is named `sub_data`.
let sub_data: Vec<SubData> = row
.try_get::<Vec<PgRow>, _>("sub_data")?
.into_iter()
.map(|sub_data_tuple| SubData::from_row(&sub_data_tuple))
.collect();
Ok(Data {
sub_data,
some_bool: row.try_get("some_bool")?,
})
}
} but I end up with
It seems like if at least |
@rex-remind101 did you find a way? |
Looks like for arrays to work one needs a newtype and implement Type and Decode for it as seen in https://github.com/launchbadge/sqlx/pull/1483/files#diff-227edfb063a81fad99246f78753bb75d1d2262b95efc8c2115fe30081fd97c3bR1154-R1170 |
I just hit that error too with
This was my code #[derive(Debug, sqlx::Type)]
#[sqlx(type_name = "http_response")]
struct HttpResponseRecord {
headers: Vec<HeaderPairRecord>,
}
#[derive(Debug, sqlx::Type)]
#[sqlx(type_name = "header_pair")]
struct HeaderPairRecord {
name: String,
value: String,
}
[...]
sqlx::query!(
r#"
INSERT INTO responses (response, created_at)
VALUES ($1, NOW())
"#,
&http_response_record as _,
)
.execute(connection)
.await?; with this table definition: CREATE TYPE header_pair AS (
name TEXT,
value TEXT
);
CREATE TYPE http_response AS (
headers header_pair[],
);
CREATE TABLE responses (
response http_response NOT NULL,
created_at timestamptz NOT NULL
); Using cargo-expand I noticed the #[automatically_derived]
impl ::sqlx::postgres::PgHasArrayType for HeaderPairRecord {
fn array_type_info() -> ::sqlx::postgres::PgTypeInfo {
::sqlx::postgres::PgTypeInfo::array_of("header_pair")
}
} which, according to But in my case, I was able to resolve the issue by disabling that derived #[derive(Debug, sqlx::Type)]
#[sqlx(type_name = "header_pair", no_pg_array)]
struct HeaderPairRecord {
name: String,
value: String,
}
impl PgHasArrayType for HeaderPairRecord {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::with_name("header_pair[]")
}
} I was surprised this worked as there are tickets and comments on this repo pointing to Postgres automatically prefixing custom type arrays with It seems implementing #3003 would work in my case, but this seems contrary to all those links above 🤔 . |
issue is open at launchbadge/sqlx#1672
I'm trying to decode an array of custom (PosgreSQL) types inside a record, using
PgRecordDecoder
. It hits the panic found here:sqlx/sqlx-core/src/postgres/type_info.rs
Line 866 in 2182925
It has an
oid
which matches the array version of my custom enum (e.g._mytype
for the code below).I think the following should reproduce it.
The text was updated successfully, but these errors were encountered: