@@ -265,18 +265,29 @@ public function transactionRollback() {
265265 public function dryRun ($ callback = null ) {
266266 $ result = null ;
267267 $ exception = null ;
268- if ($ this ->pdo ->inTransaction ()) {
269- throw new \Exception ('Connection is already in a transaction. Dry-run not possible. ' );
270- }
271- $ this ->transactionStart ();
272- try {
273- $ result = call_user_func ($ callback , $ this );
274- } catch (\Exception $ e ) {
275- $ exception = $ e ;
276- }
277- $ this ->transactionRollback ();
278- if ($ exception !== null ) {
279- throw $ exception ;
268+ if (!$ this ->pdo ->inTransaction ()) {
269+ $ this ->transactionStart ();
270+ try {
271+ $ result = call_user_func ($ callback , $ this );
272+ } catch (\Exception $ e ) {
273+ $ exception = $ e ;
274+ }
275+ $ this ->transactionRollback ();
276+ if ($ exception !== null ) {
277+ throw $ exception ;
278+ }
279+ } else {
280+ $ uniqueId = $ this ->genUniqueId ();
281+ $ this ->exec ("SAVEPOINT {$ uniqueId }" );
282+ try {
283+ $ result = call_user_func ($ callback , $ this );
284+ } catch (\Exception $ e ) {
285+ $ exception = $ e ;
286+ }
287+ $ this ->exec ("ROLLBACK TO {$ uniqueId }" );
288+ if ($ exception !== null ) {
289+ throw $ exception ;
290+ }
280291 }
281292 return $ result ;
282293 }
@@ -296,14 +307,26 @@ public function transaction($tries = 1, $callback = null) {
296307 throw new \Exception ('$callback must be a callable ' );
297308 }
298309 $ e = null ;
299- for (; $ tries --;) {
310+ if (!$ this ->pdo ->inTransaction ()) {
311+ for (; $ tries --;) {
312+ try {
313+ $ this ->transactionStart ();
314+ $ result = call_user_func ($ callback , $ this );
315+ $ this ->transactionCommit ();
316+ return $ result ;
317+ } catch (\Exception $ e ) {
318+ $ this ->transactionRollback ();
319+ }
320+ }
321+ } else {
322+ $ uniqueId = $ this ->genUniqueId ();
300323 try {
301- $ this ->transactionStart ( );
324+ $ this ->exec ( " SAVEPOINT { $ uniqueId }" );
302325 $ result = call_user_func ($ callback , $ this );
303- $ this ->transactionCommit ( );
326+ $ this ->exec ( " RELEASE SAVEPOINT { $ uniqueId }" );
304327 return $ result ;
305328 } catch (\Exception $ e ) {
306- $ this ->transactionRollback ( );
329+ $ this ->exec ( " ROLLBACK TO { $ uniqueId }" );
307330 }
308331 }
309332 throw $ e ;
@@ -355,4 +378,21 @@ private function exceptionHandler($fn) {
355378 $ this ->exceptionInterpreter ->throwMoreConcreteException ($ e );
356379 }
357380 }
381+
382+ /**
383+ * @return string
384+ */
385+ private function genUniqueId () {
386+ // Generate a unique id from a former random-uuid-generator
387+ return sprintf ('ID%04x%04x%04x%04x%04x%04x%04x%04x ' ,
388+ mt_rand (0 , 0xffff ),
389+ mt_rand (0 , 0xffff ),
390+ mt_rand (0 , 0xffff ),
391+ mt_rand (0 , 0x0fff ) | 0x4000 ,
392+ mt_rand (0 , 0x3fff ) | 0x8000 ,
393+ mt_rand (0 , 0xffff ),
394+ mt_rand (0 , 0xffff ),
395+ mt_rand (0 , 0xffff )
396+ );
397+ }
358398}
0 commit comments