1
+ use std:: collections:: btree_map;
1
2
use crate :: error:: Error ;
2
3
use crate :: ext:: ustr:: UStr ;
3
4
use crate :: io:: StatementId ;
@@ -14,6 +15,9 @@ use futures_core::future::BoxFuture;
14
15
use smallvec:: SmallVec ;
15
16
use sqlx_core:: query_builder:: QueryBuilder ;
16
17
use std:: sync:: Arc ;
18
+ use sqlx_core:: column:: { ColumnOrigin , TableColumn } ;
19
+ use sqlx_core:: hash_map;
20
+ use crate :: connection:: TableColumns ;
17
21
18
22
/// Describes the type of the `pg_type.typtype` column
19
23
///
@@ -122,13 +126,20 @@ impl PgConnection {
122
126
let type_info = self
123
127
. maybe_fetch_type_info_by_oid ( field. data_type_id , should_fetch)
124
128
. 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
+ } ;
125
135
126
136
let column = PgColumn {
127
137
ordinal : index,
128
138
name : name. clone ( ) ,
129
139
type_info,
130
140
relation_id : field. relation_id ,
131
141
relation_attribute_no : field. relation_attribute_no ,
142
+ origin,
132
143
} ;
133
144
134
145
columns. push ( column) ;
@@ -188,6 +199,54 @@ impl PgConnection {
188
199
Ok ( PgTypeInfo ( PgType :: DeclareWithOid ( oid) ) )
189
200
}
190
201
}
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
+ }
191
250
192
251
fn fetch_type_by_oid ( & mut self , oid : Oid ) -> BoxFuture < ' _ , Result < PgTypeInfo , Error > > {
193
252
Box :: pin ( async move {
0 commit comments