aboutsummaryrefslogtreecommitdiffstats
path: root/erts/doc/src/driver.xml
diff options
context:
space:
mode:
Diffstat (limited to 'erts/doc/src/driver.xml')
-rw-r--r--erts/doc/src/driver.xml50
1 files changed, 27 insertions, 23 deletions
diff --git a/erts/doc/src/driver.xml b/erts/doc/src/driver.xml
index 12c79aee90..9f246c4a6c 100644
--- a/erts/doc/src/driver.xml
+++ b/erts/doc/src/driver.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2010</year>
+ <year>2001</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -63,7 +63,8 @@
<p>This is a simple driver for accessing a postgres
database using the libpq C client library. Postgres
is used because it's free and open source. For information
- on postgres, refer to the website www.postgres.org.</p>
+ on postgres, refer to the website
+ <url href="http://www.postgres.org">www.postgres.org</url>.</p>
<p>The driver is synchronous, it uses the synchronous calls of
the client library. This is only for simplicity, and is
generally not good, since it will
@@ -196,18 +197,21 @@ static ErlDrvData start(ErlDrvPort port, char *command)
<p>We call disconnect to log out from the database.
(This should have been done from Erlang, but just in case.)</p>
<code type="none"><![CDATA[
- static int do_disconnect(our_data_t* data, ei_x_buff* x);
+static int do_disconnect(our_data_t* data, ei_x_buff* x);
static void stop(ErlDrvData drv_data)
{
- do_disconnect((our_data_t*)drv_data, NULL);
+ our_data_t* data = (our_data_t*)drv_data;
+
+ do_disconnect(data, NULL);
+ driver_free(data);
}
]]></code>
<p>We use the binary format only to return data to the emulator;
input data is a string paramater for <c><![CDATA[connect]]></c> and
<c><![CDATA[select]]></c>. The returned data consists of Erlang terms.</p>
<p>The functions <c><![CDATA[get_s]]></c> and <c><![CDATA[ei_x_to_new_binary]]></c> are
- utilities that is used to make the code shorter. <c><![CDATA[get_s]]></c>
+ utilities that are used to make the code shorter. <c><![CDATA[get_s]]></c>
duplicates the string and zero-terminates it, since the
postgres client library wants that. <c><![CDATA[ei_x_to_new_binary]]></c>
takes an <c><![CDATA[ei_x_buff]]></c> buffer and allocates a binary and
@@ -241,7 +245,7 @@ static int control(ErlDrvData drv_data, unsigned int command, char *buf,
return r;
}
]]></code>
- <p>In <c><![CDATA[do_connect]]></c> is where we log in to the database. If the connection
+ <p><c><![CDATA[do_connect]]></c> is where we log in to the database. If the connection
was successful we store the connection handle in our driver
data, and return ok. Otherwise, we return the error message
from postgres, and store <c><![CDATA[NULL]]></c> in the driver data.</p>
@@ -261,7 +265,7 @@ static int do_connect(const char *s, our_data_t* data, ei_x_buff* x)
}
]]></code>
<p>If we are connected (if the connection handle is not <c><![CDATA[NULL]]></c>),
- we log out from the database. We need to check if a we should
+ we log out from the database. We need to check if we should
encode an ok, since we might get here from the <c><![CDATA[stop]]></c>
function, which doesn't return data to the emulator.</p>
<code type="none"><![CDATA[
@@ -276,7 +280,7 @@ static int do_disconnect(our_data_t* data, ei_x_buff* x)
return 0;
}
]]></code>
- <p>We execute a query and encodes the result. Encoding is done
+ <p>We execute a query and encode the result. Encoding is done
in another C module, <c><![CDATA[pg_encode.c]]></c> which is also provided
as sample code.</p>
<code type="none"><![CDATA[
@@ -288,7 +292,7 @@ static int do_select(const char* s, our_data_t* data, ei_x_buff* x)
return 0;
}
]]></code>
- <p>Here we simply checks the result from postgres, and
+ <p>Here we simply check the result from postgres, and
if it's data we encode it as lists of lists with
column data. Everything from postgres is C strings,
so we just use <c><![CDATA[ei_x_encode_string]]></c> to send
@@ -389,7 +393,7 @@ disconnect(Port) ->
select(Port, Query) ->
binary_to_term(port_control(Port, ?DRV_SELECT, Query)).
]]></code>
- <p>The api is simple: <c><![CDATA[connect/1]]></c> loads the driver, opens it
+ <p>The API is simple: <c><![CDATA[connect/1]]></c> loads the driver, opens it
and logs on to the database, returning the Erlang port
if successful, <c><![CDATA[select/2]]></c> sends a query to the driver,
and returns the result, <c><![CDATA[disconnect/1]]></c> closes the
@@ -413,8 +417,8 @@ select(Port, Query) ->
<title>Sample asynchronous driver</title>
<p>Sometimes database queries can take long time to
complete, in our <c><![CDATA[pg_sync]]></c> driver, the emulator
- halts while the driver is doing it's job. This is
- often not acceptable, since no other Erlang processes
+ halts while the driver is doing its job. This is
+ often not acceptable, since no other Erlang process
gets a chance to do anything. To improve on our
postgres driver, we reimplement it using the asynchronous
calls in LibPQ.</p>
@@ -469,7 +473,7 @@ typedef struct our_data_t {
whether the driver is waiting for a connection or waiting
for the result of a query. (This is needed since the entry
<c><![CDATA[ready_io]]></c> will be called both when connecting and
- when there is query result.)</p>
+ when there is a query result.)</p>
<code type="none"><![CDATA[
static int do_connect(const char *s, our_data_t* data)
{
@@ -568,7 +572,7 @@ static void ready_io(ErlDrvData drv_data, ErlDrvEvent event)
connection is successful, or error if it's not. If the
connection is not yet established, we simply return; <c><![CDATA[ready_io]]></c>
will be called again.</p>
- <p>If we have result from a connect, indicated that we have data in
+ <p>If we have a result from a connect, indicated by having data in
the <c><![CDATA[x]]></c> buffer, we no longer need to select on
output (<c><![CDATA[ready_output]]></c>), so we remove this by calling
<c><![CDATA[driver_select]]></c>.</p>
@@ -627,9 +631,9 @@ return_port_data(Port) ->
message queue. The function <c><![CDATA[return_port_data]]></c> above
receives data from the port. Since the data is in
binary format, we use <c><![CDATA[binary_to_term/1]]></c> to convert
- it to Erlang term. Note that the driver is opened in
- binary mode, <c><![CDATA[open_port/2]]></c> is called with the option
- <c><![CDATA[[binary]]]></c>. This means that data sent from the driver
+ it to an Erlang term. Note that the driver is opened in
+ binary mode (<c><![CDATA[open_port/2]]></c> is called with the option
+ <c><![CDATA[[binary]]]></c>). This means that data sent from the driver
to the emulator is sent as binaries. Without the <c><![CDATA[binary]]></c>
option, they would have been lists of integers.</p>
</section>
@@ -643,15 +647,15 @@ return_port_data(Port) ->
of a list of integers. For large lists (more than 100000
elements), this will take some time, so we will perform this
as an asynchronous task.</p>
- <p>The asynchronous api for drivers are quite complicated. First
+ <p>The asynchronous API for drivers is quite complicated. First
of all, the work must be prepared. In our example we do this
in <c><![CDATA[output]]></c>. We could have used <c><![CDATA[control]]></c> just as well,
but we want some variation in our examples. In our driver, we allocate
- a structure that contains all needed for the asynchronous task
+ a structure that contains anything that's needed for the asynchronous task
to do the work. This is done in the main emulator thread.
Then the asynchronous function is called from a driver thread,
- separate from the main emulator thread. Note that the driver-
- functions are not reentrant, so they shouldn't be used.
+ separate from the main emulator thread. Note that the driver-functions
+ are not reentrant, so they shouldn't be used.
Finally, after the function is completed, the driver callback
<c><![CDATA[ready_async]]></c> is called from the main emulator thread,
this is where we return the result to Erlang. (We can't
@@ -689,7 +693,7 @@ static ErlDrvEntry next_perm_driver_entry = {
be sent later from the <c><![CDATA[ready_async]]></c> call-back.</p>
<p>The <c><![CDATA[async_data]]></c> will be passed to the <c><![CDATA[do_perm]]></c> function.
We do not use a <c><![CDATA[async_free]]></c> function (the last argument to
- <c><![CDATA[driver_async]]></c>, it's only used if the task is cancelled
+ <c><![CDATA[driver_async]]></c>), it's only used if the task is cancelled
programmatically.</p>
<code type="none"><![CDATA[
struct our_async_data {
@@ -740,7 +744,7 @@ static void ready_async(ErlDrvData drv_data, ErlDrvThreadData async_data)
ErlDrvPort port = reinterpret_cast<ErlDrvPort>(drv_data);
our_async_data* d = reinterpret_cast<our_async_data*>(async_data);
int n = d->data.size(), result_n = n*2 + 3;
- ErlDrvTermData* result = new ErlDrvTermData[result_n], * rp = result;
+ ErlDrvTermData *result = new ErlDrvTermData[result_n], *rp = result;
for (vector<int>::iterator i = d->data.begin();
i != d->data.end(); ++i) {
*rp++ = ERL_DRV_INT;