ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/PApp-SQL/SQL.xs
Revision: 1.2
Committed: Tue Oct 24 04:21:45 2000 UTC (23 years, 7 months ago) by root
Branch: MAIN
Changes since 1.1: +1 -1 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.2 #define is_dbh(sv) ((sv) && sv_isobject (sv) && sv_derived_from ((sv), "DBI::db"))
6 root 1.1
7     typedef struct lru_node {
8     struct lru_node *next;
9     struct lru_node *prev;
10     U32 hash;
11     SV *dbh;
12     SV *sql;
13    
14     SV *sth;
15     #if 0 /* method cache */
16     GV *execute;
17     GV *bind_columns;
18     GV *fetch;
19     #endif
20     } lru_node;
21    
22     static lru_node lru_list;
23     static int lru_size;
24     static int lru_maxsize;
25    
26     #define lru_init lru_list.next = &lru_list; lru_list.prev = &lru_list /* other fields are zero */
27    
28     /* this is primitive, yet effective */
29     /* the returned value must never be zero (or bad things will happen) */
30     #define lru_hash do { \
31     hash = (((U32)dbh)>>2); \
32     hash += *statement;\
33     hash += len; \
34     } while (0)
35    
36     /* fetch and "use" */
37     /* could be done using a single call (we could call prepare!) */
38     static SV *lru_fetch(SV *dbh, SV *sql)
39     {
40     lru_node *n;
41    
42     U32 hash;
43     STRLEN len;
44     char *statement = SvPV (sql, len);
45    
46     dbh = SvRV (dbh);
47    
48     lru_hash;
49    
50     /*fprintf (stderr, "F: %08lx %s\n", hash, SvPV_nolen (sql));/*D*/
51    
52     n = &lru_list;
53     do {
54     n = n->next;
55     if (!n->hash)
56     return 0;
57     } while (n->hash != hash
58     || !sv_eq (n->sql, sql)
59     || n->dbh != dbh);
60    
61     /* found, so return to the start of the list */
62     n->prev->next = n->next;
63     n->next->prev = n->prev;
64    
65     n->next = lru_list.next;
66     n->prev = &lru_list;
67     lru_list.next->prev = n;
68     lru_list.next = n;
69    
70     return n->sth;
71     }
72    
73     static void lru_nukeone(void)
74     {
75     lru_node *n;
76     /* nuke at the end */
77    
78     n = lru_list.prev;
79    
80     lru_list.prev = n->prev;
81     n->prev->next = &lru_list;
82    
83     /*fprintf (stderr, "N: %s\n", SvPV_nolen (n->sql));/*D*/
84    
85     SvREFCNT_dec (n->dbh);
86     SvREFCNT_dec (n->sql);
87     SvREFCNT_dec (n->sth);
88     Safefree (n);
89    
90     lru_size--;
91     }
92    
93     /* store a not-yet existing entry(!) */
94     static void lru_store(SV *dbh, SV *sql, SV *sth)
95     {
96     lru_node *n;
97    
98     U32 hash;
99     STRLEN len;
100     char *statement = SvPV (sql, len);
101    
102     dbh = SvRV (dbh);
103    
104     lru_hash;
105    
106     /*fprintf (stderr, "S: %08lx %s\n", hash, SvPV_nolen (sql));/*D*/
107    
108     lru_size++;
109     if (lru_size > lru_maxsize)
110     lru_nukeone ();
111    
112     New (0, n, 1, lru_node);
113    
114     n->hash = hash;
115     n->dbh = dbh; SvREFCNT_inc (dbh); /* note: this is the dbi hash itself, not the reference */
116     n->sql = newSVsv (sql);
117     n->sth = sth; SvREFCNT_inc (sth);
118    
119     n->next = lru_list.next;
120     n->prev = &lru_list;
121     lru_list.next->prev = n;
122     lru_list.next = n;
123     }
124    
125     static void lru_cachesize (int size)
126     {
127     if (size >= 0)
128     {
129     lru_maxsize = size;
130     while (lru_size > lru_maxsize)
131     lru_nukeone ();
132     }
133     }
134    
135     static GV *sql_exec;
136     static GV *DBH;
137    
138     MODULE = PApp::SQL PACKAGE = PApp::SQL
139    
140     PROTOTYPES: DISABLE
141    
142     BOOT:
143     {
144     sql_exec = gv_fetchpv ("PApp::SQL::sql_exec", TRUE, SVt_PV);
145     DBH = gv_fetchpv ("PApp::SQL::DBH" , TRUE, SVt_PV);
146    
147     /* apache might BOOT: twice :( */
148     if (lru_size)
149     lru_cachesize (0);
150    
151     lru_init;
152     lru_cachesize (50);
153     }
154    
155     int
156     cachesize(size = -1)
157     int size
158     CODE:
159     RETVAL = lru_maxsize;
160     lru_cachesize (size);
161     OUTPUT:
162     RETVAL
163    
164     void
165     sql_exec(...)
166     ALIAS:
167     sql_fetch = 1
168     sql_fetchall = 2
169     sql_exists = 4
170     PPCODE:
171     {
172     if (items == 0)
173     croak ("Usage: sql_exec [database-handle,] [bind-var-refs,... ] \"sql-statement\", [arguments, ...]");
174     else
175     {
176     int arg = 0;
177     int bind_first, bind_last;
178     int count;
179     SV *dbh = ST(0);
180     SV *sth;
181     SV *sql;
182     SV *execute;
183    
184     /* save our arguments against destruction through function calls */
185     SP += items;
186    
187     /* first check wether we should use an explicit db handle */
188     if (!is_dbh (dbh))
189     {
190     dbh = get_sv ("DBH", FALSE);
191     if (!is_dbh (dbh))
192     {
193     dbh = GvSV(DBH);
194     if (!is_dbh (dbh))
195     croak ("sql_exec: no $DBH found in current package or in PApp::SQL::");
196     }
197     }
198     else
199     arg++; /* we consumed one argument */
200    
201     /* count the remaining references (for bind_columns) */
202     bind_first = arg;
203     while (items > arg && SvROK (ST(arg)))
204     arg++;
205    
206     bind_last = arg;
207    
208     /* consume the sql-statement itself */
209     if (items <= arg)
210     croak ("sql_exec: required argument \"sql-statement\" missing");
211    
212     if (!SvPOK (ST(arg)))
213     croak ("sql_exec: sql-statement must be a string");
214    
215     sql = ST(arg); arg++;
216    
217     if (ix == 4)
218     {
219     SV *neu = sv_2mortal (newSVpv ("select count(*) > 0 from ", 0));
220     sv_catsv (neu, sql);
221     sv_catpv (neu, " limit 1");
222     sql = neu;
223     ix = 1; /* sql_fetch */
224     }
225    
226     /* check cache for existing statement handle (NYI) */
227     sth = lru_fetch (dbh, sql);
228     if (!sth)
229     {
230     PUSHMARK (SP);
231     EXTEND (SP, 2);
232     PUSHs (dbh);
233     PUSHs (sql);
234     PUTBACK;
235     count = call_method ("prepare", G_SCALAR);
236     SPAGAIN;
237    
238     if (count != 1)
239     croak ("sql_exec: unable to prepare() statement '%s': %s",
240     SvPV_nolen (sql),
241     SvPV_nolen (get_sv ("DBI::errstr", TRUE)));
242    
243     sth = POPs;
244    
245     lru_store (dbh, sql, sth);
246     }
247    
248     PUSHMARK (SP);
249     EXTEND (SP, items - arg + 1);
250     PUSHs (sth);
251     while (items > arg)
252     {
253     PUSHs (ST(arg));
254     arg++;
255     }
256    
257     PUTBACK;
258     /* { static GV *execute;
259     if (!execute) execute = gv_fetchmethod_autoload(SvSTASH(SvRV(sth)), "execute", 0);
260     count = call_sv(GvCV(execute), G_SCALAR);
261     }*/
262     count = call_method ("execute", G_SCALAR);
263     SPAGAIN;
264    
265     if (count != 1)
266     croak ("sql_exec: execute() didn't return any value ('%s'): %s",
267     SvPV_nolen (sql),
268     SvPV_nolen (get_sv ("DBI::errstr", TRUE)));
269    
270     execute = POPs;
271    
272     if (!SvTRUE (execute))
273     croak ("sql_exec: unable to execute statement '%s' (%s)",
274     SvPV_nolen (sql),
275     SvPV_nolen (get_sv ("DBI::errstr", TRUE)));
276    
277     sv_setsv (GvSV(sql_exec), execute);
278    
279     if (bind_first != bind_last)
280     {
281     PUSHMARK (SP);
282     EXTEND (SP, bind_last - bind_first + 2);
283     PUSHs (sth);
284     do {
285     PUSHs (ST(bind_first));
286     bind_first++;
287     } while (bind_first != bind_last);
288    
289     PUTBACK;
290     count = call_method ("bind_columns", G_SCALAR);
291     SPAGAIN;
292    
293     if (count != 1)
294     croak ("sql_exec: bind_columns() didn't return any value ('%s'): %s",
295     SvPV_nolen (sql),
296     SvPV_nolen (get_sv ("DBI::errstr", TRUE)));
297    
298     if (!SvOK (POPs))
299     croak ("sql_exec: bind_columns() didn't return a true ('%s'): %s",
300     SvPV_nolen (sql),
301     SvPV_nolen (get_sv ("DBI::errstr", TRUE)));
302     }
303    
304     /* free our arguments from the stack */
305     SP -= items;
306    
307     if (ix == 1)
308     { /* sql_fetch */
309     SV *row;
310    
311     PUSHMARK (SP);
312     XPUSHs (sth);
313     PUTBACK;
314     count = call_method ("fetchrow_arrayref", G_SCALAR);
315     SPAGAIN;
316    
317     if (count != 1)
318     abort ();
319    
320     row = POPs;
321    
322     if (SvROK (row))
323     {
324     AV *av;
325    
326     switch (GIMME_V)
327     {
328     case G_VOID:
329     /* no thing */
330     break;
331     case G_SCALAR:
332     /* the first element */
333     XPUSHs (*av_fetch ((AV *)SvRV (row), 0, 1));
334     break;
335     case G_ARRAY:
336     av = (AV *)SvRV (row);
337     count = AvFILL (av) + 1;
338     EXTEND (SP, count);
339     for (arg = 0; arg < count; arg++)
340     PUSHs (AvARRAY (av)[arg]);
341    
342     break;
343     default:
344     abort ();
345     }
346     }
347     }
348     else if (ix == 2)
349     { /* sql_fetchall */
350     SV *rows;
351    
352     PUSHMARK (SP);
353     XPUSHs (sth);
354     PUTBACK;
355     count = call_method ("fetchall_arrayref", G_SCALAR);
356     SPAGAIN;
357    
358     if (count != 1)
359     abort ();
360    
361     rows = POPs;
362    
363     if (SvROK (rows))
364     {
365     AV *av = (AV *)SvRV (rows);
366     count = AvFILL (av) + 1;
367    
368     if (count)
369     {
370     int columns = AvFILL ((AV *)SvRV (AvARRAY(av)[0])) + 1; /* columns? */
371    
372     EXTEND (SP, count);
373     if (columns == 1)
374     for (arg = 0; arg < count; arg++)
375     PUSHs (AvARRAY ((AV *)SvRV (AvARRAY (av)[arg]))[0]);
376     else
377     for (arg = 0; arg < count; arg++)
378     PUSHs (AvARRAY (av)[arg]);
379     }
380     }
381     }
382     else
383     XPUSHs (sth);
384    
385     if (ix || GIMME_V == G_VOID)
386     {
387     PUSHMARK (SP);
388     XPUSHs (sth);
389     PUTBACK;
390     (void) call_method ("finish", G_DISCARD);
391     SPAGAIN;
392     }
393     }
394     }
395    
396    
397