@@ -315,74 +315,64 @@ defmodule Sqlitex.Statement do
315315 { :error , :invalid_returning_clause }
316316 end
317317
318- defp returning_query ( % __MODULE__ { database: db ,
319- statement: statement ,
320- returning: { table , cols , command , ref } } )
321- do
322- with_savepoint ( db , fn ->
323- with_temp_table ( db , cols , fn tmp_tbl ->
324- err = with_temp_trigger ( db , table , tmp_tbl , cols , command , ref , fn ->
325- :esqlite3 . fetchall ( statement )
326- end )
327-
328- case err do
329- { :error , _ } -> err
330- _ ->
331- fields = Enum . join ( cols , ", " )
332- :esqlite3 . q ( "SELECT #{ fields } FROM #{ tmp_tbl } " , db )
333- end
334- end )
335- end )
336- end
337-
338- defp with_savepoint ( db , func ) do
318+ defp returning_query ( % __MODULE__ { database: db } = stmt ) do
339319 sp = "sp_#{ random_id ( ) } "
340- [ ] = :esqlite3 . q ( "SAVEPOINT #{ sp } " , db )
341- case safe_call ( db , func , sp ) do
320+ { :ok , _ } = db_exec ( db , "SAVEPOINT #{ sp } " )
321+
322+ case returning_query_in_savepoint ( sp , stmt ) do
342323 { :error , _ } = error ->
343- [ ] = :esqlite3 . q ( "ROLLBACK TO SAVEPOINT #{ sp } " , db )
344- [ ] = :esqlite3 . q ( "RELEASE #{ sp } " , db )
324+ rollback ( db , sp )
345325 error
346326 result ->
347- [ ] = :esqlite3 . q ( "RELEASE #{ sp } " , db )
327+ { :ok , _ } = db_exec ( db , "RELEASE #{ sp } " )
348328 result
349329 end
350330 end
351331
352- defp safe_call ( db , func , sp ) do
353- func . ( )
332+ defp returning_query_in_savepoint ( sp , % __MODULE__ { database: db ,
333+ statement: statement ,
334+ returning: { table , cols , cmd , ref } } )
335+ do
336+ temp_table = "t_#{ random_id ( ) } "
337+ temp_fields = Enum . join ( cols , ", " )
338+
339+ trigger_name = "tr_#{ random_id ( ) } "
340+ trigger_fields = Enum . map_join ( cols , ", " , & "#{ ref } .#{ & 1 } " )
341+ trigger = """
342+ CREATE TEMP TRIGGER #{ trigger_name } AFTER #{ cmd } ON main.#{ table } BEGIN
343+ INSERT INTO #{ temp_table } SELECT #{ trigger_fields } ;
344+ END;
345+ """
346+
347+ column_names = Enum . join ( cols , ", " )
348+
349+ with { :ok , _ } = db_exec ( db , "CREATE TEMP TABLE #{ temp_table } (#{ temp_fields } )" ) ,
350+ { :ok , _ } = db_exec ( db , trigger ) ,
351+ _ = :esqlite3 . fetchall ( statement ) ,
352+ { :ok , rows } = db_exec ( db , "SELECT #{ column_names } FROM #{ temp_table } " ) ,
353+ { :ok , _ } = db_exec ( db , "DROP TRIGGER IF EXISTS #{ trigger_name } " ) ,
354+ { :ok , _ } = db_exec ( db , "DROP TABLE IF EXISTS #{ temp_table } " )
355+ do
356+ rows
357+ end
354358 catch
355- e in RuntimeError ->
356- [ ] = :esqlite3 . q ( "ROLLBACK TO SAVEPOINT #{ sp } " , db )
357- [ ] = :esqlite3 . q ( "RELEASE #{ sp } " , db )
359+ e ->
360+ rollback ( db , sp )
358361 raise e
359362 end
360363
361- defp with_temp_table ( db , returning , func ) do
362- tmp = "t_#{ random_id ( ) } "
363- fields = Enum . join ( returning , ", " )
364- results = case :esqlite3 . q ( "CREATE TEMP TABLE #{ tmp } (#{ fields } )" , db ) do
365- { :error , _ } = err -> err
366- _ -> func . ( tmp )
367- end
368- :esqlite3 . q ( "DROP TABLE IF EXISTS #{ tmp } " , db )
369- results
364+ defp rollback ( db , sp ) do
365+ { :ok , _ } = db_exec ( db , "ROLLBACK TO SAVEPOINT #{ sp } " )
366+ { :ok , _ } = db_exec ( db , "RELEASE #{ sp } " )
370367 end
371368
372- defp with_temp_trigger ( db , table , tmp_tbl , returning , command , ref , func ) do
373- tmp = "tr_" <> random_id ( )
374- fields = Enum . map_join ( returning , ", " , & "#{ ref } .#{ & 1 } " )
375- sql = """
376- CREATE TEMP TRIGGER #{ tmp } AFTER #{ command } ON main.#{ table } BEGIN
377- INSERT INTO #{ tmp_tbl } SELECT #{ fields } ;
378- END;
379- """
380- results = case :esqlite3 . q ( sql , db ) do
381- { :error , _ } = err -> err
382- _ -> func . ( )
369+ defp db_exec ( db , sql ) do
370+ case :esqlite3 . q ( sql , db ) do
371+ { :error , _ } = error ->
372+ error
373+ result ->
374+ { :ok , result }
383375 end
384- :esqlite3 . q ( "DROP TRIGGER IF EXISTS #{ tmp } " , db )
385- results
386376 end
387377
388378 defp random_id , do: :rand . uniform |> Float . to_string |> String . slice ( 2 .. 10 )
0 commit comments