dbd/postgresql/connection.c

1
#include "dbd_postgresql.h"
2
 
3
int dbd_postgresql_statement_create(lua_State *L, connection_t *conn, const char *sql_query);
4
 
5
static int run(connection_t *conn, const char *command) {
6
    PGresult *result = PQexec(conn->postgresql, command);
7
    ExecStatusType status;
8
 
9
    if (!result)
10
        return 1;
11
 
12
    status = PQresultStatus(result);
13
    PQclear(result);
14
 
15
    if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK)
16
        return 1;
17
 
18
    return 0;
19
}
20
 
21
static int commit(connection_t *conn) {
22
    return run(conn, "COMMIT");
23
}
24
 
25
 
26
static int begin(connection_t *conn) {
27
    return run(conn, "BEGIN");
28
}
29
 
30
 
31
static int rollback(connection_t *conn) {
32
    return run(conn, "ROLLBACK");
33
}
34
 
35
 
36
/*
37
 * connection = DBD.PostgreSQL.New(dbname, user, password, host, port)
38
 */
39
static int connection_new(lua_State *L) {
40
    int n = lua_gettop(L);
41
    connection_t *conn = NULL;
42
 
43
    const char *host = NULL;
44
    const char *user = NULL;
45
    const char *password = NULL;
46
    const char *db = NULL;
47
    const char *port = NULL;
48
 
49
    const char *options = NULL; /* TODO always NULL */
50
    const char *tty = NULL; /* TODO always NULL */
51
 
52
    char portbuf[18];
53
 
54
    /* db, user, password, host, port */
55
    switch (n) {
56
    case 5:
57
	if (lua_isnil(L, 5) == 0) 
58
	{
59
	    int pport = luaL_checkint(L, 5);
60
 
61
	    if (pport >= 1 && pport <= 65535) {
62
		snprintf(portbuf, sizeof(portbuf), "%d", pport);
63
		port = portbuf;
64
	    } else {
65
		luaL_error(L, DBI_ERR_INVALID_PORT, pport);
66
	    }
67
	}
68
    case 4: 
69
	if (lua_isnil(L, 4) == 0) 
70
	    host = luaL_checkstring(L, 4);
71
    case 3:
72
	if (lua_isnil(L, 3) == 0) 
73
	    password = luaL_checkstring(L, 3);
74
    case 2:
75
	if (lua_isnil(L, 2) == 0) 
76
	    user = luaL_checkstring(L, 2);
77
    case 1:
78
	/*
79
	 * db is the only mandatory parameter
80
	 */
81
	db = luaL_checkstring(L, 1);
82
    }
83
 
84
    conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t));
85
 
86
    conn->postgresql = PQsetdbLogin(host, port, options, tty, db, user, password);
87
    conn->statement_id = 0;
88
    conn->autocommit = 0;
89
    begin(conn);
90
 
91
    if (PQstatus(conn->postgresql) != CONNECTION_OK) {
92
	lua_pushnil(L);
93
	lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, PQerrorMessage(conn->postgresql));
94
	return 2;
95
    }
96
 
97
    luaL_getmetatable(L, DBD_POSTGRESQL_CONNECTION);
98
    lua_setmetatable(L, -2);
99
 
100
    return 1;
101
}
102
 
103
/*
104
 * success = connection:autocommit(on)
105
 */
106
static int connection_autocommit(lua_State *L) {
107
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
108
    int on = lua_toboolean(L, 2); 
109
    int err = 0;
110
 
111
    if (conn->postgresql) {
112
	if (on != conn->autocommit) {
113
	    if (on)
114
		err = rollback(conn);
115
	    else
116
		err = begin(conn);
117
	}
118
 
119
	conn->autocommit = on;	
120
    }
121
 
122
    lua_pushboolean(L, !err);
123
    return 1;
124
}
125
 
126
/*
127
 * success = connection:close()
128
 */
129
static int connection_close(lua_State *L) {
130
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
131
    int disconnect = 0;   
132
 
133
    if (conn->postgresql) {
134
	/*
135
	 * if autocommit is turned off, we probably
136
	 * want to rollback any outstanding transactions.
137
	 */
138
	if (!conn->autocommit)
139
	    rollback(conn);
140
 
141
	PQfinish(conn->postgresql);
142
	disconnect = 1;
143
	conn->postgresql = NULL;
144
    }
145
 
146
    lua_pushboolean(L, disconnect);
147
    return 1;
148
}
149
 
150
/*
151
 * success = connection:commit()
152
 */
153
static int connection_commit(lua_State *L) {
154
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
155
    int err = 0;
156
 
157
    if (conn->postgresql) {
158
	commit(conn);
159
 
160
	if (!conn->autocommit)
161
	    err = begin(conn);
162
	else
163
	    err = 1;
164
    }
165
 
166
    lua_pushboolean(L, !err);
167
    return 1;
168
}
169
 
170
/*
171
 * ok = connection:ping()
172
 */
173
static int connection_ping(lua_State *L) {
174
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
175
    int ok = 0;   
176
 
177
    if (conn->postgresql) {
178
	ConnStatusType status = PQstatus(conn->postgresql);
179
 
180
	if (status == CONNECTION_OK)
181
	    ok = 1;
182
    }
183
 
184
    lua_pushboolean(L, ok);
185
    return 1;
186
}
187
 
188
/*
189
 * statement = connection:prepare(sql_string)
190
 */
191
static int connection_prepare(lua_State *L) {
192
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
193
 
194
    if (conn->postgresql) {
195
	return dbd_postgresql_statement_create(L, conn, luaL_checkstring(L, 2));
196
    }
197
 
198
    lua_pushnil(L);    
199
    lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE);
200
    return 2;
201
}
202
 
203
/*
204
 * quoted = connection:quote(str)
205
 */
206
static int connection_quote(lua_State *L) {
207
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
208
    size_t len;
209
    const char *from = luaL_checklstring(L, 2, &len);
210
    char *to = (char *)calloc(len*2+1, sizeof(char));
211
    int err = 0;
212
    int quoted_len;
213
 
214
    if (!conn->postgresql) {
215
        luaL_error(L, DBI_ERR_DB_UNAVAILABLE);
216
    }
217
 
218
    quoted_len = PQescapeStringConn(conn->postgresql, to, from, len, &err);
219
 
220
    if (err) {
221
        free(to);
222
        
223
       luaL_error(L, DBI_ERR_QUOTING_STR, PQerrorMessage(conn->postgresql));
224
    }
225
 
226
    lua_pushlstring(L, to, quoted_len);
227
    free(to);
228
 
229
    return 1;
230
}
231
 
232
/*
233
 * success = connection:rollback()
234
 */
235
static int connection_rollback(lua_State *L) {
236
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
237
    int err = 0;
238
 
239
    if (conn->postgresql) {
240
	rollback(conn);
241
 
242
	if (!conn->autocommit)
243
	    err = begin(conn);
244
	else
245
	    err = 1;
246
    }
247
 
248
    lua_pushboolean(L, !err);
249
    return 1;
250
}
251
 
252
/*
253
 * __gc
254
 */
255
static int connection_gc(lua_State *L) {
256
    /* always close the connection */
257
    connection_close(L);
258
 
259
    return 0;
260
}
261
 
262
/*
263
 * __tostring
264
 */
265
static int connection_tostring(lua_State *L) {
266
    connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION);
267
 
268
    lua_pushfstring(L, "%s: %p", DBD_POSTGRESQL_CONNECTION, conn);
269
 
270
    return 1;
271
}
272
 
273
int dbd_postgresql_connection(lua_State *L) {
274
    static const luaL_Reg connection_methods[] = {
275
	{"autocommit", connection_autocommit},
276
	{"close", connection_close},
277
	{"commit", connection_commit},
278
	{"ping", connection_ping},
279
	{"prepare", connection_prepare},
280
	{"quote", connection_quote},
281
	{"rollback", connection_rollback},
282
	{NULL, NULL}
283
    };
284
 
285
    static const luaL_Reg connection_class_methods[] = {
286
	{"New", connection_new},
287
	{NULL, NULL}
288
    };
289
 
290
    luaL_newmetatable(L, DBD_POSTGRESQL_CONNECTION);
291
    luaL_register(L, 0, connection_methods);
292
    lua_pushvalue(L,-1);
293
    lua_setfield(L, -2, "__index");
294
 
295
    lua_pushcfunction(L, connection_gc);
296
    lua_setfield(L, -2, "__gc");
297
 
298
    lua_pushcfunction(L, connection_tostring);
299
    lua_setfield(L, -2, "__tostring");
300
 
301
    luaL_register(L, DBD_POSTGRESQL_CONNECTION, connection_class_methods);
302
 
303
    return 1;    
304
}