From 50f2383b3ba8fd60b04b7f22facb11538ffb019f Mon Sep 17 00:00:00 2001 From: Niklas Korz Date: Fri, 21 Jul 2023 14:35:25 +0200 Subject: [PATCH] Fix PostgreSQL enum arrays and case-sensitive types (#108) * Fix PostgreSQL enum arrays * Remove redundant clones * Put back `udt_name_regtype` and refactoring * Refactoring * Fixup * Refactoring * `to_regtype` instead of `::regtype` to avoid panic * CONCAT-fix for ::regtype and minimal test case * cleanup * cleanup --------- Co-authored-by: Billy Chan --- src/postgres/parser/column.rs | 17 ++++++++++------- src/postgres/query/column.rs | 13 ++++++++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/postgres/parser/column.rs b/src/postgres/parser/column.rs index c932b727..046cf814 100644 --- a/src/postgres/parser/column.rs +++ b/src/postgres/parser/column.rs @@ -213,13 +213,16 @@ pub fn parse_array_attributes( def.col_type = match udt_name_regtype { None => panic!("parse_array_attributes(_) received an empty udt_name_regtype"), Some(typename) => { - let typename = typename.replacen("[]", "", 1); - let is_enum = enums.contains_key(&typename); - Some(RcOrArc::new(Type::from_str( - &typename, - Some(&typename), - is_enum, - ))) + let typename = &typename.replacen('"', "", 2).replacen("[]", "", 1); + let arr_col_type = if let Some(variants) = enums.get(typename) { + Type::Enum(EnumDef { + typename: typename.to_string(), + values: variants.clone(), + }) + } else { + Type::from_str(typename, Some(typename), false) + }; + Some(RcOrArc::new(arr_col_type)) } }; } diff --git a/src/postgres/query/column.rs b/src/postgres/query/column.rs index ffebe158..06bd6a1c 100644 --- a/src/postgres/query/column.rs +++ b/src/postgres/query/column.rs @@ -1,6 +1,6 @@ use super::{InformationSchema, SchemaQueryBuilder}; use crate::sqlx_types::postgres::PgRow; -use sea_query::{Alias, BinOper, Expr, Iden, Query, SeaRc, SelectStatement}; +use sea_query::{BinOper, Expr, Iden, Query, SeaRc, SelectStatement}; #[derive(Debug, sea_query::Iden)] /// Ref: https://www.postgresql.org/docs/13/infoschema-columns.html @@ -94,8 +94,10 @@ impl SchemaQueryBuilder { ColumnsField::UdtName, ]) .expr( - Expr::expr(Expr::cust("udt_name::regtype").cast_as(Alias::new("text"))) - .binary(BinOper::As, Expr::col(Alias::new("udt_name_regtype"))), + // The double quotes are required to correctly handle user types containing + // upper case letters. + Expr::expr(Expr::cust("CONCAT('\"', udt_name, '\"')::regtype").cast_as(Text)) + .binary(BinOper::As, Expr::col(UdtNameRegtype)), ) .from((InformationSchema::Schema, InformationSchema::Columns)) .and_where(Expr::col(ColumnsField::TableSchema).eq(schema.to_string())) @@ -135,3 +137,8 @@ impl From<&PgRow> for ColumnQueryResult { Self::default() } } + +#[derive(Iden)] +struct Text; +#[derive(Iden)] +struct UdtNameRegtype;