1
/* ``The contents of this file are subject to the Erlang Public License,
2
* Version 1.1, (the "License"); you may not use this file except in
3
* compliance with the License. You should have received a copy of the
4
* Erlang Public License along with this software. If not, it can be
5
* retrieved via the world wide web at http://www.erlang.org/.
7
* Software distributed under the License is distributed on an "AS IS"
8
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
* the License for the specific language governing rights and limitations
12
* The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
* Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
* AB. All Rights Reserved.''
20
* Purpose: A driver using libpq to connect to Postgres
21
* from erlang, a sample for the driver documentation
24
#include <erl_driver.h>
34
#include "pg_encode.h"
36
/* Driver interface declarations */
37
static ErlDrvData start(ErlDrvPort port, char *command);
38
static void stop(ErlDrvData drv_data);
39
static int control(ErlDrvData drv_data, unsigned int command, char *buf,
40
int len, char **rbuf, int rlen);
41
static void ready_io(ErlDrvData drv_data, ErlDrvEvent event);
43
static ErlDrvEntry pq_driver_entry = {
48
ready_io, /* ready_input */
49
ready_io, /* ready_output */
50
"pg_async", /* the name of the driver */
56
NULL, /* ready_async */
62
typedef struct our_data_t {
69
/* Keep the following definitions in alignment with the FUNC_LIST
73
#define DRV_CONNECT 'C'
74
#define DRV_DISCONNECT 'D'
75
#define DRV_SELECT 'S'
77
/* #define L fprintf(stderr, "%d\r\n", __LINE__) */
79
/* INITIALIZATION AFTER LOADING */
82
* This is the init function called after this driver has been loaded.
83
* It must *not* be declared static. Must return the address to
88
return &pq_driver_entry;
91
static char* get_s(const char* buf, int len);
92
static int do_connect(const char *s, our_data_t* data);
93
static int do_disconnect(our_data_t* data);
94
static int do_select(const char* s, our_data_t* data);
96
/* DRIVER INTERFACE */
97
static ErlDrvData start(ErlDrvPort port, char *command)
99
our_data_t* data = driver_alloc(sizeof(our_data_t));
102
return (ErlDrvData)data;
105
static void stop(ErlDrvData drv_data)
107
do_disconnect((our_data_t*)drv_data);
110
static int control(ErlDrvData drv_data, unsigned int command, char *buf,
111
int len, char **rbuf, int rlen)
114
char* s = get_s(buf, len);
115
our_data_t* data = (our_data_t*)drv_data;
117
case DRV_CONNECT: r = do_connect(s, data); break;
118
case DRV_DISCONNECT: r = do_disconnect(data); break;
119
case DRV_SELECT: r = do_select(s, data); break;
120
default: r = -1; break;
126
static int do_connect(const char *s, our_data_t* data)
128
PGconn* conn = PQconnectStart(s);
129
if (PQstatus(conn) == CONNECTION_BAD) {
131
ei_x_new_with_version(&x);
132
encode_error(&x, conn);
135
driver_output(data->port, x.buff, x.index);
139
int socket = PQsocket(conn);
140
data->socket = socket;
141
driver_select(data->port, (ErlDrvEvent)socket, DO_READ, 1);
142
driver_select(data->port, (ErlDrvEvent)socket, DO_WRITE, 1);
144
data->connecting = 1;
148
static int do_disconnect(our_data_t* data)
151
driver_select(data->port, (ErlDrvEvent)data->socket, DO_READ, 0);
152
driver_select(data->port, (ErlDrvEvent)data->socket, DO_WRITE, 0);
153
PQfinish(data->conn);
155
ei_x_new_with_version(&x);
157
driver_output(data->port, x.buff, x.index);
162
static int do_select(const char* s, our_data_t* data)
164
data->connecting = 0;
165
PGconn* conn = data->conn;
166
/* if there's an error return it now */
167
if (PQsendQuery(conn, s) == 0) {
169
ei_x_new_with_version(&x);
170
encode_error(&x, conn);
171
driver_output(data->port, x.buff, x.index);
174
/* else wait for ready_output to get results */
178
static void ready_io(ErlDrvData drv_data, ErlDrvEvent event)
180
PGresult* res = NULL;
181
our_data_t* data = (our_data_t*)drv_data;
182
PGconn* conn = data->conn;
184
ei_x_new_with_version(&x);
185
if (data->connecting) {
186
ConnStatusType status;
188
status = PQstatus(conn);
189
if (status == CONNECTION_OK)
191
else if (status == CONNECTION_BAD)
192
encode_error(&x, conn);
194
PQconsumeInput(conn);
197
res = PQgetResult(conn);
198
encode_result(&x, res, conn);
201
res = PQgetResult(conn);
208
driver_output(data->port, x.buff, x.index);
209
if (data->connecting)
210
driver_select(data->port, (ErlDrvEvent)data->socket, DO_WRITE, 0);
216
static char* get_s(const char* buf, int len)
219
if (len < 1 || len > 1000) return NULL;
220
result = driver_alloc(len+1);
221
memcpy(result, buf, len);