Commits

Will Glozer committed 4c7648f

return error tuple when an EXIT message is received

Comments (0)

Files changed (3)

 * Simple Query
 
   {ok, Columns, Rows} = pgsql:squery(C, Sql).
-  {error, #error{}}   = pgsql:squery(C, InvalidSql).
+  {error, Error}      = pgsql:squery(C, InvalidSql).
 
   Columns       - list of column records, see pgsql.hrl for definition.
   Rows          - list of tuples, one for each row.
   {ok, Count}                = pgsql:equery(C, "update ...", [Parameters]).
   {ok, Count, Columns, Rows} = pgsql:equery(C, "insert ... returning ...", [Parameters]).
 
-  {error, #error{}}          = pgsql:equery(C, "invalid SQL", [Parameters]).
+  {error, Error}             = pgsql:equery(C, "invalid SQL", [Parameters]).
 
   Parameters    - optional list of values to be bound to $1, $2, $3, etc.
 
   ok = pgsql:close(C, statement | portal, Name).
   ok = pgsql:sync(C).
 
-  All functions return {error, #error{}} when an error occurs.
+  All functions return {error, Error} when an error occurs.
 
 * Data Representation
 
   bytea       = <<1, 2>>
 
   record      = {int2, time, text, ...} (decode only)
+
+* Errors
+
+  Errors originating from the PostgreSQL backend are returned as {error, #error{}},
+  see pgsql.hrl for the record definition. epgsql may also return {error, Atom}
+  where Atom is 'timeout' or 'closed'.
 %% -- internal functions --
 
 receive_result(C, Result) ->
-    case receive_result(C, [], []) of
+    try receive_result(C, [], []) of
         done    -> Result;
-        timeout -> {error, timeout};
         R       -> receive_result(C, R)
+    catch
+        throw:E -> E
     end.
 
 receive_results(C, Results) ->
-    case receive_result(C, [], []) of
+    try receive_result(C, [], []) of
         done    -> lists:reverse(Results);
-        timeout -> lists:reverse([{error, timeout} | Results]);
         R       -> receive_results(C, [R | Results])
+    catch
+        throw:E -> E
     end.
 
 receive_result(C, Cols, Rows) ->
         {pgsql, C, done} ->
             done;
         {pgsql, C, timeout} ->
-            timeout
+            throw({error, timeout});
+        {'EXIT', C, _Reason} ->
+            throw({error, closed})
     end.
 
 receive_extended_result(C)->
         {pgsql, C, {notice, _N}} ->
             receive_extended_result(C, Rows);
         {pgsql, C, timeout} ->
-            {error, timeout}
+            {error, timeout};
+        {'EXIT', C, _Reason} ->
+            {error, closed}
     end.

test_src/pgsql_tests.erl

       end,
       [{timeout, 10}]).
 
+connection_closed_test() ->
+    P = self(),
+    F = fun() ->
+                process_flag(trap_exit, true),
+                {ok, C} = pgsql:connect(?host, [{port, ?port}]),
+                P ! {connected, C},
+                receive
+                    Any -> P ! Any
+                end
+        end,
+    spawn_link(F),
+    receive
+        {connected, C} ->
+            timer:sleep(100),
+            pgsql:close(C),
+            {'EXIT', C, _} = receive R -> R end
+    end,
+    flush().
+
+active_connection_closed_test() ->
+    P = self(),
+    F = fun() ->
+                process_flag(trap_exit, true),
+                {ok, C} = pgsql:connect(?host, [{port, ?port}]),
+                P ! {connected, C},
+                R = pgsql:squery(C, "select pg_sleep(10)"),
+                P ! R
+        end,
+    spawn_link(F),
+    receive
+        {connected, C} ->
+            timer:sleep(100),
+            pgsql:close(C),
+            {error, closed} = receive R -> R end
+    end,
+    flush().
+
 %% -- run all tests --
 
 run_tests() ->