sauraww opened a new issue, #106:
URL: https://github.com/apache/casbin-rust-diesel-adapter/issues/106

   ### Problem
   
   With Postgres in v1.2.0, DieselAdapter::new() always runs `CREATE TABLE IF 
NOT EXISTS casbin_rule (...)` when the adapter starts. There is no option to 
skip it. This makes it impossible to construct an adapter against a **read-only 
Postgres connection** . For example, this is useful for a read-only replica 
where casbin_rule is copied from the primary database and the app only needs to 
read policies.
   
   ### Root cause
   
   ```rust
   // adapter.rs
   pub fn new<U: Into<String>>(url: U, pool_size: u32) -> Result<Self> {
       ...
       Self::with_pool(pool)
   }
   
   pub fn with_pool(pool: Pool<ConnectionManager<adapter::Connection>>) -> 
Result<Self> {
       let conn = pool.get()...;
       adapter::new(conn).map(|_| Self { pool, is_filtered: false })
   }
   ```
   
   ```rust
   // actions.rs
   #[cfg(feature = "postgres")]
   pub fn new(conn: Result<Pool>) -> Result<usize> {
       conn.and_then(|mut conn| {
           sql_query("CREATE TABLE IF NOT EXISTS casbin_rule 
(...)").execute(&mut conn)
           ...
       })
   }
   ```
   
   `IF NOT EXISTS` lets Postgres check whether the table already exists, 
instead of the adapter checking first. The problem is that Postgres requires 
DDL statements to run inside a writable transaction to *evaluate* whether the 
no-op applies — it isn't skipped just because the table happens to already 
exist. Against a read replica this fails deterministically every time with:
   
   ```
   DatabaseError(ReadOnlyTransaction, "cannot execute CREATE TABLE in a 
read-only transaction")
   ```
   
   ### Steps to reproduce
   
   1. Point Postgres at a  read replica connection string (any setup where 
`SELECT pg_is_in_recovery();` returns `true`), with `casbin_rule` already 
present via replication.
   2. Call `DieselAdapter::new(replica_url, pool_size)`.
   3. Observe the error above on every call, regardless of whether the table 
exists.
   
   ### Expected behavior
   
   There should be a way to construct a `DieselAdapter` for a database where 
the schema is known to already exist, without issuing any DDL — e.g. for 
enforcement-only nodes reading from a replica in an active/passive or 
read-replica deployment.
   
   Suggested fix
   A simple fix would be to add a constructor that does not create the table:
   ```rust
   /// Creates an adapter without creating the `casbin_rule` table.
   ///
   /// Use this when the table is already managed outside the adapter,
   /// such as on a read-only replica.
   pub fn new_without_schema_init<U: Into<String>>(
       url: U,
       pool_size: u32,
   ) -> Result<Self> {
       let manager = ConnectionManager::new(url);
       let pool = Pool::builder()
           .connection_timeout(Duration::from_secs(10))
           .max_size(pool_size)
           .build(manager)
           .map_err(|err| 
CasbinError::from(AdapterError(Box::new(Error::PoolError(err)))))?;
   
       Ok(Self {
           pool,
           is_filtered: false,
       })
   }
   ```
   This does not change the existing new() behavior, so it is 
backward-compatible.
   This constructor only skips table creation. It does not stop write 
operations, so callers using a read-only database must avoid policy changes 
such as add_policy or save_policy.
   Happy to open a PR if this API shape works for the maintainers.
   ### Environment
   
   - `diesel-adapter` = 1.2.0
   - `casbin` = 2.19.0
   - Postgres (`postgres` feature), r2d2 pooling
   - Failure occurs specifically on standby/replica connections 
(`pg_is_in_recovery() = true`)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to