14 case FLOAT8OID: |
14 case FLOAT8OID: |
15 lua_type = LUA_PUSH_NUMBER; |
15 lua_type = LUA_PUSH_NUMBER; |
16 break; |
16 break; |
17 |
17 |
18 case BOOLOID: |
18 case BOOLOID: |
19 lua_type = LUA_PUSH_BOOLEAN; |
19 lua_type = LUA_PUSH_BOOLEAN; |
20 break; |
20 break; |
21 |
21 |
22 default: |
22 default: |
23 lua_type = LUA_PUSH_STRING; |
23 lua_type = LUA_PUSH_STRING; |
24 } |
24 } |
25 |
25 |
26 return lua_type; |
26 return lua_type; |
27 } |
27 } |
28 |
28 |
|
29 static int deallocate(statement_t *statement) { |
|
30 char command[IDLEN+11]; |
|
31 |
|
32 snprintf(command, IDLEN+11, "DEALLOCATE %s", statement->name); |
|
33 |
|
34 PGresult *result = PQexec(statement->postgresql, command); |
|
35 ExecStatusType status; |
|
36 |
|
37 if (!result) |
|
38 return 1; |
|
39 |
|
40 status = PQresultStatus(result); |
|
41 PQclear(result); |
|
42 |
|
43 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) |
|
44 return 1; |
|
45 |
|
46 return 0; |
|
47 } |
|
48 |
|
49 |
29 /* |
50 /* |
30 * num_affected_rows = statement:affected() |
51 * num_affected_rows = statement:affected() |
31 */ |
52 */ |
32 static int statement_affected(lua_State *L) { |
53 static int statement_affected(lua_State *L) { |
33 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); |
54 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); |
46 */ |
67 */ |
47 static int statement_close(lua_State *L) { |
68 static int statement_close(lua_State *L) { |
48 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); |
69 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); |
49 |
70 |
50 if (statement->result) { |
71 if (statement->result) { |
|
72 /* |
|
73 * Deallocate prepared statement on the |
|
74 * server side |
|
75 */ |
|
76 deallocate(statement); |
|
77 |
51 PQclear(statement->result); |
78 PQclear(statement->result); |
52 statement->result = NULL; |
79 statement->result = NULL; |
53 } |
80 } |
54 |
81 |
55 return 0; |
82 return 0; |
|
83 } |
|
84 |
|
85 /* |
|
86 * column_names = statement:columns() |
|
87 */ |
|
88 static int statement_columns(lua_State *L) { |
|
89 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); |
|
90 |
|
91 int i; |
|
92 int num_columns; |
|
93 int d = 1; |
|
94 |
|
95 if (!statement->result) { |
|
96 luaL_error(L, DBI_ERR_INVALID_STATEMENT); |
|
97 return 0; |
|
98 } |
|
99 |
|
100 num_columns = PQnfields(statement->result); |
|
101 lua_newtable(L); |
|
102 for (i = 0; i < num_columns; i++) { |
|
103 const char *name = PQfname(statement->result, i); |
|
104 |
|
105 LUA_PUSH_ARRAY_STRING(d, name); |
|
106 } |
|
107 |
|
108 return 1; |
56 } |
109 } |
57 |
110 |
58 /* |
111 /* |
59 * success = statement:execute(...) |
112 * success = statement:execute(...) |
60 */ |
113 */ |
76 |
129 |
77 /* |
130 /* |
78 * convert and copy parameters into a string array |
131 * convert and copy parameters into a string array |
79 */ |
132 */ |
80 for (p = 2; p <= n; p++) { |
133 for (p = 2; p <= n; p++) { |
81 int i = p - 2; |
134 int i = p - 2; |
82 int type = lua_type(L, p); |
135 int type = lua_type(L, p); |
83 char err[64]; |
136 char err[64]; |
84 |
137 |
85 switch(type) { |
138 switch(type) { |
86 case LUA_TNIL: |
139 case LUA_TNIL: |
87 params[i] = NULL; |
140 params[i] = NULL; |
88 break; |
141 break; |
89 case LUA_TBOOLEAN: |
142 case LUA_TBOOLEAN: |
90 /* |
143 /* |
91 * boolean values in postgresql can either be |
144 * boolean values in postgresql can either be |
92 * t/f or 1/0. Pass integer values rather than |
145 * t/f or 1/0. Pass integer values rather than |
93 * strings to maintain semantic compatibility |
146 * strings to maintain semantic compatibility |
94 * with other DBD drivers that pass booleans |
147 * with other DBD drivers that pass booleans |
95 * as integers. |
148 * as integers. |
96 */ |
149 */ |
97 params[i] = lua_toboolean(L, p) ? "1" : "0"; |
150 params[i] = lua_toboolean(L, p) ? "1" : "0"; |
98 break; |
151 break; |
99 case LUA_TNUMBER: |
152 case LUA_TNUMBER: |
100 case LUA_TSTRING: |
153 case LUA_TSTRING: |
101 params[i] = lua_tostring(L, p); |
154 params[i] = lua_tostring(L, p); |
102 break; |
155 break; |
103 default: |
156 default: |
104 snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); |
157 snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); |
105 errstr = err; |
158 errstr = err; |
106 goto cleanup; |
159 goto cleanup; |
107 } |
160 } |
108 } |
161 } |
109 |
162 |
110 result = PQexecPrepared( |
163 result = PQexecPrepared( |
111 statement->postgresql, |
164 statement->postgresql, |
112 statement->name, |
165 statement->name, |
113 num_bind_params, |
166 num_bind_params, |
114 (const char **)params, |
167 (const char **)params, |
115 NULL, |
168 NULL, |
116 NULL, |
169 NULL, |
117 0 |
170 0 |
118 ); |
171 ); |
119 |
172 |
120 cleanup: |
173 cleanup: |
121 free(params); |
174 free(params); |
122 |
175 |
123 if (errstr) { |
176 if (errstr) { |
124 lua_pushboolean(L, 0); |
177 lua_pushboolean(L, 0); |
125 lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); |
178 lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); |
126 return 2; |
179 return 2; |
127 } |
180 } |
128 |
181 |
129 if (!result) { |
182 if (!result) { |
130 lua_pushboolean(L, 0); |
183 lua_pushboolean(L, 0); |
131 lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, PQerrorMessage(statement->postgresql)); |
184 lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, PQerrorMessage(statement->postgresql)); |
132 return 2; |
185 return 2; |
133 } |
186 } |
134 |
187 |
135 status = PQresultStatus(result); |
188 status = PQresultStatus(result); |
136 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { |
189 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { |
137 lua_pushboolean(L, 0); |
190 lua_pushboolean(L, 0); |
138 lua_pushfstring(L, DBI_ERR_BINDING_EXEC, PQresultErrorMessage(result)); |
191 lua_pushfstring(L, DBI_ERR_BINDING_EXEC, PQresultErrorMessage(result)); |
139 return 2; |
192 return 2; |
140 } |
193 } |
141 |
194 |
142 statement->result = result; |
195 statement->result = result; |
143 |
196 |
144 lua_pushboolean(L, 1); |
197 lua_pushboolean(L, 1); |
145 return 1; |
198 return 1; |
146 } |
199 } |
147 |
200 |
148 /* |
201 /* |
149 * must be called after an execute |
202 * can only be called after an execute |
150 */ |
203 */ |
151 static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { |
204 static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { |
152 int tuple = statement->tuple++; |
205 int tuple = statement->tuple++; |
153 int i; |
206 int i; |
154 int num_columns; |
207 int num_columns; |
155 int d = 1; |
208 int d = 1; |
156 |
209 |
157 if (!statement->result) { |
210 if (!statement->result) { |
158 luaL_error(L, DBI_ERR_FETCH_INVALID); |
211 luaL_error(L, DBI_ERR_FETCH_INVALID); |
159 return 0; |
212 return 0; |
160 } |
213 } |
161 |
214 |
162 if (PQresultStatus(statement->result) != PGRES_TUPLES_OK) { |
215 if (PQresultStatus(statement->result) != PGRES_TUPLES_OK) { |
163 lua_pushnil(L); |
216 lua_pushnil(L); |
164 return 1; |
217 return 1; |
165 } |
218 } |
166 |
219 |
167 if (tuple >= PQntuples(statement->result)) { |
220 if (tuple >= PQntuples(statement->result)) { |
168 lua_pushnil(L); /* no more results */ |
221 lua_pushnil(L); /* no more results */ |
169 return 1; |
222 return 1; |
170 } |
223 } |
171 |
224 |
172 num_columns = PQnfields(statement->result); |
225 num_columns = PQnfields(statement->result); |
173 lua_newtable(L); |
226 lua_newtable(L); |
174 for (i = 0; i < num_columns; i++) { |
227 for (i = 0; i < num_columns; i++) { |
175 const char *name = PQfname(statement->result, i); |
228 const char *name = PQfname(statement->result, i); |
176 |
229 |
177 if (PQgetisnull(statement->result, tuple, i)) { |
230 if (PQgetisnull(statement->result, tuple, i)) { |
178 if (named_columns) { |
231 if (named_columns) { |
179 LUA_PUSH_ATTRIB_NIL(name); |
232 LUA_PUSH_ATTRIB_NIL(name); |
180 } else { |
233 } else { |
181 LUA_PUSH_ARRAY_NIL(d); |
234 LUA_PUSH_ARRAY_NIL(d); |
182 } |
235 } |
183 } else { |
236 } else { |
184 const char *value = PQgetvalue(statement->result, tuple, i); |
237 const char *value = PQgetvalue(statement->result, tuple, i); |
185 lua_push_type_t lua_push = postgresql_to_lua_push(PQftype(statement->result, i)); |
238 lua_push_type_t lua_push = postgresql_to_lua_push(PQftype(statement->result, i)); |
186 |
239 |
187 /* |
240 /* |
188 * data is returned as strings from PSQL |
241 * data is returned as strings from PSQL |
189 * convert them here into Lua types |
242 * convert them here into Lua types |
190 */ |
243 */ |
191 |
244 |
192 if (lua_push == LUA_PUSH_NIL) { |
245 if (lua_push == LUA_PUSH_NIL) { |
307 /* |
360 /* |
308 * convert SQL string into a PSQL API compatible SQL statement |
361 * convert SQL string into a PSQL API compatible SQL statement |
309 */ |
362 */ |
310 new_sql = replace_placeholders(L, '$', sql_query); |
363 new_sql = replace_placeholders(L, '$', sql_query); |
311 |
364 |
312 snprintf(name, IDLEN, "%017u", ++conn->statement_id); |
365 snprintf(name, IDLEN, "dbd-postgresql-%017u", ++conn->statement_id); |
313 |
366 |
314 result = PQprepare(conn->postgresql, name, new_sql, 0, NULL); |
367 result = PQprepare(conn->postgresql, name, new_sql, 0, NULL); |
315 |
368 |
316 /* |
369 /* |
317 * free converted statement after use |
370 * free converted statement after use |
318 */ |
371 */ |
319 free(new_sql); |
372 free(new_sql); |
320 |
373 |
321 if (!result) { |
374 if (!result) { |
322 lua_pushnil(L); |
375 lua_pushnil(L); |
323 lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, PQerrorMessage(statement->postgresql)); |
376 lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, PQerrorMessage(statement->postgresql)); |
324 return 2; |
377 return 2; |
325 } |
378 } |
326 |
379 |
327 status = PQresultStatus(result); |
380 status = PQresultStatus(result); |
328 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { |
381 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { |
329 const char *err_string = PQresultErrorMessage(result); |
382 const char *err_string = PQresultErrorMessage(result); |
330 PQclear(result); |
383 PQclear(result); |
331 |
384 |
332 lua_pushnil(L); |
385 lua_pushnil(L); |
333 lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, err_string); |
386 lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, err_string); |
334 return 2; |
387 return 2; |
335 } |
388 } |
336 |
389 |
337 PQclear(result); |
390 PQclear(result); |
338 |
391 |
339 statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); |
392 statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); |
349 return 1; |
402 return 1; |
350 } |
403 } |
351 |
404 |
352 int dbd_postgresql_statement(lua_State *L) { |
405 int dbd_postgresql_statement(lua_State *L) { |
353 static const luaL_Reg statement_methods[] = { |
406 static const luaL_Reg statement_methods[] = { |
354 {"affected", statement_affected}, |
407 {"affected", statement_affected}, |
355 {"close", statement_close}, |
408 {"close", statement_close}, |
356 {"execute", statement_execute}, |
409 {"columns", statement_columns}, |
357 {"fetch", statement_fetch}, |
410 {"execute", statement_execute}, |
358 {"rowcount", statement_rowcount}, |
411 {"fetch", statement_fetch}, |
359 {"rows", statement_rows}, |
412 {"rowcount", statement_rowcount}, |
360 {NULL, NULL} |
413 {"rows", statement_rows}, |
|
414 {NULL, NULL} |
361 }; |
415 }; |
362 |
416 |
363 static const luaL_Reg statement_class_methods[] = { |
417 static const luaL_Reg statement_class_methods[] = { |
364 {NULL, NULL} |
418 {NULL, NULL} |
365 }; |
419 }; |
366 |
420 |
367 luaL_newmetatable(L, DBD_POSTGRESQL_STATEMENT); |
421 luaL_newmetatable(L, DBD_POSTGRESQL_STATEMENT); |
368 luaL_register(L, 0, statement_methods); |
422 luaL_register(L, 0, statement_methods); |
369 lua_pushvalue(L,-1); |
423 lua_pushvalue(L,-1); |