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

« back to all changes in this revision

Viewing changes to erts/example/pg_async.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_encode.h"
 
35
 
 
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);
 
42
 
 
43
static ErlDrvEntry pq_driver_entry = {
 
44
    NULL,                       /* init */
 
45
    start, 
 
46
    stop, 
 
47
    NULL,                       /* output */
 
48
    ready_io,                   /* ready_input */
 
49
    ready_io,                   /* ready_output */ 
 
50
    "pg_async",                 /* the name of the driver */
 
51
    NULL,                       /* finish */
 
52
    NULL,                       /* handle */
 
53
    control, 
 
54
    NULL,                       /* timeout */
 
55
    NULL,                       /* outputv */
 
56
    NULL,                       /* ready_async */
 
57
    NULL,                       /* flush */
 
58
    NULL,                       /* call */
 
59
    NULL                        /* event */
 
60
};
 
61
 
 
62
typedef struct our_data_t {
 
63
    PGconn* conn;
 
64
    ErlDrvPort port;
 
65
    int socket;
 
66
    int connecting;
 
67
} our_data_t;
 
68
 
 
69
/* Keep the following definitions in alignment with the FUNC_LIST
 
70
 * in erl_pq_sync.erl
 
71
 */
 
72
 
 
73
#define DRV_CONNECT             'C'
 
74
#define DRV_DISCONNECT          'D'
 
75
#define DRV_SELECT              'S'
 
76
 
 
77
/* #define L     fprintf(stderr, "%d\r\n", __LINE__) */
 
78
 
 
79
/* INITIALIZATION AFTER LOADING */
 
80
 
 
81
/* 
 
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 
 
84
 * the driver entry.
 
85
 */
 
86
DRIVER_INIT(pq_drv)
 
87
{
 
88
    return &pq_driver_entry;
 
89
}
 
90
 
 
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);
 
95
 
 
96
/* DRIVER INTERFACE */
 
97
static ErlDrvData start(ErlDrvPort port, char *command)
 
98
 
99
    our_data_t* data = driver_alloc(sizeof(our_data_t));
 
100
    data->port = port;
 
101
    data->conn = NULL;
 
102
    return (ErlDrvData)data;
 
103
}
 
104
 
 
105
static void stop(ErlDrvData drv_data)
 
106
{
 
107
    do_disconnect((our_data_t*)drv_data);
 
108
}
 
109
 
 
110
static int control(ErlDrvData drv_data, unsigned int command, char *buf,
 
111
                   int len, char **rbuf, int rlen)
 
112
{
 
113
    int r;
 
114
    char* s = get_s(buf, len);
 
115
    our_data_t* data = (our_data_t*)drv_data;
 
116
    switch (command) {
 
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;
 
121
    }
 
122
    driver_free(s);
 
123
    return r;
 
124
}
 
125
 
 
126
static int do_connect(const char *s, our_data_t* data)
 
127
{
 
128
    PGconn* conn = PQconnectStart(s);
 
129
    if (PQstatus(conn) == CONNECTION_BAD) {
 
130
        ei_x_buff x;
 
131
        ei_x_new_with_version(&x);
 
132
        encode_error(&x, conn);
 
133
        PQfinish(conn);
 
134
        conn = NULL;
 
135
        driver_output(data->port, x.buff, x.index);
 
136
        ei_x_free(&x);
 
137
    }
 
138
    PQconnectPoll(conn);
 
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);
 
143
    data->conn = conn;
 
144
    data->connecting = 1;
 
145
    return 0;
 
146
}
 
147
 
 
148
static int do_disconnect(our_data_t* data)
 
149
{
 
150
    ei_x_buff x;
 
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);
 
154
    data->conn = NULL;
 
155
    ei_x_new_with_version(&x);
 
156
    encode_ok(&x);
 
157
    driver_output(data->port, x.buff, x.index);
 
158
    ei_x_free(&x);
 
159
    return 0;
 
160
}
 
161
 
 
162
static int do_select(const char* s, our_data_t* data)
 
163
{
 
164
    data->connecting = 0;
 
165
    PGconn* conn = data->conn;
 
166
    /* if there's an error return it now */
 
167
    if (PQsendQuery(conn, s) == 0) {
 
168
        ei_x_buff x;
 
169
        ei_x_new_with_version(&x);
 
170
        encode_error(&x, conn);
 
171
        driver_output(data->port, x.buff, x.index);
 
172
        ei_x_free(&x);
 
173
    }
 
174
    /* else wait for ready_output to get results */
 
175
    return 0;
 
176
}
 
177
 
 
178
static void ready_io(ErlDrvData drv_data, ErlDrvEvent event)
 
179
{
 
180
    PGresult* res = NULL;
 
181
    our_data_t* data = (our_data_t*)drv_data;
 
182
    PGconn* conn = data->conn;
 
183
    ei_x_buff x;
 
184
    ei_x_new_with_version(&x);
 
185
    if (data->connecting) {
 
186
        ConnStatusType status;
 
187
        PQconnectPoll(conn);
 
188
        status = PQstatus(conn);
 
189
        if (status == CONNECTION_OK)
 
190
            encode_ok(&x);
 
191
        else if (status == CONNECTION_BAD)
 
192
            encode_error(&x, conn);
 
193
    } else {
 
194
        PQconsumeInput(conn);
 
195
        if (PQisBusy(conn))
 
196
            return;
 
197
        res = PQgetResult(conn);
 
198
        encode_result(&x, res, conn);
 
199
        PQclear(res);
 
200
        for (;;) {
 
201
            res = PQgetResult(conn);
 
202
            if (res == NULL)
 
203
                break;
 
204
            PQclear(res);
 
205
        }
 
206
    }
 
207
    if (x.index > 1) {
 
208
        driver_output(data->port, x.buff, x.index);
 
209
        if (data->connecting) 
 
210
            driver_select(data->port, (ErlDrvEvent)data->socket, DO_WRITE, 0);
 
211
    }
 
212
    ei_x_free(&x);
 
213
}
 
214
 
 
215
/* utilities */
 
216
static char* get_s(const char* buf, int len)
 
217
{
 
218
    char* result;
 
219
    if (len < 1 || len > 1000) return NULL;
 
220
    result = driver_alloc(len+1);
 
221
    memcpy(result, buf, len);
 
222
    result[len] = '\0';
 
223
    return result;
 
224
}