ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/PApp-SQL/SQL.xs
Revision: 1.27
Committed: Thu Sep 20 09:00:44 2012 UTC (11 years, 8 months ago) by root
Branch: MAIN
Changes since 1.26: +2 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.22 /* import some stuff from DBIXS.h and DBI.xs */
6     #define DBIXS_VERSION 93
7     #define DBI_MAGIC '~'
8    
9     #define DBISTATE_PERLNAME "DBI::_dbistate"
10 root 1.24 #define DBISTATE_ADDRSV (perl_get_sv (DBISTATE_PERLNAME, 0x05))
11 root 1.22 #define DBIS_PUBLISHED_LVALUE (*(INT2PTR(dbistate_t**, &SvIVX(DBISTATE_ADDRSV))))
12    
13 root 1.24 static SV *sql_varchar, *sql_integer, *sql_double;
14     static SV *tmp_iv;
15    
16 root 1.22 struct dbistate_st {
17     #define DBISTATE_VERSION 94 /* Must change whenever dbistate_t does */
18     /* this must be the first member in structure */
19     void (*check_version) _((const char *name,
20     int dbis_cv, int dbis_cs, int need_dbixs_cv,
21     int drc_s, int dbc_s, int stc_s, int fdc_s));
22    
23     /* version and size are used to check for DBI/DBD version mis-match */
24     U16 version; /* version of this structure */
25     U16 size;
26     U16 xs_version; /* version of the overall DBIXS / DBD interface */
27     U16 spare_pad;
28     };
29     typedef struct dbistate_st dbistate_t;
30    
31     #define DBIcf_ACTIVE 0x000004 /* needs finish/disconnect before clear */
32    
33     typedef U32 imp_sth;
34    
35     /* not strictly part of the API... */
36     static imp_sth *
37     sth_get_imp (SV *sth)
38     {
39     MAGIC *mg = mg_find (SvRV (sth), PERL_MAGIC_tied);
40     sth = mg->mg_obj;
41     mg = mg_find (SvRV (sth), DBI_MAGIC);
42     return (imp_sth *)SvPVX (mg->mg_obj);
43     }
44    
45     #define DBI_STH_ACTIVE(imp) (*(imp) & DBIcf_ACTIVE)
46    
47     /* end of import section */
48    
49 root 1.3 #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 6))
50 root 1.5 # define get_sv perl_get_sv
51 root 1.3 # define call_method perl_call_method
52 root 1.5 # define call_sv perl_call_sv
53 root 1.3 #endif
54    
55 root 1.11 #if (PERL_VERSION > 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION >= 6))
56 root 1.5 # define CAN_UTF8 1
57     #endif
58    
59 root 1.22 #define MAX_CACHED_STATEMENT_SIZE 2048
60 root 1.14
61 root 1.5 static SV *
62     sql_upgrade_utf8 (SV *sv)
63     {
64     #if CAN_UTF8
65 root 1.24 if (SvPOKp (sv))
66 root 1.5 sv_utf8_upgrade (sv);
67     #endif
68     return sv;
69     }
70    
71     static SV *
72 root 1.13 mortalcopy_and_maybe_force_utf8(int utf8, SV *sv)
73 root 1.5 {
74 root 1.13 sv = sv_mortalcopy (sv);
75 root 1.5 #if CAN_UTF8
76 root 1.24 if (utf8 && SvPOKp (sv))
77 root 1.5 SvUTF8_on (sv);
78     #endif
79     return sv;
80     }
81    
82     #define maybe_upgrade_utf8(utf8,sv) ((utf8) ? sql_upgrade_utf8 (sv) : (sv))
83    
84 root 1.2 #define is_dbh(sv) ((sv) && sv_isobject (sv) && sv_derived_from ((sv), "DBI::db"))
85 root 1.1
86 root 1.24 typedef struct mc_node
87     {
88     struct mc_node *next;
89     HV *stash;
90     U32 gen;
91    
92     /* DBH */
93     SV *prepare;
94    
95     /* STH */
96     SV *execute;
97     SV *bind_param;
98     SV *bind_columns;
99     SV *fetchrow_arrayref;
100     SV *fetchall_arrayref;
101     SV *finish;
102     } mc_node;
103    
104     static mc_node *first;
105    
106     static mc_node *
107     mc_find (HV *stash)
108     {
109     mc_node *mc;
110     U32 gen = PL_sub_generation;
111    
112     #ifdef HvMROMETA
113     gen += HvMROMETA (stash)->cache_gen;
114     #endif
115    
116     for (mc = first; mc; mc = mc->next)
117     if (mc->stash == stash && mc->gen == gen)
118     return mc;
119    
120     if (!mc)
121     {
122     Newz (0, mc, 1, mc_node);
123     mc->stash = stash;
124    
125     mc->next = first;
126     first = mc;
127     }
128     else
129     {
130     mc->execute =
131     mc->bind_param =
132     mc->bind_columns =
133     mc->fetchrow_arrayref =
134     mc->fetchall_arrayref =
135     mc->finish = 0;
136     }
137    
138     mc->gen = gen;
139    
140     return mc;
141     }
142    
143     static void
144     mc_cache (mc_node *mc, SV **method, const char *name)
145     {
146     *method = (SV *)gv_fetchmethod_autoload (mc->stash, name, 0);
147    
148     if (!method)
149     croak ("%s: method not found in stash, pelase report.", name);
150     }
151    
152     #define mc_cache(mc, method) mc_cache ((mc), &((mc)->method), # method)
153    
154     typedef struct lru_node
155     {
156 root 1.1 struct lru_node *next;
157     struct lru_node *prev;
158 root 1.24
159     U32 hash;
160 root 1.1 SV *dbh;
161     SV *sql;
162    
163     SV *sth;
164 root 1.22 imp_sth *sth_imp;
165 root 1.24
166     mc_node *mc;
167 root 1.1 } lru_node;
168    
169     static lru_node lru_list;
170     static int lru_size;
171     static int lru_maxsize;
172    
173 root 1.22 #define lru_init() lru_list.next = &lru_list; lru_list.prev = &lru_list /* other fields are zero */
174 root 1.1
175     /* this is primitive, yet effective */
176     /* the returned value must never be zero (or bad things will happen) */
177 root 1.24 static U32
178     lru_hash (SV *dbh, SV *sql)
179     {
180     STRLEN i, l;
181     char *b = SvPV (sql, l);
182 root 1.26 U32 hash = 2166136261U;
183 root 1.24
184     hash = (hash ^ (U32)dbh) * 16777619U;
185     hash = (hash ^ l) * 16777619U;
186    
187     for (i = 7; i < l; i += i >> 2)
188     hash = (hash ^ b [i]) * 16777619U;
189    
190     return hash;
191     }
192 root 1.1
193     /* fetch and "use" */
194 root 1.24 static lru_node *
195 root 1.22 lru_fetch (SV *dbh, SV *sql)
196 root 1.1 {
197     lru_node *n;
198     U32 hash;
199    
200     dbh = SvRV (dbh);
201 root 1.24 hash = lru_hash (dbh, sql);
202 root 1.1
203     n = &lru_list;
204     do {
205     n = n->next;
206 root 1.22
207 root 1.1 if (!n->hash)
208     return 0;
209     } while (n->hash != hash
210 root 1.22 || DBI_STH_ACTIVE (n->sth_imp)
211 root 1.1 || !sv_eq (n->sql, sql)
212     || n->dbh != dbh);
213    
214     /* found, so return to the start of the list */
215     n->prev->next = n->next;
216     n->next->prev = n->prev;
217    
218     n->next = lru_list.next;
219     n->prev = &lru_list;
220     lru_list.next->prev = n;
221     lru_list.next = n;
222    
223 root 1.24 return n;
224 root 1.1 }
225    
226 root 1.22 static void
227     lru_trim (void)
228 root 1.1 {
229 root 1.22 while (lru_size > lru_maxsize)
230     {
231     /* nuke at the end */
232     lru_node *n = lru_list.prev;
233 root 1.1
234 root 1.22 n = lru_list.prev;
235 root 1.1
236 root 1.22 lru_list.prev = n->prev;
237     n->prev->next = &lru_list;
238 root 1.1
239 root 1.22 SvREFCNT_dec (n->dbh);
240     SvREFCNT_dec (n->sql);
241     SvREFCNT_dec (n->sth);
242     Safefree (n);
243    
244     lru_size--;
245     }
246 root 1.1 }
247    
248     /* store a not-yet existing entry(!) */
249 root 1.22 static void
250 root 1.24 lru_store (SV *dbh, SV *sql, SV *sth, mc_node *mc)
251 root 1.1 {
252     lru_node *n;
253     U32 hash;
254    
255 root 1.22 if (!lru_maxsize)
256     return;
257    
258 root 1.1 dbh = SvRV (dbh);
259 root 1.24 hash = lru_hash (dbh, sql);
260 root 1.1
261     lru_size++;
262 root 1.22 lru_trim ();
263 root 1.1
264     New (0, n, 1, lru_node);
265    
266 root 1.22 n->hash = hash;
267     n->dbh = dbh; SvREFCNT_inc (dbh); /* note: this is the dbi hash itself, not the reference */
268     n->sql = newSVsv (sql);
269     n->sth = sth; SvREFCNT_inc (sth);
270     n->sth_imp = sth_get_imp (sth);
271 root 1.24 n->mc = mc;
272 root 1.1
273 root 1.22 n->next = lru_list.next;
274     n->prev = &lru_list;
275 root 1.1 lru_list.next->prev = n;
276     lru_list.next = n;
277     }
278    
279 root 1.22 static void
280     lru_cachesize (int size)
281 root 1.1 {
282     if (size >= 0)
283     {
284     lru_maxsize = size;
285 root 1.22 lru_trim ();
286 root 1.1 }
287     }
288    
289     static GV *sql_exec;
290     static GV *DBH;
291 root 1.5
292     #define newconstpv(str) newSVpvn ((str), sizeof (str))
293 root 1.1
294     MODULE = PApp::SQL PACKAGE = PApp::SQL
295    
296     PROTOTYPES: DISABLE
297    
298     BOOT:
299     {
300 root 1.22 struct dbistate_st *dbis = DBIS_PUBLISHED_LVALUE;
301    
302 root 1.23 /* this is actually wrong, we should call the check member, apparently */
303 root 1.22 assert (dbis->version == DBISTATE_VERSION);
304     assert (dbis->xs_version == DBIXS_VERSION);
305    
306 root 1.24 tmp_iv = newSViv (0);
307    
308 root 1.1 sql_exec = gv_fetchpv ("PApp::SQL::sql_exec", TRUE, SVt_PV);
309     DBH = gv_fetchpv ("PApp::SQL::DBH" , TRUE, SVt_PV);
310    
311     /* apache might BOOT: twice :( */
312     if (lru_size)
313     lru_cachesize (0);
314    
315 root 1.22 lru_init ();
316 root 1.24 lru_cachesize (100);
317 root 1.1 }
318    
319 root 1.24 void
320     boot2 (SV *t_str, SV *t_int, SV *t_dbl)
321     CODE:
322     sql_varchar = newSVsv (t_str);
323     sql_integer = newSVsv (t_int);
324     sql_double = newSVsv (t_dbl);
325    
326 root 1.1 int
327     cachesize(size = -1)
328     int size
329     CODE:
330     RETVAL = lru_maxsize;
331     lru_cachesize (size);
332     OUTPUT:
333     RETVAL
334    
335     void
336     sql_exec(...)
337     ALIAS:
338 root 1.5 sql_uexec = 1
339 root 1.27 sql_fetch = 2
340 root 1.5 sql_ufetch = 3
341     sql_fetchall = 4
342     sql_ufetchall = 5
343     sql_exists = 6
344     sql_uexists = 7
345 root 1.1 PPCODE:
346     {
347     if (items == 0)
348     croak ("Usage: sql_exec [database-handle,] [bind-var-refs,... ] \"sql-statement\", [arguments, ...]");
349     else
350     {
351 root 1.24 int i;
352 root 1.1 int arg = 0;
353     int bind_first, bind_last;
354     int count;
355 root 1.24 lru_node *lru;
356 root 1.1 SV *dbh = ST(0);
357     SV *sth;
358     SV *sql;
359     SV *execute;
360 root 1.24 mc_node *mc;
361 root 1.9 STRLEN dc, dd; /* dummy */
362 root 1.24 I32 orig_stack = SP - PL_stack_base;
363 root 1.1
364     /* save our arguments against destruction through function calls */
365     SP += items;
366    
367     /* first check wether we should use an explicit db handle */
368     if (!is_dbh (dbh))
369     {
370 root 1.12 /* the next line doesn't work - check why later maybe */
371     /* dbh = get_sv ("DBH", FALSE);
372 root 1.1 if (!is_dbh (dbh))
373 root 1.12 {*/
374 root 1.20 dbh = GvSV (DBH);
375 root 1.1 if (!is_dbh (dbh))
376 root 1.12 croak ("sql_exec: no $DBH argument and no fallback in $PApp::SQL::DBH");
377     /*croak ("sql_exec: no $DBH found in current package or in PApp::SQL::");
378     }*/
379 root 1.1 }
380     else
381     arg++; /* we consumed one argument */
382    
383 root 1.20 /* be more Coro-friendly by keeping a copy, so different threads */
384 root 1.21 /* can replace their global handles */
385 root 1.20 dbh = sv_2mortal (newSVsv (dbh));
386    
387 root 1.1 /* count the remaining references (for bind_columns) */
388     bind_first = arg;
389     while (items > arg && SvROK (ST(arg)))
390     arg++;
391    
392     bind_last = arg;
393    
394     /* consume the sql-statement itself */
395     if (items <= arg)
396     croak ("sql_exec: required argument \"sql-statement\" missing");
397    
398     if (!SvPOK (ST(arg)))
399     croak ("sql_exec: sql-statement must be a string");
400    
401     sql = ST(arg); arg++;
402    
403 root 1.5 if ((ix & ~1) == 6)
404 root 1.1 {
405     SV *neu = sv_2mortal (newSVpv ("select count(*) > 0 from ", 0));
406     sv_catsv (neu, sql);
407     sv_catpv (neu, " limit 1");
408     sql = neu;
409 root 1.7 ix -= 4; /* sql_fetch */
410 root 1.1 }
411    
412 root 1.24 /* now prepare all parameters, by unmagicalising them and upgrading them */
413     for (i = arg; i < items; ++i)
414     {
415     SV *sv = ST (i);
416    
417     /* we sv_mortalcopy magical values since DBI seems to have a memory
418     * leak when magical values are passed into execute().
419     */
420     if (SvMAGICAL (sv))
421     ST (i) = sv = sv_mortalcopy (sv);
422    
423     if ((ix & 1) && SvPOKp (sv) && !SvUTF8 (sv))
424     {
425     ST (i) = sv = sv_mortalcopy (sv);
426     sv_utf8_upgrade (sv);
427     }
428     }
429    
430 root 1.4 /* check cache for existing statement handle */
431 root 1.24 lru = SvCUR (sql) <= MAX_CACHED_STATEMENT_SIZE
432     ? lru_fetch (dbh, sql)
433     : 0;
434     if (!lru)
435 root 1.1 {
436 root 1.24 mc = mc_find (SvSTASH (SvRV (dbh)));
437    
438     if (!mc->prepare)
439     mc_cache (mc, prepare);
440    
441 root 1.1 PUSHMARK (SP);
442     EXTEND (SP, 2);
443     PUSHs (dbh);
444     PUSHs (sql);
445     PUTBACK;
446 root 1.24 count = call_sv (mc->prepare, G_SCALAR);
447 root 1.1 SPAGAIN;
448    
449     if (count != 1)
450     croak ("sql_exec: unable to prepare() statement '%s': %s",
451 root 1.3 SvPV (sql, dc),
452 root 1.9 SvPV (get_sv ("DBI::errstr", TRUE), dd));
453 root 1.1
454     sth = POPs;
455    
456 root 1.25 if (!SvROK (sth))
457     croak ("sql_exec: buggy DBD driver, prepare returned non-reference for '%s': %s",
458     SvPV (sql, dc),
459     SvPV (get_sv ("DBI::errstr", TRUE), dd));
460    
461 root 1.24 mc = mc_find (SvSTASH (SvRV (sth)));
462    
463     if (!mc->bind_param)
464     {
465     mc_cache (mc, bind_param);
466     mc_cache (mc, execute);
467     mc_cache (mc, finish);
468     }
469    
470     if (SvCUR (sql) <= MAX_CACHED_STATEMENT_SIZE)
471     lru_store (dbh, sql, sth, mc);
472    
473     /* on first execution we unfortunately need to use bind_param
474     * to mark any numeric parameters as such.
475     */
476     SvIV_set (tmp_iv, 0);
477    
478     while (items > arg)
479     {
480     SV *sv = ST (arg);
481     /* we sv_mortalcopy magical values since DBI seems to have a memory
482     * leak when magical values are passed into execute().
483     */
484    
485     PUSHMARK (SP);
486     EXTEND (SP, 4);
487     PUSHs (sth);
488     SvIVX (tmp_iv)++;
489     PUSHs (tmp_iv);
490     PUSHs (sv);
491    
492     PUSHs (
493     SvPOKp (sv) ? sql_varchar
494     : SvNOKp (sv) ? sql_double
495     : SvIOKp (sv) ? sql_integer
496     : sql_varchar
497     );
498    
499     PUTBACK;
500     call_sv (mc->bind_param, G_VOID);
501     SPAGAIN;
502    
503     arg++;
504     }
505    
506     /* now use execute without any arguments */
507     PUSHMARK (SP);
508     EXTEND (SP, 1);
509     PUSHs (sth);
510 root 1.1 }
511 root 1.24 else
512     {
513     sth = sv_2mortal (SvREFCNT_inc (lru->sth));
514     mc = lru->mc;
515 root 1.1
516 root 1.24 /* we have previously executed this statement, so we
517     * use the cached types and use execute with arguments.
518 root 1.15 */
519 root 1.24
520     PUSHMARK (SP);
521     EXTEND (SP, items - arg + 1);
522     PUSHs (sth);
523     while (items > arg)
524     {
525     SV *sv = ST (arg);
526 root 1.27 PUSHs (sv);
527 root 1.24 arg++;
528     }
529 root 1.1 }
530    
531     PUTBACK;
532     /* { static GV *execute;
533     if (!execute) execute = gv_fetchmethod_autoload(SvSTASH(SvRV(sth)), "execute", 0);
534     count = call_sv(GvCV(execute), G_SCALAR);
535     }*/
536 root 1.24 count = call_sv (mc->execute, G_SCALAR);
537 root 1.1 SPAGAIN;
538    
539     if (count != 1)
540     croak ("sql_exec: execute() didn't return any value ('%s'): %s",
541 root 1.3 SvPV (sql, dc),
542 root 1.10 SvPV (get_sv ("DBI::errstr", TRUE), dd));
543 root 1.1
544     execute = POPs;
545    
546     if (!SvTRUE (execute))
547     croak ("sql_exec: unable to execute statement '%s' (%s)",
548 root 1.3 SvPV (sql, dc),
549 root 1.10 SvPV (get_sv ("DBI::errstr", TRUE), dd));
550 root 1.1
551 root 1.24 sv_setsv (GvSV (sql_exec), execute);
552 root 1.1
553     if (bind_first != bind_last)
554     {
555     PUSHMARK (SP);
556     EXTEND (SP, bind_last - bind_first + 2);
557     PUSHs (sth);
558     do {
559 stefan 1.16 #if CAN_UTF8
560 root 1.17 if (ix & 1)
561     SvUTF8_on (SvRV(ST(bind_first)));
562 stefan 1.16 #endif
563 root 1.1 PUSHs (ST(bind_first));
564     bind_first++;
565     } while (bind_first != bind_last);
566    
567     PUTBACK;
568 root 1.24
569     if (!mc->bind_columns)
570     mc_cache (mc, bind_columns);
571    
572     count = call_sv (mc->bind_columns, G_SCALAR);
573    
574 root 1.1 SPAGAIN;
575    
576     if (count != 1)
577     croak ("sql_exec: bind_columns() didn't return any value ('%s'): %s",
578 root 1.3 SvPV (sql, dc),
579 root 1.10 SvPV (get_sv ("DBI::errstr", TRUE), dd));
580 root 1.1
581 root 1.19 if (!SvOK (TOPs))
582 root 1.1 croak ("sql_exec: bind_columns() didn't return a true ('%s'): %s",
583 root 1.3 SvPV (sql, dc),
584 root 1.10 SvPV (get_sv ("DBI::errstr", TRUE), dd));
585 root 1.19
586     POPs;
587 root 1.1 }
588    
589 root 1.5 if ((ix & ~1) == 2)
590 root 1.1 { /* sql_fetch */
591     SV *row;
592    
593     PUSHMARK (SP);
594     XPUSHs (sth);
595     PUTBACK;
596 root 1.24
597     if (!mc->fetchrow_arrayref)
598     mc_cache (mc, fetchrow_arrayref);
599    
600     count = call_sv (mc->fetchrow_arrayref, G_SCALAR);
601 root 1.1 SPAGAIN;
602    
603     if (count != 1)
604     abort ();
605    
606     row = POPs;
607    
608 root 1.24 SP = PL_stack_base + orig_stack;
609    
610 root 1.1 if (SvROK (row))
611     {
612     AV *av;
613    
614     switch (GIMME_V)
615     {
616     case G_VOID:
617     /* no thing */
618     break;
619     case G_SCALAR:
620     /* the first element */
621 root 1.13 XPUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, *av_fetch ((AV *)SvRV (row), 0, 1)));
622 root 1.24 count = 1;
623 root 1.1 break;
624     case G_ARRAY:
625     av = (AV *)SvRV (row);
626     count = AvFILL (av) + 1;
627     EXTEND (SP, count);
628     for (arg = 0; arg < count; arg++)
629 root 1.13 PUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, AvARRAY (av)[arg]));
630 root 1.1
631     break;
632     default:
633     abort ();
634     }
635     }
636     }
637 root 1.5 else if ((ix & ~1) == 4)
638 root 1.1 { /* sql_fetchall */
639     SV *rows;
640    
641     PUSHMARK (SP);
642     XPUSHs (sth);
643     PUTBACK;
644 root 1.24
645     if (!mc->fetchall_arrayref)
646     mc_cache (mc, fetchall_arrayref);
647    
648     count = call_sv (mc->fetchall_arrayref, G_SCALAR);
649 root 1.1 SPAGAIN;
650    
651     if (count != 1)
652     abort ();
653    
654     rows = POPs;
655    
656 root 1.24 SP = PL_stack_base + orig_stack;
657    
658 root 1.1 if (SvROK (rows))
659     {
660     AV *av = (AV *)SvRV (rows);
661     count = AvFILL (av) + 1;
662    
663     if (count)
664     {
665 root 1.6 int columns = AvFILL ((AV *) SvRV (AvARRAY (av)[0])) + 1; /* columns? */
666 root 1.1
667     EXTEND (SP, count);
668     if (columns == 1)
669     for (arg = 0; arg < count; arg++)
670 root 1.13 PUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, AvARRAY ((AV *)SvRV (AvARRAY (av)[arg]))[0]));
671 root 1.1 else
672     for (arg = 0; arg < count; arg++)
673 root 1.13 PUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, AvARRAY (av)[arg]));
674 root 1.1 }
675     }
676     }
677     else
678 root 1.24 {
679     SP = PL_stack_base + orig_stack;
680     XPUSHs (sth);
681     }
682 root 1.1
683 root 1.5 if (ix > 1 || GIMME_V == G_VOID)
684 root 1.1 {
685 root 1.24 orig_stack = SP - PL_stack_base;
686    
687 root 1.1 PUSHMARK (SP);
688     XPUSHs (sth);
689     PUTBACK;
690 root 1.24
691     if (!mc->finish)
692     mc_cache (mc, finish);
693    
694     call_sv (mc->finish, G_DISCARD);
695 root 1.1 SPAGAIN;
696 root 1.24
697     SP = PL_stack_base + orig_stack;
698 root 1.1 }
699     }
700     }
701    
702    
703