@@ -25,6 +25,21 @@ public function __construct(
2525     * @param array<string, mixed> $options 
2626     */ 
2727    public  function  loadFromCsv (string  $ tablestring  $ filePatharray  $ optionsstring 
28+     {
29+         $ sqlParts
30+         foreach  ($ this loadFromCsvGenerator ($ table$ filePath$ optionsas  $ sql
31+             $ sqlParts$ sql
32+         }
33+         return  $ sqlParts''  : implode ("\n" , $ sqlParts
34+     }
35+ 
36+     /** 
37+      * Load data from CSV file using generator for memory efficiency. 
38+      * 
39+      * @param array<string, mixed> $options 
40+      * @return \Generator<string> 
41+      */ 
42+     public  function  loadFromCsvGenerator (string  $ tablestring  $ filePatharray  $ options\Generator  
2843    {
2944        $ defaults
3045            'fieldChar '  => ', ' ,
@@ -90,8 +105,6 @@ public function loadFromCsv(string $table, string $filePath, array $options = []
90105
91106        $ batchSizeself ::DEFAULT_BATCH_SIZE ;
92107        $ batch
93-         $ sqlParts
94-         $ rows0 ;
95108
96109        // Read and build batches 
97110        while  (!$ fileeof ()) {
@@ -133,25 +146,18 @@ public function loadFromCsv(string $table, string $filePath, array $options = []
133146            }
134147
135148            $ batch'( '  . implode (',  ' , $ vals') ' ;
136-             $ rows
137149
138150            if  (count ($ batch$ batchSize
139-                 $ sqlParts [] =  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsQ') ' 
151+                 yield  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsQ') ' 
140152                    . ' VALUES  '  . implode (',  ' , $ batch'; ' ;
141153                $ batch
142154            }
143155        }
144156
145157        if  (!empty ($ batch
146-             $ sqlParts [] =  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsQ') ' 
158+             yield  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsQ') ' 
147159                . ' VALUES  '  . implode (',  ' , $ batch'; ' ;
148160        }
149- 
150-         if  ($ rows0 ) {
151-             return  '' ;
152-         }
153- 
154-         return  implode ("\n" , $ sqlParts
155161    }
156162
157163    /** 
@@ -160,6 +166,21 @@ public function loadFromCsv(string $table, string $filePath, array $options = []
160166     * @param array<string, mixed> $options 
161167     */ 
162168    public  function  loadFromXml (string  $ tablestring  $ filePatharray  $ optionsstring 
169+     {
170+         $ sqlParts
171+         foreach  ($ this loadFromXmlGenerator ($ table$ filePath$ optionsas  $ sql
172+             $ sqlParts$ sql
173+         }
174+         return  $ sqlParts''  : implode ("\n" , $ sqlParts
175+     }
176+ 
177+     /** 
178+      * Load data from XML file using generator for memory efficiency. 
179+      * 
180+      * @param array<string, mixed> $options 
181+      * @return \Generator<string> 
182+      */ 
183+     public  function  loadFromXmlGenerator (string  $ tablestring  $ filePatharray  $ options\Generator  
163184    {
164185        $ defaults
165186            'rowTag '  => '<row> ' ,
@@ -181,99 +202,92 @@ public function loadFromXml(string $table, string $filePath, array $options = []
181202        $ tableQ$ this quoteIdentifier ($ table
182203        $ columns
183204        $ batch
184-         $ batchesSql
185205        $ batchSizeself ::DEFAULT_BATCH_SIZE ;
186-         $ rowsProcessed0 ;
187206        $ skipped0 ;
188207
189-         while  ($ readerread ()) {
190-             if  ($ readernodeType  !== XMLReader::ELEMENT ) {
191-                 continue ;
192-             }
193- 
194-             if  ($ readerlocalName  !== $ rowTag
195-                 continue ;
196-             }
208+         try  {
209+             while  ($ readerread ()) {
210+                 if  ($ readernodeType  !== XMLReader::ELEMENT ) {
211+                     continue ;
212+                 }
197213
198-             // Skip first N logical row elements if requested 
199-             if  ($ skipped$ skipRows
200-                 $ skipped
201-                 $ readernext ();
202-                 continue ;
203-             }
214+                 if  ($ readerlocalName  !== $ rowTag
215+                     continue ;
216+                 }
204217
205-             $ xml$ readerreadOuterXml ();
206-             if  ($ xml'' ) {
207-                 $ readernext ();
208-                 continue ;
209-             }
218+                 // Skip first N logical row elements if requested 
219+                 if  ($ skipped$ skipRows
220+                     $ skipped
221+                     $ readernext ();
222+                     continue ;
223+                 }
210224
211-             $ elem simplexml_load_string ( $ xml 
212-             if  ($ elem false ) {
213-                 $ readernext ();
214-                 continue ;
215-             }
225+                  $ xml $ reader -> readOuterXml ( );
226+                  if  ($ xml '' ) {
227+                      $ readernext ();
228+                      continue ;
229+                  }
216230
217-             // Determine columns from the first encountered row 
218-             if  ($ columns [] ) {
219-                 foreach  ( $ elem -> children ()  as   $ child ) { 
220-                     $ columns [] = ( string ) $ child -> getName () ;
231+                  $ elem  =  simplexml_load_string ( $ xml ); 
232+                  if  ($ elem false ) {
233+                      $ reader -> next (); 
234+                     continue ;
221235                }
222236
223-                 // fallback to attributes if no child elements  
237+                 // Determine columns from the first encountered row  
224238                if  ($ columns
225-                     foreach  ($ elemattributes () as  $ name$ val
226-                         $ columnsstring )$ name
239+                     foreach  ($ elemchildren () as  $ child
240+                         $ columnsstring )$ childgetName ();
241+                     }
242+ 
243+                     // fallback to attributes if no child elements 
244+                     if  ($ columns
245+                         foreach  ($ elemattributes () as  $ name$ val
246+                             $ columnsstring )$ name
247+                         }
248+                     }
249+ 
250+                     if  ($ columns
251+                         $ readerclose ();
252+                         return ;
227253                    }
228254                }
229255
230-                 if  ($ columns
231-                     $ readerclose ();
232-                     return  '' ;
256+                 $ values
257+                 foreach  ($ columnsas  $ col
258+                     $ valnull ;
259+ 
260+                     if  (isset ($ elem$ colstring )$ elem$ col'' ) {
261+                         $ valstring )$ elem$ col
262+                     } elseif  ($ elemattributes ()->{$ colnull ) {
263+                         $ valstring )$ elemattributes ()->{$ col
264+                     }
265+ 
266+                     $ values$ this quoteValue ($ val
233267                }
234-             }
235268
236-             $ values
237-             foreach  ($ columnsas  $ col
238-                 $ valnull ;
269+                 $ batch'( '  . implode (',  ' , $ values') ' ;
239270
240-                 if  (isset ($ elem$ colstring )$ elem$ col'' ) {
241-                     $ valstring )$ elem$ col
242-                 } elseif  ($ elemattributes ()->{$ colnull ) {
243-                     $ valstring )$ elemattributes ()->{$ col
271+                 if  (count ($ batch$ batchSize
272+                     $ colsEscapedarray_map (fn  ($ c$ this quoteColumnName ($ c$ columns
273+ 
274+                     yield  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsEscaped') ' 
275+                         . ' VALUES  '  . implode (',  ' , $ batch'; ' ;
276+                     $ batch
244277                }
245278
246-                 $ values [] =  $ this -> quoteValue ( $ val 
279+                 $ reader -> next ( );
247280            }
248281
249-             $ batch'( '  . implode (',  ' , $ values') ' ;
250-             $ rowsProcessed
251- 
252-             if  (count ($ batch$ batchSize
282+             if  ($ batch
253283                $ colsEscapedarray_map (fn  ($ c$ this quoteColumnName ($ c$ columns
254284
255-                 $ batchesSql [] =  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsEscaped') ' 
285+                 yield  'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsEscaped') ' 
256286                    . ' VALUES  '  . implode (',  ' , $ batch'; ' ;
257-                 $ batch
258287            }
259- 
260-             $ readernext ();
288+         }  finally  { 
289+             $ readerclose ();
261290        }
262- 
263-         $ readerclose ();
264- 
265-         if  ($ batch
266-             $ colsEscapedarray_map (fn  ($ c$ this quoteColumnName ($ c$ columns
267- 
268-             $ batchesSql'INSERT INTO  '  . $ tableQ' ( '  . implode (',  ' , $ colsEscaped') ' 
269-                 . ' VALUES  '  . implode (',  ' , $ batch'; ' ;
270-         }
271- 
272-         if  ($ rowsProcessed0 ) {
273-             return  '' ;
274-         }
275- 
276-         return  implode ("\n" , $ batchesSql
277291    }
278292
279293    /** 
0 commit comments