Skip to content

Query!() macros appear to not check the type name of domain and composite types in certain situations in postgres databases. #4003

@kairoswater-jason

Description

@kairoswater-jason

I have found these related issues/pull requests

#3641

This issue persists even with the above fix

Description

When writing SELECT and INSERT queries on the examples below, the query macro appears to behave inconsistently with regards to type checking.

In certain situations it will recognize that the SQL NewType type_created_at and the Rust NewType CreatedAt are distinct types from the SQL type timestamptz and the Rust type OffsetDateTime. Other times it will treat them as equivalent. The OffsetDateTime::type_into()::type_compatible(...) and CreatedAt::type_into()::type_compatible(...) functions correctly reports that they are different and incompatible types. Checking on the SQL side seems to sometimes but not always check the custom type name/domain name (perhaps via pg_catalog.pg_type.typname or alternatively via information_schema.columns.domain_name and information_schema.columns.udt_name).

The inconsistent behavior seems like a bug.

        let created_at_type = CreatedAt::type_info();
        let datetime_type = OffsetDateTime::type_info();
        println!("{:?}", created_at_type.type_compatible(&datetime_type));
        println!("{:?}", datetime_type.type_compatible(&created_at_type));

//---- types::tests::check_compatible stdout ----
//false
//false

I also found that I can insert a newtype (struct MyNewType(OffsetDateTime)) as if it was a different composite type (struct MyCompositeType { time: OffsetDateTime }). It appears using the as operator in macro bindings effectively turns off type checking entirely in postgres even if a type is supplied.

        //swapping out the commented values do not result in errors on a table using MyCompositeType/my_composite_type
        let inserted_id = sqlx::query_file_scalar!("queries/my_insert.sql",
            my_newtype as MyNewType, //my_composite_type as MyCompositeType
        ).fetch_one(&mut *conn).await?;

Reproduction steps

CREATE DOMAIN type_created_at AS timestamptz;
CRATE TYPE type_created_at2 AS ( created_at2 timestamptz);
CREATE TABLE my_service.table_mytest (
	created_at type_created_at NULL,
	created_at2 type_created_at2 NULL,
	random_timestamp timestamptz NULL
);
#[derive(sqlx::Type, PartialEq, Eq, Debug, Clone)]
#[sqlx(type_name = "type_created_at")]
pub struct CreatedAt(pub OffsetDateTime);

#[derive(sqlx::Type, PartialEq, Eq, Debug, Clone)]
#[sqlx(type_name = "type_created_at2")]
pub struct CreatedAt2{ pub created_at2: OffsetDateTime }

todo: various examples of the different types of select and insert queries failing (behaving differently)

particularly the as operator for insert statements
and implicit conversion for select statements

SQLx version

0.9 - head as of a few days ago

Enabled SQLx features

["postgres", "runtime-tokio", "time", "json", "uuid"]

Database server and version

Postgres

Operating system

Linux

Rust version

rustc 1.90.0-nightly

extra tags for search: information_schema, columns, udt_name, domain_name, typname, pg_type. pg_catalog

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions