<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
<year>2003</year><year>2009</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
</legalnotice>
<title>Error handling</title>
<prepared>Ingela Anderton</prepared>
<responsible></responsible>
<docno></docno>
<approved></approved>
<checked></checked>
<date></date>
<rev></rev>
<file>error_handling.xml</file>
</header>
<section>
<title>Strategy </title>
<p>On a conceptual level starting a database connection using the
Erlang ODBC API is a basic client server application. The client
process uses the API to start and communicate with the server
process that manages the connection. The strategy of the Erlang
ODBC application is that programming faults in the application
itself will cause the connection process to terminate
abnormally.(When a process terminates abnormally its supervisor
will log relevant error reports.) Calls to API functions during or
after termination of the connection process, will return <c>{error, connection_closed}</c>. Contextual errors on the other
hand will not terminate the connection it will only return
<c>{error, Reason} </c> to the client, where <c>Reason</c> may be
any erlang term.</p>
<section>
<title>Clients </title>
<p>The connection is associated with the process that created it
and can only be accessed through it. The reason for this is to
preserve the semantics of result sets and transactions when
select_count/[2,3] is called or auto_commit is turned off.
Attempts to use the connection from another process will
fail. This will not effect the connection. On the other hand, if
the client process dies the connection will be terminated.</p>
</section>
<section>
<title>Timeouts </title>
<p>All request made by the client to the connection are
synchronous. If the timeout is used and expires the client
process will exit with reason timeout. Proably the right thing
to do is let the client die and perhaps be restarted by its
supervisor. But if the client chooses to catch this timeout,
it is a good idea to wait a little while before trying
again. If there are too many consecutive timeouts that are
caught the connection process will conclude that there is
something radically wrong and terminate the connection.</p>
</section>
<section>
<title>Gaurds </title>
<p>All API-functions are guarded and if you pass an argument of
the wrong type a runtime error will occur. All input parameters
to internal functions are trusted to be correct. It is a good
programming practise to only distrust input from truly external
sources. You are not supposed to catch these errors, it will
only make the code very messy and much more complex, which
introduces more bugs and in the worst case also covers up the
actual faults. Put your effort on testing instead, you should
trust your own input.</p>
</section>
</section>
<section>
<title>The whole picture </title>
<p>As the Erlang ODBC application relies on third party products
and communicates with a database that probably runs on an other
computer in the network there are plenty of things that might go
wrong. To fully understand the things that might happen it
facilitate to know the design of the Erlang ODBC application,
hence here follows a short description of the current design.</p>
<note>
<p>Please note that design is something, that not
necessarily will, but might change in future releases. While the
semantics of the API will not change as it is independent of the
implementation.</p>
</note>
<image file="odbc_app_arc.gif">
<icaption>Architecture of the Erlang odbc application</icaption>
</image>
<p>When you do application:start(odbc) the only thing that
happens is that a supervisor process is started. For each call
to the API function connect/2 a process is spawned and added as
a child to the Erlang ODBC supervisor. The supervisors only
tasks are to provide error-log reports, if a child process should
die abnormally, and the possibility to do a code change. Only
the client process has the knowledge to decide if this
connection managing process should be restarted.</p>
<p>The erlang connection process spawned by connect/2, will open a
port to a c-process that handles the communication with the
database through Microsoft's ODBC API. The erlang port will be
kept open for exit signal propagation, if something goes wrong
in the c-process and it exits we want know as mush as possible
about the reason. The main communication with the c-process is
done through sockets. The C-process consists of two threads,
the supervisor thread and the database handler thread. The
supervisor thread checks for shutdown messages on the supervisor
socket and the database handler thread receives requests and sends
answers on the database socket. If the database thread seems to
hang on some database call, the erlang control process will send
a shutdown message on the supervisor socket, in this case the
c-process will exit. If the c-process crashes/exits it will
bring the erlang-process down too and vice versa i.e. the
connection is terminated.</p>
<note>
<p>The function connect/2 will start the odbc application if
that is not already done. In this case a supervisor information
log will be produced stating that the odbc application was started
as a temporary application. It is really the responsibility of the
application that uses the API too make sure it is started in the
desired way.</p>
</note>
<section>
<title>Error types</title>
<p>The types of errors that may occur can be divide into the
following categories.</p>
<list type="bulleted">
<item>Configuration problems - Everything from that the
database was not set up right to that the c-program that
should be run through the erlang port was not compiled for
your platform.</item>
<item>Errors discovered by the ODBC driver - If calls to the
ODBC-driver fails due to circumstances that can not be
controlled by the Erlang ODBC application programmer, an
error string will be dug up from the driver. This string
will be the <c>Reason</c> in the <c>{error, Reason} </c>
return value. How good this error message is will of course
be driver dependent. Examples of such circumstances are
trying to insert the same key twice, invalid SQL-queries and
that the database has gone off line.</item>
<item>Connection termination - If a connection is terminated
in an abnormal way, or if you try to use a connection that
you have already terminated in a normal way by calling
disconnect/1, the return value will be<c>{error, connection_closed}</c>. A connection could end abnormally
because of an programming error in the Erlang ODBC
application, but also if the ODBC driver crashes.</item>
<item>Contextual errors - If API functions are used in the
wrong context, the <c>Reason</c> in the error tuple will
be a descriptive atom. For instance if you try to call the
function <c>last/[1,2] </c> without first calling <c>select_count/[2,3] </c> to associate a result set with the
connection. If the ODBC-driver does not support some
functions, or if you disabled some functionality for a
connection and then try to use it.</item>
</list>
</section>
</section>
</chapter>