1+ use std:: collections:: btree_map;
12use crate :: error:: Error ;
23use crate :: ext:: ustr:: UStr ;
34use crate :: io:: StatementId ;
@@ -14,6 +15,9 @@ use futures_core::future::BoxFuture;
1415use smallvec:: SmallVec ;
1516use sqlx_core:: query_builder:: QueryBuilder ;
1617use std:: sync:: Arc ;
18+ use sqlx_core:: column:: { ColumnOrigin , TableColumn } ;
19+ use sqlx_core:: hash_map;
20+ use crate :: connection:: TableColumns ;
1721
1822/// Describes the type of the `pg_type.typtype` column
1923///
@@ -122,13 +126,20 @@ impl PgConnection {
122126 let type_info = self
123127 . maybe_fetch_type_info_by_oid ( field. data_type_id , should_fetch)
124128 . await ?;
129+
130+ let origin = if let ( Some ( relation_oid) , Some ( attribute_no) ) = ( field. relation_id , field. relation_attribute_no ) {
131+ self . maybe_fetch_column_origin ( relation_oid, attribute_no, should_fetch) . await ?
132+ } else {
133+ ColumnOrigin :: Expression
134+ } ;
125135
126136 let column = PgColumn {
127137 ordinal : index,
128138 name : name. clone ( ) ,
129139 type_info,
130140 relation_id : field. relation_id ,
131141 relation_attribute_no : field. relation_attribute_no ,
142+ origin,
132143 } ;
133144
134145 columns. push ( column) ;
@@ -188,6 +199,54 @@ impl PgConnection {
188199 Ok ( PgTypeInfo ( PgType :: DeclareWithOid ( oid) ) )
189200 }
190201 }
202+
203+ async fn maybe_fetch_column_origin (
204+ & mut self ,
205+ relation_id : Oid ,
206+ attribute_no : i16 ,
207+ should_fetch : bool ,
208+ ) -> Result < ColumnOrigin , Error > {
209+ let mut table_columns = match self . cache_table_to_column_names . entry ( relation_id) {
210+ hash_map:: Entry :: Occupied ( table_columns) => {
211+ table_columns. into_mut ( )
212+ } ,
213+ hash_map:: Entry :: Vacant ( vacant) => {
214+ if !should_fetch { return Ok ( ColumnOrigin :: Unknown ) ; }
215+
216+ let table_name: String = query_scalar ( "SELECT $1::oid::regclass::text" )
217+ . bind ( relation_id)
218+ . fetch_one ( & mut * self )
219+ . await ?;
220+
221+ vacant. insert ( TableColumns {
222+ table_name : table_name. into ( ) ,
223+ columns : Default :: default ( ) ,
224+ } )
225+ }
226+ } ;
227+
228+ let column_name = match table_columns. columns . entry ( attribute_no) {
229+ btree_map:: Entry :: Occupied ( occupied) => Arc :: clone ( occupied. get ( ) ) ,
230+ btree_map:: Entry :: Vacant ( vacant) => {
231+ if !should_fetch { return Ok ( ColumnOrigin :: Unknown ) ; }
232+
233+ let column_name: String = query_scalar (
234+ "SELECT attname FROM pg_attribute WHERE attrelid = $1 AND attnum = $2"
235+ )
236+ . bind ( relation_id)
237+ . bind ( attribute_no)
238+ . fetch_one ( & mut * self )
239+ . await ?;
240+
241+ Arc :: clone ( vacant. insert ( column_name. into ( ) ) )
242+ }
243+ } ;
244+
245+ Ok ( ColumnOrigin :: Table ( TableColumn {
246+ table : table_columns. table_name . clone ( ) ,
247+ name : column_name
248+ } ) )
249+ }
191250
192251 fn fetch_type_by_oid ( & mut self , oid : Oid ) -> BoxFuture < ' _ , Result < PgTypeInfo , Error > > {
193252 Box :: pin ( async move {
0 commit comments