~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to erts/example/pg_async2.c

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/.
 
6
 * 
 
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
 
10
 * under the License.
 
11
 * 
 
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.''
 
15
 * 
 
16
 *     $Id$
 
17
 */
 
18
 
 
19
/*
 
20
 * Purpose: A driver using libpq to connect to Postgres
 
21
 * from erlang, a sample for the driver documentation
 
22
 */
 
23
 
 
24
#include <erl_driver.h>
 
25
 
 
26
#include <libpq-fe.h>
 
27
 
 
28
#include <ei.h>
 
29
 
 
30
#include <stdlib.h>
 
31
#include <stdio.h>
 
32
#include <string.h>
 
33
 
 
34
#include "pg_encode2.h"
 
35
 
 
36
#define L     fprintf(stderr, "%d\r\n", __LINE__)
 
37
 
 
38
/* Driver interface declarations */
 
39
static ErlDrvData start(ErlDrvPort port, char *command);
 
40
static void stop(ErlDrvData drv_data);
 
41
static int control(ErlDrvData drv_data, unsigned int command, char *buf, 
 
42
                   int len, char **rbuf, int rlen); 
 
43
static void ready_input(ErlDrvData drv_data, ErlDrvEvent event);
 
44
 
 
45
static ErlDrvEntry pq_driver_entry = {
 
46
    NULL,                       /* init */
 
47
    start, 
 
48
    stop, 
 
49
    NULL,                       /* output */
 
50
    ready_input,                /* ready_input */
 
51
    NULL,                       /* ready_output */ 
 
52
    "pg_async2", 
 
53
    NULL,                       /* finish */
 
54
    NULL,                       /* handle */
 
55
    control, 
 
56
    NULL,                       /* timeout */
 
57
    NULL,                       /* outputv */
 
58
    NULL,
 
59
    NULL,
 
60
    NULL,
 
61
    NULL
 
62
};
 
63
 
 
64
typedef struct our_data_t {
 
65
    PGconn* conn;
 
66
    ErlDrvPort port;
 
67
    int socket;
 
68
    char* s;
 
69
} our_data_t;
 
70
 
 
71
our_data_t our_data;
 
72
 
 
73
/* Keep the following definitions in alignment with the FUNC_LIST
 
74
 * in erl_pq_sync.erl
 
75
 */
 
76
 
 
77
#define DRV_CONNECT             1
 
78
#define DRV_DISCONNECT          2
 
79
#define DRV_SELECT              3
 
80
 
 
81
/* INITIALIZATION AFTER LOADING */
 
82
 
 
83
/* 
 
84
 * This is the init function called after this driver has been loaded.
 
85
 * It must *not* be declared static. Must return the address to 
 
86
 * the driver entry.
 
87
 */
 
88
 
 
89
#ifdef __cplusplus
 
90
extern "C" {                    /* this should be in the DRIVER_INIT macro! */
 
91
#endif
 
92
DRIVER_INIT(pq_drv)
 
93
{
 
94
    return &pq_driver_entry;
 
95
}
 
96
#ifdef __cplusplus
 
97
}
 
98
#endif
 
99
 
 
100
/* DRIVER INTERFACE */
 
101
static ErlDrvData start(ErlDrvPort port, char *command)
 
102
 
103
    our_data_t* data = driver_alloc(sizeof(our_data_t));
 
104
    data->port = port;
 
105
    data->conn = NULL;
 
106
    return (ErlDrvData)data;
 
107
}
 
108
 
 
109
 
 
110
static char* get_s(const char* buf, int len);
 
111
static void free_s(char* s);
 
112
 
 
113
static int do_connect(const char *s, our_data_t* data);
 
114
static int do_disconnect(our_data_t* data);
 
115
static int do_select(const char* s, our_data_t* data);
 
116
 
 
117
static void stop(ErlDrvData drv_data)
 
118
{
 
119
    do_disconnect((our_data_t*)drv_data);
 
120
}
 
121
 
 
122
 
 
123
/* Since we are operating in binary mode, the return value from control
 
124
 * is irrelevant, as long as it is not negative.
 
125
 */
 
126
static int control(ErlDrvData drv_data, unsigned int command, char *buf, 
 
127
                   int len, char **rbuf, int rlen)
 
128
{
 
129
    int r;
 
130
    char* s;
 
131
 
 
132
    s = get_s(buf, len);
 
133
    switch (command) {
 
134
    case DRV_CONNECT:
 
135
        r = do_connect(s, (our_data_t*)drv_data);
 
136
        break;
 
137
    case DRV_DISCONNECT:
 
138
        r = do_disconnect((our_data_t*)drv_data);
 
139
        break;
 
140
    case DRV_SELECT:
 
141
        r = do_select(s, (our_data_t*)drv_data);
 
142
        break;
 
143
    default:
 
144
        r = -1;
 
145
        break;
 
146
    }
 
147
    free_s(s);
 
148
    return r;
 
149
}
 
150
 
 
151
static int do_connect(const char *s, our_data_t* data)
 
152
{
 
153
    ei_x_buff x;
 
154
    PGconn* conn = PQconnectdb(s);
 
155
 
 
156
    ei_x_new_with_version(&x);
 
157
    if (PQstatus(conn) != CONNECTION_OK) {
 
158
        encode_error(&x, conn);
 
159
        PQfinish(conn);
 
160
        conn = NULL;
 
161
    } else {
 
162
        encode_ok(&x);
 
163
        data->socket = PQsocket(conn);
 
164
        driver_select(data->port, (ErlDrvEvent)data->socket, DO_READ, 1);
 
165
    }
 
166
    driver_output(data->port, x.buff, x.index);
 
167
    ei_x_free(&x);
 
168
    data->conn = conn;
 
169
    return 0;
 
170
}
 
171
 
 
172
static int do_disconnect(our_data_t* data)
 
173
{
 
174
    ei_x_buff x;
 
175
 
 
176
    if (data->socket == 0)
 
177
        return 0;
 
178
    driver_select(data->port, (ErlDrvEvent)data->socket, DO_READ, 0);
 
179
    data->socket = 0;
 
180
    PQfinish(data->conn);
 
181
    data->conn = NULL;
 
182
    ei_x_new_with_version(&x);
 
183
    encode_ok(&x);
 
184
    driver_output(data->port, x.buff, x.index);
 
185
    ei_x_free(&x);
 
186
    return 0;
 
187
}
 
188
 
 
189
static int do_select(const char* s, our_data_t* data)
 
190
{
 
191
    PGconn* conn = data->conn;
 
192
 
 
193
    /* if there's an error return it now */
 
194
    if (PQsendQueryParams(conn, s, 0, NULL, NULL, NULL, NULL, 1) == 0) {
 
195
        ei_x_buff x;
 
196
        ei_x_new_with_version(&x);
 
197
        encode_error(&x, conn);
 
198
        driver_output(data->port, x.buff, x.index);
 
199
        ei_x_free(&x);
 
200
    }
 
201
    /* else wait for ready_output to get results */
 
202
    return 0;
 
203
}
 
204
 
 
205
static void ready_input(ErlDrvData drv_data, ErlDrvEvent event)
 
206
{
 
207
    our_data_t* data = (our_data_t*)drv_data;
 
208
    PGconn* conn = data->conn;
 
209
    ei_x_buff x;
 
210
    PGresult* res;
 
211
 
 
212
    PQconsumeInput(conn);
 
213
    if (PQisBusy(conn)) 
 
214
        return;
 
215
    ei_x_new_with_version(&x);
 
216
    res = PQgetResult(conn);
 
217
    encode_result(&x, res, conn);
 
218
    driver_output(data->port, x.buff, x.index);
 
219
    ei_x_free(&x);
 
220
    PQclear(res);
 
221
    for (;;) {
 
222
        res = PQgetResult(conn);
 
223
        if (res == NULL)
 
224
            break;
 
225
        PQclear(res);
 
226
    }
 
227
}
 
228
 
 
229
/* utilities */
 
230
 
 
231
static char* get_s(const char* buf, int len)
 
232
{
 
233
    char* result;
 
234
    if (len < 1 || len > 1000) return NULL;
 
235
    result = driver_alloc(len+1);
 
236
    memcpy(result, buf, len);
 
237
    result[len] = '\0';
 
238
    return result;
 
239
}
 
240
 
 
241
static void free_s(char* s)
 
242
{
 
243
    driver_free(s);
 
244
}