1 | #include "EXTERN.h" |
1 | #include "EXTERN.h" |
2 | #include "perl.h" |
2 | #include "perl.h" |
3 | #include "XSUB.h" |
3 | #include "XSUB.h" |
4 | |
4 | |
5 | #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 6)) |
5 | #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 6)) |
6 | # define get_sv perl_get_sv |
6 | # define get_sv perl_get_sv |
7 | # define call_method perl_call_method |
7 | # define call_method perl_call_method |
|
|
8 | # define call_sv perl_call_sv |
8 | #endif |
9 | #endif |
|
|
10 | |
|
|
11 | #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 5)) |
|
|
12 | # define CAN_UTF8 1 |
|
|
13 | #endif |
|
|
14 | |
|
|
15 | static SV * |
|
|
16 | sql_upgrade_utf8 (SV *sv) |
|
|
17 | { |
|
|
18 | #if CAN_UTF8 |
|
|
19 | if (SvPOK (sv)) |
|
|
20 | sv_utf8_upgrade (sv); |
|
|
21 | #endif |
|
|
22 | return sv; |
|
|
23 | } |
|
|
24 | |
|
|
25 | static SV * |
|
|
26 | sql_force_utf8 (SV *sv) |
|
|
27 | { |
|
|
28 | #if CAN_UTF8 |
|
|
29 | if (SvPOK (sv)) |
|
|
30 | SvUTF8_on (sv); |
|
|
31 | #endif |
|
|
32 | return sv; |
|
|
33 | } |
|
|
34 | |
|
|
35 | #define maybe_upgrade_utf8(utf8,sv) ((utf8) ? sql_upgrade_utf8 (sv) : (sv)) |
|
|
36 | #define maybe_force_utf8(utf8,sv) ((utf8) ? sql_force_utf8 (sv) : (sv)) |
9 | |
37 | |
10 | #define is_dbh(sv) ((sv) && sv_isobject (sv) && sv_derived_from ((sv), "DBI::db")) |
38 | #define is_dbh(sv) ((sv) && sv_isobject (sv) && sv_derived_from ((sv), "DBI::db")) |
11 | |
39 | |
12 | typedef struct lru_node { |
40 | typedef struct lru_node { |
13 | struct lru_node *next; |
41 | struct lru_node *next; |
… | |
… | |
19 | SV *sth; |
47 | SV *sth; |
20 | #if 0 /* method cache */ |
48 | #if 0 /* method cache */ |
21 | GV *execute; |
49 | GV *execute; |
22 | GV *bind_columns; |
50 | GV *bind_columns; |
23 | GV *fetch; |
51 | GV *fetch; |
|
|
52 | GV *finish; |
24 | #endif |
53 | #endif |
25 | } lru_node; |
54 | } lru_node; |
26 | |
55 | |
27 | static lru_node lru_list; |
56 | static lru_node lru_list; |
28 | static int lru_size; |
57 | static int lru_size; |
… | |
… | |
137 | } |
166 | } |
138 | } |
167 | } |
139 | |
168 | |
140 | static GV *sql_exec; |
169 | static GV *sql_exec; |
141 | static GV *DBH; |
170 | static GV *DBH; |
|
|
171 | static SV *sv_prepare, *sv_execute, *sv_bind_columns, *sv_fetchrow_arrayref, *sv_finish; |
|
|
172 | |
|
|
173 | #define newconstpv(str) newSVpvn ((str), sizeof (str)) |
142 | |
174 | |
143 | MODULE = PApp::SQL PACKAGE = PApp::SQL |
175 | MODULE = PApp::SQL PACKAGE = PApp::SQL |
144 | |
176 | |
145 | PROTOTYPES: DISABLE |
177 | PROTOTYPES: DISABLE |
146 | |
178 | |
147 | BOOT: |
179 | BOOT: |
148 | { |
180 | { |
149 | sql_exec = gv_fetchpv ("PApp::SQL::sql_exec", TRUE, SVt_PV); |
181 | sql_exec = gv_fetchpv ("PApp::SQL::sql_exec", TRUE, SVt_PV); |
150 | DBH = gv_fetchpv ("PApp::SQL::DBH" , TRUE, SVt_PV); |
182 | DBH = gv_fetchpv ("PApp::SQL::DBH" , TRUE, SVt_PV); |
|
|
183 | |
|
|
184 | if (!sv_prepare) |
|
|
185 | { |
|
|
186 | sv_prepare = newconstpv ("prepare"); |
|
|
187 | sv_execute = newconstpv ("execute"); |
|
|
188 | sv_bind_columns = newconstpv ("bind_columns"); |
|
|
189 | sv_fetchrow_arrayref = newconstpv ("fetchrow_arrayref"); |
|
|
190 | sv_finish = newconstpv ("finish"); |
|
|
191 | } |
151 | |
192 | |
152 | /* apache might BOOT: twice :( */ |
193 | /* apache might BOOT: twice :( */ |
153 | if (lru_size) |
194 | if (lru_size) |
154 | lru_cachesize (0); |
195 | lru_cachesize (0); |
155 | |
196 | |
… | |
… | |
167 | RETVAL |
208 | RETVAL |
168 | |
209 | |
169 | void |
210 | void |
170 | sql_exec(...) |
211 | sql_exec(...) |
171 | ALIAS: |
212 | ALIAS: |
|
|
213 | sql_uexec = 1 |
172 | sql_fetch = 1 |
214 | sql_fetch = 2 |
|
|
215 | sql_ufetch = 3 |
173 | sql_fetchall = 2 |
216 | sql_fetchall = 4 |
|
|
217 | sql_ufetchall = 5 |
174 | sql_exists = 4 |
218 | sql_exists = 6 |
|
|
219 | sql_uexists = 7 |
175 | PPCODE: |
220 | PPCODE: |
176 | { |
221 | { |
177 | if (items == 0) |
222 | if (items == 0) |
178 | croak ("Usage: sql_exec [database-handle,] [bind-var-refs,... ] \"sql-statement\", [arguments, ...]"); |
223 | croak ("Usage: sql_exec [database-handle,] [bind-var-refs,... ] \"sql-statement\", [arguments, ...]"); |
179 | else |
224 | else |
… | |
… | |
218 | if (!SvPOK (ST(arg))) |
263 | if (!SvPOK (ST(arg))) |
219 | croak ("sql_exec: sql-statement must be a string"); |
264 | croak ("sql_exec: sql-statement must be a string"); |
220 | |
265 | |
221 | sql = ST(arg); arg++; |
266 | sql = ST(arg); arg++; |
222 | |
267 | |
223 | if (ix == 4) |
268 | if ((ix & ~1) == 6) |
224 | { |
269 | { |
225 | SV *neu = sv_2mortal (newSVpv ("select count(*) > 0 from ", 0)); |
270 | SV *neu = sv_2mortal (newSVpv ("select count(*) > 0 from ", 0)); |
226 | sv_catsv (neu, sql); |
271 | sv_catsv (neu, sql); |
227 | sv_catpv (neu, " limit 1"); |
272 | sv_catpv (neu, " limit 1"); |
228 | sql = neu; |
273 | sql = neu; |
229 | ix = 1; /* sql_fetch */ |
274 | ix -= 6; /* sql_fetch */ |
230 | } |
275 | } |
231 | |
276 | |
232 | /* check cache for existing statement handle */ |
277 | /* check cache for existing statement handle */ |
233 | sth = lru_fetch (dbh, sql); |
278 | sth = lru_fetch (dbh, sql); |
234 | if (!sth) |
279 | if (!sth) |
… | |
… | |
236 | PUSHMARK (SP); |
281 | PUSHMARK (SP); |
237 | EXTEND (SP, 2); |
282 | EXTEND (SP, 2); |
238 | PUSHs (dbh); |
283 | PUSHs (dbh); |
239 | PUSHs (sql); |
284 | PUSHs (sql); |
240 | PUTBACK; |
285 | PUTBACK; |
241 | count = call_method ("prepare", G_SCALAR); |
286 | count = call_sv (sv_prepare, G_METHOD | G_SCALAR); |
242 | SPAGAIN; |
287 | SPAGAIN; |
243 | |
288 | |
244 | if (count != 1) |
289 | if (count != 1) |
245 | croak ("sql_exec: unable to prepare() statement '%s': %s", |
290 | croak ("sql_exec: unable to prepare() statement '%s': %s", |
246 | SvPV (sql, dc), |
291 | SvPV (sql, dc), |
… | |
… | |
254 | PUSHMARK (SP); |
299 | PUSHMARK (SP); |
255 | EXTEND (SP, items - arg + 1); |
300 | EXTEND (SP, items - arg + 1); |
256 | PUSHs (sth); |
301 | PUSHs (sth); |
257 | while (items > arg) |
302 | while (items > arg) |
258 | { |
303 | { |
259 | PUSHs (ST(arg)); |
304 | PUSHs (maybe_upgrade_utf8 (ix & 1, ST(arg))); |
260 | arg++; |
305 | arg++; |
261 | } |
306 | } |
262 | |
307 | |
263 | PUTBACK; |
308 | PUTBACK; |
264 | /* { static GV *execute; |
309 | /* { static GV *execute; |
265 | if (!execute) execute = gv_fetchmethod_autoload(SvSTASH(SvRV(sth)), "execute", 0); |
310 | if (!execute) execute = gv_fetchmethod_autoload(SvSTASH(SvRV(sth)), "execute", 0); |
266 | count = call_sv(GvCV(execute), G_SCALAR); |
311 | count = call_sv(GvCV(execute), G_SCALAR); |
267 | }*/ |
312 | }*/ |
268 | count = call_method ("execute", G_SCALAR); |
313 | count = call_sv (sv_execute, G_METHOD | G_SCALAR); |
269 | SPAGAIN; |
314 | SPAGAIN; |
270 | |
315 | |
271 | if (count != 1) |
316 | if (count != 1) |
272 | croak ("sql_exec: execute() didn't return any value ('%s'): %s", |
317 | croak ("sql_exec: execute() didn't return any value ('%s'): %s", |
273 | SvPV (sql, dc), |
318 | SvPV (sql, dc), |
… | |
… | |
291 | PUSHs (ST(bind_first)); |
336 | PUSHs (ST(bind_first)); |
292 | bind_first++; |
337 | bind_first++; |
293 | } while (bind_first != bind_last); |
338 | } while (bind_first != bind_last); |
294 | |
339 | |
295 | PUTBACK; |
340 | PUTBACK; |
296 | count = call_method ("bind_columns", G_SCALAR); |
341 | count = call_sv (sv_bind_columns, G_METHOD | G_SCALAR); |
297 | SPAGAIN; |
342 | SPAGAIN; |
298 | |
343 | |
299 | if (count != 1) |
344 | if (count != 1) |
300 | croak ("sql_exec: bind_columns() didn't return any value ('%s'): %s", |
345 | croak ("sql_exec: bind_columns() didn't return any value ('%s'): %s", |
301 | SvPV (sql, dc), |
346 | SvPV (sql, dc), |
… | |
… | |
308 | } |
353 | } |
309 | |
354 | |
310 | /* free our arguments from the stack */ |
355 | /* free our arguments from the stack */ |
311 | SP -= items; |
356 | SP -= items; |
312 | |
357 | |
313 | if (ix == 1) |
358 | if ((ix & ~1) == 2) |
314 | { /* sql_fetch */ |
359 | { /* sql_fetch */ |
315 | SV *row; |
360 | SV *row; |
316 | |
361 | |
317 | PUSHMARK (SP); |
362 | PUSHMARK (SP); |
318 | XPUSHs (sth); |
363 | XPUSHs (sth); |
319 | PUTBACK; |
364 | PUTBACK; |
320 | count = call_method ("fetchrow_arrayref", G_SCALAR); |
365 | count = call_sv (sv_fetchrow_arrayref, G_METHOD | G_SCALAR); |
321 | SPAGAIN; |
366 | SPAGAIN; |
322 | |
367 | |
323 | if (count != 1) |
368 | if (count != 1) |
324 | abort (); |
369 | abort (); |
325 | |
370 | |
… | |
… | |
334 | case G_VOID: |
379 | case G_VOID: |
335 | /* no thing */ |
380 | /* no thing */ |
336 | break; |
381 | break; |
337 | case G_SCALAR: |
382 | case G_SCALAR: |
338 | /* the first element */ |
383 | /* the first element */ |
339 | XPUSHs (*av_fetch ((AV *)SvRV (row), 0, 1)); |
384 | XPUSHs (maybe_force_utf8 (ix & 1, *av_fetch ((AV *)SvRV (row), 0, 1))); |
340 | break; |
385 | break; |
341 | case G_ARRAY: |
386 | case G_ARRAY: |
342 | av = (AV *)SvRV (row); |
387 | av = (AV *)SvRV (row); |
343 | count = AvFILL (av) + 1; |
388 | count = AvFILL (av) + 1; |
344 | EXTEND (SP, count); |
389 | EXTEND (SP, count); |
345 | for (arg = 0; arg < count; arg++) |
390 | for (arg = 0; arg < count; arg++) |
346 | PUSHs (AvARRAY (av)[arg]); |
391 | PUSHs (maybe_force_utf8 (ix & 1, AvARRAY (av)[arg])); |
347 | |
392 | |
348 | break; |
393 | break; |
349 | default: |
394 | default: |
350 | abort (); |
395 | abort (); |
351 | } |
396 | } |
352 | } |
397 | } |
353 | } |
398 | } |
354 | else if (ix == 2) |
399 | else if ((ix & ~1) == 4) |
355 | { /* sql_fetchall */ |
400 | { /* sql_fetchall */ |
356 | SV *rows; |
401 | SV *rows; |
357 | |
402 | |
358 | PUSHMARK (SP); |
403 | PUSHMARK (SP); |
359 | XPUSHs (sth); |
404 | XPUSHs (sth); |
360 | PUTBACK; |
405 | PUTBACK; |
361 | count = call_method ("fetchall_arrayref", G_SCALAR); |
406 | count = call_sv (sv_fetchrow_arrayref, G_METHOD | G_SCALAR); |
362 | SPAGAIN; |
407 | SPAGAIN; |
363 | |
408 | |
364 | if (count != 1) |
409 | if (count != 1) |
365 | abort (); |
410 | abort (); |
366 | |
411 | |
… | |
… | |
376 | int columns = AvFILL ((AV *)SvRV (AvARRAY(av)[0])) + 1; /* columns? */ |
421 | int columns = AvFILL ((AV *)SvRV (AvARRAY(av)[0])) + 1; /* columns? */ |
377 | |
422 | |
378 | EXTEND (SP, count); |
423 | EXTEND (SP, count); |
379 | if (columns == 1) |
424 | if (columns == 1) |
380 | for (arg = 0; arg < count; arg++) |
425 | for (arg = 0; arg < count; arg++) |
381 | PUSHs (AvARRAY ((AV *)SvRV (AvARRAY (av)[arg]))[0]); |
426 | PUSHs (maybe_force_utf8 (ix & 1, AvARRAY ((AV *)SvRV (AvARRAY (av)[arg]))[0])); |
382 | else |
427 | else |
383 | for (arg = 0; arg < count; arg++) |
428 | for (arg = 0; arg < count; arg++) |
384 | PUSHs (AvARRAY (av)[arg]); |
429 | PUSHs (maybe_force_utf8 (ix & 1, AvARRAY (av)[arg])); |
385 | } |
430 | } |
386 | } |
431 | } |
387 | } |
432 | } |
388 | else |
433 | else |
389 | XPUSHs (sth); |
434 | XPUSHs (sth); |
390 | |
435 | |
391 | if (ix || GIMME_V == G_VOID) |
436 | if (ix > 1 || GIMME_V == G_VOID) |
392 | { |
437 | { |
393 | PUSHMARK (SP); |
438 | PUSHMARK (SP); |
394 | XPUSHs (sth); |
439 | XPUSHs (sth); |
395 | PUTBACK; |
440 | PUTBACK; |
396 | (void) call_method ("finish", G_DISCARD); |
441 | (void) call_sv (sv_finish, G_METHOD | G_DISCARD); |
397 | SPAGAIN; |
442 | SPAGAIN; |
398 | } |
443 | } |
399 | } |
444 | } |
400 | } |
445 | } |
401 | |
446 | |