-
Notifications
You must be signed in to change notification settings - Fork 80
Open
Labels
Description
library(DBI)
library(RPostgres)
# Connection -------------------------------------------------------------------
creds <- c(
user = "postgres",
psw = "postgres",
host = "localhost"
)
con <- dbConnect(
Postgres(),
dbname = "postgres",
user = creds[["user"]],
password = creds[["psw"]],
host = creds[["host"]]
)
# Create custom user enum type -------------------------------------------------
q_drop <- "DROP TYPE IF EXISTS \"UserRole\" CASCADE;"
dbExecute(con, q_drop)
#> NOTICE: drop cascades to column role of table sample_users
#> [1] 0
q_create_typ <- "CREATE TYPE \"UserRole\" AS ENUM ('user', 'admin');"
dbExecute(con, q_create_typ)
#> [1] 0
# Create table -----------------------------------------------------------------
dbExecute(con, "DROP TABLE IF EXISTS sample_users")
#> [1] 0
q_create_tbl <- "
CREATE TABLE sample_users (
role \"UserRole\" NOT NULL DEFAULT 'user'
);"
dbExecute(con, q_create_tbl)
#> [1] 0
# Check How Custom Type is represented correctly in DB -------------------------
q_list_types <- "
SELECT
t.typname AS type_name,
CASE
WHEN t.typtype = 'e' THEN 'ENUM'
WHEN t.typtype = 'c' THEN 'COMPOSITE'
WHEN t.typtype = 'd' THEN 'DOMAIN'
WHEN t.typtype = 'r' THEN 'RANGE'
WHEN t.typtype = 'm' THEN 'MULTIRANGE'
ELSE t.typtype::text
END AS type_category,
n.nspname AS schema_name
FROM
pg_type t
JOIN
pg_namespace n ON t.typnamespace = n.oid
WHERE
-- Filter for user-defined types (not system types)
n.nspname NOT IN ('pg_catalog', 'information_schema')
-- Exclude array types and implicit types
AND t.typelem = 0
AND t.typtype NOT IN ('p')
ORDER BY
schema_name,
type_name;
"
dbGetQuery(con, q_list_types)
#> type_name type_category schema_name
#> 1 UserRole ENUM public
#> 2 sample_users COMPOSITE public
# Insert data ------------------------------------------------------------------
q_ins <- "INSERT INTO sample_users (role)
VALUES ('admin'), ('user');"
dbExecute(con, q_ins)
#> [1] 2
out <- dbGetQuery(con, "SELECT * FROM sample_users;")
# Issue (1) --------------------------------------------------------------------
# pq_NA rather than pq_UserRole
constructive::construct(out)
#> list(
#> role = c("admin", "user") |>
#> structure(class = "pq_NA")
#> ) |>
#> structure(row.names = c(NA, -2L), class = "data.frame")
# `match()` call returning NA in debug(RPostgres:::type_lookup)
# Apparently, the oid in the typnames data.frame from `ret` does not match with the one from con.
# UserRole it's there but with a different oid
# Issue (2) --------------------------------------------------------------------
# derived from issue 1: cannot use dplyr::rows_insert()
dbExecute(con, "DROP TABLE IF EXISTS sample_users")
#> [1] 0
q_create_tbl <- "
CREATE TABLE sample_users (
role \"UserRole\" NOT NULL DEFAULT 'user'
);"
dbExecute(con, q_create_tbl)
#> [1] 0
target <- dplyr::tbl(con, "sample_users")
source <- tibble::tibble(
role = c("admin", "user") |>
structure(class = "pq_UserRole")
)
try(dplyr::rows_insert(target, source, conflict = "ignore", copy = TRUE))
#> Error in db_copy_to(dest$con, name, df, overwrite = overwrite, types = types, :
#> Can't copy data to table "dbplyr_BP9t2EMwur".
#> Caused by error in `dplyr::db_write_table()`:
#> ! Can't write table table "dbplyr_BP9t2EMwur".
#> Caused by error:
#> ! Failed to fetch row : ERROR: type "na" does not exist at character 55Created on 2025-05-23 with reprex v2.1.1