@@ -219,18 +219,39 @@ pub fn transform_global_sql(
219219 source_tree : & SourceTree ,
220220 materialized_ctes : & HashSet < String > ,
221221) -> ( Vec < String > , Option < String > ) {
222+ // Collect side-effect statements (CREATE, INSERT, UPDATE, DELETE) that
223+ // need to run before the main query. These appear alongside a trailing
224+ // SELECT or VISUALISE FROM.
225+ //
226+ // Only structured DML is handled here — other_sql_statement nodes
227+ // (INSTALL, LOAD, SET, …) are pre-executed in prepare_data_with_reader.
228+ let root = source_tree. root ( ) ;
229+
230+ let side_effect_stmts = r#"
231+ (sql_statement
232+ [(create_statement)
233+ (insert_statement)
234+ (update_statement)
235+ (delete_statement)] @stmt)
236+ "# ;
237+ let side_effects: Vec < String > = source_tree
238+ . find_texts ( & root, side_effect_stmts)
239+ . into_iter ( )
240+ . map ( |s| transform_cte_references ( s. trim ( ) , materialized_ctes) )
241+ . filter ( |s| !s. is_empty ( ) )
242+ . collect ( ) ;
243+
222244 // Try to extract trailing SELECT (WITH...SELECT or direct SELECT)
223245 let select_sql = split_with_query ( source_tree)
224246 . map ( |( _, select) | select)
225247 . or_else ( || {
226248 // Fallback: direct SELECT statement (no WITH clause)
227- let root = source_tree. root ( ) ;
228249 source_tree. find_text ( & root, "(sql_statement (select_statement) @select)" )
229250 } ) ;
230251
231252 if let Some ( select_sql) = select_sql {
232253 return (
233- vec ! [ ] ,
254+ side_effects ,
234255 Some ( transform_cte_references ( & select_sql, materialized_ctes) ) ,
235256 ) ;
236257 }
@@ -239,30 +260,10 @@ pub fn transform_global_sql(
239260 return ( vec ! [ ] , None ) ;
240261 }
241262
242- // We have non-SELECT executable SQL (CREATE, INSERT, …) and/or
243- // VISUALISE FROM. Split them: side-effect statements run directly,
244- // VISUALISE FROM becomes the queryable part.
245- //
246- // Only structured DML is handled here — other_sql_statement nodes
247- // (INSTALL, LOAD, SET, …) are pre-executed in prepare_data_with_reader.
263+ // We have non-SELECT executable SQL and/or VISUALISE FROM.
264+ // Side-effects run directly, VISUALISE FROM becomes the queryable part.
248265 // A bare WITH clause without a trailing statement is not executable on
249266 // its own (its CTEs are already materialized separately).
250- let root = source_tree. root ( ) ;
251-
252- let side_effect_stmts = r#"
253- (sql_statement
254- [(create_statement)
255- (insert_statement)
256- (update_statement)
257- (delete_statement)] @stmt)
258- "# ;
259- let side_effects: Vec < String > = source_tree
260- . find_texts ( & root, side_effect_stmts)
261- . into_iter ( )
262- . map ( |s| transform_cte_references ( s. trim ( ) , materialized_ctes) )
263- . filter ( |s| !s. is_empty ( ) )
264- . collect ( ) ;
265-
266267 let viz_from_query = source_tree
267268 . find_text (
268269 & root,
0 commit comments