Plan SQL with bound parameters and RLS injection. Used by prepared statement execution to bind parameters at the AST level (not via SQL text substitution), then plan and inject RLS as normal.
(
&self,
sql: &str,
params: &[nodedb_sql::ParamValue],
tenant_id: crate::types::TenantId,
database_id: crate::types::DatabaseId,
sec: &PlanSecurityConte
| 374 | /// Used by prepared statement execution to bind parameters at the AST level |
| 375 | /// (not via SQL text substitution), then plan and inject RLS as normal. |
| 376 | pub async fn plan_sql_with_params_and_rls( |
| 377 | &self, |
| 378 | sql: &str, |
| 379 | params: &[nodedb_sql::ParamValue], |
| 380 | tenant_id: crate::types::TenantId, |
| 381 | database_id: crate::types::DatabaseId, |
| 382 | sec: &PlanSecurityContext<'_>, |
| 383 | ) -> crate::Result<Vec<nodedb_physical::physical_task::PhysicalTask>> { |
| 384 | let inputs = match &self.catalog_inputs { |
| 385 | Some(i) => i, |
| 386 | None => { |
| 387 | return Err(crate::Error::PlanError { |
| 388 | detail: "no catalog available for SQL planning".into(), |
| 389 | }); |
| 390 | } |
| 391 | }; |
| 392 | // Fresh adapter per plan call: same rationale as |
| 393 | // `plan_with_nodedb_sql`. The params-and-rls path does |
| 394 | // not currently surface the recorded version set to |
| 395 | // callers (prepared statements with bound parameters go |
| 396 | // through a different cache key), but constructing the |
| 397 | // adapter fresh keeps the adapter's state per-plan and |
| 398 | // allows future extension. |
| 399 | let catalog = inputs.build_adapter(tenant_id.as_u64(), database_id); |
| 400 | let plans = nodedb_sql::plan_sql_with_params(sql, params, &catalog).map_err(|e| { |
| 401 | crate::Error::PlanError { |
| 402 | detail: format!("{e}"), |
| 403 | } |
| 404 | })?; |
| 405 | let ctx = super::sql_plan_convert::ConvertContext { |
| 406 | retention_registry: self.retention_registry.clone(), |
| 407 | array_catalog: self.array_catalog.clone(), |
| 408 | credentials: self |
| 409 | .catalog_inputs |
| 410 | .as_ref() |
| 411 | .map(|i| Arc::clone(&i.credentials)), |
| 412 | wal: self.wal.clone(), |
| 413 | surrogate_assigner: self.surrogate_assigner.clone(), |
| 414 | cluster_enabled: self.cluster_enabled, |
| 415 | bitemporal_retention_registry: self.bitemporal_retention_registry.clone(), |
| 416 | max_vector_dim: self |
| 417 | .max_vector_dim |
| 418 | .load(std::sync::atomic::Ordering::Relaxed), |
| 419 | database_id, |
| 420 | }; |
| 421 | let mut tasks = super::sql_plan_convert::convert(&plans, tenant_id, &ctx)?; |
| 422 | |
| 423 | // Inject RLS predicates. |
| 424 | super::rls_injection::inject_rls(&mut tasks, sec.rls_store, sec.auth)?; |
| 425 | |
| 426 | if let Some(cache) = sec.permission_cache { |
| 427 | super::rls_injection::inject_permission_tree(&mut tasks, cache, sec.auth)?; |
| 428 | } |
| 429 | |
| 430 | Ok(tasks) |
| 431 | } |
| 432 | } |
| 433 |
no test coverage detected