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 | |
|
|
5 | /* 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 | #define DBISTATE_ADDRSV (perl_get_sv(DBISTATE_PERLNAME, 0x05)) |
|
|
11 | #define DBIS_PUBLISHED_LVALUE (*(INT2PTR(dbistate_t**, &SvIVX(DBISTATE_ADDRSV)))) |
|
|
12 | |
|
|
13 | struct dbistate_st { |
|
|
14 | #define DBISTATE_VERSION 94 /* Must change whenever dbistate_t does */ |
|
|
15 | /* this must be the first member in structure */ |
|
|
16 | void (*check_version) _((const char *name, |
|
|
17 | int dbis_cv, int dbis_cs, int need_dbixs_cv, |
|
|
18 | int drc_s, int dbc_s, int stc_s, int fdc_s)); |
|
|
19 | |
|
|
20 | /* version and size are used to check for DBI/DBD version mis-match */ |
|
|
21 | U16 version; /* version of this structure */ |
|
|
22 | U16 size; |
|
|
23 | U16 xs_version; /* version of the overall DBIXS / DBD interface */ |
|
|
24 | U16 spare_pad; |
|
|
25 | }; |
|
|
26 | typedef struct dbistate_st dbistate_t; |
|
|
27 | |
|
|
28 | #define DBIcf_ACTIVE 0x000004 /* needs finish/disconnect before clear */ |
|
|
29 | |
|
|
30 | typedef U32 imp_sth; |
|
|
31 | |
|
|
32 | /* not strictly part of the API... */ |
|
|
33 | static imp_sth * |
|
|
34 | sth_get_imp (SV *sth) |
|
|
35 | { |
|
|
36 | MAGIC *mg = mg_find (SvRV (sth), PERL_MAGIC_tied); |
|
|
37 | sth = mg->mg_obj; |
|
|
38 | mg = mg_find (SvRV (sth), DBI_MAGIC); |
|
|
39 | return (imp_sth *)SvPVX (mg->mg_obj); |
|
|
40 | } |
|
|
41 | |
|
|
42 | #define DBI_STH_ACTIVE(imp) (*(imp) & DBIcf_ACTIVE) |
|
|
43 | |
|
|
44 | /* end of import section */ |
4 | |
45 | |
5 | #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 6)) |
46 | #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 6)) |
6 | # define get_sv perl_get_sv |
47 | # define get_sv perl_get_sv |
7 | # define call_method perl_call_method |
48 | # define call_method perl_call_method |
8 | # define call_sv perl_call_sv |
49 | # define call_sv perl_call_sv |
9 | #endif |
50 | #endif |
10 | |
51 | |
11 | #if (PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION <= 5)) |
52 | #if (PERL_VERSION > 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION >= 6)) |
12 | # define CAN_UTF8 1 |
53 | # define CAN_UTF8 1 |
13 | #endif |
54 | #endif |
|
|
55 | |
|
|
56 | #define MAX_CACHED_STATEMENT_SIZE 2048 |
14 | |
57 | |
15 | static SV * |
58 | static SV * |
16 | sql_upgrade_utf8 (SV *sv) |
59 | sql_upgrade_utf8 (SV *sv) |
17 | { |
60 | { |
18 | #if CAN_UTF8 |
61 | #if CAN_UTF8 |
… | |
… | |
21 | #endif |
64 | #endif |
22 | return sv; |
65 | return sv; |
23 | } |
66 | } |
24 | |
67 | |
25 | static SV * |
68 | static SV * |
26 | sql_force_utf8 (SV *sv) |
69 | mortalcopy_and_maybe_force_utf8(int utf8, SV *sv) |
27 | { |
70 | { |
|
|
71 | sv = sv_mortalcopy (sv); |
28 | #if CAN_UTF8 |
72 | #if CAN_UTF8 |
29 | if (SvPOK (sv)) |
73 | if (utf8 && SvPOK (sv)) |
30 | SvUTF8_on (sv); |
74 | SvUTF8_on (sv); |
31 | #endif |
75 | #endif |
32 | return sv; |
76 | return sv; |
33 | } |
77 | } |
34 | |
78 | |
35 | #define maybe_upgrade_utf8(utf8,sv) ((utf8) ? sql_upgrade_utf8 (sv) : (sv)) |
79 | #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)) |
|
|
37 | |
80 | |
38 | #define is_dbh(sv) ((sv) && sv_isobject (sv) && sv_derived_from ((sv), "DBI::db")) |
81 | #define is_dbh(sv) ((sv) && sv_isobject (sv) && sv_derived_from ((sv), "DBI::db")) |
39 | |
82 | |
40 | typedef struct lru_node { |
83 | typedef struct lru_node { |
41 | struct lru_node *next; |
84 | struct lru_node *next; |
42 | struct lru_node *prev; |
85 | struct lru_node *prev; |
43 | U32 hash; |
86 | U32 hash; /* bit 31 is used to mark active nodes */ |
44 | SV *dbh; |
87 | SV *dbh; |
45 | SV *sql; |
88 | SV *sql; |
46 | |
89 | |
47 | SV *sth; |
90 | SV *sth; |
|
|
91 | imp_sth *sth_imp; |
48 | #if 0 /* method cache */ |
92 | #if 0 /* method cache */ |
49 | GV *execute; |
93 | GV *execute; |
50 | GV *bind_columns; |
94 | GV *bind_columns; |
51 | GV *fetch; |
95 | GV *fetch; |
52 | GV *finish; |
96 | GV *finish; |
… | |
… | |
55 | |
99 | |
56 | static lru_node lru_list; |
100 | static lru_node lru_list; |
57 | static int lru_size; |
101 | static int lru_size; |
58 | static int lru_maxsize; |
102 | static int lru_maxsize; |
59 | |
103 | |
60 | #define lru_init lru_list.next = &lru_list; lru_list.prev = &lru_list /* other fields are zero */ |
104 | #define lru_init() lru_list.next = &lru_list; lru_list.prev = &lru_list /* other fields are zero */ |
61 | |
105 | |
62 | /* this is primitive, yet effective */ |
106 | /* this is primitive, yet effective */ |
63 | /* the returned value must never be zero (or bad things will happen) */ |
107 | /* the returned value must never be zero (or bad things will happen) */ |
64 | #define lru_hash do { \ |
108 | #define lru_hash \ |
|
|
109 | do { \ |
65 | hash = (((U32)dbh)>>2); \ |
110 | hash = (((U32)(long)dbh)>>4); \ |
66 | hash += *statement;\ |
111 | hash += *statement; \ |
67 | hash += len; \ |
112 | hash += len; \ |
68 | } while (0) |
113 | } while (0) |
69 | |
114 | |
70 | /* fetch and "use" */ |
115 | /* fetch and "use" */ |
71 | /* could be done using a single call (we could call prepare!) */ |
116 | /* could be done using a single call (we could call prepare!) */ |
|
|
117 | static SV * |
72 | static SV *lru_fetch(SV *dbh, SV *sql) |
118 | lru_fetch (SV *dbh, SV *sql) |
73 | { |
119 | { |
74 | lru_node *n; |
120 | lru_node *n; |
75 | |
121 | |
76 | U32 hash; |
122 | U32 hash; |
77 | STRLEN len; |
123 | STRLEN len; |
… | |
… | |
79 | |
125 | |
80 | dbh = SvRV (dbh); |
126 | dbh = SvRV (dbh); |
81 | |
127 | |
82 | lru_hash; |
128 | lru_hash; |
83 | |
129 | |
84 | /*fprintf (stderr, "F: %08lx %s\n", hash, SvPV_nolen (sql));/*D*/ |
|
|
85 | |
|
|
86 | n = &lru_list; |
130 | n = &lru_list; |
87 | do { |
131 | do { |
88 | n = n->next; |
132 | n = n->next; |
|
|
133 | |
89 | if (!n->hash) |
134 | if (!n->hash) |
90 | return 0; |
135 | return 0; |
91 | } while (n->hash != hash |
136 | } while (n->hash != hash |
|
|
137 | || DBI_STH_ACTIVE (n->sth_imp) |
92 | || !sv_eq (n->sql, sql) |
138 | || !sv_eq (n->sql, sql) |
93 | || n->dbh != dbh); |
139 | || n->dbh != dbh); |
94 | |
140 | |
95 | /* found, so return to the start of the list */ |
141 | /* found, so return to the start of the list */ |
96 | n->prev->next = n->next; |
142 | n->prev->next = n->next; |
… | |
… | |
99 | n->next = lru_list.next; |
145 | n->next = lru_list.next; |
100 | n->prev = &lru_list; |
146 | n->prev = &lru_list; |
101 | lru_list.next->prev = n; |
147 | lru_list.next->prev = n; |
102 | lru_list.next = n; |
148 | lru_list.next = n; |
103 | |
149 | |
104 | return n->sth; |
150 | return sv_2mortal (SvREFCNT_inc (n->sth)); |
105 | } |
151 | } |
106 | |
152 | |
107 | static void lru_nukeone(void) |
153 | static void |
|
|
154 | lru_trim (void) |
|
|
155 | { |
|
|
156 | while (lru_size > lru_maxsize) |
|
|
157 | { |
|
|
158 | /* nuke at the end */ |
|
|
159 | lru_node *n = lru_list.prev; |
|
|
160 | |
|
|
161 | n = lru_list.prev; |
|
|
162 | |
|
|
163 | lru_list.prev = n->prev; |
|
|
164 | n->prev->next = &lru_list; |
|
|
165 | |
|
|
166 | SvREFCNT_dec (n->dbh); |
|
|
167 | SvREFCNT_dec (n->sql); |
|
|
168 | SvREFCNT_dec (n->sth); |
|
|
169 | Safefree (n); |
|
|
170 | |
|
|
171 | lru_size--; |
|
|
172 | } |
|
|
173 | } |
|
|
174 | |
|
|
175 | /* store a not-yet existing entry(!) */ |
|
|
176 | static void |
|
|
177 | lru_store (SV *dbh, SV *sql, SV *sth) |
108 | { |
178 | { |
109 | lru_node *n; |
179 | lru_node *n; |
110 | /* nuke at the end */ |
|
|
111 | |
|
|
112 | n = lru_list.prev; |
|
|
113 | |
|
|
114 | lru_list.prev = n->prev; |
|
|
115 | n->prev->next = &lru_list; |
|
|
116 | |
|
|
117 | /*fprintf (stderr, "N: %s\n", SvPV_nolen (n->sql));/*D*/ |
|
|
118 | |
|
|
119 | SvREFCNT_dec (n->dbh); |
|
|
120 | SvREFCNT_dec (n->sql); |
|
|
121 | SvREFCNT_dec (n->sth); |
|
|
122 | Safefree (n); |
|
|
123 | |
|
|
124 | lru_size--; |
|
|
125 | } |
|
|
126 | |
|
|
127 | /* store a not-yet existing entry(!) */ |
|
|
128 | static void lru_store(SV *dbh, SV *sql, SV *sth) |
|
|
129 | { |
|
|
130 | lru_node *n; |
|
|
131 | |
|
|
132 | U32 hash; |
180 | U32 hash; |
133 | STRLEN len; |
181 | STRLEN len; |
|
|
182 | char *statement; |
|
|
183 | |
|
|
184 | if (!lru_maxsize) |
|
|
185 | return; |
|
|
186 | |
134 | char *statement = SvPV (sql, len); |
187 | statement = SvPV (sql, len); |
135 | |
|
|
136 | dbh = SvRV (dbh); |
188 | dbh = SvRV (dbh); |
137 | |
189 | |
138 | lru_hash; |
190 | lru_hash; |
139 | |
191 | |
140 | /*fprintf (stderr, "S: %08lx %s\n", hash, SvPV_nolen (sql));/*D*/ |
|
|
141 | |
|
|
142 | lru_size++; |
192 | lru_size++; |
143 | if (lru_size > lru_maxsize) |
193 | lru_trim (); |
144 | lru_nukeone (); |
|
|
145 | |
194 | |
146 | New (0, n, 1, lru_node); |
195 | New (0, n, 1, lru_node); |
147 | |
196 | |
148 | n->hash = hash; |
197 | n->hash = hash; |
149 | n->dbh = dbh; SvREFCNT_inc (dbh); /* note: this is the dbi hash itself, not the reference */ |
198 | n->dbh = dbh; SvREFCNT_inc (dbh); /* note: this is the dbi hash itself, not the reference */ |
150 | n->sql = newSVsv (sql); |
199 | n->sql = newSVsv (sql); |
151 | n->sth = sth; SvREFCNT_inc (sth); |
200 | n->sth = sth; SvREFCNT_inc (sth); |
|
|
201 | n->sth_imp = sth_get_imp (sth); |
152 | |
202 | |
153 | n->next = lru_list.next; |
203 | n->next = lru_list.next; |
154 | n->prev = &lru_list; |
204 | n->prev = &lru_list; |
155 | lru_list.next->prev = n; |
205 | lru_list.next->prev = n; |
156 | lru_list.next = n; |
206 | lru_list.next = n; |
157 | } |
207 | } |
158 | |
208 | |
|
|
209 | static void |
159 | static void lru_cachesize (int size) |
210 | lru_cachesize (int size) |
160 | { |
211 | { |
161 | if (size >= 0) |
212 | if (size >= 0) |
162 | { |
213 | { |
163 | lru_maxsize = size; |
214 | lru_maxsize = size; |
164 | while (lru_size > lru_maxsize) |
215 | lru_trim (); |
165 | lru_nukeone (); |
|
|
166 | } |
216 | } |
167 | } |
217 | } |
168 | |
218 | |
169 | static GV *sql_exec; |
219 | static GV *sql_exec; |
170 | static GV *DBH; |
220 | static GV *DBH; |
… | |
… | |
178 | |
228 | |
179 | PROTOTYPES: DISABLE |
229 | PROTOTYPES: DISABLE |
180 | |
230 | |
181 | BOOT: |
231 | BOOT: |
182 | { |
232 | { |
|
|
233 | struct dbistate_st *dbis = DBIS_PUBLISHED_LVALUE; |
|
|
234 | |
|
|
235 | /* this is atcually wrong, we should call the check member, apparently */ |
|
|
236 | assert (dbis->version == DBISTATE_VERSION); |
|
|
237 | assert (dbis->xs_version == DBIXS_VERSION); |
|
|
238 | |
183 | sql_exec = gv_fetchpv ("PApp::SQL::sql_exec", TRUE, SVt_PV); |
239 | sql_exec = gv_fetchpv ("PApp::SQL::sql_exec", TRUE, SVt_PV); |
184 | DBH = gv_fetchpv ("PApp::SQL::DBH" , TRUE, SVt_PV); |
240 | DBH = gv_fetchpv ("PApp::SQL::DBH" , TRUE, SVt_PV); |
185 | |
241 | |
186 | if (!sv_prepare) |
242 | if (!sv_prepare) |
187 | { |
243 | { |
… | |
… | |
195 | |
251 | |
196 | /* apache might BOOT: twice :( */ |
252 | /* apache might BOOT: twice :( */ |
197 | if (lru_size) |
253 | if (lru_size) |
198 | lru_cachesize (0); |
254 | lru_cachesize (0); |
199 | |
255 | |
200 | lru_init; |
256 | lru_init (); |
201 | lru_cachesize (50); |
257 | lru_cachesize (50); |
202 | } |
258 | } |
203 | |
259 | |
204 | int |
260 | int |
205 | cachesize(size = -1) |
261 | cachesize(size = -1) |
… | |
… | |
231 | int count; |
287 | int count; |
232 | SV *dbh = ST(0); |
288 | SV *dbh = ST(0); |
233 | SV *sth; |
289 | SV *sth; |
234 | SV *sql; |
290 | SV *sql; |
235 | SV *execute; |
291 | SV *execute; |
236 | STRLEN dc; |
292 | STRLEN dc, dd; /* dummy */ |
237 | |
293 | |
238 | /* save our arguments against destruction through function calls */ |
294 | /* save our arguments against destruction through function calls */ |
239 | SP += items; |
295 | SP += items; |
240 | |
296 | |
241 | /* first check wether we should use an explicit db handle */ |
297 | /* first check wether we should use an explicit db handle */ |
242 | if (!is_dbh (dbh)) |
298 | if (!is_dbh (dbh)) |
243 | { |
299 | { |
|
|
300 | /* the next line doesn't work - check why later maybe */ |
244 | dbh = get_sv ("DBH", FALSE); |
301 | /* dbh = get_sv ("DBH", FALSE); |
245 | if (!is_dbh (dbh)) |
302 | if (!is_dbh (dbh)) |
246 | { |
303 | {*/ |
247 | dbh = GvSV(DBH); |
304 | dbh = GvSV (DBH); |
248 | if (!is_dbh (dbh)) |
305 | if (!is_dbh (dbh)) |
|
|
306 | croak ("sql_exec: no $DBH argument and no fallback in $PApp::SQL::DBH"); |
249 | croak ("sql_exec: no $DBH found in current package or in PApp::SQL::"); |
307 | /*croak ("sql_exec: no $DBH found in current package or in PApp::SQL::"); |
250 | } |
308 | }*/ |
251 | } |
309 | } |
252 | else |
310 | else |
253 | arg++; /* we consumed one argument */ |
311 | arg++; /* we consumed one argument */ |
|
|
312 | |
|
|
313 | /* be more Coro-friendly by keeping a copy, so different threads */ |
|
|
314 | /* can replace their global handles */ |
|
|
315 | dbh = sv_2mortal (newSVsv (dbh)); |
254 | |
316 | |
255 | /* count the remaining references (for bind_columns) */ |
317 | /* count the remaining references (for bind_columns) */ |
256 | bind_first = arg; |
318 | bind_first = arg; |
257 | while (items > arg && SvROK (ST(arg))) |
319 | while (items > arg && SvROK (ST(arg))) |
258 | arg++; |
320 | arg++; |
… | |
… | |
272 | { |
334 | { |
273 | SV *neu = sv_2mortal (newSVpv ("select count(*) > 0 from ", 0)); |
335 | SV *neu = sv_2mortal (newSVpv ("select count(*) > 0 from ", 0)); |
274 | sv_catsv (neu, sql); |
336 | sv_catsv (neu, sql); |
275 | sv_catpv (neu, " limit 1"); |
337 | sv_catpv (neu, " limit 1"); |
276 | sql = neu; |
338 | sql = neu; |
277 | ix -= 6; /* sql_fetch */ |
339 | ix -= 4; /* sql_fetch */ |
278 | } |
340 | } |
279 | |
341 | |
280 | /* check cache for existing statement handle */ |
342 | /* check cache for existing statement handle */ |
281 | sth = lru_fetch (dbh, sql); |
343 | sth = lru_fetch (dbh, sql); |
282 | if (!sth) |
344 | if (!sth) |
… | |
… | |
290 | SPAGAIN; |
352 | SPAGAIN; |
291 | |
353 | |
292 | if (count != 1) |
354 | if (count != 1) |
293 | croak ("sql_exec: unable to prepare() statement '%s': %s", |
355 | croak ("sql_exec: unable to prepare() statement '%s': %s", |
294 | SvPV (sql, dc), |
356 | SvPV (sql, dc), |
295 | SvPV (get_sv ("DBI::errstr", TRUE), dc)); |
357 | SvPV (get_sv ("DBI::errstr", TRUE), dd)); |
296 | |
358 | |
297 | sth = POPs; |
359 | sth = POPs; |
298 | |
360 | |
|
|
361 | if (SvLEN (sql) < MAX_CACHED_STATEMENT_SIZE) |
299 | lru_store (dbh, sql, sth); |
362 | lru_store (dbh, sql, sth); |
300 | } |
363 | } |
301 | |
364 | |
302 | PUSHMARK (SP); |
365 | PUSHMARK (SP); |
303 | EXTEND (SP, items - arg + 1); |
366 | EXTEND (SP, items - arg + 1); |
304 | PUSHs (sth); |
367 | PUSHs (sth); |
305 | while (items > arg) |
368 | while (items > arg) |
306 | { |
369 | { |
|
|
370 | SV *sv = ST(arg); |
|
|
371 | /* we sv_mortalcopy magical values since DBI seems to have a memory |
|
|
372 | * leak when magical values are passed into execute(). |
|
|
373 | */ |
307 | PUSHs (maybe_upgrade_utf8 (ix & 1, ST(arg))); |
374 | PUSHs (maybe_upgrade_utf8 (ix & 1, SvMAGICAL(sv) ? sv_mortalcopy(sv) : sv)); |
308 | arg++; |
375 | arg++; |
309 | } |
376 | } |
310 | |
377 | |
311 | PUTBACK; |
378 | PUTBACK; |
312 | /* { static GV *execute; |
379 | /* { static GV *execute; |
… | |
… | |
317 | SPAGAIN; |
384 | SPAGAIN; |
318 | |
385 | |
319 | if (count != 1) |
386 | if (count != 1) |
320 | croak ("sql_exec: execute() didn't return any value ('%s'): %s", |
387 | croak ("sql_exec: execute() didn't return any value ('%s'): %s", |
321 | SvPV (sql, dc), |
388 | SvPV (sql, dc), |
322 | SvPV (get_sv ("DBI::errstr", TRUE), dc)); |
389 | SvPV (get_sv ("DBI::errstr", TRUE), dd)); |
323 | |
390 | |
324 | execute = POPs; |
391 | execute = POPs; |
325 | |
392 | |
326 | if (!SvTRUE (execute)) |
393 | if (!SvTRUE (execute)) |
327 | croak ("sql_exec: unable to execute statement '%s' (%s)", |
394 | croak ("sql_exec: unable to execute statement '%s' (%s)", |
328 | SvPV (sql, dc), |
395 | SvPV (sql, dc), |
329 | SvPV (get_sv ("DBI::errstr", TRUE), dc)); |
396 | SvPV (get_sv ("DBI::errstr", TRUE), dd)); |
330 | |
397 | |
331 | sv_setsv (GvSV(sql_exec), execute); |
398 | sv_setsv (GvSV(sql_exec), execute); |
332 | |
399 | |
333 | if (bind_first != bind_last) |
400 | if (bind_first != bind_last) |
334 | { |
401 | { |
335 | PUSHMARK (SP); |
402 | PUSHMARK (SP); |
336 | EXTEND (SP, bind_last - bind_first + 2); |
403 | EXTEND (SP, bind_last - bind_first + 2); |
337 | PUSHs (sth); |
404 | PUSHs (sth); |
338 | do { |
405 | do { |
|
|
406 | #if CAN_UTF8 |
|
|
407 | if (ix & 1) |
|
|
408 | SvUTF8_on (SvRV(ST(bind_first))); |
|
|
409 | #endif |
339 | PUSHs (ST(bind_first)); |
410 | PUSHs (ST(bind_first)); |
340 | bind_first++; |
411 | bind_first++; |
341 | } while (bind_first != bind_last); |
412 | } while (bind_first != bind_last); |
342 | |
413 | |
343 | PUTBACK; |
414 | PUTBACK; |
… | |
… | |
345 | SPAGAIN; |
416 | SPAGAIN; |
346 | |
417 | |
347 | if (count != 1) |
418 | if (count != 1) |
348 | croak ("sql_exec: bind_columns() didn't return any value ('%s'): %s", |
419 | croak ("sql_exec: bind_columns() didn't return any value ('%s'): %s", |
349 | SvPV (sql, dc), |
420 | SvPV (sql, dc), |
350 | SvPV (get_sv ("DBI::errstr", TRUE), dc)); |
421 | SvPV (get_sv ("DBI::errstr", TRUE), dd)); |
351 | |
422 | |
352 | if (!SvOK (POPs)) |
423 | if (!SvOK (TOPs)) |
353 | croak ("sql_exec: bind_columns() didn't return a true ('%s'): %s", |
424 | croak ("sql_exec: bind_columns() didn't return a true ('%s'): %s", |
354 | SvPV (sql, dc), |
425 | SvPV (sql, dc), |
355 | SvPV (get_sv ("DBI::errstr", TRUE), dc)); |
426 | SvPV (get_sv ("DBI::errstr", TRUE), dd)); |
|
|
427 | |
356 | } |
428 | POPs; |
|
|
429 | } |
357 | |
430 | |
358 | /* free our arguments from the stack */ |
431 | /* restore our arguments again */ |
359 | SP -= items; |
432 | SP -= items; |
360 | |
433 | |
361 | if ((ix & ~1) == 2) |
434 | if ((ix & ~1) == 2) |
362 | { /* sql_fetch */ |
435 | { /* sql_fetch */ |
363 | SV *row; |
436 | SV *row; |
… | |
… | |
382 | case G_VOID: |
455 | case G_VOID: |
383 | /* no thing */ |
456 | /* no thing */ |
384 | break; |
457 | break; |
385 | case G_SCALAR: |
458 | case G_SCALAR: |
386 | /* the first element */ |
459 | /* the first element */ |
387 | XPUSHs (maybe_force_utf8 (ix & 1, *av_fetch ((AV *)SvRV (row), 0, 1))); |
460 | XPUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, *av_fetch ((AV *)SvRV (row), 0, 1))); |
388 | break; |
461 | break; |
389 | case G_ARRAY: |
462 | case G_ARRAY: |
390 | av = (AV *)SvRV (row); |
463 | av = (AV *)SvRV (row); |
391 | count = AvFILL (av) + 1; |
464 | count = AvFILL (av) + 1; |
392 | EXTEND (SP, count); |
465 | EXTEND (SP, count); |
393 | for (arg = 0; arg < count; arg++) |
466 | for (arg = 0; arg < count; arg++) |
394 | PUSHs (maybe_force_utf8 (ix & 1, AvARRAY (av)[arg])); |
467 | PUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, AvARRAY (av)[arg])); |
395 | |
468 | |
396 | break; |
469 | break; |
397 | default: |
470 | default: |
398 | abort (); |
471 | abort (); |
399 | } |
472 | } |
… | |
… | |
424 | int columns = AvFILL ((AV *) SvRV (AvARRAY (av)[0])) + 1; /* columns? */ |
497 | int columns = AvFILL ((AV *) SvRV (AvARRAY (av)[0])) + 1; /* columns? */ |
425 | |
498 | |
426 | EXTEND (SP, count); |
499 | EXTEND (SP, count); |
427 | if (columns == 1) |
500 | if (columns == 1) |
428 | for (arg = 0; arg < count; arg++) |
501 | for (arg = 0; arg < count; arg++) |
429 | PUSHs (maybe_force_utf8 (ix & 1, AvARRAY ((AV *)SvRV (AvARRAY (av)[arg]))[0])); |
502 | PUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, AvARRAY ((AV *)SvRV (AvARRAY (av)[arg]))[0])); |
430 | else |
503 | else |
431 | for (arg = 0; arg < count; arg++) |
504 | for (arg = 0; arg < count; arg++) |
432 | PUSHs (maybe_force_utf8 (ix & 1, AvARRAY (av)[arg])); |
505 | PUSHs (mortalcopy_and_maybe_force_utf8 (ix & 1, AvARRAY (av)[arg])); |
433 | } |
506 | } |
434 | } |
507 | } |
435 | } |
508 | } |
436 | else |
509 | else |
437 | XPUSHs (sth); |
510 | XPUSHs (sth); |