@@ -50,29 +50,33 @@ pub struct QueryContext {
5050}
5151
5252/// Inputs needed to construct an `OriginCatalog` per plan call.
53+ ///
54+ /// Tenant is intentionally **not** stored here: every plan call passes the
55+ /// effective tenant to `build_adapter`, so a single `QueryContext` shared
56+ /// across a pgwire handler can serve queries from connections belonging to
57+ /// different tenants without cross-tenant catalog resolution.
5358#[ derive( Clone ) ]
5459struct CatalogInputs {
5560 credentials : Arc < CredentialStore > ,
5661 shared : Option < std:: sync:: Weak < crate :: control:: state:: SharedState > > ,
57- tenant_id : u32 ,
5862 retention_policy_registry :
5963 Option < Arc < crate :: engine:: timeseries:: retention_policy:: RetentionPolicyRegistry > > ,
6064}
6165
6266impl CatalogInputs {
63- fn build_adapter ( & self ) -> super :: catalog_adapter:: OriginCatalog {
67+ fn build_adapter ( & self , tenant_id : u32 ) -> super :: catalog_adapter:: OriginCatalog {
6468 if let Some ( weak) = & self . shared
6569 && let Some ( shared) = weak. upgrade ( )
6670 {
6771 super :: catalog_adapter:: OriginCatalog :: new_with_lease (
6872 & shared,
69- self . tenant_id ,
73+ tenant_id,
7074 self . retention_policy_registry . clone ( ) ,
7175 )
7276 } else {
7377 super :: catalog_adapter:: OriginCatalog :: new (
7478 Arc :: clone ( & self . credentials ) ,
75- self . tenant_id ,
79+ tenant_id,
7680 self . retention_policy_registry . clone ( ) ,
7781 )
7882 }
@@ -97,10 +101,9 @@ impl QueryContext {
97101 /// path would return instantly anyway, but going through the
98102 /// sub-planner without a direct `Arc<SharedState>` reference
99103 /// would require threading one through every call site.
100- pub fn for_state ( state : & crate :: control:: state:: SharedState , tenant_id : u32 ) -> Self {
104+ pub fn for_state ( state : & crate :: control:: state:: SharedState ) -> Self {
101105 Self :: with_catalog (
102106 Arc :: clone ( & state. credentials ) ,
103- tenant_id,
104107 Some ( Arc :: clone ( & state. retention_policy_registry ) ) ,
105108 )
106109 }
@@ -110,16 +113,12 @@ impl QueryContext {
110113 /// query's plan acquires descriptor leases before execution.
111114 /// Callers must hold an `Arc<SharedState>` — the adapter
112115 /// downgrades to `Weak` internally.
113- pub fn for_state_with_lease (
114- state : & Arc < crate :: control:: state:: SharedState > ,
115- tenant_id : u32 ,
116- ) -> Self {
116+ pub fn for_state_with_lease ( state : & Arc < crate :: control:: state:: SharedState > ) -> Self {
117117 let retention = Some ( Arc :: clone ( & state. retention_policy_registry ) ) ;
118118 Self {
119119 catalog_inputs : Some ( CatalogInputs {
120120 credentials : Arc :: clone ( & state. credentials ) ,
121121 shared : Some ( Arc :: downgrade ( state) ) ,
122- tenant_id,
123122 retention_policy_registry : retention. clone ( ) ,
124123 } ) ,
125124 retention_registry : retention,
@@ -136,15 +135,13 @@ impl QueryContext {
136135 /// that construct a context without an `Arc<SharedState>`.
137136 pub fn with_catalog (
138137 credentials : Arc < CredentialStore > ,
139- tenant_id : u32 ,
140138 retention_policy_registry : Option <
141139 Arc < crate :: engine:: timeseries:: retention_policy:: RetentionPolicyRegistry > ,
142140 > ,
143141 ) -> Self {
144142 let catalog_inputs = Some ( CatalogInputs {
145143 credentials,
146144 shared : None ,
147- tenant_id,
148145 retention_policy_registry : retention_policy_registry. clone ( ) ,
149146 } ) ;
150147
@@ -193,7 +190,7 @@ impl QueryContext {
193190 // `recorded_versions` field is per-plan state, and
194191 // two concurrent plans through a shared QueryContext
195192 // would otherwise interleave their recorded sets.
196- let catalog = inputs. build_adapter ( ) ;
193+ let catalog = inputs. build_adapter ( tenant_id . as_u32 ( ) ) ;
197194 let plans = nodedb_sql:: plan_sql ( sql, & catalog) . map_err ( |e| match e {
198195 nodedb_sql:: SqlError :: RetryableSchemaChanged { descriptor } => {
199196 crate :: Error :: RetryableSchemaChanged { descriptor }
@@ -292,7 +289,7 @@ impl QueryContext {
292289 // through a different cache key), but constructing the
293290 // adapter fresh keeps the adapter's state per-plan and
294291 // allows future extension.
295- let catalog = inputs. build_adapter ( ) ;
292+ let catalog = inputs. build_adapter ( tenant_id . as_u32 ( ) ) ;
296293 let plans = nodedb_sql:: plan_sql_with_params ( sql, params, & catalog) . map_err ( |e| {
297294 crate :: Error :: PlanError {
298295 detail : format ! ( "{e}" ) ,
0 commit comments