@@ -2,10 +2,10 @@ use anyhow::Result as AnyResult;
2
2
use libc:: c_long;
3
3
use pgrx:: pg_sys:: {
4
4
error, fetch_search_path_array, get_namespace_oid, get_relname_relid, palloc0,
5
- CustomExecMethods , CustomScan , CustomScanMethods , CustomScanState , EState , ExplainState ,
6
- InvalidOid , List , ListCell , MyLatch , MyProcNumber , Node , NodeTag , Oid , ParamListInfo ,
7
- RegisterCustomScanMethods , ResetLatch , TupleTableSlot , WaitLatch , PG_WAIT_EXTENSION ,
8
- WL_LATCH_SET , WL_POSTMASTER_DEATH , WL_TIMEOUT ,
5
+ CustomExecMethods , CustomScan , CustomScanMethods , CustomScanState , EState , ExplainPropertyText ,
6
+ ExplainState , InvalidOid , List , ListCell , MyLatch , MyProcNumber , Node , NodeTag , Oid ,
7
+ ParamListInfo , RegisterCustomScanMethods , ResetLatch , TupleTableSlot , WaitLatch ,
8
+ PG_WAIT_EXTENSION , WL_LATCH_SET , WL_POSTMASTER_DEATH , WL_TIMEOUT ,
9
9
} ;
10
10
use pgrx:: { check_for_interrupts, pg_guard} ;
11
11
use rmp:: decode:: { read_array_len, read_bin_len} ;
@@ -16,8 +16,8 @@ use std::time::Duration;
16
16
use crate :: error:: FusionError ;
17
17
use crate :: ipc:: { my_slot, Bus , SlotStream } ;
18
18
use crate :: protocol:: {
19
- consume_header, read_error, send_metadata, send_params, send_query, Direction , NeedSchema ,
20
- Packet ,
19
+ consume_header, read_error, request_explain , send_metadata, send_params, send_query, Direction ,
20
+ NeedSchema , Packet ,
21
21
} ;
22
22
23
23
const BACKEND_WAIT_TIMEOUT : Duration = Duration :: from_millis ( 100 ) ;
@@ -60,27 +60,23 @@ pub(crate) fn exec_methods() -> *const CustomExecMethods {
60
60
EXEC_METHODS . with ( |m| & * m as * const CustomExecMethods )
61
61
}
62
62
63
- #[ repr( C ) ]
64
- struct ScanState {
65
- css : CustomScanState ,
63
+ #[ pg_guard]
64
+ #[ inline( always) ]
65
+ fn wait_stream ( ) -> SlotStream {
66
+ let my_proc_number = unsafe { MyProcNumber } ;
67
+ loop {
68
+ let Some ( slot) = Bus :: new ( ) . slot_locked ( my_slot ( ) , my_proc_number) else {
69
+ wait_latch ( Some ( BACKEND_WAIT_TIMEOUT ) ) ;
70
+ continue ;
71
+ } ;
72
+ return SlotStream :: from ( slot) ;
73
+ }
66
74
}
67
75
68
76
#[ pg_guard]
69
77
#[ no_mangle]
70
78
unsafe extern "C" fn create_df_scan_state ( cscan : * mut CustomScan ) -> * mut Node {
71
79
let my_proc_number = unsafe { MyProcNumber } ;
72
- let wait_stream = || -> SlotStream {
73
- let stream;
74
- loop {
75
- let Some ( slot) = Bus :: new ( ) . slot_locked ( my_slot ( ) , my_proc_number) else {
76
- wait_latch ( Some ( BACKEND_WAIT_TIMEOUT ) ) ;
77
- continue ;
78
- } ;
79
- stream = Some ( SlotStream :: from ( slot) ) ;
80
- break ;
81
- }
82
- stream. expect ( "Failed to acquire a slot stream" )
83
- } ;
84
80
let list = ( * cscan) . custom_private ;
85
81
let pattern = ( * list_nth ( list, 0 ) ) . ptr_value as * mut c_char ;
86
82
let stream = wait_stream ( ) ;
@@ -120,8 +116,11 @@ unsafe extern "C" fn create_df_scan_state(cscan: *mut CustomScan) -> *mut Node {
120
116
}
121
117
break ;
122
118
}
123
- Packet :: Bind | Packet :: Parse => {
124
- error ! ( "Unexpected packet in backend: {:?}" , header. packet)
119
+ Packet :: Bind | Packet :: Parse | Packet :: Explain => {
120
+ error ! (
121
+ "Unexpected packet for create custom plan: {:?}" ,
122
+ header. packet
123
+ )
125
124
}
126
125
}
127
126
}
@@ -136,36 +135,85 @@ unsafe extern "C" fn create_df_scan_state(cscan: *mut CustomScan) -> *mut Node {
136
135
methods : exec_methods ( ) ,
137
136
..Default :: default ( )
138
137
} ;
139
- let state = ScanState { css } ;
140
- let mut node = PgNode :: empty ( std:: mem:: size_of :: < ScanState > ( ) ) ;
138
+ let mut node = PgNode :: empty ( std:: mem:: size_of :: < CustomScanState > ( ) ) ;
141
139
node. set_tag ( NodeTag :: T_CustomScanState ) ;
142
140
node. set_data ( unsafe {
143
141
std:: slice:: from_raw_parts (
144
- & state as * const _ as * const u8 ,
145
- std:: mem:: size_of :: < ScanState > ( ) ,
142
+ & css as * const _ as * const u8 ,
143
+ std:: mem:: size_of :: < CustomScanState > ( ) ,
146
144
)
147
145
} ) ;
148
146
node. mut_node ( )
149
147
}
150
148
149
+ #[ pg_guard]
150
+ #[ no_mangle]
151
151
unsafe extern "C" fn begin_df_scan ( node : * mut CustomScanState , estate : * mut EState , eflags : i32 ) {
152
152
todo ! ( )
153
153
}
154
154
155
+ #[ pg_guard]
156
+ #[ no_mangle]
155
157
unsafe extern "C" fn exec_df_scan ( node : * mut CustomScanState ) -> * mut TupleTableSlot {
156
158
todo ! ( )
157
159
}
158
160
161
+ #[ pg_guard]
162
+ #[ no_mangle]
159
163
unsafe extern "C" fn end_df_scan ( node : * mut CustomScanState ) {
160
164
todo ! ( )
161
165
}
162
166
167
+ #[ pg_guard]
168
+ #[ no_mangle]
163
169
unsafe extern "C" fn explain_df_scan (
164
- node : * mut CustomScanState ,
165
- ancestors : * mut List ,
170
+ _node : * mut CustomScanState ,
171
+ _ancestors : * mut List ,
166
172
es : * mut ExplainState ,
167
173
) {
168
- todo ! ( )
174
+ let my_proc_number = unsafe { MyProcNumber } ;
175
+ let stream = wait_stream ( ) ;
176
+ if let Err ( err) = request_explain ( my_slot ( ) , stream) {
177
+ error ! ( "Failed to request explain: {}" , err) ;
178
+ }
179
+ loop {
180
+ wait_latch ( Some ( BACKEND_WAIT_TIMEOUT ) ) ;
181
+ let Some ( slot) = Bus :: new ( ) . slot_locked ( my_slot ( ) , my_proc_number) else {
182
+ continue ;
183
+ } ;
184
+ let mut stream = SlotStream :: from ( slot) ;
185
+ let header = consume_header ( & mut stream) . expect ( "Failed to consume header" ) ;
186
+ if header. direction != Direction :: ToBackend {
187
+ continue ;
188
+ }
189
+ match header. packet {
190
+ Packet :: None => {
191
+ // No data, just continue waiting.
192
+ continue ;
193
+ }
194
+ Packet :: Failure => {
195
+ let msg = read_error ( & mut stream) . expect ( "Failed to read the error message" ) ;
196
+ error ! ( "Failed to compile the query: {}" , msg) ;
197
+ }
198
+ Packet :: Metadata | Packet :: Bind | Packet :: Parse => {
199
+ error ! ( "Unexpected packet for explain: {:?}" , header. packet)
200
+ }
201
+ Packet :: Explain => {
202
+ let len = read_bin_len ( & mut stream)
203
+ . expect ( "Failed to read the length in explain message" ) ;
204
+ let explain = stream
205
+ . look_ahead ( len as usize )
206
+ . expect ( "Failed to read the explain message" ) ;
207
+ unsafe {
208
+ ExplainPropertyText (
209
+ "DataFusion Plan\0 " . as_ptr ( ) as _ ,
210
+ explain. as_ptr ( ) as _ ,
211
+ es,
212
+ ) ;
213
+ }
214
+ }
215
+ }
216
+ }
169
217
}
170
218
171
219
// We expect that the header is already consumed and the packet type is `Packet::Metadata`.
0 commit comments