1515// specific language governing permissions and limitations
1616// under the License.
1717
18- //! Tests for DELETE and UPDATE planning to verify filter and assignment extraction.
18+ //! Tests for DELETE, UPDATE, and TRUNCATE planning to verify filter and assignment extraction.
1919
2020use std:: any:: Any ;
2121use std:: sync:: { Arc , Mutex } ;
@@ -165,6 +165,69 @@ impl TableProvider for CaptureUpdateProvider {
165165 }
166166}
167167
168+ /// A TableProvider that captures whether truncate() was called.
169+ struct CaptureTruncateProvider {
170+ schema : SchemaRef ,
171+ truncate_called : Arc < Mutex < bool > > ,
172+ }
173+
174+ impl CaptureTruncateProvider {
175+ fn new ( schema : SchemaRef ) -> Self {
176+ Self {
177+ schema,
178+ truncate_called : Arc :: new ( Mutex :: new ( false ) ) ,
179+ }
180+ }
181+
182+ fn was_truncated ( & self ) -> bool {
183+ * self . truncate_called . lock ( ) . unwrap ( )
184+ }
185+ }
186+
187+ impl std:: fmt:: Debug for CaptureTruncateProvider {
188+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
189+ f. debug_struct ( "CaptureTruncateProvider" )
190+ . field ( "schema" , & self . schema )
191+ . finish ( )
192+ }
193+ }
194+
195+ #[ async_trait]
196+ impl TableProvider for CaptureTruncateProvider {
197+ fn as_any ( & self ) -> & dyn Any {
198+ self
199+ }
200+
201+ fn schema ( & self ) -> SchemaRef {
202+ Arc :: clone ( & self . schema )
203+ }
204+
205+ fn table_type ( & self ) -> TableType {
206+ TableType :: Base
207+ }
208+
209+ async fn scan (
210+ & self ,
211+ _state : & dyn Session ,
212+ _projection : Option < & Vec < usize > > ,
213+ _filters : & [ Expr ] ,
214+ _limit : Option < usize > ,
215+ ) -> Result < Arc < dyn ExecutionPlan > > {
216+ Ok ( Arc :: new ( EmptyExec :: new ( Arc :: clone ( & self . schema ) ) ) )
217+ }
218+
219+ async fn truncate (
220+ & self ,
221+ _state : & dyn Session ,
222+ ) -> Result < Arc < dyn ExecutionPlan > > {
223+ * self . truncate_called . lock ( ) . unwrap ( ) = true ;
224+
225+ Ok ( Arc :: new ( EmptyExec :: new ( Arc :: new ( Schema :: new ( vec ! [
226+ Field :: new( "count" , DataType :: UInt64 , false ) ,
227+ ] ) ) ) ) )
228+ }
229+ }
230+
168231fn test_schema ( ) -> SchemaRef {
169232 Arc :: new ( Schema :: new ( vec ! [
170233 Field :: new( "id" , DataType :: Int32 , false ) ,
@@ -269,6 +332,26 @@ async fn test_update_assignments() -> Result<()> {
269332 Ok ( ( ) )
270333}
271334
335+ #[ tokio:: test]
336+ async fn test_truncate_calls_provider ( ) -> Result < ( ) > {
337+ let provider = Arc :: new ( CaptureTruncateProvider :: new ( test_schema ( ) ) ) ;
338+ let ctx = SessionContext :: new ( ) ;
339+
340+ ctx. register_table ( "t" , Arc :: clone ( & provider) as Arc < dyn TableProvider > ) ?;
341+
342+ ctx. sql ( "TRUNCATE TABLE t" )
343+ . await ?
344+ . collect ( )
345+ . await ?;
346+
347+ assert ! (
348+ provider. was_truncated( ) ,
349+ "truncate() should be called on the TableProvider"
350+ ) ;
351+
352+ Ok ( ( ) )
353+ }
354+
272355#[ tokio:: test]
273356async fn test_unsupported_table_delete ( ) -> Result < ( ) > {
274357 let schema = test_schema ( ) ;
@@ -295,3 +378,18 @@ async fn test_unsupported_table_update() -> Result<()> {
295378 assert ! ( result. is_err( ) || result. unwrap( ) . collect( ) . await . is_err( ) ) ;
296379 Ok ( ( ) )
297380}
381+
382+ #[ tokio:: test]
383+ async fn test_unsupported_table_truncate ( ) -> Result < ( ) > {
384+ let schema = test_schema ( ) ;
385+ let ctx = SessionContext :: new ( ) ;
386+
387+ let empty_table = datafusion:: datasource:: empty:: EmptyTable :: new ( schema) ;
388+ ctx. register_table ( "empty_t" , Arc :: new ( empty_table) ) ?;
389+
390+ let result = ctx. sql ( "TRUNCATE TABLE empty_t" ) . await ;
391+
392+ assert ! ( result. is_err( ) || result. unwrap( ) . collect( ) . await . is_err( ) ) ;
393+
394+ Ok ( ( ) )
395+ }
0 commit comments