File Coverage

FU.xs
Criterion Covered Total %
statement 36 140 25.7
branch 10 116 8.6
condition n/a
subroutine n/a
pod n/a
total 46 256 17.9


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include /* struct timespec & clock_gettime() */
4             #include /* strerror() */
5             #include /* inet_ntop(), inet_ntoa() */
6             #include /* send(), fd passing */
7             #include /* fd passing */
8             #include /* dlopen() etc */
9              
10              
11             #undef PERL_IMPLICIT_SYS
12             #define PERL_NO_GET_CONTEXT
13             #include "EXTERN.h"
14             #include "perl.h"
15             #include "XSUB.h"
16              
17             #ifndef av_push_simple
18             #define av_push_simple av_push
19             #endif
20             #ifndef BOOL_INTERNALS_sv_isbool_true
21             #define BOOL_INTERNALS_sv_isbool_true(x) SvTRUEx(x)
22             #endif
23             #ifndef newSV_true
24             #define newSV_true() newSVsv(&PL_sv_yes)
25             #endif
26             #ifndef newSV_false
27             #define newSV_false() newSVsv(&PL_sv_no)
28             #endif
29              
30             /* Disable key/value struct packing in khashl, so we can safely take a pointer
31             * to values inside the hash table. */
32             #define kh_packed
33              
34             #include "c/khashl.h"
35             #include "c/common.c"
36              
37             #include "c/compress.c"
38             #include "c/fcgi.c"
39             #include "c/fdpass.c"
40             #include "c/jsonfmt.c"
41             #include "c/jsonparse.c"
42             #include "c/xmlwr.c"
43              
44             #include "c/libpq.h"
45             #include "c/pgtypes.c"
46             #include "c/pgconn.c"
47             #include "c/pgst.c"
48              
49              
50             #define FUPG_CONN_COOKIE \
51             if (c->cookie) fu_confess("Invalid operation on the top-level connection while a transaction object exists")
52              
53             #define FUPG_TXN_COOKIE \
54             if (!t->cookie) fu_confess("Invalid operation on a transaction that has already been marked as done"); \
55             if (t->cookie != t->conn->cookie) fu_confess("Invalid operation on transaction while a subtransaction object exists")
56              
57             #define FUPG_ST_COOKIE \
58             if (st->cookie != st->conn->cookie) fu_confess("Invalid cross-transaction operation on statement object")
59              
60             #define FUPG_STFLAGS do {\
61             if (!ix) ix = FUPG_CACHE;\
62             if (items == 1 || SvTRUE(ST(1))) x->stflags |= ix; \
63             else x->stflags &= ~ix; \
64             } while(0)
65              
66             MODULE = FU
67              
68             PROTOTYPES: DISABLE
69              
70              
71             TYPEMAP: <
72             TYPEMAP
73             fufcgi * FUFCGI
74             fuxmlwr * FUXMLWR
75             fupg_conn * FUPG_CONN
76             fupg_txn * FUPG_TXN
77             fupg_st * FUPG_ST
78             fupg_copy * FUPG_COPY
79              
80             INPUT
81             FUFCGI
82             if (sv_derived_from($arg, \"FU::fcgi\")) $var = (fufcgi *)SvIVX(SvRV($arg));
83             else fu_confess(\"invalid FastCGI object\");
84              
85             FUXMLWR
86             if (sv_derived_from($arg, \"FU::XMLWriter\")) $var = (fuxmlwr *)SvIVX(SvRV($arg));
87             else fu_confess(\"invalid FU::XMLWriter object\");
88              
89             FUPG_CONN
90             if (sv_derived_from($arg, \"FU::Pg::conn\")) $var = (fupg_conn *)SvIVX(SvRV($arg));
91             else fu_confess(\"invalid connection object\");
92              
93             FUPG_TXN
94             if (sv_derived_from($arg, \"FU::Pg::txn\")) $var = (fupg_txn *)SvIVX(SvRV($arg));
95             else fu_confess(\"invalid transaction object\");
96              
97             FUPG_ST
98             if (sv_derived_from($arg, \"FU::Pg::st\")) $var = (fupg_st *)SvIVX(SvRV($arg));
99             else fu_confess(\"invalid statement object\");
100              
101             FUPG_COPY
102             if (sv_derived_from($arg, \"FU::Pg::copy\")) $var = (fupg_copy *)SvIVX(SvRV($arg));
103             else fu_confess(\"invalid COPY object\");
104             #"
105             EOT
106              
107              
108             MODULE = FU PACKAGE = FU::Util
109              
110             void to_bool(SV *val)
111             PROTOTYPE: $
112             CODE:
113 37           SvGETMAGIC(val);
114 37           int r = fu_2bool(aTHX_ val);
115 37 100         ST(0) = r < 0 ? &PL_sv_undef : r ? &PL_sv_yes : &PL_sv_no;
    100          
116              
117             void json_format(SV *val, ...)
118             CODE:
119 4735           ST(0) = fujson_fmt_xs(aTHX_ ax, items, val);
120              
121             void json_parse(SV *val, ...)
122             CODE:
123 708           ST(0) = fujson_parse_xs(aTHX_ ax, items, val);
124              
125             void gzip_lib()
126             PROTOTYPE:
127             CODE:
128 3           ST(0) = sv_2mortal(newSVpv(fugz_lib(), 0));
129              
130             void gzip_compress(IV level, SV *in)
131             CODE:
132 8           ST(0) = fugz_compress(aTHX_ level, in);
133              
134             void brotli_compress(IV level, SV *in)
135             CODE:
136 1           ST(0) = fubr_compress(aTHX_ level, in);
137              
138             void fdpass_send(int socket, int fd, SV *data)
139             CODE:
140             STRLEN buflen;
141 2           const char *buf = SvPVbyte(data, buflen);
142 2           ST(0) = sv_2mortal(newSViv(fufdpass_send(socket, fd, buf, buflen)));
143              
144             void fdpass_recv(int socket, UV len)
145             CODE:
146 4           XSRETURN(fufdpass_recv(aTHX_ ax, socket, len));
147              
148              
149              
150             MODULE = FU PACKAGE = FU::fcgi
151              
152             void new(int fd, int maxproc)
153             CODE:
154 57           fufcgi *ctx = safemalloc(sizeof(*ctx));
155 57           ctx->fd = fd;
156 57           ctx->maxproc = maxproc;
157 57           ctx->reqid = ctx->keepconn = ctx->len = ctx->off = 0;
158 57           ST(0) = fu_selfobj(ctx, "FU::fcgi");
159              
160             void read_req(fufcgi *ctx, SV *headers, SV *params)
161             CODE:
162 56           ST(0) = sv_2mortal(newSViv(fufcgi_read_req(aTHX_ ctx, headers, params)));
163 56           ctx->off = ctx->len = 0;
164              
165             void keepalive(fufcgi *ctx)
166             CODE:
167 0 0         ST(0) = ctx->keepconn ? &PL_sv_yes : &PL_sv_no;
168              
169             void print(fufcgi *ctx, SV *sv)
170             CODE:
171             STRLEN len;
172 11           const char *buf = SvPVbyte(sv, len);
173 11           fufcgi_print(aTHX_ ctx, buf, len);
174              
175             void flush(fufcgi *ctx)
176             CODE:
177 7           fufcgi_done(aTHX_ ctx);
178              
179             void DESTROY(fufcgi *ctx)
180             CODE:
181 57           safefree(ctx);
182              
183              
184              
185             MODULE = FU PACKAGE = FU::Pg
186              
187             void _load_libpq()
188             CODE:
189 4 50         if (!PQconnectdb) fupg_load();
190              
191             void lib_version()
192             CODE:
193 0           XSRETURN_IV(PQlibVersion());
194              
195             void connect(const char *pkg, const char *conninfo)
196             CODE:
197             (void)pkg;
198 0           ST(0) = fupg_connect(aTHX_ conninfo);
199              
200              
201              
202             MODULE = FU PACKAGE = FU::Pg::conn
203              
204             void server_version(fupg_conn *c)
205             CODE:
206 0           XSRETURN_IV(PQserverVersion(c->conn));
207              
208             void _debug_trace(fupg_conn *c, bool on)
209             CODE:
210 0 0         if (on) PQtrace(c->conn, stderr);
211 0           else PQuntrace(c->conn);
212 0           ST(0) = c->self;
213              
214             void query_trace(fupg_conn *c, SV *cb)
215             CODE:
216 0 0         if (c->trace) SvREFCNT_dec(c->trace);
217 0           SvGETMAGIC(cb);
218 0 0         c->trace = SvOK(cb) ? SvREFCNT_inc(cb) : NULL;
219              
220             void conn(fupg_conn *c)
221             CODE:
222 0           ST(0) = sv_newmortal();
223 0           sv_setrv_inc(ST(0), c->self);
224 0           sv_bless(ST(0), gv_stashpv("FU::Pg::conn", 0));
225              
226             void status(fupg_conn *c)
227             CODE:
228 0           ST(0) = sv_2mortal(newSVpv(fupg_conn_status(c), 0));
229              
230             void escape_literal(fupg_conn *c, SV *v)
231             CODE:
232             STRLEN len;
233 0           const char *str = SvPVutf8(v, len);
234 0           char *r = PQescapeLiteral(c->conn, str, len);
235 0 0         if (!r) fupg_conn_croak(c, "escapeLiteral");
236 0           ST(0) = newSVpvn_flags(r, strlen(r), SVf_UTF8|SVs_TEMP);
237 0           PQfreemem(r);
238              
239             void escape_identifier(fupg_conn *c, SV *v)
240             CODE:
241             STRLEN len;
242 0           const char *str = SvPVutf8(v, len);
243 0           char *r = PQescapeIdentifier(c->conn, str, len);
244 0 0         if (!r) fupg_conn_croak(c, "escapeIdentifier");
245 0           ST(0) = newSVpvn_flags(r, strlen(r), SVf_UTF8|SVs_TEMP);
246 0           PQfreemem(r);
247              
248             void cache(fupg_conn *x, ...)
249             ALIAS:
250             FU::Pg::conn::text_params = FUPG_TEXT_PARAMS
251             FU::Pg::conn::text_results = FUPG_TEXT_RESULTS
252             FU::Pg::conn::text = FUPG_TEXT
253             CODE:
254 0 0         FUPG_STFLAGS;
    0          
    0          
255              
256             void cache_size(fupg_conn *c, unsigned int n)
257             CODE:
258 0           c->prep_max = n;
259 0           fupg_prepared_prune(c);
260 0           XSRETURN(1);
261              
262             void disconnect(fupg_conn *c)
263             CODE:
264 0           fupg_conn_disconnect(c);
265              
266             void DESTROY(fupg_conn *c)
267             CODE:
268 0           fupg_conn_destroy(aTHX_ c);
269              
270             void txn(fupg_conn *c)
271             CODE:
272 0 0         FUPG_CONN_COOKIE;
273 0           ST(0) = fupg_conn_txn(aTHX_ c);
274              
275             void exec(fupg_conn *c, SV *sv)
276             CODE:
277 0 0         FUPG_CONN_COOKIE;
278 0           ST(0) = fupg_exec(aTHX_ c, SvPVutf8_nolen(sv));
279              
280             void sql(fupg_conn *c, SV *sv, ...)
281             CODE:
282 0 0         FUPG_CONN_COOKIE;
283 0           ST(0) = fupg_sql(aTHX_ c, c->stflags, SvPVutf8_nolen(sv), ax, items);
284              
285             void copy(fupg_conn *c, SV *sv)
286             CODE:
287 0 0         FUPG_CONN_COOKIE;
288 0           ST(0) = fupg_copy_exec(aTHX_ c, SvPVutf8_nolen(sv));
289              
290             void _set_type(fupg_conn *c, SV *name, SV *sendsv, SV *recvsv)
291             CODE:
292 0           fupg_set_type(aTHX_ c, name, sendsv, recvsv);
293 0           XSRETURN(1);
294              
295             void perl2bin(fupg_conn *c, int oid, SV *sv)
296             CODE:
297 0           ST(0) = fupg_perl2bin(aTHX_ c, oid, sv);
298              
299             void bin2perl(fupg_conn *c, int oid, SV *sv)
300             CODE:
301 0           ST(0) = fupg_bin2perl(aTHX_ c, oid, sv);
302              
303             void bin2text(fupg_conn *c, ...)
304             CODE:
305 0           XSRETURN(fupg_bintext(aTHX_ c, 0, ax, items));
306              
307             void text2bin(fupg_conn *c, ...)
308             CODE:
309 0           XSRETURN(fupg_bintext(aTHX_ c, 1, ax, items));
310              
311              
312             MODULE = FU PACKAGE = FU::Pg::txn
313              
314             void DESTROY(fupg_txn *t)
315             CODE:
316 0           fupg_txn_destroy(aTHX_ t);
317              
318             void cache(fupg_txn *x, ...)
319             ALIAS:
320             FU::Pg::txn::text_params = FUPG_TEXT_PARAMS
321             FU::Pg::txn::text_results = FUPG_TEXT_RESULTS
322             FU::Pg::txn::text = FUPG_TEXT
323             CODE:
324 0 0         FUPG_STFLAGS;
    0          
    0          
325              
326             void conn(fupg_txn *t)
327             CODE:
328 0           ST(0) = sv_newmortal();
329 0           sv_setrv_inc(ST(0), t->conn->self);
330 0           sv_bless(ST(0), gv_stashpv("FU::Pg::conn", 0));
331              
332             void status(fupg_txn *t)
333             CODE:
334 0           ST(0) = sv_2mortal(newSVpv(fupg_txn_status(t), 0));
335              
336             void txn(fupg_txn *t)
337             CODE:
338 0 0         FUPG_TXN_COOKIE;
    0          
339 0           ST(0) = fupg_txn_txn(aTHX_ t);
340              
341             void commit(fupg_txn *t)
342             CODE:
343 0 0         FUPG_TXN_COOKIE;
    0          
344 0           fupg_txn_commit(t);
345              
346             void rollback(fupg_txn *t)
347             CODE:
348 0 0         FUPG_TXN_COOKIE;
    0          
349 0           fupg_txn_rollback(t);
350              
351             void exec(fupg_txn *t, SV *sv)
352             CODE:
353 0 0         FUPG_TXN_COOKIE;
    0          
354 0           ST(0) = fupg_exec(aTHX_ t->conn, SvPVutf8_nolen(sv));
355              
356             void sql(fupg_txn *t, SV *sv, ...)
357             CODE:
358 0 0         FUPG_TXN_COOKIE;
    0          
359 0           ST(0) = fupg_sql(aTHX_ t->conn, t->stflags, SvPVutf8_nolen(sv), ax, items);
360              
361             # XXX: The copy object should probably keep a ref on the transaction
362             void copy(fupg_txn *t, SV *sv)
363             CODE:
364 0 0         FUPG_TXN_COOKIE;
    0          
365 0           ST(0) = fupg_copy_exec(aTHX_ t->conn, SvPVutf8_nolen(sv));
366              
367              
368              
369             MODULE = FU PACKAGE = FU::Pg::st
370              
371             void cache(fupg_st *x, ...)
372             ALIAS:
373             FU::Pg::st::text_params = FUPG_TEXT_PARAMS
374             FU::Pg::st::text_results = FUPG_TEXT_RESULTS
375             FU::Pg::st::text = FUPG_TEXT
376             CODE:
377 0 0         if (ix == 0 && x->prepared) fu_confess("Invalid attempt to change statement configuration after it has already been prepared or executed");
    0          
378 0 0         FUPG_STFLAGS;
    0          
    0          
379 0           XSRETURN(1);
380              
381             void exec(fupg_st *st)
382             CODE:
383 0 0         FUPG_ST_COOKIE;
384 0           ST(0) = fupg_st_exec(aTHX_ st);
385              
386             void val(fupg_st *st)
387             CODE:
388 0 0         FUPG_ST_COOKIE;
389 0           ST(0) = fupg_st_val(aTHX_ st);
390              
391             void rowl(fupg_st *st)
392             CODE:
393 0 0         FUPG_ST_COOKIE;
394 0           XSRETURN(fupg_st_rowl(aTHX_ st, ax));
395              
396             void rowa(fupg_st *st)
397             CODE:
398 0 0         FUPG_ST_COOKIE;
399 0           ST(0) = fupg_st_rowa(aTHX_ st);
400              
401             void rowh(fupg_st *st)
402             CODE:
403 0 0         FUPG_ST_COOKIE;
404 0           ST(0) = fupg_st_rowh(aTHX_ st);
405              
406             void alla(fupg_st *st)
407             CODE:
408 0 0         FUPG_ST_COOKIE;
409 0           ST(0) = fupg_st_alla(aTHX_ st);
410              
411             void allh(fupg_st *st)
412             CODE:
413 0 0         FUPG_ST_COOKIE;
414 0           ST(0) = fupg_st_allh(aTHX_ st);
415              
416             void flat(fupg_st *st)
417             CODE:
418 0 0         FUPG_ST_COOKIE;
419 0           ST(0) = fupg_st_flat(aTHX_ st);
420              
421             void kvv(fupg_st *st)
422             CODE:
423 0 0         FUPG_ST_COOKIE;
424 0           ST(0) = fupg_st_kvv(aTHX_ st);
425              
426             void kva(fupg_st *st)
427             CODE:
428 0 0         FUPG_ST_COOKIE;
429 0           ST(0) = fupg_st_kva(aTHX_ st);
430              
431             void kvh(fupg_st *st)
432             CODE:
433 0 0         FUPG_ST_COOKIE;
434 0           ST(0) = fupg_st_kvh(aTHX_ st);
435              
436             void param_types(fupg_st *st)
437             CODE:
438 0 0         FUPG_ST_COOKIE;
439 0           ST(0) = fupg_st_param_types(aTHX_ st);
440              
441             void param_values(fupg_st *st);
442             CODE:
443 0           ST(0) = fupg_st_param_values(aTHX_ st);
444              
445             void columns(fupg_st *st)
446             CODE:
447 0 0         FUPG_ST_COOKIE;
448 0           ST(0) = fupg_st_columns(aTHX_ st);
449              
450             void nrows(fupg_st *st)
451             CODE:
452 0 0         ST(0) = st->result ? sv_2mortal(newSViv(PQntuples(st->result))) : &PL_sv_undef;
453              
454             void query(fupg_st *st)
455             CODE:
456 0           ST(0) = newSVpvn_flags(st->query, strlen(st->query), SVs_TEMP|SVf_UTF8);
457              
458             void exec_time(fupg_st *st)
459             CODE:
460 0 0         ST(0) = st->exectime <= 0 ? &PL_sv_undef : sv_2mortal(newSVnv(st->exectime));
461              
462             void prepare_time(fupg_st *st)
463             CODE:
464 0 0         ST(0) = !st->prepared ? &PL_sv_undef : sv_2mortal(newSVnv(st->preptime));
465              
466             void get_cache(fupg_st *st)
467             ALIAS:
468             FU::Pg::st::get_text_params = FUPG_TEXT_PARAMS
469             FU::Pg::st::get_text_results = FUPG_TEXT_RESULTS
470             CODE:
471 0 0         if (!ix) ix = FUPG_CACHE;
472 0 0         ST(0) = st->stflags & ix ? &PL_sv_yes : &PL_sv_no;
473              
474             void DESTROY(fupg_st *st)
475             CODE:
476 0           fupg_st_destroy(aTHX_ st);
477              
478              
479             MODULE = FU PACKAGE = FU::Pg::copy
480              
481             void write(fupg_copy *c, SV *sv)
482             CODE:
483 0           fupg_copy_write(aTHX_ c, sv);
484              
485             void read(fupg_copy *c)
486             CODE:
487 0           ST(0) = fupg_copy_read(aTHX_ c, 0);
488              
489             void is_binary(fupg_copy *c)
490             CODE:
491 0 0         ST(0) = c->bin ? &PL_sv_yes : &PL_sv_no;
492              
493             void close(fupg_copy *c)
494             CODE:
495 0           fupg_copy_close(aTHX_ c, 0);
496              
497             void DESTROY(fupg_copy *c)
498             CODE:
499 0           fupg_copy_destroy(aTHX_ c);
500              
501              
502             MODULE = FU PACKAGE = FU::XMLWriter
503              
504             void _new()
505             CODE:
506 25           ST(0) = fuxmlwr_new(aTHX);
507              
508             void _done(fuxmlwr *wr)
509             CODE:
510 21           ST(0) = sv_2mortal(fustr_done(&wr->out));
511 21           fustr_init(&wr->out, NULL, SIZE_MAX);
512              
513             void lit_(SV *sv)
514             CODE:
515 4 100         if (!fuxmlwr_tail) fu_confess("No active FU::XMLWriter instance");
516             STRLEN len;
517 3           const char *buf = SvPVutf8(sv, len);
518 3           fustr_write(&fuxmlwr_tail->out, buf, len);
519              
520             void txt_(SV *sv)
521             CODE:
522 4 100         if (!fuxmlwr_tail) fu_confess("No active FU::XMLWriter instance");
523 3           fuxmlwr_escape(aTHX_ fuxmlwr_tail, sv);
524              
525             void tag_(SV *sv, ...)
526             CODE:
527 16 50         if (!fuxmlwr_tail) fu_confess("No active FU::XMLWriter instance");
528             STRLEN len;
529 16           const char *tagname = SvPV(sv, len);
530 16           fuxmlwr_isname(tagname);
531 12           fuxmlwr_tag(aTHX_ fuxmlwr_tail, ax, 1, items, 0, tagname, len);
532              
533             INCLUDE_COMMAND: $^X -e '$FU::XMLWriter::XSPRINT=1; require "./FU/XMLWriter.pm"'
534              
535             void DESTROY(fuxmlwr *wr)
536             CODE:
537 25           fuxmlwr_destroy(aTHX_ wr);