Handle SET commands: parse, validate, store in session.
(
&self,
identity: &AuthenticatedIdentity,
addr: &std::net::SocketAddr,
sql: &str,
)
| 78 | impl NodeDbPgHandler { |
| 79 | /// Handle SET commands: parse, validate, store in session. |
| 80 | pub(super) fn handle_set( |
| 81 | &self, |
| 82 | identity: &AuthenticatedIdentity, |
| 83 | addr: &std::net::SocketAddr, |
| 84 | sql: &str, |
| 85 | ) -> PgWireResult<Vec<Response>> { |
| 86 | use super::super::session::parse_set_command; |
| 87 | use pgwire::api::results::Tag; |
| 88 | |
| 89 | // Handle SET TRANSACTION ... and SET SESSION CHARACTERISTICS AS TRANSACTION ... |
| 90 | let upper = sql.to_uppercase(); |
| 91 | if upper.starts_with("SET TRANSACTION") || upper.starts_with("SET SESSION CHARACTERISTICS") |
| 92 | { |
| 93 | match classify_transaction_cmd(&upper, sql) { |
| 94 | TransactionCmd::SetReadOnly => { |
| 95 | self.sessions.set_parameter( |
| 96 | addr, |
| 97 | "transaction_access_mode".into(), |
| 98 | "read_only".into(), |
| 99 | ); |
| 100 | return Ok(vec![Response::Execution(Tag::new("SET"))]); |
| 101 | } |
| 102 | TransactionCmd::SetReadWrite => { |
| 103 | self.sessions.set_parameter( |
| 104 | addr, |
| 105 | "transaction_access_mode".into(), |
| 106 | "read_write".into(), |
| 107 | ); |
| 108 | return Ok(vec![Response::Execution(Tag::new("SET"))]); |
| 109 | } |
| 110 | TransactionCmd::AcceptIsolation => { |
| 111 | return Ok(vec![Response::Execution(Tag::new("SET"))]); |
| 112 | } |
| 113 | TransactionCmd::RejectIsolation(message) => { |
| 114 | return Err(sqlstate_error( |
| 115 | nodedb_types::error::sqlstate::FEATURE_NOT_SUPPORTED, |
| 116 | &message, |
| 117 | )); |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // `SET ROLE <name>` and `SET SESSION AUTHORIZATION '<name>'` use |
| 123 | // PostgreSQL's space-not-equals syntax, so `parse_set_command` (which |
| 124 | // splits on `=` / `TO`) returns `None` for them. Catch the keywords |
| 125 | // before falling through to that parser — both must reject explicitly |
| 126 | // rather than land on the silent success path (the root cause behind |
| 127 | // SET TENANT looking like a no-op). |
| 128 | if upper.starts_with("SET ROLE ") || upper == "SET ROLE" { |
| 129 | return Err(sqlstate_error( |
| 130 | nodedb_types::error::sqlstate::FEATURE_NOT_SUPPORTED, |
| 131 | "SET ROLE is not supported: a session's role set is identity-bound \ |
| 132 | at CREATE USER time. Use GRANT/REVOKE ROLE TO <user> to change \ |
| 133 | a user's roles, or reconnect with a different user.", |
| 134 | )); |
| 135 | } |
| 136 | if upper.starts_with("SET SESSION AUTHORIZATION") { |
| 137 | return Err(sqlstate_error( |
no test coverage detected