rpm  5.4.10
rpmsql.c
Go to the documentation of this file.
1 #include "system.h"
2 
3 #include <popt.h>
4 
5 #define _RPMIOB_INTERNAL /* rpmiobSlurp */
6 #include "rpmio_internal.h" /* XXX fdGetFILE */
7 #include <rpmmacro.h>
8 #include <rpmdir.h>
9 #include <rpmurl.h>
10 #include <mire.h>
11 
12 #if defined(WITH_DBSQL)
13 #include <dbsql.h>
14 #elif defined(WITH_SQLITE)
15 #define SQLITE_OS_UNIX 1
16 #define SQLITE_THREADSAFE 1
17 #define SQLITE_THREAD_OVERRIDE_LOCK -1
18 #define SQLITE_TEMP_STORE 1
19 #include <sqlite3.h>
20 #endif /* WITH_SQLITE */
21 
22 #define _RPMSQL_INTERNAL
23 #define _RPMVT_INTERNAL
24 #define _RPMVC_INTERNAL
25 #include <rpmsql.h>
26 
27 #ifdef NOTYET /* XXX FIXME */
28 #include <editline/readline.h>
29 #elif defined(HAVE_READLINE) && HAVE_READLINE==1
30 # include <readline/readline.h>
31 # include <readline/history.h>
32 #endif
33 
34 # define readline(sql, p) local_getline(sql, p)
35 # define add_history(X)
36 # define read_history(X)
37 # define write_history(X)
38 # define stifle_history(X)
39 
40 #include "debug.h"
41 
42 /*@unchecked@*/
43 int _rpmsql_debug = 0;
44 
45 /*@unchecked@*/
46 int _rpmvt_debug = 0;
47 
48 /*@unchecked@*/
49 int _rpmvc_debug = 0;
50 
51 /*@unchecked@*/ /*@relnull@*/
53 
54 /*@unchecked@*/
55 volatile int _rpmsqlSeenInterrupt;
56 
57 #if defined(WITH_SQLITE)
58 /*@unchecked@*/
59 static struct rpmsql_s _sql;
60 #endif /* defined(WITH_SQLITE) */
61 
62 /*==============================================================*/
63 
64 #define VTDBG(_vt, _l) if ((_vt)->debug) fprintf _l
65 #define VTDBGNOISY(_vt, _l) if ((_vt)->debug < 0) fprintf _l
66 
70 static void rpmvtFini(void * _VT)
71  /*@globals fileSystem @*/
72  /*@modifies *_VT, fileSystem @*/
73 {
74  struct rpmVT_s * VT = _VT;
75  rpmvt vt = &VT->vt;
76 
77 
78 VTDBGNOISY(vt, (stderr, "==> %s(%p)\n", __FUNCTION__, vt));
79  vt->argv = argvFree(vt->argv);
80  vt->argc = 0;
81  vt->fields = argvFree(vt->fields);
82  vt->nfields = 0;
83  vt->cols = argvFree(vt->cols);
84  vt->ncols = 0;
85  vt->av = argvFree(vt->av);
86  vt->ac = 0;
87 }
88 
89 /*@unchecked@*/ /*@only@*/ /*@null@*/
91 
92 static rpmvt rpmvtGetPool(/*@null@*/ rpmioPool pool)
93  /*@globals _rpmvtPool, fileSystem @*/
94  /*@modifies pool, _rpmvtPool, fileSystem @*/
95 {
96  struct rpmVT_s * VT;
97 
98  if (_rpmvtPool == NULL) {
99  _rpmvtPool = rpmioNewPool("vt", sizeof(*VT), -1, _rpmvt_debug,
100  NULL, NULL, rpmvtFini);
101  pool = _rpmvtPool;
102  }
103  VT = (struct rpmVT_s *) rpmioGetPool(pool, sizeof(*VT));
104  memset(((char *)VT)+sizeof(VT->_item), 0, sizeof(*VT)-sizeof(VT->_item));
105  return &VT->vt;
106 }
107 
108 rpmvt rpmvtNew(void * db, void * pModule, const char *const * argv, rpmvd vd)
109 {
110  rpmvt vt = rpmvtLink(rpmvtGetPool(_rpmvtPool));
111 
112  vt->db = db;
113  (void) argvAppend(&vt->argv, (ARGV_t) argv);
114  vt->argc = argvCount(vt->argv);
115  if (vd->split && vd->parse && *vd->parse) {
116  char * parse = rpmExpand(vd->parse, NULL);
117  int xx;
118  xx = argvSplit(&vt->fields, parse, vd->split);
119 assert(xx == 0);
120  vt->nfields = argvCount(vt->fields);
121  parse = _free(parse);
122  }
123 
124  vt->av = NULL;
125  vt->ac = 0;
126 
127  vt->vd = vd;
128  vt->debug = _rpmvt_debug;
129 
130 VTDBG(vt, (stderr, "\tdbpath: %s\n", vd->dbpath));
131 VTDBG(vt, (stderr, "\tprefix: %s\n", vd->prefix));
132 VTDBG(vt, (stderr, "\t split: %s\n", vd->split));
133 VTDBG(vt, (stderr, "\t parse: %s\n", vd->parse));
134 VTDBG(vt, (stderr, "\t regex: %s\n", vd->regex));
135 
136  return vt;
137 }
138 
139 /*==============================================================*/
140 
141 #if defined(WITH_SQLITE)
142 
143 typedef struct key_s {
144  const char * k;
145  uint32_t v;
146 } KEY;
147 static KEY sqlTypes[] = {
148  { "blob", SQLITE_BLOB },
149  { "float", SQLITE_FLOAT },
150  { "int", SQLITE_INTEGER },
151  { "integer",SQLITE_INTEGER },
152  { "null", SQLITE_NULL },
153  { "text", SQLITE_TEXT },
154 };
155 static size_t nsqlTypes = sizeof(sqlTypes) / sizeof(sqlTypes[0]);
156 
157 static const char * hasSqlType(const char * s)
158 {
159  int i;
160  for (i = 0; i < (int)nsqlTypes; i++) {
161  const char * k = sqlTypes[i].k;
162  const char * se = strcasestr(s, k);
163  if (se == NULL || se <= s || se[-1] != ' ')
164  continue;
165  se += strlen(k);
166  if (*se && *se != ' ')
167  continue;
168  return se;
169  }
170  return NULL;
171 }
172 
173 static char * _rpmvtJoin(const char * a, const char ** argv, const char * z)
174 {
175  static const char _type[] = " TEXT";
176  const char ** av;
177  size_t na = (sizeof("\t")-1) + (a ? strlen(a) : 0);
178  size_t nb = 0;
179  size_t nz = (z ? strlen(z) : 0) + strlen(_type) + (sizeof(",\n")-1);
180  char *t, *te;
181 
182  for (av = argv; *av != NULL; av++)
183  nb += na + strlen(*av) + nz;
184 
185  te = t = xmalloc(nb + 1);
186  for (av = argv; *av != NULL; av++) {
187  *te++ = '\t';
188  te = stpcpy(te, a);
189  te = stpcpy(te, *av);
190  if (hasSqlType(*av) == NULL)
191  te = stpcpy(te, _type);
192  te = stpcpy(te, z);
193  *te++ = ',';
194  *te++ = '\n';
195  }
196  *te = '\0';
197 
198  return t;
199 }
200 
201 static char * _rpmvtAppendCols(rpmvt vt, const char ** av)
202 {
203  char * h = _rpmvtJoin("", av, "");
204  int xx = argvAppend(&vt->cols, av);
205  char * u;
206  char * hu;
207  /* XXX permit user column overrides w/o a argv[3] selector. */
208  rpmvd vd = vt->vd;
209  int fx = (vd->fx == 3 ? 3 : 4);
210 
211  av = (const char **) (vt->argc > fx ? &vt->argv[fx] : vt->fields);
212 assert(av);
213  u = _rpmvtJoin("", av, "");
214  u[strlen(u)-2] = ' '; /* XXX nuke the final comma */
215  xx = argvAppend(&vt->cols, av);
216 
217 #define dbN vt->argv[1]
218 #define tblN vt->argv[2]
219  hu = rpmExpand("CREATE TABLE ", dbN, ".", tblN, " (\n", h, u, ");", NULL);
220 #undef dbN
221 #undef tblN
222 
223  u = _free(u);
224  h = _free(h);
225 
226 VTDBG(vt, (stderr, "%s\n", hu));
227  return hu;
228 }
229 
230 int rpmvtLoadArgv(rpmvt vt, rpmvt * vtp)
231 {
232  sqlite3 * db = (sqlite3 *) vt->db;
233  rpmvd vd = vt->vd;
234 
235  static const char * hidden[] = { "path HIDDEN", "id HIDDEN", NULL };
236  const char * hu;
237 
238  char * uri = NULL;
239  struct stat sb;
240 
241  const char * fn = NULL;
242 
243  int rc = SQLITE_OK;
244  int xx;
245 
246 VTDBG(vt, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, vt, vtp));
247 if (vt->debug)
248 argvPrint("vt->argv", (ARGV_t)vt->argv, NULL);
249 
250  /* Set the columns in the schema. */
251  hu = _rpmvtAppendCols(vt, hidden);
252  rc = rpmsqlCmd(NULL, "declare_vtab", db,
253  sqlite3_declare_vtab(db, hu));
254  hu = _free(hu);
255 
256  if (vt->argv[3]) {
257  /* XXX slice out the quotes that sqlite passes through ... */
258  static char _quotes[] = "'\"";
259  int quoted = (strchr(_quotes, *vt->argv[3]) != NULL);
260  const char * prefix;
261  const char * path = NULL;
262  /* XXX Prefer user override to global prefix (if absolute path). */
263  (void) urlPath(vt->argv[3]+quoted, &path);
264  prefix = (*path != '/' && vd->prefix ? vd->prefix : "");
265  uri = rpmGetPath(prefix, path, NULL);
266  uri[strlen(uri)-quoted] = '\0';
267  } else
268  uri = rpmGetPath(vd->prefix, fn, NULL);
269 
270  (void) urlPath(uri, (const char **) &fn);
271 
272  if (!strcasecmp(vt->argv[0], "nixdb")) {
273  const char * out = rpmExpand("%{sql ", vd->dbpath, ":",
274  "select path from ValidPaths where glob('", fn, "', path);",
275  "}", NULL);
276  (void) argvSplit(&vt->av, out, "\n");
277  out = _free(out);
278  } else
279 
280  if (!strcasecmp(vt->argv[0], "Env")) {
281  int fx = 4; /* XXX user column overrides? */
282 if (vt->debug)
283 fprintf(stderr, " ENV: getenv(%p[%d])\n", &vt->argv[fx], argvCount(&vt->argv[fx]));
284  /* XXX permit glob selector filtering from argv[3]? */
285  xx = argvAppend(&vt->av, (ARGV_t)environ);
286  } else
287 
288  if (fn[0] == '/') {
289 if (vt->debug)
290 fprintf(stderr, "*** uri %s fn %s\n", uri, fn);
291  if (Glob_pattern_p(uri, 0)) { /* XXX uri */
292  const char ** av = NULL;
293  int ac = 0;
294 
295  xx = rpmGlob(uri, &ac, &av); /* XXX uri */
296 if (vt->debug)
297 fprintf(stderr, "GLOB: %d = Glob(%s) av %p[%d]\n", xx, uri, av, ac);
298  if (xx)
299  rc = SQLITE_NOTFOUND; /* XXX */
300  else
301  xx = argvAppend(&vt->av, (ARGV_t)av);
302  av = argvFree(av);
303  } else
304  if (uri[strlen(uri)-1] == '/') {
305  DIR * dir = Opendir(uri);
306  struct dirent * dp;
307 if (vt->debug)
308 fprintf(stderr, " DIR: %p = Opendir(%s)\n", dir, uri);
309  if (dir == NULL)
310  rc = SQLITE_NOTFOUND; /* XXX */
311  else
312  while ((dp = Readdir(dir)) != NULL) {
313  if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
314  continue;
315  fn = rpmGetPath(uri, "/", dp->d_name, NULL);
316  xx = argvAdd(&vt->av, fn);
317  fn = _free(fn);
318  }
319  if (dir) xx = Closedir(dir);
320  } else
321  if (!Lstat(uri, &sb)) {
322  rpmiob iob = NULL;
323  xx = rpmiobSlurp(uri, &iob);
324 if (vt->debug)
325 fprintf(stderr, "FILE: %d = Slurp(%s)\n", xx, uri);
326  if (!xx)
327  xx = argvSplit(&vt->av, rpmiobStr(iob), "\n");
328  else
329  rc = SQLITE_NOTFOUND; /* XXX */
330  iob = rpmiobFree(iob);
331  } else
332  rc = SQLITE_NOTFOUND; /* XXX */
333  } else {
334  xx = argvAppend(&vt->av, (ARGV_t)&vt->argv[3]);
335 if (vt->debug)
336 fprintf(stderr, "LIST: %d = Append(%p[%d])\n", xx, &vt->argv[3], argvCount(&vt->argv[3]));
337  }
338 
339  vt->ac = argvCount((ARGV_t)vt->av);
340 
341  uri = _free(uri);
342 
343 if (vt->debug)
344 argvPrint("vt->av", (ARGV_t)vt->av, NULL);
345 
346  if (vtp) {
347  if (!rc)
348  *vtp = (rpmvt) vt;
349  else {
350  *vtp = NULL;
351  (void) rpmvtFree(vt);
352  vt = NULL;
353  }
354  } else {
355  vt = rpmvtFree(vt);
356  vt = NULL;
357  }
358 
359 VTDBG(vt, (stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, vt, vtp, rc));
360 
361  return rc;
362 }
363 
364 /*==============================================================*/
365 
366 static struct rpmvd_s _argVD = {
367 };
368 
369 int rpmvtCreate(void * _db, void * pAux,
370  int argc, const char *const * argv,
371  rpmvt * vtp, char ** pzErr)
372 {
373  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_argVD), vtp);
374 }
375 
376 int rpmvtConnect(void * _db, void * pAux,
377  int argc, const char *const * argv,
378  rpmvt * vtp, char ** pzErr)
379 {
380  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_argVD), vtp);
381 }
382 
383 #ifdef NOTYET
384 static void dumpInfo(const char * msg, const struct sqlite3_index_info * s)
385 {
386 fprintf(stderr, "--------------------- %s\n", (msg ? msg : ""));
387 #define _PRT(f,v) fprintf(stderr, "%20s: " #f "\n", #v, s->v)
388  _PRT(%p, aConstraintUsage);
389  _PRT(%d, idxNum);
390  _PRT(%s, idxStr);
391  _PRT(%d, needToFreeIdxStr);
392  _PRT(%d, orderByConsumed);
393  _PRT(%g, estimatedCost);
394 #undef _PRT
395 }
396 #endif
397 
398 int rpmvtBestIndex(rpmvt vt, void * _pInfo)
399 {
400  sqlite3_index_info * pInfo = (sqlite3_index_info *) _pInfo;
401  int rc = SQLITE_OK;
402 #ifdef NOTYET
403  int i;
404 #endif
405 
406 VTDBG(vt, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, vt, pInfo));
407 
408 #ifdef NOTYET
409  if (pInfo->aConstraint)
410  for (i = 0; i < pInfo->nConstraint; i++) {
411  const struct sqlite3_index_constraint * p = pInfo->aConstraint + i;
412  fprintf(stderr, "\tcol %s(%d) 0x%02x 0x%02x\n", vt->cols[p->iColumn], p->iColumn,
413  p->op, p->usable);
414  }
415  if (pInfo->aOrderBy)
416  for (i = 0; i < pInfo->nOrderBy; i++) {
417  const struct sqlite3_index_orderby * p = pInfo->aOrderBy + i;
418  fprintf(stderr, "\tcol %s(%d) %s\n", vt->cols[p->iColumn], p->iColumn,
419  (p->desc ? "DESC" : "ASC"));
420  }
421  dumpInfo(__FUNCTION__, pInfo);
422 #endif
423 
424 VTDBG(vt, (stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, vt, pInfo, rc));
425 
426  return rc;
427 }
428 
429 int rpmvtDisconnect(rpmvt vt)
430 {
431  (void) rpmvtFree(vt);
432  return 0; /* SQLITE_OK */
433 }
434 
435 int rpmvtDestroy(rpmvt vt)
436 {
437  (void) rpmvtFree(vt);
438  return 0; /* SQLITE_OK */
439 }
440 
441 static const char * dumpArg(rpmvArg _v)
442 {
443  static char buf[BUFSIZ];
444  char * b = buf;
445  size_t nb = sizeof(buf);
446  sqlite3_value * v = (sqlite3_value *) _v;
447  int vtype = sqlite3_value_type(v);
448  unsigned long long ll;
449  double d;
450  const void * p;
451  const char * s;
452 
453  snprintf(b, nb, "%p(%d)", v, vtype);
454  nb -= strlen(b);
455  b += strlen(b);
456 
457  switch (vtype) {
458  case SQLITE_INTEGER:
459  ll = (unsigned long long) sqlite3_value_int64(v);
460  snprintf(b, nb, " INT %lld", ll);
461  break;
462  case SQLITE_FLOAT:
463  d = sqlite3_value_double(v);
464  snprintf(b, nb, " REAL %g", d);
465  break;
466  case SQLITE_BLOB:
467  p = sqlite3_value_blob(v);
468  snprintf(b, nb, " BLOB %p", p);
469  break;
470  case SQLITE_NULL:
471  snprintf(b, nb, " NULL");
472  break;
473  case SQLITE_TEXT:
474  s = (const char *)sqlite3_value_text(v);
475  snprintf(b, nb, " TEXT \"%s\"", s);
476  break;
477  default:
478  snprintf(b, nb, " UNKNOWN");
479  break;
480  }
481 
482  return buf;
483 }
484 
485 static void dumpArgv(const char * msg, int argc, rpmvArg * _argv)
486 {
487  if (argc > 0 && _argv) {
488  int i;
489  fprintf(stderr, "--------------------- %s\n", (msg ? msg : ""));
490  for (i = 0; i < argc; i++)
491  fprintf(stderr, "\targv[%d] %s\n", i, dumpArg(_argv[i]));
492  }
493 }
494 
495 int rpmvtUpdate(rpmvt vt, int argc, rpmvArg * _argv, int64_t * pRowid)
496 {
497  sqlite3_value ** argv = (sqlite3_value **) _argv;
498  int rc = SQLITE_OK;
499 
500 VTDBG(vt, (stderr, "--> %s(%p,%p[%u],%p)\n", __FUNCTION__, vt, argv, (unsigned)argc, pRowid));
501 
502  if (argc == 0 || argv == NULL) {
503 if (vt->debug)
504 dumpArgv("ERROR", argc, _argv);
505  rc = SQLITE_NOTFOUND; /* XXX */
506  } else
507  if (argc == 1) {
508 VTDBG(vt, (stderr, "\tDELETE ROW 0x%llx\n", *(unsigned long long *)argv[0]));
509  } else
510  if (argv[0] == NULL) {
511 VTDBG(vt, (stderr, "\tADD ROW 0x%llx\n", *(unsigned long long *)argv[1]));
512 if (vt->debug)
513 dumpArgv("ADD ROW", argc, _argv);
514  } else
515  if (argv[0] == argv[1]) {
516 VTDBG(vt, (stderr, "\tUPDATE ROW 0x%llx\n", *(unsigned long long *)argv[1]));
517 if (vt->debug)
518 dumpArgv("UPDATE argv", argc-2, _argv+2);
519  } else {
520 VTDBG(vt, (stderr, "\tREPLACE ROW 0x%llx from 0x%llx\n",
521  *(unsigned long long *)argv[0], *(unsigned long long *)argv[1]));
522 if (vt->debug)
523 dumpArgv("REPLACE argv", argc-2, _argv+2);
524  }
525 
526 VTDBG(vt, (stderr, "<-- %s(%p,%p[%u],%p) rc %d\n", __FUNCTION__, vt, argv, (unsigned)argc, pRowid, rc));
527  return rc;
528 }
529 
530 int rpmvtBegin(rpmvt vt)
531 {
532  int rc = SQLITE_OK;
533 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc));
534  return rc;
535 }
536 
537 int rpmvtSync(rpmvt vt)
538 {
539  int rc = SQLITE_OK;
540 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc));
541  return rc;
542 }
543 
544 int rpmvtCommit(rpmvt vt)
545 {
546  int rc = SQLITE_OK;
547 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc));
548  return rc;
549 }
550 
551 int rpmvtRollback(rpmvt vt)
552 {
553  int rc = SQLITE_OK;
554 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc));
555  return rc;
556 }
557 
558 int rpmvtFindFunction(rpmvt vt, int nArg, const char * zName,
559  void (**pxFunc)(void *, int, rpmvArg *),
560  void ** ppArg)
561 {
562  int rc = SQLITE_OK;
563 VTDBG(vt, (stderr, "<-- %s(%p,%d,%s,%p,%p) rc %d\n", __FUNCTION__, vt, nArg, zName, pxFunc, ppArg, rc));
564  return rc;
565 }
566 
567 int rpmvtRename(rpmvt vt, const char * zNew)
568 {
569  int rc = SQLITE_OK;
570 VTDBG(vt, (stderr, "<-- %s(%p,%s) rc %d\n", __FUNCTION__, vt, zNew, rc));
571  return rc;
572 }
573 #endif /* defined(WITH_SQLITE) */
574 
575 /*==============================================================*/
576 
577 #define VCDBG(_vc, _l) if ((_vc)->debug) fprintf _l
578 #define VCDBGNOISY(_vc, _l) if ((_vc)->debug < 0) fprintf _l
579 
583 static void rpmvcFini(void * _VC)
584  /*@globals fileSystem @*/
585  /*@modifies *_VC, fileSystem @*/
586 {
587  struct rpmVC_s * VC = _VC;
588  rpmvc vc = &VC->vc;
589 
590 VCDBGNOISY(vc, (stderr, "==> %s(%p)\n", __FUNCTION__, vc));
591  if (vc->vt)
592  (void) rpmvtFree(vc->vt);
593  vc->vt = NULL;
594 }
595 
596 /*@unchecked@*/ /*@only@*/ /*@null@*/
598 
599 static rpmvc rpmvcGetPool(/*@null@*/ rpmioPool pool)
600  /*@globals _rpmvcPool, fileSystem @*/
601  /*@modifies pool, _rpmvcPool, fileSystem @*/
602 {
603  struct rpmVC_s * VC;
604 
605  if (_rpmvcPool == NULL) {
606  _rpmvcPool = rpmioNewPool("vc", sizeof(*VC), -1, _rpmvc_debug,
607  NULL, NULL, rpmvcFini);
608  pool = _rpmvcPool;
609  }
610  VC = (struct rpmVC_s *) rpmioGetPool(pool, sizeof(*VC));
611  memset(((char *)VC)+sizeof(VC->_item), 0, sizeof(*VC)-sizeof(VC->_item));
612  return &VC->vc;
613 }
614 
615 rpmvc rpmvcNew(rpmvt vt, int nrows)
616 {
617  rpmvc vc = rpmvcLink(rpmvcGetPool(_rpmvcPool));
618 
619  vc->vt = rpmvtLink(vt);
620  vc->ix = -1;
621 
622  vc->debug = _rpmvc_debug;
623  vc->nrows = nrows;
624  vc->vd = NULL;
625 
626  return vc;
627 }
628 
629 /*==============================================================*/
630 
631 #if defined(WITH_SQLITE)
632 
633 int rpmvcOpen(rpmvt vt, rpmvc * vcp)
634 {
635  rpmvc vc = rpmvcNew(vt, vt->ac);
636  int rc = SQLITE_OK;
637 
638  if (vcp)
639  *vcp = vc;
640  else
641  (void) rpmvcFree(vc);
642 
643  return rc;
644 }
645 
646 int rpmvcClose(rpmvc vc)
647 {
648  /* XXX unnecessary but the debug spewage is confusing. */
649  if (vc->vt)
650  (void) rpmvtFree(vc->vt);
651  vc->vt = NULL;
652  (void) rpmvcFree(vc);
653  return 0; /* SQLITE_OK */
654 }
655 
656 int rpmvcFilter(rpmvc vc, int idxNum, const char * idxStr,
657  int argc, rpmvArg * _argv)
658 {
659  sqlite3_value ** argv = (sqlite3_value **) _argv;
660  int rc = SQLITE_OK;
661 
662 VCDBGNOISY(vc, (stderr, "--> %s(%p,%d,%s,%p[%u]) [%d:%d]\n", __FUNCTION__, vc, idxNum, idxStr, argv, (unsigned)argc, vc->ix, vc->nrows));
663 dumpArgv(__FUNCTION__, argc, _argv);
664 
665  if (vc->nrows > 0)
666  vc->ix = 0;
667 
668 VCDBGNOISY(vc, (stderr, "<-- %s(%p,%d,%s,%p[%u]) [%d:%d] rc %d\n", __FUNCTION__, vc, idxNum, idxStr, argv, (unsigned)argc, vc->ix, vc->nrows, rc));
669 
670  return rc;
671 }
672 
673 int rpmvcNext(rpmvc vc)
674 {
675  int rc = SQLITE_OK;
676 
677  if (vc->ix >= 0 && vc->ix < vc->nrows) /* XXX needed? */
678  vc->ix++;
679 
680 if (!(vc->ix >= 0 && vc->ix < vc->nrows))
681 VCDBGNOISY(vc, (stderr, "<-- %s(%p) rc %d (%d:%d)\n", __FUNCTION__, vc, rc, vc->ix, vc->nrows));
682  return rc;
683 }
684 
685 int rpmvcEof(rpmvc vc)
686 {
687  int rc = (vc->ix >= 0 && vc->ix < vc->nrows ? 0 : 1);
688 
689 if (rc)
690 VCDBGNOISY(vc, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vc, rc));
691  return rc;
692 }
693 
694 /*==============================================================*/
695 
696 int rpmvcColumn(rpmvc vc, void * _pContext, int colx)
697 {
698  sqlite3_context * pContext = (sqlite3_context *) _pContext;
699  rpmvt vt = vc->vt;
700  rpmvd vd = vt->vd;
701  const char * path = vt->av[vc->ix];
702  const char * col = vt->cols[colx];
703  int rc = SQLITE_OK;
704 
705  size_t nb;
706  miRE mire = NULL;
707  int noffsets = 0;
708  int * offsets = NULL;
709  int xx;
710  int i;
711 
712  /* Use a PCRE pattern for parsing column value. */
713  if (vd->regex) {
714  mire = mireNew(RPMMIRE_REGEX, 0);
715  xx = mireSetCOptions(mire, RPMMIRE_REGEX, 0, 0, NULL);
716  xx = mireRegcomp(mire, vd->regex); /* XXX move to rpmvtNew */
717 
718  noffsets = 10 * 3;
719  nb = noffsets * sizeof(*offsets);
720  offsets = memset(alloca(nb), -1, nb);
721  xx = mireSetEOptions(mire, offsets, noffsets);
722 
723 nb = strlen(path);
724  xx = mireRegexec(mire, path, nb);
725 assert(xx == 0);
726 
727  for (i = 0; i < noffsets; i += 2) {
728  if (offsets[i] < 0)
729  continue;
730 assert(offsets[i ] >= 0 && offsets[i ] <= (int)nb);
731 assert(offsets[i+1] >= 0 && offsets[i+1] <= (int)nb);
732  offsets[i+1] -= offsets[i]; /* XXX convert offset to length */
733 VCDBGNOISY(vc, (stderr, "\t%d [%d,%d] %.*s\n", i/2, offsets[i], offsets[i+1], offsets[i+1], path+offsets[i]));
734  }
735 
736  }
737 
738  if (!strcmp(col, "path"))
739  sqlite3_result_text(pContext, path, -1, SQLITE_STATIC);
740  else
741  if (vd->regex) {
742  /* Use a PCRE pattern for parsing column value. */
743 assert(vt->fields);
744  for (i = 0; i < vt->nfields; i++) {
745  /* Slurp file contents for unknown field values. */
746  /* XXX procdb/yumdb */
747  /* XXX uri's? */
748  if (path[0] == '/' && !strcmp("*", vt->fields[i])) {
749  const char * fn = rpmGetPath(path, "/", col, NULL);
750  if (!Access(fn, R_OK)) {
751  rpmiob iob = NULL;
752  xx = rpmiobSlurp(fn, &iob);
753  sqlite3_result_text(pContext, rpmiobStr(iob), rpmiobLen(iob), SQLITE_TRANSIENT);
754  iob = rpmiobFree(iob);
755  } else
756  sqlite3_result_null(pContext);
757  break;
758  } else
759  if (!strcmp(col, vt->fields[i])) {
760  int ix = 2 * (i + 1);
761  const char * s = path + offsets[ix];
762  size_t ns = offsets[ix+1]; /* XXX convert offset to length */
763  sqlite3_result_text(pContext, s, ns, SQLITE_STATIC);
764  break;
765  }
766  }
767  if (i == vt->nfields)
768  sqlite3_result_null(pContext);
769  } else
770  if (vd->split && strlen(vd->split) == 1 && vt->nfields > 0) {
771  /* Simple argv split on a separator char. */
772  /* XXX using argvSplit has extra malloc's, needs SQLITE_TRANSIENT */
773  ARGV_t av = NULL; /* XXX move to rpmvcNext for performance */
774  xx = argvSplit(&av, path, vd->split);
775 assert(vt->fields);
776  for (i = 0; i < vt->nfields; i++) {
777  if (strcmp(col, vt->fields[i]))
778  continue;
779  sqlite3_result_text(pContext, av[i], -1, SQLITE_TRANSIENT);
780  break;
781  }
782  if (i == vt->nfields)
783  sqlite3_result_null(pContext);
784  av = argvFree(av);
785  } else
786  sqlite3_result_null(pContext); /* XXX unnecessary */
787 
788  if (mire) {
789  xx = mireSetEOptions(mire, NULL, 0);
790  mire = mireFree(mire);
791  }
792 
793 if (rc)
794 VCDBG(vc, (stderr, "<-- %s(%p,%p,%d) rc %d\n", __FUNCTION__, vc, pContext, colx, rc));
795 
796  return rc;
797 }
798 
799 int rpmvcRowid(rpmvc vc, int64_t * pRowid)
800 {
801  int rc = SQLITE_OK;
802 
803  if (pRowid)
804  *pRowid = vc->ix;
805 
806 if (rc)
807 VCDBG(vc, (stderr, "<-- %s(%p,%p) rc %d rowid 0x%llx\n", __FUNCTION__, vc, pRowid, rc, (unsigned long long)(pRowid ? *pRowid : 0xf00)));
808  return rc;
809 }
810 #endif /* defined(WITH_SQLITE) */
811 
812 /*==============================================================*/
813 
814 static void _rpmsqlDebugDump(rpmsql sql,
815  const char * _func, const char * _fn, unsigned _ln)
816 {
817 SQLDBG((stderr, "==> %s:%u %s(%p) _rpmsqlI %p\n", _fn, _ln, _func, sql, _rpmsqlI));
818  if (sql) {
819  fprintf(stderr, "\t flags: 0x%x\n", sql->flags);
820  fprintf(stderr, "\t av: %p[%u]\n", sql->av, (unsigned)argvCount(sql->av));
821  fprintf(stderr, "\t I: %p\n", sql->I);
822  fprintf(stderr, "\t S: %p\n", sql->S);
823  fprintf(stderr, "\t init: %s\n", sql->zInitFile);
824  fprintf(stderr, "\t database: %s\n", sql->zDbFilename);
825  fprintf(stderr, "\t table: %s\n", sql->zDestTable);
826 
827  fprintf(stderr, "\t mode: 0x%x\n", sql->mode);
828  fprintf(stderr, "\t cnt: 0x%x\n", sql->cnt);
829  fprintf(stderr, "\t iob: %p\n", sql->iob);
830  fprintf(stderr, "\t IN ifd: %p\n", sql->ifd);
831  fprintf(stderr, "\t OUT ofd: %p\n", sql->ofd);
832  fprintf(stderr, "\t LOG lfd: %p\n", sql->lfd);
833  fprintf(stderr, "\tTRACE tfd: %p\n", sql->tfd);
834 
835  if (sql->explainPrev.valid) {
836  fprintf(stderr, "\t explain:\n");
837  fprintf(stderr, "\t\t mode: 0x%x\n", sql->explainPrev.mode);
838  fprintf(stderr, "\t\tflags: 0x%x\n", sql->explainPrev.flags);
839  }
840 
841  fprintf(stderr, "\tseparator: %.*s\n", (int)sizeof(sql->separator), sql->separator);
842  fprintf(stderr, "\tnullvalue: %.*s\n", (int)sizeof(sql->nullvalue), sql->nullvalue);
843  fprintf(stderr, "\t outfile: %s\n", sql->outfile);
844  fprintf(stderr, "\t home: %s\n", sql->zHome);
845  fprintf(stderr, "\t initrc: %s\n", sql->zInitrc);
846  fprintf(stderr, "\t history: %s\n", sql->zHistory);
847  fprintf(stderr, "\t prompt: %s\n", sql->zPrompt);
848  fprintf(stderr, "\t continue: %s\n", sql->zContinue);
849 
850  fprintf(stderr, "\t buf: %p[%u]\n", sql->buf, (unsigned)sql->nbuf);
851  fprintf(stderr, "\t b: %p[%u]\n", sql->b, (unsigned)sql->nb);
852  }
853 }
854 #define rpmsqlDebugDump(_sql) \
855  _rpmsqlDebugDump(_sql, __FUNCTION__, __FILE__, __LINE__)
856 
857 #if defined(WITH_SQLITE)
858 
863 /*@mayexit@*/ /*@printflike@*/
864 static void rpmsql_error(int lvl, const char *fmt, ...)
865 #if defined(__GNUC__) && __GNUC__ >= 2
866  __attribute__((format (printf, 2, 3)))
867 #endif
868  /*@globals fileSystem @*/
869  /*@modifies fileSystem @*/;
870 static void
871 rpmsql_error(int lvl, const char *fmt, ...)
872 {
873  va_list ap;
874 
875  (void) fflush(NULL);
876  if (lvl >= 1)
877  (void) fprintf(stderr, "Error: ");
878  va_start(ap, fmt);
879  (void) vfprintf(stderr, fmt, ap);
880  va_end (ap);
881  (void) fprintf(stderr, "\n");
882  if (lvl > 1)
883  exit(EXIT_FAILURE);
884 }
885 
891 int rpmsqlCmd(/*@null@*/ rpmsql sql, const char * msg, void * _db, int rc)
892  /*@globals fileSystem @*/
893  /*@modifies fileSystem @*/
894 {
895  sqlite3 * db;
896 
897  switch (rc) {
898  case SQLITE_OK:
899  case SQLITE_ROW:
900  case SQLITE_DONE:
901  /* XXX ignore noisy debug spewage */
902  if (1 || !_rpmsql_debug)
903  break;
904  /*@fallthrough@*/
905  default:
906  /* XXX system sqlite3 w loadable modules */
907  if (sql)
908  db = (sqlite3 *) (_db ? _db : sql->I);
909  else
910  db = (sqlite3 *) _db;
911  rpmsql_error(0, "sqlite3_%s(%p): rc(%d) %s", msg, db, rc,
912  sqlite3_errmsg(db));
913  break;
914  }
915  return rc;
916 }
917 #endif /* defined(WITH_SQLITE) */
918 
919 /*==============================================================*/
920 
921 #if defined(WITH_SQLITE)
922 
926 static void _rpmsqlBeginTimer(rpmsql sql)
927 {
928  if (sql->enableTimer)
929  getrusage(RUSAGE_SELF, &sql->sBegin);
930 }
931 
932 /* Return the difference of two time_structs in seconds */
933 static double timeDiff(struct timeval *pStart, struct timeval *pEnd)
934 {
935  return (pEnd->tv_usec - pStart->tv_usec) * 0.000001 +
936  (double) (pEnd->tv_sec - pStart->tv_sec);
937 }
938 
943 static void _rpmsqlEndTimer(rpmsql sql)
944 {
945  if (sql->enableTimer) {
946  struct rusage sEnd;
947  char b[BUFSIZ];
948  size_t nb;
949  size_t nw;
950 assert(sql->ofd);
951  getrusage(RUSAGE_SELF, &sEnd);
952  snprintf(b, sizeof(b), "CPU Time: user %f sys %f\n",
953  timeDiff(&sql->sBegin.ru_utime, &sEnd.ru_utime),
954  timeDiff(&sql->sBegin.ru_stime, &sEnd.ru_stime));
955  nb = strlen(b);
956  nw = Fwrite(b, 1, nb, sql->ofd);
957 assert(nb == nw);
958  }
959 }
960 
961 #define BEGIN_TIMER(_sql) _rpmsqlBeginTimer(_sql)
962 #define END_TIMER(_sql) _rpmsqlEndTimer(_sql)
963 #define HAS_TIMER 1
964 
965 #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
966 #endif /* defined(WITH_SQLITE) */
967 
968 /*==============================================================*/
969 
974 static rpmsql rpmsqlI(void)
975  /*@globals _rpmsqlI @*/
976  /*@modifies _rpmsqlI @*/
977 {
978  if (_rpmsqlI == NULL)
979  _rpmsqlI = rpmsqlNew(NULL, 0);
980 SQLDBG((stderr, "<== %s() _rpmsqlI %p\n", __FUNCTION__, _rpmsqlI));
981  return _rpmsqlI;
982 }
983 
984 #if defined(WITH_SQLITE)
985 
989 /*@printflike@*/
990 static int rpmsqlFprintf(rpmsql sql, const char *fmt, ...)
991 #if defined(__GNUC__) && __GNUC__ >= 2
992  __attribute__((format (printf, 2, 3)))
993 #endif
994  /*@*/;
995 static int rpmsqlFprintf(rpmsql sql, const char *fmt, ...)
996 {
997  char b[BUFSIZ];
998  size_t nb = sizeof(b);
999  int rc;
1000  va_list ap;
1001 
1002  if (sql == NULL) sql = rpmsqlI();
1003 assert(sql);
1004 
1005  /* Format the output */
1006  va_start(ap, fmt);
1007  rc = vsnprintf(b, nb, fmt, ap);
1008  va_end(ap);
1009  /* XXX just in case */
1010  if (!(rc >= 0 && rc < (int)nb))
1011  rc = nb - 1;
1012  b[rc] = '\0';
1013 
1014  /* Dispose of the output. */
1015  if (sql->ofd) {
1016  size_t nw = Fwrite(b, 1, rc, sql->ofd);
1017 assert((int)nw == rc);
1018  }
1019  if (sql->iob)
1020  (void) rpmiobAppend(sql->iob, b, 0);
1021 
1022  return rc;
1023 }
1024 
1031 #ifdef SQLITE_ENABLE_IOTRACE
1032 static void iotracePrintf(const char *zFormat, ...)
1033 {
1034  char * z;
1035  size_t nz;
1036  size_t nw;
1037  va_list ap;
1038 
1039  if (_rpmsqlI == NULL || _rpmsqlI->tfd == NULL)
1040  return;
1041  va_start(ap, zFormat);
1042  z = sqlite3_vmprintf(zFormat, ap);
1043  va_end(ap);
1044  nz = strlen(z);
1045  nw = Fwrite(z, 1, nz, sql->tfd);
1046 assert(nz == nw);
1047  sqlite3_free(z);
1048 }
1049 #endif
1050 
1051 #if defined(SQLITE_CONFIG_LOG)
1052 
1056 static void shellLog(void *_sql, int iErrCode, const char *zMsg)
1057 {
1058  rpmsql sql = (rpmsql) _sql;
1059  if (sql && sql->lfd) {
1060  char num[32];
1061  int xx = snprintf(num, sizeof(num), "(%d) ", iErrCode);
1062  const char * t = rpmExpand(num, zMsg, "\n", NULL);
1063  size_t nt = strlen(t);
1064  size_t nw = Fwrite(t, 1, nt, sql->lfd);
1065 assert(nt == nw);
1066  xx = Fflush(sql->lfd);
1067  }
1068 }
1069 #endif
1070 
1071 /*==============================================================*/
1077 #ifdef NOTYET /* XXX figger multibyte char's. */
1078 #define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
1079 #define sqliteCharVal(X) sqlite3ReadUtf8(X)
1080 #else
1081 #define sqliteNextChar(X) while( ( *++(X)) ) break
1082 #define sqliteCharVal(X) (int)(*(X))
1083 #endif
1084 
1085 #include <math.h>
1086 
1101 #define GEN_MATH_WRAP_DOUBLE_1(name, function, domain) \
1102 static void name(sqlite3_context *context, int argc, sqlite3_value **argv) {\
1103  double rVal = 0.0;\
1104 assert(argc==1);\
1105  switch (sqlite3_value_type(argv[0])) {\
1106  case SQLITE_NULL:\
1107  sqlite3_result_null(context);\
1108  break;\
1109  default:\
1110  rVal = sqlite3_value_double(argv[0]);\
1111  if (domain)\
1112  sqlite3_result_error(context, "domain error", -1);\
1113  else\
1114  sqlite3_result_double(context, function(rVal));\
1115  break;\
1116  }\
1117 }
1118 
1124 GEN_MATH_WRAP_DOUBLE_1(sqrtFunc, sqrt, rVal < 0)
1125 
1126 /* trignometric functions */
1127 GEN_MATH_WRAP_DOUBLE_1(acosFunc, acos, rVal < -1.0 || rVal > 1.0)
1128 GEN_MATH_WRAP_DOUBLE_1(asinFunc, asin, rVal < -1.0 || rVal > 1.0)
1129 GEN_MATH_WRAP_DOUBLE_1(atanFunc, atan, 0)
1130 
1131 
1136 #ifdef REFERENCE
1137 static double acosh(double x)
1138 {
1139  return log(x + sqrt(x * x - 1.0));
1140 }
1141 #endif
1142 
1143 GEN_MATH_WRAP_DOUBLE_1(acoshFunc, acosh, rVal < 1)
1144 #ifdef REFERENCE
1145 static double asinh(double x)
1146 {
1147  return log(x + sqrt(x * x + 1.0));
1148 }
1149 #endif
1150 
1151 GEN_MATH_WRAP_DOUBLE_1(asinhFunc, asinh, 0)
1152 #ifdef REFERENCE
1153 static double atanh(double x)
1154 {
1155  return (1.0 / 2.0) * log((1 + x) / (1 - x));
1156 }
1157 #endif
1158 
1159 GEN_MATH_WRAP_DOUBLE_1(atanhFunc, atanh, rVal > 1.0 || rVal < -1.0)
1160 
1161 
1164 static double cot(double x)
1165 {
1166  return 1.0 / tan(x);
1167 }
1168 
1169 GEN_MATH_WRAP_DOUBLE_1(sinFunc, sin, 0)
1170 GEN_MATH_WRAP_DOUBLE_1(cosFunc, cos, 0)
1171 GEN_MATH_WRAP_DOUBLE_1(tanFunc, tan, 0) /* XXX DOMAIN */
1172 GEN_MATH_WRAP_DOUBLE_1(cotFunc, cot, 0) /* XXX DOMAIN */
1173 
1174 static double coth(double x)
1175 {
1176  return 1.0 / tanh(x);
1177 }
1178 
1183 #ifdef REFERENCE
1184 static double sinh(double x)
1185 {
1186  return (exp(x) - exp(-x)) / 2.0;
1187 }
1188 #endif
1189 GEN_MATH_WRAP_DOUBLE_1(sinhFunc, sinh, 0)
1190 
1191 #ifdef REFERENCE
1192 static double cosh(double x)
1193 {
1194  return (exp(x) + exp(-x)) / 2.0;
1195 }
1196 #endif
1197 GEN_MATH_WRAP_DOUBLE_1(coshFunc, cosh, 0)
1198 
1199 #ifdef REFERENCE
1200 static double tanh(double x)
1201 {
1202  return sinh(x) / cosh(x);
1203 }
1204 #endif
1205 GEN_MATH_WRAP_DOUBLE_1(tanhFunc, tanh, 0)
1206 GEN_MATH_WRAP_DOUBLE_1(cothFunc, coth, 0) /* XXX DOMAIN */
1207 
1208 
1211 #ifdef REFERENCE
1212 static double log10(double x)
1213 {
1214  static double l10 = -1.0;
1215  if (l10 < 0.0) {
1216  l10 = log(10.0);
1217  }
1218  return log(x) / l10;
1219 }
1220 #endif
1221 GEN_MATH_WRAP_DOUBLE_1(logFunc, log, rVal <= 0.0)
1222 GEN_MATH_WRAP_DOUBLE_1(log10Func, log10, rVal <= 0.0)
1223 GEN_MATH_WRAP_DOUBLE_1(expFunc, exp, 0)
1224 
1225 
1228 #ifndef M_PI
1229 
1233 #define M_PI 3.14159265358979323846
1234 #endif
1235 
1239 static double deg2rad(double x)
1240 {
1241  return x * M_PI / 180.0;
1242 }
1243 
1247 static double rad2deg(double x)
1248 {
1249  return 180.0 * x / M_PI;
1250 }
1251 GEN_MATH_WRAP_DOUBLE_1(rad2degFunc, rad2deg, 0)
1252 GEN_MATH_WRAP_DOUBLE_1(deg2radFunc, deg2rad, 0)
1253 
1254 
1257 static void piFunc(sqlite3_context * context,
1258  int argc, sqlite3_value ** argv)
1259 {
1260  sqlite3_result_double(context, M_PI);
1261 }
1262 
1268 static void squareFunc(sqlite3_context * context,
1269  int argc, sqlite3_value ** argv)
1270 {
1271  double rVal = 0.0;
1272  int64_t iVal;
1273 
1274 assert(argc == 2);
1275  switch (sqlite3_value_type(argv[0])) {
1276  case SQLITE_INTEGER:
1277  iVal = sqlite3_value_int64(argv[0]);
1278  sqlite3_result_int64(context, iVal * iVal);
1279  break;
1280  case SQLITE_NULL:
1281  sqlite3_result_null(context);
1282  break;
1283  default:
1284  rVal = sqlite3_value_double(argv[0]);
1285  sqlite3_result_double(context, rVal * rVal);
1286  break;
1287  }
1288 }
1289 
1295 static void powerFunc(sqlite3_context * context,
1296  int argc, sqlite3_value ** argv)
1297 {
1298  double r1 = 0.0;
1299  double r2 = 0.0;
1300 
1301 assert(argc == 2);
1302 
1303  if (sqlite3_value_type(argv[0]) == SQLITE_NULL
1304  || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
1305  sqlite3_result_null(context);
1306  } else {
1307  r1 = sqlite3_value_double(argv[0]);
1308  r2 = sqlite3_value_double(argv[1]);
1309  if (r1 <= 0.0) {
1310  /* base must be positive */
1311  sqlite3_result_error(context, "domain error", -1);
1312  } else {
1313  sqlite3_result_double(context, pow(r1, r2));
1314  }
1315  }
1316 }
1317 
1321 static void atn2Func(sqlite3_context * context,
1322  int argc, sqlite3_value ** argv)
1323 {
1324  double r1 = 0.0;
1325  double r2 = 0.0;
1326 
1327 assert(argc == 2);
1328 
1329  if (sqlite3_value_type(argv[0]) == SQLITE_NULL
1330  || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
1331  sqlite3_result_null(context);
1332  } else {
1333  r1 = sqlite3_value_double(argv[0]);
1334  r2 = sqlite3_value_double(argv[1]);
1335  sqlite3_result_double(context, atan2(r1, r2));
1336  }
1337 }
1338 
1345 static void signFunc(sqlite3_context * context,
1346  int argc, sqlite3_value ** argv)
1347 {
1348  double rVal = 0.0;
1349  int64_t iVal;
1350 
1351 assert(argc == 1);
1352  switch (sqlite3_value_type(argv[0])) {
1353  case SQLITE_INTEGER:
1354  iVal = sqlite3_value_int64(argv[0]);
1355  iVal = (iVal > 0) ? 1 : (iVal < 0) ? -1 : 0;
1356  sqlite3_result_int64(context, iVal);
1357  break;
1358  case SQLITE_NULL:
1359  sqlite3_result_null(context);
1360  break;
1361  default:
1362  /* 2nd change below. Line for abs was: if( rVal<0 ) rVal = rVal * -1.0; */
1363 
1364  rVal = sqlite3_value_double(argv[0]);
1365  rVal = (rVal > 0) ? 1 : (rVal < 0) ? -1 : 0;
1366  sqlite3_result_double(context, rVal);
1367  break;
1368  }
1369 }
1370 
1374 static void ceilFunc(sqlite3_context * context,
1375  int argc, sqlite3_value ** argv)
1376 {
1377  double rVal = 0.0;
1378  int64_t iVal;
1379 
1380 assert(argc == 1);
1381  switch (sqlite3_value_type(argv[0])) {
1382  case SQLITE_INTEGER:
1383  iVal = sqlite3_value_int64(argv[0]);
1384  sqlite3_result_int64(context, iVal);
1385  break;
1386  case SQLITE_NULL:
1387  sqlite3_result_null(context);
1388  break;
1389  default:
1390  rVal = sqlite3_value_double(argv[0]);
1391  sqlite3_result_int64(context, ceil(rVal));
1392  break;
1393  }
1394 }
1395 
1399 static void floorFunc(sqlite3_context * context,
1400  int argc, sqlite3_value ** argv)
1401 {
1402  double rVal = 0.0;
1403  int64_t iVal;
1404 
1405 assert(argc == 1);
1406  switch (sqlite3_value_type(argv[0])) {
1407  case SQLITE_INTEGER:
1408  iVal = sqlite3_value_int64(argv[0]);
1409  sqlite3_result_int64(context, iVal);
1410  break;
1411  case SQLITE_NULL:
1412  sqlite3_result_null(context);
1413  break;
1414  default:
1415  rVal = sqlite3_value_double(argv[0]);
1416  sqlite3_result_int64(context, floor(rVal));
1417  break;
1418  }
1419 }
1420 
1425 static void replicateFunc(sqlite3_context * context,
1426  int argc, sqlite3_value ** argv)
1427 {
1428  unsigned char *z; /* input string */
1429  unsigned char *zo; /* result string */
1430  int iCount; /* times to repeat */
1431  size_t nLen; /* length of the input string (no multibyte considerations) */
1432  size_t nTLen; /* length of the result string (no multibyte considerations) */
1433  int i = 0;
1434 
1435  if (argc != 2 || SQLITE_NULL == sqlite3_value_type(argv[0]))
1436  return;
1437 
1438  iCount = sqlite3_value_int64(argv[1]);
1439 
1440  if (iCount < 0) {
1441  sqlite3_result_error(context, "domain error", -1);
1442  } else {
1443  nLen = sqlite3_value_bytes(argv[0]);
1444  nTLen = nLen * iCount;
1445  z = xmalloc(nTLen + 1);
1446  zo = xmalloc(nLen + 1);
1447  strcpy((char *) zo, (char *) sqlite3_value_text(argv[0]));
1448 
1449  for (i = 0; i < iCount; ++i)
1450  strcpy((char *) (z + i * nLen), (char *) zo);
1451 
1452  sqlite3_result_text(context, (char *) z, -1, free);
1453  zo = _free(zo);
1454  }
1455 }
1456 
1457 static void properFunc(sqlite3_context * context,
1458  int argc, sqlite3_value ** argv)
1459 {
1460  const unsigned char *z; /* input string */
1461  unsigned char *zo; /* output string */
1462  unsigned char *zt; /* iterator */
1463  char r;
1464  int c = 1;
1465 
1466 assert(argc == 1);
1467  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1468  sqlite3_result_null(context);
1469  return;
1470  }
1471 
1472  z = sqlite3_value_text(argv[0]);
1473  zo = (unsigned char *) xstrdup((const char *)z);
1474  zt = zo;
1475 
1476  while ((r = *(z++)) != 0) {
1477  if (xisblank(r)) {
1478  c = 1;
1479  } else {
1480  r = (c == 1) ? xtoupper(r) : xtolower(r);
1481  c = 0;
1482  }
1483  *(zt++) = r;
1484  }
1485  *zt = '\0';
1486 
1487  sqlite3_result_text(context, (char *) zo, -1, free);
1488 }
1489 
1490 #ifdef NOTYET /* XXX figger multibyte char's. */
1491 
1497 static void padlFunc(sqlite3_context * context,
1498  int argc, sqlite3_value ** argv)
1499 {
1500  size_t ilen; /* length to pad to */
1501  size_t zl; /* length of the input string (UTF-8 chars) */
1502  size_t i;
1503  const char *zi; /* input string */
1504  char *zo; /* output string */
1505  char *zt;
1506 
1507 assert(argc == 2);
1508  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
1509  sqlite3_result_null(context);
1510  } else {
1511  zi = (const char *) sqlite3_value_text(argv[0]);
1512  ilen = sqlite3_value_int64(argv[1]);
1513  /* check domain */
1514  if (ilen < 0) {
1515  sqlite3_result_error(context, "domain error", -1);
1516  return;
1517  }
1518  zl = sqlite3utf8CharLen(zi, -1);
1519  if (zl >= ilen) {
1520  /* string is longer than the requested pad length, return the same string (dup it) */
1521  sqlite3_result_text(context, xstrdup(zi), -1, free);
1522  } else {
1523  zo = xmalloc(strlen(zi) + ilen - zl + 1);
1524  zt = zo;
1525  for (i = 1; i + zl <= ilen; ++i)
1526  *(zt++) = ' ';
1527  /* no need to take UTF-8 into consideration here */
1528  strcpy(zt, zi);
1529  sqlite3_result_text(context, zo, -1, free);
1530  }
1531  }
1532 }
1533 
1540 static void padrFunc(sqlite3_context * context,
1541  int argc, sqlite3_value ** argv)
1542 {
1543  size_t ilen; /* length to pad to */
1544  size_t zl; /* length of the input string (UTF-8 chars) */
1545  size_t zll; /* length of the input string (bytes) */
1546  size_t i;
1547  const char *zi; /* input string */
1548  char *zo; /* output string */
1549  char *zt;
1550 
1551 assert(argc == 2);
1552  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
1553  sqlite3_result_null(context);
1554  } else {
1555  int64_t _ilen;
1556  zi = (const char *) sqlite3_value_text(argv[0]);
1557  _ilen = sqlite3_value_int64(argv[1]);
1558  /* check domain */
1559  if (_ilen < 0) {
1560  sqlite3_result_error(context, "domain error", -1);
1561  return;
1562  }
1563  ilen = _ilen;
1564  zl = sqlite3utf8CharLen(zi, -1);
1565  if (zl >= ilen) {
1566  /* string is longer than the requested pad length, return the same string (dup it) */
1567  sqlite3_result_text(context, xstrdup(zi), -1, free);
1568  } else {
1569  zll = strlen(zi);
1570  zo = xmalloc(zll + ilen - zl + 1);
1571  zt = strcpy(zo, zi) + zll;
1572  for (i = 1; i + zl <= ilen; ++i)
1573  *(zt++) = ' ';
1574  *zt = '\0';
1575  sqlite3_result_text(context, zo, -1, free);
1576  }
1577  }
1578 }
1579 
1587 static void padcFunc(sqlite3_context * context,
1588  int argc, sqlite3_value ** argv)
1589 {
1590  size_t ilen; /* length to pad to */
1591  size_t zl; /* length of the input string (UTF-8 chars) */
1592  size_t zll; /* length of the input string (bytes) */
1593  size_t i;
1594  const char *zi; /* input string */
1595  char *zo; /* output string */
1596  char *zt;
1597 
1598 assert(argc == 2);
1599  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
1600  sqlite3_result_null(context);
1601  } else {
1602  int64_t _ilen;
1603  zi = (const char *) sqlite3_value_text(argv[0]);
1604  _ilen = sqlite3_value_int64(argv[1]);
1605  /* check domain */
1606  if (_ilen < 0) {
1607  sqlite3_result_error(context, "domain error", -1);
1608  return;
1609  }
1610  ilen = _ilen;
1611  zl = sqlite3utf8CharLen(zi, -1);
1612  if (zl >= ilen) {
1613  /* string is longer than the requested pad length, return the same string (dup it) */
1614  sqlite3_result_text(context, xstrdup(zi), -1, free);
1615  } else {
1616  zll = strlen(zi);
1617  zo = xmalloc(zll + ilen - zl + 1);
1618  zt = zo;
1619  for (i = 1; 2 * i + zl <= ilen; ++i)
1620  *(zt++) = ' ';
1621  strcpy(zt, zi);
1622  zt += zll;
1623  for (; i + zl <= ilen; ++i)
1624  *(zt++) = ' ';
1625  *zt = '\0';
1626  sqlite3_result_text(context, zo, -1, free);
1627  }
1628  }
1629 }
1630 #endif
1631 
1636 static void strfilterFunc(sqlite3_context * context,
1637  int argc, sqlite3_value ** argv)
1638 {
1639  const char *zi1; /* first parameter string (searched string) */
1640  const char *zi2; /* second parameter string (vcontains valid characters) */
1641  const char *z1;
1642  const char *z21;
1643  const char *z22;
1644  char *zo; /* output string */
1645  char *zot;
1646  int c1;
1647  int c2;
1648 
1649 assert(argc == 2);
1650 
1651  if (sqlite3_value_type(argv[0]) == SQLITE_NULL
1652  || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
1653  sqlite3_result_null(context);
1654  } else {
1655  zi1 = (const char *) sqlite3_value_text(argv[0]);
1656  zi2 = (const char *) sqlite3_value_text(argv[1]);
1657  zo = xmalloc(strlen(zi1) + 1);
1658  zot = zo;
1659  z1 = zi1;
1660  while ((c1 = sqliteCharVal(z1)) != 0) {
1661  z21 = zi2;
1662  while ((c2 = sqliteCharVal(z21)) != 0 && c2 != c1)
1663  sqliteNextChar(z21);
1664  if (c2 != 0) {
1665  z22 = z21;
1666  sqliteNextChar(z22);
1667  strncpy(zot, z21, z22 - z21);
1668  zot += z22 - z21;
1669  }
1670  sqliteNextChar(z1);
1671  }
1672  *zot = '\0';
1673 
1674  sqlite3_result_text(context, zo, -1, free);
1675  }
1676 }
1677 
1685 static int _substr(const char *z1, const char *z2, int s, const char **p)
1686 {
1687  int c = 0;
1688  int rVal = -1;
1689  const char *zt1;
1690  const char *zt2;
1691  int c1;
1692  int c2;
1693 
1694  if (*z1 == '\0')
1695  return -1;
1696 
1697  while ((sqliteCharVal(z2) != 0) && (c++) < s)
1698  sqliteNextChar(z2);
1699 
1700  c = 0;
1701  while ((sqliteCharVal(z2)) != 0) {
1702  zt1 = z1;
1703  zt2 = z2;
1704 
1705  do {
1706  c1 = sqliteCharVal(zt1);
1707  c2 = sqliteCharVal(zt2);
1708  sqliteNextChar(zt1);
1709  sqliteNextChar(zt2);
1710  } while (c1 == c2 && c1 != 0 && c2 != 0);
1711 
1712  if (c1 == 0) {
1713  rVal = c;
1714  break;
1715  }
1716 
1717  sqliteNextChar(z2);
1718  ++c;
1719  }
1720  if (p)
1721  *p = z2;
1722  return rVal >= 0 ? rVal + s : rVal;
1723 }
1724 
1732 static void charindexFunc(sqlite3_context * context,
1733  int argc, sqlite3_value ** argv)
1734 {
1735  const char *z1; /* s1 string */
1736  const char *z2; /* s2 string */
1737  int s = 0;
1738  int rVal = 0;
1739 
1740 assert(argc == 2 || argc == 3);
1741  if (SQLITE_NULL == sqlite3_value_type(argv[0])
1742  || SQLITE_NULL == sqlite3_value_type(argv[1])) {
1743  sqlite3_result_null(context);
1744  return;
1745  }
1746 
1747  z1 = (const char *) sqlite3_value_text(argv[0]);
1748  z2 = (const char *) sqlite3_value_text(argv[1]);
1749  if (argc == 3) {
1750  s = sqlite3_value_int(argv[2]) - 1;
1751  if (s < 0)
1752  s = 0;
1753  } else {
1754  s = 0;
1755  }
1756 
1757  rVal = _substr(z1, z2, s, NULL);
1758  sqlite3_result_int(context, rVal + 1);
1759 }
1760 
1765 static void leftFunc(sqlite3_context * context,
1766  int argc, sqlite3_value ** argv)
1767 {
1768  int c = 0;
1769  int cc = 0;
1770  int l = 0;
1771  const unsigned char *z; /* input string */
1772  const unsigned char *zt;
1773  unsigned char *rz; /* output string */
1774 
1775 assert(argc == 2);
1776  if (SQLITE_NULL == sqlite3_value_type(argv[0])
1777  || SQLITE_NULL == sqlite3_value_type(argv[1])) {
1778  sqlite3_result_null(context);
1779  return;
1780  }
1781 
1782  z = sqlite3_value_text(argv[0]);
1783  l = sqlite3_value_int(argv[1]);
1784  zt = z;
1785 
1786  while (sqliteCharVal(zt) && c++ < l)
1787  sqliteNextChar(zt);
1788 
1789  cc = zt - z;
1790 
1791  rz = xmalloc(zt - z + 1);
1792  strncpy((char *) rz, (char *) z, zt - z);
1793  *(rz + cc) = '\0';
1794  sqlite3_result_text(context, (char *) rz, -1, free);
1795 }
1796 
1801 static void rightFunc(sqlite3_context * context,
1802  int argc, sqlite3_value ** argv)
1803 {
1804  int l = 0;
1805  int c = 0;
1806  int cc = 0;
1807  const char *z;
1808  const char *zt;
1809  const char *ze;
1810  char *rz;
1811 
1812 assert(argc == 2);
1813  if (SQLITE_NULL == sqlite3_value_type(argv[0])
1814  || SQLITE_NULL == sqlite3_value_type(argv[1])) {
1815  sqlite3_result_null(context);
1816  return;
1817  }
1818 
1819  z = (const char *) sqlite3_value_text(argv[0]);
1820  l = sqlite3_value_int(argv[1]);
1821  zt = z;
1822 
1823  while (sqliteCharVal(zt) != 0) {
1824  sqliteNextChar(zt);
1825  ++c;
1826  }
1827 
1828  ze = zt;
1829  zt = z;
1830 
1831  cc = c - l;
1832  if (cc < 0)
1833  cc = 0;
1834 
1835  while (cc-- > 0) {
1836  sqliteNextChar(zt);
1837  }
1838 
1839  rz = xmalloc(ze - zt + 1);
1840  strcpy((char *) rz, (char *) (zt));
1841  sqlite3_result_text(context, (char *) rz, -1, free);
1842 }
1843 
1847 static const char * ltrim(const char *s)
1848 {
1849  while (*s == ' ')
1850  ++s;
1851  return s;
1852 }
1853 
1858 static const char * rtrim(char *s)
1859 {
1860  char *ss = s + strlen(s) - 1;
1861  while (ss >= s && *ss == ' ')
1862  --ss;
1863  *(ss + 1) = '\0';
1864  return s;
1865 }
1866 
1870 static void ltrimFunc(sqlite3_context * context,
1871  int argc, sqlite3_value ** argv)
1872 {
1873  const char *z;
1874 
1875 assert(argc == 1);
1876  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1877  sqlite3_result_null(context);
1878  return;
1879  }
1880  z = (const char *) sqlite3_value_text(argv[0]);
1881  sqlite3_result_text(context, xstrdup(ltrim(z)), -1, free);
1882 }
1883 
1887 static void rtrimFunc(sqlite3_context * context,
1888  int argc, sqlite3_value ** argv)
1889 {
1890  const char *z;
1891 
1892 assert(argc == 1);
1893  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1894  sqlite3_result_null(context);
1895  return;
1896  }
1897  z = (const char *) sqlite3_value_text(argv[0]);
1898  sqlite3_result_text(context, rtrim(xstrdup(z)), -1, free);
1899 }
1900 
1904 static void trimFunc(sqlite3_context * context,
1905  int argc, sqlite3_value ** argv)
1906 {
1907  const char *z;
1908 
1909 assert(argc == 1);
1910  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1911  sqlite3_result_null(context);
1912  return;
1913  }
1914  z = (const char *) sqlite3_value_text(argv[0]);
1915  sqlite3_result_text(context, rtrim(xstrdup(ltrim(z))), -1, free);
1916 }
1917 
1924 static void _append(char **s1, int l1, const char *s2, int l2)
1925 {
1926  *s1 = xrealloc(*s1, (l1 + l2 + 1) * sizeof(char));
1927  strncpy((*s1) + l1, s2, l2);
1928  *(*(s1) + l1 + l2) = '\0';
1929 }
1930 
1934 static void replaceFunc(sqlite3_context * context,
1935  int argc, sqlite3_value ** argv)
1936 {
1937  const char *z1; /* string s (first parameter) */
1938  const char *z2; /* string s1 (second parameter) string to look for */
1939  const char *z3; /* string s2 (third parameter) string to replace occurrences of s1 with */
1940  size_t lz1;
1941  size_t lz2;
1942  size_t lz3;
1943  int lzo = 0;
1944  char *zo = 0;
1945  int ret = 0;
1946  const char *zt1;
1947  const char *zt2;
1948 
1949 assert(argc == 3);
1950  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1951  sqlite3_result_null(context);
1952  return;
1953  }
1954 
1955  z1 = (const char *)sqlite3_value_text(argv[0]);
1956  z2 = (const char *)sqlite3_value_text(argv[1]);
1957  z3 = (const char *)sqlite3_value_text(argv[2]);
1958  /* handle possible null values */
1959  if (z2 == NULL)
1960  z2 = "";
1961  if (z3 == NULL)
1962  z3 = "";
1963 
1964  lz1 = strlen(z1);
1965  lz2 = strlen(z2);
1966  lz3 = strlen(z3);
1967 
1968 #if 0
1969  /* special case when z2 is empty (or null) nothing will be changed */
1970  if (0 == lz2) {
1971  sqlite3_result_text(context, xstrdup(z1), -1, free);
1972  return;
1973  }
1974 #endif
1975 
1976  zt1 = z1;
1977  zt2 = z1;
1978 
1979  while (1) {
1980  ret = _substr(z2, zt1, 0, &zt2);
1981 
1982  if (ret < 0)
1983  break;
1984 
1985  _append(&zo, lzo, zt1, zt2 - zt1);
1986  lzo += zt2 - zt1;
1987  _append(&zo, lzo, z3, lz3);
1988  lzo += lz3;
1989 
1990  zt1 = zt2 + lz2;
1991  }
1992  _append(&zo, lzo, zt1, lz1 - (zt1 - z1));
1993  sqlite3_result_text(context, zo, -1, free);
1994 }
1995 
1999 static void reverseFunc(sqlite3_context * context,
2000  int argc, sqlite3_value ** argv)
2001 {
2002  const char *z;
2003  const char *zt;
2004  char *rz;
2005  char *rzt;
2006  size_t l;
2007  int i;
2008 
2009 assert(argc == 1);
2010  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
2011  sqlite3_result_null(context);
2012  return;
2013  }
2014  z = (const char *)sqlite3_value_text(argv[0]);
2015  l = strlen(z);
2016  rz = xmalloc(l + 1);
2017  rzt = rz + l;
2018  *(rzt--) = '\0';
2019 
2020  zt = z;
2021  while (sqliteCharVal(zt) != 0) {
2022  z = zt;
2023  sqliteNextChar(zt);
2024  for (i = 1; zt - i >= z; ++i)
2025  *(rzt--) = *(zt - i);
2026  }
2027 
2028  sqlite3_result_text(context, rz, -1, free);
2029 }
2030 
2031 #ifdef NOTYET /* XXX needs the sqlite3 map function */
2032 
2038 typedef struct StdevCtx StdevCtx;
2039 struct StdevCtx {
2040  double rM;
2041  double rS;
2042  int64_t cnt; /* number of elements */
2043 };
2044 
2053 typedef struct ModeCtx ModeCtx;
2054 struct ModeCtx {
2055  int64_t riM; /* integer value found so far */
2056  double rdM; /* double value found so far */
2057  int64_t cnt; /* number of elements so far */
2058  double pcnt; /* number of elements smaller than a percentile */
2059  int64_t mcnt; /* maximum number of occurrences (for mode) */
2060  int64_t mn; /* number of occurrences (for mode and percentiles) */
2061  int64_t is_double; /* whether the computation is being done for doubles (>0) or integers (=0) */
2062  map *m; /* map structure used for the computation */
2063  int done; /* whether the answer has been found */
2064 };
2065 
2069 static void varianceStep(sqlite3_context * context,
2070  int argc, sqlite3_value ** argv)
2071 {
2072  StdevCtx *p;
2073  double delta;
2074  double x;
2075 
2076 assert(argc == 1);
2077  p = sqlite3_aggregate_context(context, sizeof(*p));
2078  /* only consider non-null values */
2079  if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) {
2080  p->cnt++;
2081  x = sqlite3_value_double(argv[0]);
2082  delta = (x - p->rM);
2083  p->rM += delta / p->cnt;
2084  p->rS += delta * (x - p->rM);
2085  }
2086 }
2087 
2091 static void modeStep(sqlite3_context * context,
2092  int argc, sqlite3_value ** argv)
2093 {
2094  ModeCtx *p;
2095  int64_t xi = 0;
2096  double xd = 0.0;
2097  int64_t *iptr;
2098  double *dptr;
2099  int type;
2100 
2101 assert(argc == 1);
2102  type = sqlite3_value_numeric_type(argv[0]);
2103 
2104  if (type == SQLITE_NULL)
2105  return;
2106 
2107  p = sqlite3_aggregate_context(context, sizeof(*p));
2108 
2109  if (0 == (p->m)) {
2110  p->m = calloc(1, sizeof(map));
2111  if (type == SQLITE_INTEGER) {
2112  /* map will be used for integers */
2113  *(p->m) = map_make(int_cmp);
2114  p->is_double = 0;
2115  } else {
2116  p->is_double = 1;
2117  /* map will be used for doubles */
2118  *(p->m) = map_make(double_cmp);
2119  }
2120  }
2121 
2122  ++(p->cnt);
2123 
2124  if (0 == p->is_double) {
2125  xi = sqlite3_value_int64(argv[0]);
2126  iptr = (int64_t *) calloc(1, sizeof(int64_t));
2127  *iptr = xi;
2128  map_insert(p->m, iptr);
2129  } else {
2130  xd = sqlite3_value_double(argv[0]);
2131  dptr = (double *) calloc(1, sizeof(double));
2132  *dptr = xd;
2133  map_insert(p->m, dptr);
2134  }
2135 }
2136 
2141 static void modeIterate(void *e, int64_t c, void *pp)
2142 {
2143  int64_t ei;
2144  double ed;
2145  ModeCtx *p = (ModeCtx *) pp;
2146 
2147  if (0 == p->is_double) {
2148  ei = *(int *) (e);
2149 
2150  if (p->mcnt == c) {
2151  ++p->mn;
2152  } else if (p->mcnt < c) {
2153  p->riM = ei;
2154  p->mcnt = c;
2155  p->mn = 1;
2156  }
2157  } else {
2158  ed = *(double *) (e);
2159 
2160  if (p->mcnt == c) {
2161  ++p->mn;
2162  } else if (p->mcnt < c) {
2163  p->rdM = ed;
2164  p->mcnt = c;
2165  p->mn = 1;
2166  }
2167  }
2168 }
2169 
2175 static void medianIterate(void *e, int64_t c, void *pp)
2176 {
2177  int64_t ei;
2178  double ed;
2179  double iL;
2180  double iR;
2181  int il;
2182  int ir;
2183  ModeCtx *p = (ModeCtx *) pp;
2184 
2185  if (p->done > 0)
2186  return;
2187 
2188  iL = p->pcnt;
2189  iR = p->cnt - p->pcnt;
2190  il = p->mcnt + c;
2191  ir = p->cnt - p->mcnt;
2192 
2193  if (il >= iL) {
2194  if (ir >= iR) {
2195  ++p->mn;
2196  if (0 == p->is_double) {
2197  ei = *(int *) (e);
2198  p->riM += ei;
2199  } else {
2200  ed = *(double *) (e);
2201  p->rdM += ed;
2202  }
2203  } else {
2204  p->done = 1;
2205  }
2206  }
2207  p->mcnt += c;
2208 }
2209 
2213 static void modeFinalize(sqlite3_context * context)
2214 {
2215  ModeCtx *p = sqlite3_aggregate_context(context, 0);
2216  if (p && p->m) {
2217  map_iterate(p->m, modeIterate, p);
2218  map_destroy(p->m);
2219  free(p->m);
2220 
2221  if (1 == p->mn) {
2222  if (0 == p->is_double)
2223  sqlite3_result_int64(context, p->riM);
2224  else
2225  sqlite3_result_double(context, p->rdM);
2226  }
2227  }
2228 }
2229 
2233 static void _medianFinalize(sqlite3_context * context)
2234 {
2235  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2236  if (p && p->m) {
2237  p->done = 0;
2238  map_iterate(p->m, medianIterate, p);
2239  map_destroy(p->m);
2240  free(p->m);
2241 
2242  if (0 == p->is_double)
2243  if (1 == p->mn)
2244  sqlite3_result_int64(context, p->riM);
2245  else
2246  sqlite3_result_double(context, p->riM * 1.0 / p->mn);
2247  else
2248  sqlite3_result_double(context, p->rdM / p->mn);
2249  }
2250 }
2251 
2255 static void medianFinalize(sqlite3_context * context)
2256 {
2257  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2258  if (p != NULL) {
2259  p->pcnt = (p->cnt) / 2.0;
2260  _medianFinalize(context);
2261  }
2262 }
2263 
2267 static void lower_quartileFinalize(sqlite3_context * context)
2268 {
2269  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2270  if (p != NULL) {
2271  p->pcnt = (p->cnt) / 4.0;
2272  _medianFinalize(context);
2273  }
2274 }
2275 
2279 static void upper_quartileFinalize(sqlite3_context * context)
2280 {
2281  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2282  if (p != NULL) {
2283  p->pcnt = (p->cnt) * 3 / 4.0;
2284  _medianFinalize(context);
2285  }
2286 }
2287 
2291 static void stdevFinalize(sqlite3_context * context)
2292 {
2293  StdevCtx *p = sqlite3_aggregate_context(context, 0);
2294  if (p && p->cnt > 1)
2295  sqlite3_result_double(context, sqrt(p->rS / (p->cnt - 1)));
2296  else
2297  sqlite3_result_double(context, 0.0);
2298 }
2299 
2303 static void varianceFinalize(sqlite3_context * context)
2304 {
2305  StdevCtx *p = sqlite3_aggregate_context(context, 0);
2306  if (p && p->cnt > 1)
2307  sqlite3_result_double(context, p->rS / (p->cnt - 1));
2308  else
2309  sqlite3_result_double(context, 0.0);
2310 }
2311 #endif
2312 
2316 static void expandFunc(sqlite3_context * context,
2317  int argc, sqlite3_value ** argv)
2318 {
2319  sqlite3_result_text(context,
2320  rpmExpand((const char *)sqlite3_value_text(argv[0]), NULL), -1, free);
2321 }
2322 
2326 static void regexpFunc(sqlite3_context* context,
2327  int argc, sqlite3_value** argv)
2328 {
2329  const char * value = (const char *) sqlite3_value_text(argv[0]);
2330  const char * pattern = (const char *) sqlite3_value_text(argv[1]);
2331  miRE mire = mireNew(RPMMIRE_REGEX, 0);
2332  int rc = mireRegcomp(mire, pattern);
2333 
2334  rc = mireRegexec(mire, value, strlen(value));
2335  switch (rc) {
2336  case 0:
2337  case 1:
2338  sqlite3_result_int(context, rc);
2339  break;
2340  default:
2341  sqlite3_result_error(context, "invalid pattern", -1);
2342  break;
2343  }
2344  mire = mireFree(mire);
2345 }
2346 
2347 static struct rpmsqlCF_s __CF[] = {
2348  /* math.h extensions */
2349  { "acos", 1, 0, SQLITE_UTF8, 0, acosFunc, NULL, NULL },
2350  { "asin", 1, 0, SQLITE_UTF8, 0, asinFunc, NULL, NULL },
2351  { "atan", 1, 0, SQLITE_UTF8, 0, atanFunc, NULL, NULL },
2352  { "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func, NULL, NULL },
2353  /* XXX alias */
2354  { "atan2", 2, 0, SQLITE_UTF8, 0, atn2Func, NULL, NULL },
2355  { "acosh", 1, 0, SQLITE_UTF8, 0, acoshFunc, NULL, NULL },
2356  { "asinh", 1, 0, SQLITE_UTF8, 0, asinhFunc, NULL, NULL },
2357  { "atanh", 1, 0, SQLITE_UTF8, 0, atanhFunc, NULL, NULL },
2358 
2359 #ifdef NOTYET
2360  { "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc, NULL, NULL },
2361 #endif
2362  { "degrees", 1, 0, SQLITE_UTF8, 0, rad2degFunc, NULL, NULL },
2363  { "radians", 1, 0, SQLITE_UTF8, 0, deg2radFunc, NULL, NULL },
2364 
2365  { "cos", 1, 0, SQLITE_UTF8, 0, cosFunc, NULL, NULL },
2366  { "sin", 1, 0, SQLITE_UTF8, 0, sinFunc, NULL, NULL },
2367  { "tan", 1, 0, SQLITE_UTF8, 0, tanFunc, NULL, NULL },
2368  { "cot", 1, 0, SQLITE_UTF8, 0, cotFunc, NULL, NULL },
2369  { "cosh", 1, 0, SQLITE_UTF8, 0, coshFunc, NULL, NULL },
2370  { "sinh", 1, 0, SQLITE_UTF8, 0, sinhFunc, NULL, NULL },
2371  { "tanh", 1, 0, SQLITE_UTF8, 0, tanhFunc, NULL, NULL },
2372  { "coth", 1, 0, SQLITE_UTF8, 0, cothFunc, NULL, NULL },
2373 
2374  { "exp", 1, 0, SQLITE_UTF8, 0, expFunc, NULL, NULL },
2375  { "log", 1, 0, SQLITE_UTF8, 0, logFunc, NULL, NULL },
2376  { "log10", 1, 0, SQLITE_UTF8, 0, log10Func, NULL, NULL },
2377  { "power", 2, 0, SQLITE_UTF8, 0, powerFunc, NULL, NULL },
2378  { "sign", 1, 0, SQLITE_UTF8, 0, signFunc, NULL, NULL },
2379  { "sqrt", 1, 0, SQLITE_UTF8, 0, sqrtFunc, NULL, NULL },
2380  { "square", 1, 0, SQLITE_UTF8, 0, squareFunc, NULL, NULL },
2381 
2382  { "ceil", 1, 0, SQLITE_UTF8, 0, ceilFunc, NULL, NULL },
2383  { "floor", 1, 0, SQLITE_UTF8, 0, floorFunc, NULL, NULL },
2384 
2385  { "pi", 0, 0, SQLITE_UTF8, 1, piFunc, NULL, NULL },
2386 
2387  /* string extensions */
2388  { "replicate", 2, 0, SQLITE_UTF8, 0, replicateFunc, NULL, NULL },
2389  { "charindex", 2, 0, SQLITE_UTF8, 0, charindexFunc, NULL, NULL },
2390  { "charindex", 3, 0, SQLITE_UTF8, 0, charindexFunc, NULL, NULL },
2391  { "leftstr", 2, 0, SQLITE_UTF8, 0, leftFunc, NULL, NULL },
2392  { "rightstr", 2, 0, SQLITE_UTF8, 0, rightFunc, NULL, NULL },
2393  { "ltrim", 1, 0, SQLITE_UTF8, 0, ltrimFunc, NULL, NULL },
2394  { "rtrim", 1, 0, SQLITE_UTF8, 0, rtrimFunc, NULL, NULL },
2395  { "trim", 1, 0, SQLITE_UTF8, 0, trimFunc, NULL, NULL },
2396  { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc, NULL, NULL },
2397  { "reverse", 1, 0, SQLITE_UTF8, 0, reverseFunc, NULL, NULL },
2398  { "proper", 1, 0, SQLITE_UTF8, 0, properFunc, NULL, NULL },
2399 #ifdef NOTYET /* XXX figger multibyte char's. */
2400  { "padl", 2, 0, SQLITE_UTF8, 0, padlFunc, NULL, NULL },
2401  { "padr", 2, 0, SQLITE_UTF8, 0, padrFunc, NULL, NULL },
2402  { "padc", 2, 0, SQLITE_UTF8, 0, padcFunc, NULL, NULL },
2403 #endif
2404  { "strfilter", 2, 0, SQLITE_UTF8, 0, strfilterFunc, NULL, NULL },
2405 
2406  /* statistical aggregate extensions */
2407 #ifdef NOTYET /* XXX needs the sqlite3 map function */
2408  { "stdev", 1, 0, SQLITE_UTF8, 0, NULL, varianceStep, stdevFinalize },
2409  { "variance", 1, 0, SQLITE_UTF8, 0, NULL, varianceStep, varianceFinalize },
2410  { "mode", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, modeFinalize },
2411  { "median", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, medianFinalize },
2412  { "lower_quartile", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, lower_quartileFinalize },
2413  { "upper_quartile", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, upper_quartileFinalize },
2414 #endif
2415 
2416  /* RPM extensions. */
2417  { "expand", 1, 0, SQLITE_UTF8, 0, expandFunc, NULL, NULL },
2418  { "regexp", 2, 0, SQLITE_UTF8, 0, regexpFunc, NULL, NULL },
2419  { NULL, 0, 0, 0, 0, NULL, NULL, NULL }
2420 };
2421 
2422 rpmsqlCF _rpmsqlCFT = __CF;
2423 
2424 int _rpmsqlLoadCFT(rpmsql sql, void * _CF)
2425 {
2426  sqlite3 * db = (sqlite3 *)sql->I;
2427  rpmsqlCF CF;
2428  int rc = 0;
2429 
2430 SQLDBG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, sql, _CF));
2431  if (_CF == NULL)
2432  _CF = _rpmsqlCFT;
2433  if (_CF)
2434  for (CF = (rpmsqlCF) _CF; CF->zName != NULL; CF++) {
2435  void * _pApp = NULL;
2436  int xx;
2437 
2438  switch (CF->argType) {
2439  default:
2440  case 0: _pApp = NULL; break;
2441  case 1: _pApp = (void *)db; break;
2442  case 2: _pApp = (void *)-1; break;
2443  }
2444 
2445  xx = rpmsqlCmd(sql, "create_function", db,
2446  sqlite3_create_function(db, CF->zName, CF->nArg, CF->eTextRep,
2447  _pApp, CF->xFunc, CF->xStep, CF->xFinal));
2448 SQLDBG((stderr, "\t%s(%s) xx %d\n", "sqlite3_create_function", CF->zName, xx));
2449  if (xx && rc == 0)
2450  rc = xx;
2451 
2452 #ifdef NOTYET
2453  if (CF->needColSeq) {
2454  FuncDef *pFunc = sqlite3FindFunction(db, CF->zName,
2455  strlen(CF_>zName), CF->nArg, CF->eTextRep, 0);
2456  if (pFunc) pFunc->needCollSeq = 1;
2457  }
2458 #endif
2459 
2460  }
2461 SQLDBG((stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, sql, rc));
2462  return rc;
2463 }
2464 
2465 /*==============================================================*/
2466 
2467 static struct rpmvd_s _envVD = {
2468  .split = "=",
2469  .parse = "key=val",
2470  .regex = "^([^=]+)=(.*)$",
2471  .idx = 1,
2472 };
2473 
2474 static int envCreateConnect(void * _db, void * pAux,
2475  int argc, const char *const * argv,
2476  rpmvt * vtp, char ** pzErr)
2477 {
2478  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_envVD), vtp);
2479 }
2480 
2481 struct sqlite3_module envModule = {
2482  .xCreate = (void *) envCreateConnect,
2483  .xConnect = (void *) envCreateConnect,
2484 };
2485 
2486 /*==============================================================*/
2487 
2488 static struct rpmvd_s _grdbVD = {
2489  .prefix = "%{?_etc_group}%{!?_etc_group:/etc/group}",
2490  .split = ":",
2491  /* XXX "group" is a reserved keyword. */
2492  .parse = "_group:passwd:gid:groups",
2493  .regex = "^([^:]*):([^:]*):([^:]*):([^:]*)$",
2494  .idx = 3,
2495 };
2496 
2497 static int grdbCreateConnect(void * _db, void * pAux,
2498  int argc, const char *const * argv,
2499  rpmvt * vtp, char ** pzErr)
2500 {
2501  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_grdbVD), vtp);
2502 }
2503 
2504 struct sqlite3_module grdbModule = {
2505  .xCreate = (void *) grdbCreateConnect,
2506  .xConnect = (void *) grdbCreateConnect,
2507 };
2508 
2509 /*==============================================================*/
2510 
2511 static struct rpmvd_s _procdbVD = {
2512  .prefix = "%{?_procdb}%{!?_procdb:/proc/[0-9]}",
2513  .split = "/-",
2514  .parse = "dir/pid/*",
2515  .regex = "^(.+/)([0-9]+)$",
2516  .idx = 2,
2517 };
2518 
2519 static int procdbCreateConnect(void * _db, void * pAux,
2520  int argc, const char *const * argv,
2521  rpmvt * vtp, char ** pzErr)
2522 {
2523  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_procdbVD), vtp);
2524 }
2525 
2526 struct sqlite3_module procdbModule = {
2527  .xCreate = (void *) procdbCreateConnect,
2528  .xConnect = (void *) procdbCreateConnect,
2529 };
2530 
2531 /*==============================================================*/
2532 
2533 static struct rpmvd_s _pwdbVD = {
2534  .prefix = "%{?_etc_passwd}%{!?_etc_passwd:/etc/passwd}",
2535  .split = ":",
2536  .parse = "user:passwd:uid:gid:gecos:dir:shell",
2537  .regex = "^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)$",
2538  .idx = 3,
2539 };
2540 
2541 static int pwdbCreateConnect(void * _db, void * pAux,
2542  int argc, const char *const * argv,
2543  rpmvt * vtp, char ** pzErr)
2544 {
2545  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_pwdbVD), vtp);
2546 }
2547 
2548 struct sqlite3_module pwdbModule = {
2549  .xCreate = (void *) pwdbCreateConnect,
2550  .xConnect = (void *) pwdbCreateConnect,
2551 };
2552 
2553 /*==============================================================*/
2554 
2555 static struct rpmvd_s _repodbVD = {
2556  /* XXX where to map the default? */
2557  .prefix = "%{?_repodb}%{!?_repodb:/X/popt/}",
2558  .split = "/-.",
2559  .parse = "dir/file-NVRA-N-V-R.A",
2560  .regex = "^(.+/)(((.*)-([^-]+)-([^-]+)\\.([^.]+))\\.rpm)$",
2561  .idx = 2,
2562 };
2563 
2564 static int repodbCreateConnect(void * _db, void * pAux,
2565  int argc, const char *const * argv,
2566  rpmvt * vtp, char ** pzErr)
2567 {
2568  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_repodbVD), vtp);
2569 }
2570 
2571 struct sqlite3_module repodbModule = {
2572  .xCreate = (void *) repodbCreateConnect,
2573  .xConnect = (void *) repodbCreateConnect,
2574 };
2575 
2576 /*==============================================================*/
2577 
2578 static int _stat_debug = 0;
2579 
2580 static struct rpmvd_s _statVD = {
2581  .split = " ,",
2582  .parse = "st_dev,st_ino,st_mode,st_nlink,st_uid,st_gid,st_rdev,st_size,st_blksize,st_blocks,st_atime,st_mtime,st_ctime",
2583 };
2584 
2585 static int statCreateConnect(void * _db, void * pAux,
2586  int argc, const char *const * argv,
2587  rpmvt * vtp, char ** pzErr)
2588 {
2589  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_statVD), vtp);
2590 }
2591 
2592 static int statColumn(rpmvc vc, void * _pContext, int colx)
2593 {
2594  sqlite3_context * pContext = (sqlite3_context *) _pContext;
2595  rpmvt vt = vc->vt;
2596  const char * path = vt->av[vc->ix];
2597  const char * col = vt->cols[colx];
2598  struct stat sb, *st = &sb; /* XXX move to rpmvcNext for performance */
2599  int ret = Lstat(path, &sb);
2600  int rc = SQLITE_OK;
2601 
2602 if (_stat_debug < 0)
2603 fprintf(stderr, "--> %s(%p,%p,%d)\n", __FUNCTION__, vc, pContext, colx);
2604 
2605 
2606  if (!strcmp(col, "path"))
2607  sqlite3_result_text(pContext, path, -1, SQLITE_STATIC);
2608  else if (!strcmp(col, "st_dev") && !ret)
2609  sqlite3_result_int64(pContext, st->st_dev);
2610  else if (!strcmp(col, "st_ino") && !ret)
2611  sqlite3_result_int64(pContext, st->st_ino);
2612  else if (!strcmp(col, "st_mode") && !ret)
2613  sqlite3_result_int64(pContext, st->st_mode);
2614  else if (!strcmp(col, "st_nlink") && !ret)
2615  sqlite3_result_int64(pContext, st->st_nlink);
2616  else if (!strcmp(col, "st_uid") && !ret)
2617  sqlite3_result_int64(pContext, st->st_uid);
2618  else if (!strcmp(col, "st_gid") && !ret)
2619  sqlite3_result_int64(pContext, st->st_gid);
2620  else if (!strcmp(col, "st_rdev") && !ret)
2621  sqlite3_result_int64(pContext, st->st_rdev);
2622  else if (!strcmp(col, "st_size") && !ret)
2623  sqlite3_result_int64(pContext, st->st_size);
2624  else if (!strcmp(col, "st_blksize") && !ret)
2625  sqlite3_result_int64(pContext, st->st_blksize);
2626  else if (!strcmp(col, "st_blocks") && !ret)
2627  sqlite3_result_int64(pContext, st->st_blocks);
2628  else if (!strcmp(col, "st_atime") && !ret)
2629  sqlite3_result_int64(pContext, st->st_atime);
2630  else if (!strcmp(col, "st_mtime") && !ret)
2631  sqlite3_result_int64(pContext, st->st_mtime);
2632  else if (!strcmp(col, "st_ctime") && !ret)
2633  sqlite3_result_int64(pContext, st->st_ctime);
2634  /* XXX pick up *BSD derangements */
2635  else
2636  sqlite3_result_null(pContext);
2637 
2638 if (_stat_debug < 0)
2639 fprintf(stderr, "<-- %s(%p,%p,%d) rc %d\n", __FUNCTION__, vc, pContext, colx, rc);
2640 
2641  return rc;
2642 }
2643 
2644 struct sqlite3_module statModule = {
2645  .xCreate = (void *) statCreateConnect,
2646  .xConnect = (void *) statCreateConnect,
2647  .xColumn = (void *) statColumn,
2648 };
2649 
2650 /*==============================================================*/
2651 
2652 static struct rpmvd_s _yumdbVD = {
2653  .prefix = "%{?_yumdb}%{!?_yumdb:/var/lib/yum/yumdb}/",
2654  .split = "/-",
2655  .parse = "dir/hash-NVRA-N-V-R-A/*",
2656  .regex = "^(.+/)([^-]+)-((.*)-([^-]+)-([^-]+)-([^-]+))$",
2657  .idx = 2,
2658 };
2659 
2660 static int yumdbCreateConnect(void * _db, void * pAux,
2661  int argc, const char *const * argv,
2662  rpmvt * vtp, char ** pzErr)
2663 {
2664  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_yumdbVD), vtp);
2665 }
2666 
2667 struct sqlite3_module yumdbModule = {
2668  .xCreate = (void *) yumdbCreateConnect,
2669  .xConnect = (void *) yumdbCreateConnect,
2670 };
2671 
2672 /*==============================================================*/
2673 
2674 struct sqlite3_module _rpmvmTemplate = {
2675  .xCreate = (void *) rpmvtCreate,
2676  .xConnect = (void *) rpmvtConnect,
2677  .xBestIndex = (void *) rpmvtBestIndex,
2678  .xDisconnect = (void *) rpmvtDisconnect,
2679  .xDestroy = (void *) rpmvtDestroy,
2680  .xOpen = (void *) rpmvcOpen,
2681  .xClose = (void *) rpmvcClose,
2682  .xFilter = (void *) rpmvcFilter,
2683  .xNext = (void *) rpmvcNext,
2684  .xEof = (void *) rpmvcEof,
2685  .xColumn = (void *) rpmvcColumn,
2686  .xRowid = (void *) rpmvcRowid,
2687  .xUpdate = (void *) rpmvtUpdate,
2688  .xBegin = (void *) rpmvtBegin,
2689  .xSync = (void *) rpmvtSync,
2690  .xCommit = (void *) rpmvtCommit,
2691  .xRollback = (void *) rpmvtRollback,
2692  .xFindFunction = (void *) rpmvtFindFunction,
2693  .xRename = (void *) rpmvtRename
2694 };
2695 
2696 static struct rpmsqlVMT_s __VMT[] = {
2697  { "Argv", NULL, NULL },
2698  { "Env", &envModule, NULL },
2699  { "Grdb", &grdbModule, NULL },
2700  { "Procdb", &procdbModule, NULL },
2701  { "Pwdb", &pwdbModule, NULL },
2702  { "Repodb", &repodbModule, NULL },
2703  { "Stat", &statModule, NULL },
2704  { "Yumdb", &yumdbModule, NULL },
2705  { NULL, NULL, NULL }
2706 };
2707 
2708 static void rpmsqlVMFree(void * _VM)
2709  /*@*/
2710 {
2711 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, _VM));
2712  if (_VM)
2713  free(_VM);
2714 }
2715 
2716 #ifdef UNUSED
2717 static void dumpVM(const char * msg, const rpmsqlVM s)
2718 {
2719 fprintf(stderr, "--------------------- %s\n", (msg ? msg : ""));
2720 #define VMPRT(f) if (s->f) fprintf(stderr, "%20s: %p\n", #f, s->f)
2721  VMPRT(xCreate);
2722  VMPRT(xConnect);
2723  VMPRT(xBestIndex);
2724  VMPRT(xDisconnect);
2725  VMPRT(xDestroy);
2726  VMPRT(xOpen);
2727  VMPRT(xClose);
2728  VMPRT(xFilter);
2729  VMPRT(xNext);
2730  VMPRT(xEof);
2731  VMPRT(xColumn);
2732  VMPRT(xRowid);
2733  VMPRT(xUpdate);
2734  VMPRT(xBegin);
2735  VMPRT(xSync);
2736  VMPRT(xCommit);
2737  VMPRT(xRollback);
2738  VMPRT(xFindFunction);
2739  VMPRT(xRename);
2740 #undef VMPRT
2741 }
2742 #endif
2743 
2744 static /*@only@*/ rpmsqlVM rpmsqlVMNew(/*@null@*/ const rpmsqlVM s)
2745 {
2746  rpmsqlVM t = xcalloc(1, sizeof(*t));
2747 
2748 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, s));
2749  *t = _rpmvmTemplate; /* structure assignment */
2750 
2751  if (s) {
2752  if (s->iVersion) t->iVersion = s->iVersion;
2753 #define VMCPY(f) if (s->f) t->f = ((s->f != (void *)-1) ? s->f : NULL)
2754  VMCPY(xCreate);
2755  VMCPY(xConnect);
2756  VMCPY(xBestIndex);
2757  VMCPY(xDisconnect);
2758  VMCPY(xDestroy);
2759  VMCPY(xOpen);
2760  VMCPY(xClose);
2761  VMCPY(xFilter);
2762  VMCPY(xNext);
2763  VMCPY(xEof);
2764  VMCPY(xColumn);
2765  VMCPY(xRowid);
2766  VMCPY(xUpdate);
2767  VMCPY(xBegin);
2768  VMCPY(xSync);
2769  VMCPY(xCommit);
2770  VMCPY(xRollback);
2771  VMCPY(xFindFunction);
2772  VMCPY(xRename);
2773 #undef VMCPY
2774  }
2775 SQLDBG((stderr, "<-- %s(%p) %p\n", __FUNCTION__, s, t));
2776  return t;
2777 }
2778 
2779 int _rpmsqlLoadVMT(void * _db, const rpmsqlVMT _VMT)
2780 {
2781  sqlite3 * db = (sqlite3 *) _db;
2782  rpmsqlVMT VMT;
2783  int rc = 0;
2784 
2785 SQLDBG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, _db, _VMT));
2786  for (VMT = (rpmsqlVMT)_VMT; VMT->zName != NULL; VMT++) {
2787  int xx;
2788 
2789  xx = rpmsqlCmd(_rpmsqlI, "create_module_v2", db,
2790  sqlite3_create_module_v2(db, VMT->zName,
2791  rpmsqlVMNew(VMT->module), VMT->data, rpmsqlVMFree));
2792 SQLDBG((stderr, "\t%s(%s) xx %d\n", "sqlite3_create_module_v2", VMT->zName, xx));
2793  if (xx && rc == 0)
2794  rc = xx;
2795 
2796  }
2797 SQLDBG((stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, _db, _VMT, rc));
2798  return rc;
2799 }
2800 
2801 /*==============================================================*/
2802 /* XXX HACK: AWOL in -lsqlite3 on CM14 */
2803 #if SQLITE_VERSION_NUMBER <= 3006015
2804 #define sqlite3_enable_load_extension(db, onoff) SQLITE_OK
2805 #define sqlite3_load_extension(db, zFile, zProc, pzErrMsg) SQLITE_OK
2806 #endif
2807 
2813 static int _rpmsqlOpenDB(rpmsql sql)
2814 {
2815  int rc = -1; /* assume failure */
2816  sqlite3 * db;
2817 
2818 assert(sql);
2819 
2820  db = (sqlite3 *)sql->I;
2821  if (db == NULL) {
2822  int rc;
2823  rc = rpmsqlCmd(sql, "open", db, /* XXX watchout: arg order */
2824  sqlite3_open(sql->zDbFilename, &db));
2825  sql->I = db;
2826 
2827  if (db && rc == SQLITE_OK) {
2828  (void) _rpmsqlLoadCFT(sql, _rpmsqlCFT);
2829  (void) _rpmsqlLoadVMT(db, __VMT);
2830  }
2831 
2832  if (db == NULL || sqlite3_errcode(db) != SQLITE_OK) {
2833  /* XXX rpmlog */
2834  rpmsql_error(1, _("unable to open database \"%s\": %s"),
2835  sql->zDbFilename, sqlite3_errmsg(db));
2836  goto exit;
2837  }
2838  /* Enable extension loading (if not disabled). */
2839  if (!F_ISSET(sql, NOLOAD))
2840  (void) rpmsqlCmd(sql, "enable_load_extension", db,
2841  sqlite3_enable_load_extension(db, 1));
2842  }
2843  rc = 0;
2844 
2845 exit:
2846 SQLDBG((stderr, "<-- %s(%p) rc %d %s\n", __FUNCTION__, sql, rc, sql->zDbFilename));
2847  return rc;
2848 }
2849 
2850 #endif /* defined(WITH_SQLITE) */
2851 
2852 /*==============================================================*/
2853 
2854 #if defined(WITH_SQLITE)
2855 
2858 static int isNumber(const char *z, int *realnum)
2859 {
2860  if (*z == '-' || *z == '+')
2861  z++;
2862  if (!isdigit(*z))
2863  return 0;
2864  z++;
2865  if (realnum)
2866  *realnum = 0;
2867  while (isdigit(*z))
2868  z++;
2869  if (*z == '.') {
2870  z++;
2871  if (!isdigit(*z))
2872  return 0;
2873  while (isdigit(*z))
2874  z++;
2875  if (realnum)
2876  *realnum = 1;
2877  }
2878  if (*z == 'e' || *z == 'E') {
2879  z++;
2880  if (*z == '+' || *z == '-')
2881  z++;
2882  if (!isdigit(*z))
2883  return 0;
2884  while (isdigit(*z))
2885  z++;
2886  if (realnum)
2887  *realnum = 1;
2888  }
2889  return *z == 0;
2890 }
2891 
2896 static int strlen30(const char *z)
2897 {
2898  const char *z2 = z;
2899  while (*z2)
2900  z2++;
2901  return 0x3fffffff & (int) (z2 - z);
2902 }
2903 #endif /* defined(WITH_SQLITE) */
2904 
2905 /*==============================================================*/
2906 #if defined(WITH_SQLITE)
2907 
2911 static void output_hex_blob(rpmsql sql, const void *pBlob, int nBlob)
2912 {
2913  char *zBlob = (char *) pBlob;
2914  int i;
2915 
2916 SQLDBG((stderr, "--> %s(%p,%p[%u])\n", __FUNCTION__, sql, pBlob, (unsigned)nBlob));
2917  rpmsqlFprintf(sql, "X'");
2918  for (i = 0; i < nBlob; i++)
2919  rpmsqlFprintf(sql, "%02x", zBlob[i]);
2920  rpmsqlFprintf(sql, "'");
2921 }
2922 
2927 static void output_quoted_string(rpmsql sql, const char *z)
2928 {
2929  int i;
2930  int nSingle = 0;
2931 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z));
2932  for (i = 0; z[i]; i++) {
2933  if (z[i] == '\'')
2934  nSingle++;
2935  }
2936  if (nSingle == 0) {
2937  rpmsqlFprintf(sql, "'%s'", z);
2938  } else {
2939  rpmsqlFprintf(sql, "'");
2940  while (*z) {
2941  for (i = 0; z[i] && z[i] != '\''; i++)
2942  ;
2943  if (i == 0) {
2944  rpmsqlFprintf(sql, "''");
2945  z++;
2946  } else if (z[i] == '\'') {
2947  rpmsqlFprintf(sql, "%.*s''", i, z);
2948  z += i + 1;
2949  } else {
2950  rpmsqlFprintf(sql, "%s", z);
2951  break;
2952  }
2953  }
2954  rpmsqlFprintf(sql, "'");
2955  }
2956 }
2957 
2962 static void output_c_string(rpmsql sql, const char *z)
2963 {
2964  unsigned int c;
2965 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z));
2966  rpmsqlFprintf(sql, "\"");
2967  while ((c = *(z++)) != 0) {
2968  if (c == '\\')
2969  rpmsqlFprintf(sql, "\\\\");
2970  else if (c == '\t')
2971  rpmsqlFprintf(sql, "\\t");
2972  else if (c == '\n')
2973  rpmsqlFprintf(sql, "\\n");
2974  else if (c == '\r')
2975  rpmsqlFprintf(sql, "\\r");
2976  else if (!isprint(c))
2977  rpmsqlFprintf(sql, "\\%03o", c & 0xff);
2978  else
2979  rpmsqlFprintf(sql, "%c", c);
2980  }
2981  rpmsqlFprintf(sql, "\"");
2982 }
2983 
2989 static void output_html_string(rpmsql sql, const char *z)
2990 {
2991  int i;
2992 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z));
2993  while (*z) {
2994  for (i = 0; z[i]
2995  && z[i] != '<'
2996  && z[i] != '&'
2997  && z[i] != '>' && z[i] != '\"' && z[i] != '\''; i++) {
2998  }
2999  if (i > 0)
3000  rpmsqlFprintf(sql, "%.*s", i, z);
3001  if (z[i] == '<')
3002  rpmsqlFprintf(sql, "&lt;");
3003  else if (z[i] == '&')
3004  rpmsqlFprintf(sql, "&amp;");
3005  else if (z[i] == '>')
3006  rpmsqlFprintf(sql, "&gt;");
3007  else if (z[i] == '\"')
3008  rpmsqlFprintf(sql, "&quot;");
3009  else if (z[i] == '\'')
3010  rpmsqlFprintf(sql, "&#39;");
3011  else
3012  break;
3013  z += i + 1;
3014  }
3015 }
3016 
3021 /*@unchecked@*/
3022 static const char needCsvQuote[] = {
3023  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3024  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3025  1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
3026  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3027  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3028  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3029  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3030  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
3031  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3032  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3033  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3034  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3035  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3036  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3037  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3038  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3039 };
3040 
3048 static void output_csv(rpmsql sql, const char *z, int bSep)
3049 {
3050 SQLDBG((stderr, "--> %s(%p,%s,0x%x)\n", __FUNCTION__, sql, z, bSep));
3051  if (z == 0) {
3052  rpmsqlFprintf(sql, "%s", sql->nullvalue);
3053  } else {
3054  int i;
3055  int nSep = strlen30(sql->separator);
3056  for (i = 0; z[i]; i++) {
3057  if (needCsvQuote[((unsigned char *) z)[i]]
3058  || (z[i] == sql->separator[0] &&
3059  (nSep == 1 || memcmp(z, sql->separator, nSep) == 0))) {
3060  i = 0;
3061  break;
3062  }
3063  }
3064  if (i == 0) {
3065  rpmsqlFprintf(sql, "\"");
3066  for (i = 0; z[i]; i++) {
3067  if (z[i] == '"')
3068  rpmsqlFprintf(sql, "\"");
3069  rpmsqlFprintf(sql, "%c", z[i]);
3070  }
3071  rpmsqlFprintf(sql, "\"");
3072  } else {
3073  rpmsqlFprintf(sql, "%s", z);
3074  }
3075  }
3076  if (bSep)
3077  rpmsqlFprintf(sql, "%s", sql->separator);
3078 }
3079 
3085 static int _rpmsqlShellCallback(void * _sql, int nArg, char **azArg, char **azCol,
3086  int *aiType)
3087 {
3088  rpmsql sql = (rpmsql) _sql;
3089  int w;
3090  int i;
3091 
3092 SQLDBG((stderr, "--> %s(%p,%d,%p,%p,%p)\n", __FUNCTION__, _sql, nArg, azArg, azCol, aiType));
3093  switch (sql->mode) {
3094  case RPMSQL_MODE_LINE:
3095  w = 5;
3096  if (azArg == 0)
3097  break;
3098  for (i = 0; i < nArg; i++) {
3099  int len = strlen30(azCol[i] ? azCol[i] : "");
3100  if (len > w)
3101  w = len;
3102  }
3103  if (sql->cnt++ > 0)
3104  rpmsqlFprintf(sql, "\n");
3105  for (i = 0; i < nArg; i++)
3106  rpmsqlFprintf(sql, "%*s = %s\n", w, azCol[i],
3107  azArg[i] ? azArg[i] : sql->nullvalue);
3108  break;
3109  case RPMSQL_MODE_EXPLAIN:
3110  case RPMSQL_MODE_COLUMN:
3111  if (sql->cnt++ == 0) {
3112  for (i = 0; i < nArg; i++) {
3113  int n;
3114  w = (i < ArraySize(sql->colWidth) ? sql->colWidth[i] : 0);
3115 
3116  if (w <= 0) {
3117  w = strlen30(azCol[i] ? azCol[i] : "");
3118  if (w < 10)
3119  w = 10;
3120  n = strlen30(azArg && azArg[i]
3121  ? azArg[i] : sql-> nullvalue);
3122  if (w < n)
3123  w = n;
3124  }
3125  if (i < ArraySize(sql->actualWidth))
3126  sql->actualWidth[i] = w;
3127  if (F_ISSET(sql, SHOWHDR)) {
3128  rpmsqlFprintf(sql, "%-*.*s%s", w, w, azCol[i],
3129  i == nArg - 1 ? "\n" : " ");
3130  }
3131  }
3132  if (F_ISSET(sql, SHOWHDR)) {
3133  for (i = 0; i < nArg; i++) {
3134  w = (i < ArraySize(sql->actualWidth)
3135  ? sql->actualWidth[i] : 10);
3136 
3137  rpmsqlFprintf(sql, "%-*.*s%s", w, w,
3138  "-----------------------------------"
3139  "----------------------------------------------------------",
3140  i == nArg - 1 ? "\n" : " ");
3141  }
3142  }
3143  }
3144  if (azArg == 0)
3145  break;
3146  for (i = 0; i < nArg; i++) {
3147  w = (i < ArraySize(sql->actualWidth) ? sql->actualWidth[i] : 10);
3148  if (sql->mode == RPMSQL_MODE_EXPLAIN && azArg[i] &&
3149  strlen30(azArg[i]) > w) {
3150  w = strlen30(azArg[i]);
3151  }
3152  rpmsqlFprintf(sql, "%-*.*s%s", w, w,
3153  azArg[i] ? azArg[i] : sql->nullvalue,
3154  i == nArg - 1 ? "\n" : " ");
3155  }
3156  break;
3157  case RPMSQL_MODE_SEMI:
3158  case RPMSQL_MODE_LIST:
3159  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3160  for (i = 0; i < nArg; i++)
3161  rpmsqlFprintf(sql, "%s%s", azCol[i],
3162  i == nArg - 1 ? "\n" : sql->separator);
3163  }
3164 
3165  if (azArg == 0)
3166  break;
3167  for (i = 0; i < nArg; i++) {
3168  char *z = azArg[i];
3169  if (z == 0)
3170  z = sql->nullvalue;
3171  rpmsqlFprintf(sql, "%s", z);
3172  if (i < nArg - 1)
3173  rpmsqlFprintf(sql, "%s", sql->separator);
3174  else if (sql->mode == RPMSQL_MODE_SEMI)
3175  rpmsqlFprintf(sql, ";\n");
3176  else
3177  rpmsqlFprintf(sql, "\n");
3178  }
3179  break;
3180  case RPMSQL_MODE_HTML:
3181  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3182  rpmsqlFprintf(sql, "<TR>");
3183  for (i = 0; i < nArg; i++) {
3184  rpmsqlFprintf(sql, "<TH>");
3185  output_html_string(sql, azCol[i]);
3186  rpmsqlFprintf(sql, "</TH>\n");
3187  }
3188  rpmsqlFprintf(sql, "</TR>\n");
3189  }
3190  if (azArg == 0)
3191  break;
3192  rpmsqlFprintf(sql, "<TR>");
3193  for (i = 0; i < nArg; i++) {
3194  rpmsqlFprintf(sql, "<TD>");
3195  output_html_string(sql, azArg[i] ? azArg[i] : sql->nullvalue);
3196  rpmsqlFprintf(sql, "</TD>\n");
3197  }
3198  rpmsqlFprintf(sql, "</TR>\n");
3199  break;
3200  case RPMSQL_MODE_TCL:
3201  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3202  for (i = 0; i < nArg; i++) {
3203  output_c_string(sql, azCol[i] ? azCol[i] : "");
3204  rpmsqlFprintf(sql, "%s", sql->separator);
3205  }
3206  rpmsqlFprintf(sql, "\n");
3207  }
3208  if (azArg == 0)
3209  break;
3210  for (i = 0; i < nArg; i++) {
3211  output_c_string(sql, azArg[i] ? azArg[i] : sql->nullvalue);
3212  rpmsqlFprintf(sql, "%s", sql->separator);
3213  }
3214  rpmsqlFprintf(sql, "\n");
3215  break;
3216  case RPMSQL_MODE_CSV:
3217  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3218  for (i = 0; i < nArg; i++)
3219  output_csv(sql, azCol[i] ? azCol[i] : "", i < nArg - 1);
3220  rpmsqlFprintf(sql, "\n");
3221  }
3222  if (azArg == 0)
3223  break;
3224  for (i = 0; i < nArg; i++)
3225  output_csv(sql, azArg[i], i < nArg - 1);
3226  rpmsqlFprintf(sql, "\n");
3227  break;
3228  case RPMSQL_MODE_INSERT:
3229  sql->cnt++;
3230  if (azArg == 0)
3231  break;
3232  rpmsqlFprintf(sql, "INSERT INTO %s VALUES(", sql->zDestTable);
3233  for (i = 0; i < nArg; i++) {
3234  char *zSep = i > 0 ? "," : "";
3235  if ((azArg[i] == 0) || (aiType && aiType[i] == SQLITE_NULL)) {
3236  rpmsqlFprintf(sql, "%sNULL", zSep);
3237  } else if (aiType && aiType[i] == SQLITE_TEXT) {
3238  if (zSep[0])
3239  rpmsqlFprintf(sql, "%s", zSep);
3240  output_quoted_string(sql, azArg[i]);
3241  } else if (aiType
3242  && (aiType[i] == SQLITE_INTEGER
3243  || aiType[i] == SQLITE_FLOAT)) {
3244  rpmsqlFprintf(sql, "%s%s", zSep, azArg[i]);
3245  } else if (aiType && aiType[i] == SQLITE_BLOB && sql->S) {
3246  sqlite3_stmt * pStmt = (sqlite3_stmt *)sql->S;
3247  const void *pBlob = sqlite3_column_blob(pStmt, i);
3248  int nBlob = sqlite3_column_bytes(pStmt, i);
3249  if (zSep[0])
3250  rpmsqlFprintf(sql, "%s", zSep);
3251  output_hex_blob(sql, pBlob, nBlob);
3252  } else if (isNumber(azArg[i], 0)) {
3253  rpmsqlFprintf(sql, "%s%s", zSep, azArg[i]);
3254  } else {
3255  if (zSep[0])
3256  rpmsqlFprintf(sql, "%s", zSep);
3257  output_quoted_string(sql, azArg[i]);
3258  }
3259  }
3260  rpmsqlFprintf(sql, ");\n");
3261  break;
3262  }
3263  return 0;
3264 }
3265 
3271 static int callback(void *_sql, int nArg, char **azArg, char **azCol)
3272 {
3273  /* since we don't have type info, call the _rpmsqlShellCallback with a NULL value */
3274  return _rpmsqlShellCallback(_sql, nArg, azArg, azCol, NULL);
3275 }
3276 
3283 static void set_table_name(rpmsql sql, const char *zName)
3284 {
3285  int i, n;
3286  int needQuote;
3287  char *z;
3288 
3289 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, zName));
3290  sql->zDestTable = _free(sql->zDestTable);
3291  if (zName == NULL)
3292  return;
3293  needQuote = !xisalpha((unsigned char) *zName) && *zName != '_';
3294  for (i = n = 0; zName[i]; i++, n++) {
3295  if (!xisalnum((unsigned char) zName[i]) && zName[i] != '_') {
3296  needQuote = 1;
3297  if (zName[i] == '\'')
3298  n++;
3299  }
3300  }
3301  if (needQuote)
3302  n += 2;
3303  sql->zDestTable = z = xmalloc(n + 1);
3304  n = 0;
3305  if (needQuote)
3306  z[n++] = '\'';
3307  for (i = 0; zName[i]; i++) {
3308  z[n++] = zName[i];
3309  if (zName[i] == '\'')
3310  z[n++] = '\'';
3311  }
3312  if (needQuote)
3313  z[n++] = '\'';
3314  z[n] = 0;
3315 }
3316 
3326 static char *appendText(char *zIn, char const *zAppend, char quote)
3327 {
3328  int len;
3329  int i;
3330  int nAppend = strlen30(zAppend);
3331  int nIn = (zIn ? strlen30(zIn) : 0);
3332 
3333 SQLDBG((stderr, "--> %s(%s,%s,0x%02x)\n", __FUNCTION__, zIn, zAppend, quote));
3334  len = nAppend + nIn + 1;
3335  if (quote) {
3336  len += 2;
3337  for (i = 0; i < nAppend; i++) {
3338  if (zAppend[i] == quote)
3339  len++;
3340  }
3341  }
3342 
3343  zIn = (char *) xrealloc(zIn, len);
3344 
3345  if (quote) {
3346  char *zCsr = &zIn[nIn];
3347  *zCsr++ = quote;
3348  for (i = 0; i < nAppend; i++) {
3349  *zCsr++ = zAppend[i];
3350  if (zAppend[i] == quote)
3351  *zCsr++ = quote;
3352  }
3353  *zCsr++ = quote;
3354  *zCsr++ = '\0';
3355 assert((zCsr - zIn) == len);
3356  } else {
3357  memcpy(&zIn[nIn], zAppend, nAppend);
3358  zIn[len - 1] = '\0';
3359  }
3360 
3361  return zIn;
3362 }
3363 
3364 
3373 static int run_table_dump_query(rpmsql sql, sqlite3 * db,
3374  const char *zSelect, const char *zFirstRow)
3375 {
3376  sqlite3_stmt * pSelect;
3377  int rc;
3378 SQLDBG((stderr, "--> %s(%p,%p,%s,%s)\n", __FUNCTION__, sql, db, zSelect, zFirstRow));
3379  rc = rpmsqlCmd(sql, "prepare", db,
3380  sqlite3_prepare(db, zSelect, -1, &pSelect, 0));
3381  if (rc || pSelect == NULL)
3382  return rc;
3383 
3384  while ((rc = rpmsqlCmd(sql, "step", db,
3385  sqlite3_step(pSelect))) == SQLITE_ROW)
3386  {
3387  if (zFirstRow) {
3388  rpmsqlFprintf(sql, "%s", zFirstRow);
3389  zFirstRow = NULL;
3390  }
3391  rpmsqlFprintf(sql, "%s;\n", sqlite3_column_text(pSelect, 0));
3392  }
3393 
3394  return rpmsqlCmd(sql, "finalize", db,
3395  sqlite3_finalize(pSelect));
3396 }
3397 #endif /* defined(WITH_SQLITE) */
3398 
3399 /*==============================================================*/
3400 
3401 #if defined(WITH_SQLITE)
3402 #define iseol(_c) ((char)(_c) == '\n' || (char)(_c) == '\r')
3403 
3411 /*@null@*/
3412 static char *
3413 rpmsqlFgets(/*@returned@*/ char * buf, size_t nbuf, rpmsql sql)
3414  /*@globals fileSystem @*/
3415  /*@modifies buf, fileSystem @*/
3416 {
3417  FD_t ifd = sql->ifd;
3418 /* XXX sadly, fgets(3) cannot be used against a LIBIO wrapped .fpio FD_t */
3419 FILE * ifp = (!F_ISSET(sql, PROMPT) ? fdGetFILE(ifd) : stdin);
3420  char *q = buf - 1; /* initialize just before buffer. */
3421  size_t nb = 0;
3422  size_t nr = 0;
3423  int pc = 0, bc = 0;
3424  char *p = buf;
3425 
3426 #ifdef NOISY /* XXX obliterates CLI input */
3427 SQLDBG((stderr, "--> %s(%p[%u],%p) ifd %p fp %p fileno %d fdno %d\n", __FUNCTION__, buf, (unsigned)nbuf, sql, ifd, ifp, (ifp ? fileno(ifp) : -3), Fileno(ifd)));
3428 #endif /* NOISY */
3429 assert(ifp != NULL);
3430 
3431  if (ifp != NULL)
3432  do {
3433  *(++q) = '\0'; /* terminate and move forward. */
3434  if (fgets(q, (int)nbuf, ifp) == NULL) /* read next line. */
3435  break;
3436  nb = strlen(q);
3437  nr += nb; /* trim trailing \r and \n */
3438  for (q += nb - 1; nb > 0 && iseol(*q); q--)
3439  nb--;
3440  for (; p <= q; p++) {
3441  switch (*p) {
3442  case '\\':
3443  switch (*(p+1)) {
3444  case '\r': /*@switchbreak@*/ break;
3445  case '\n': /*@switchbreak@*/ break;
3446  case '\0': /*@switchbreak@*/ break;
3447  default: p++; /*@switchbreak@*/ break;
3448  }
3449  /*@switchbreak@*/ break;
3450  case '%':
3451  switch (*(p+1)) {
3452  case '{': p++, bc++; /*@switchbreak@*/ break;
3453  case '(': p++, pc++; /*@switchbreak@*/ break;
3454  case '%': p++; /*@switchbreak@*/ break;
3455  }
3456  /*@switchbreak@*/ break;
3457  case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
3458  case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
3459  case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
3460  case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
3461  }
3462  }
3463  if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
3464  *(++q) = '\0'; /* trim trailing \r, \n */
3465  break;
3466  }
3467  q++; p++; nb++; /* copy newline too */
3468  nbuf -= nb;
3469  if (*q == '\r') /* XXX avoid \r madness */
3470  *q = '\n';
3471  } while (nbuf > 0);
3472 
3473 SQLDBG((stderr, "<-- %s(%p[%u],%p) nr %u\n", __FUNCTION__, buf, (unsigned)nbuf, sql, (unsigned)nr));
3474 
3475  return (nr > 0 ? buf : NULL);
3476 }
3477 
3488 static char *local_getline(rpmsql sql, /*@null@*/const char *zPrompt)
3489 {
3490  char * t;
3491 
3492 SQLDBG((stderr, "--> %s(%s) ofd %p\n", __FUNCTION__, zPrompt, sql->ofd));
3493 
3494  if (sql->ofd && zPrompt && *zPrompt) {
3495  size_t nb = strlen(zPrompt);
3496  size_t nw = Fwrite(zPrompt, 1, nb, sql->ofd);
3497 assert(nb == nw);
3498  (void) Fflush(sql->ofd);
3499  }
3500 
3501 assert(sql->ifd != NULL);
3502  t = rpmsqlFgets(sql->buf, sql->nbuf, sql);
3503 
3504 SQLDBG((stderr, "<-- %s(%s) ofd %p\n", __FUNCTION__, zPrompt, sql->ofd));
3505 
3506  return t;
3507 }
3508 
3516 static char *rpmsqlInputOneLine(rpmsql sql, const char *zPrior)
3517 {
3518  const char *zPrompt;
3519  char *zResult;
3520 
3521 SQLDBG((stderr, "--> %s(%s)\n", __FUNCTION__, zPrior));
3522 
3523 assert(sql->buf != NULL);
3524 assert(sql->ifd != NULL);
3525 
3526  if (!F_ISSET(sql, PROMPT)) {
3527  zResult = local_getline(sql, NULL);
3528  } else {
3529  zPrompt = (zPrior && zPrior[0]) ? sql->zContinue : sql->zPrompt;
3530  zResult = readline(sql, zPrompt);
3531  if (zResult) {
3532 #if defined(HAVE_READLINE) && HAVE_READLINE==1
3533  if (*zResult)
3534  add_history(zResult);
3535  /* XXX readline returns malloc'd memory. copy & free. */
3536  if (zResult != sql->buf) {
3537  strncpy(sql->buf, zResult, sql->nbuf);
3538  zResult = _free(zResult);
3539  zResult = sql->buf;
3540  }
3541 #endif
3542  }
3543  }
3544 
3545 SQLDBG((stderr, "<-- %s(%s)\n", __FUNCTION__, zPrior));
3546 
3547  return zResult;
3548 }
3549 
3550 #endif /* defined(WITH_SQLITE) */
3551 
3552 /*==============================================================*/
3553 
3554 #if defined(WITH_SQLITE)
3555 
3558 static char *save_err_msg(sqlite3 * db)
3559 {
3560  const char * s = sqlite3_errmsg(db);
3561  int nb = strlen30(s) + 1;
3562  return memcpy(xmalloc(nb), s, nb);
3563 }
3564 
3575 static int _rpmsqlShellExec(rpmsql sql, const char *zSql,
3576  int (*xCallback) (void *, int, char **, char **, int *),
3577  char **pzErrMsg
3578  )
3579 {
3580  sqlite3 * db = (sqlite3 *) sql->I;
3581  sqlite3_stmt * pStmt = NULL; /* Statement to execute. */
3582  int rc = SQLITE_OK; /* Return Code */
3583  const char *zLeftover; /* Tail of unprocessed SQL */
3584 
3585 SQLDBG((stderr, "--> %s(%p,%s,%p,%p)\n", __FUNCTION__, sql, zSql, xCallback, pzErrMsg));
3586  if (pzErrMsg)
3587  *pzErrMsg = NULL;
3588 
3589  while (zSql[0] && rc == SQLITE_OK) {
3590  rc = rpmsqlCmd(sql, "prepare_v2", db,
3591  sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover));
3592  if (rc)
3593  goto bottom;
3594 
3595  /* this happens for a comment or white-space */
3596  if (pStmt == NULL)
3597  goto bottom;
3598 
3599  /* echo the sql statement if echo on */
3600  if (sql->ofd && F_ISSET(sql, ECHO)) {
3601  const char *zStmtSql = sqlite3_sql(pStmt);
3602  rpmsqlFprintf(sql, "%s\n", zStmtSql ? zStmtSql : zSql);
3603  (void) Fflush(sql->ofd);
3604  }
3605 
3606  /* perform the first step. this will tell us if we
3607  ** have a result set or not and how wide it is.
3608  */
3609  rc = rpmsqlCmd(sql, "step", db,
3610  sqlite3_step(pStmt));
3611  /* if we have a result set... */
3612  if (rc == SQLITE_ROW) {
3613  /* if we have a callback... */
3614  if (xCallback) {
3615  /* allocate space for col name ptr, value ptr, and type */
3616  int nCol = sqlite3_column_count(pStmt);
3617  size_t nb = 3 * nCol * sizeof(const char *) + 1;
3618  char ** azCols = xmalloc(nb); /* Result names */
3619  char ** azVals = &azCols[nCol]; /* Result values */
3620  int * aiTypes = (int *) &azVals[nCol]; /* Result types */
3621  int i;
3622 
3623  /* save off ptrs to column names */
3624  for (i = 0; i < nCol; i++)
3625  azCols[i] = (char *) sqlite3_column_name(pStmt, i);
3626 
3627  /* save off the prepared statement handle and reset row count */
3628  sql->S = (void *) pStmt;
3629  sql->cnt = 0;
3630  do {
3631  /* extract the data and data types */
3632  for (i = 0; i < nCol; i++) {
3633  azVals[i] = (char *) sqlite3_column_text(pStmt, i);
3634  aiTypes[i] = sqlite3_column_type(pStmt, i);
3635  if (!azVals[i] && (aiTypes[i] != SQLITE_NULL)) {
3636  rc = SQLITE_NOMEM;
3637  break; /* from for */
3638  }
3639  } /* end for */
3640 
3641  /* if data and types extraction failed... */
3642  if (rc != SQLITE_ROW)
3643  break;
3644 
3645  /* call the supplied callback with the result row data */
3646  if (xCallback (sql, nCol, azVals, azCols, aiTypes)) {
3647  rc = SQLITE_ABORT;
3648  break;
3649  }
3650  rc = rpmsqlCmd(sql, "step", db,
3651  sqlite3_step(pStmt));
3652  } while (rc == SQLITE_ROW);
3653  azCols = _free(azCols);
3654  sql->S = NULL;
3655  } else {
3656  do {
3657  rc = rpmsqlCmd(sql, "step", db,
3658  sqlite3_step(pStmt));
3659  } while (rc == SQLITE_ROW);
3660  }
3661  }
3662 
3663  /* Finalize the statement just executed. If this fails, save a
3664  ** copy of the error message. Otherwise, set zSql to point to the
3665  ** next statement to execute. */
3666  rc = rpmsqlCmd(sql, "finalize", db,
3667  sqlite3_finalize(pStmt));
3668 
3669 bottom:
3670  /* On error, retrieve message and exit. */
3671  if (rc) {
3672  if (pzErrMsg)
3673  *pzErrMsg = save_err_msg(db);
3674  break;
3675  }
3676 
3677  /* Move to next sql statement */
3678  zSql = zLeftover;
3679  while (xisspace(zSql[0]))
3680  zSql++;
3681  } /* end while */
3682 
3683  return rc;
3684 }
3685 #endif /* defined(WITH_SQLITE) */
3686 
3687 /*==============================================================*/
3688 
3689 #if defined(WITH_SQLITE)
3690 
3698 static int dump_callback(void *_sql, int nArg, char **azArg, char **azCol)
3699 {
3700  rpmsql sql = (rpmsql) _sql;
3701  sqlite3 * db = (sqlite3 *) sql->I;
3702  int rc;
3703  const char *zTable;
3704  const char *zType;
3705  const char *zSql;
3706  const char *zPrepStmt = 0;
3707  int ec = 1; /* assume failure */
3708 
3709 SQLDBG((stderr, "--> %s(%p,%d,%p,%p)\n", __FUNCTION__, _sql, nArg, azArg, azCol));
3710  azCol = azCol;
3711  if (nArg != 3)
3712  goto exit;
3713  zTable = azArg[0];
3714  zType = azArg[1];
3715  zSql = azArg[2];
3716 
3717  if (!strcmp(zTable, "sqlite_sequence")) {
3718  zPrepStmt = "DELETE FROM sqlite_sequence;\n";
3719  } else if (!strcmp(zTable, "sqlite_stat1")) {
3720  rpmsqlFprintf(sql, "ANALYZE sqlite_master;\n");
3721  } else if (!strncmp(zTable, "sqlite_", 7)) {
3722  ec = 0; /* XXX success */
3723  goto exit;
3724  } else if (!strncmp(zSql, "CREATE VIRTUAL TABLE", 20)) {
3725  char *zIns;
3726  if (!F_ISSET(sql, WRITABLE)) {
3727  rpmsqlFprintf(sql, "PRAGMA writable_schema=ON;\n");
3728  sql->flags |= RPMSQL_FLAGS_WRITABLE;
3729  }
3730  zIns =
3731  sqlite3_mprintf
3732  ("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
3733  "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql);
3734  rpmsqlFprintf(sql, "%s\n", zIns);
3735  sqlite3_free(zIns);
3736  ec = 0; /* XXX success */
3737  goto exit;
3738  } else
3739  rpmsqlFprintf(sql, "%s;\n", zSql);
3740 
3741  if (!strcmp(zType, "table")) {
3742  sqlite3_stmt * pTableInfo = NULL;
3743  char *zSelect = 0;
3744  char *zTableInfo = 0;
3745  char *zTmp = 0;
3746  int nRow = 0;
3747 
3748  zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
3749  zTableInfo = appendText(zTableInfo, zTable, '"');
3750  zTableInfo = appendText(zTableInfo, ");", 0);
3751 
3752  rc = rpmsqlCmd(sql, "prepare", db,
3753  sqlite3_prepare(db, zTableInfo, -1, &pTableInfo, 0));
3754  zTableInfo = _free(zTableInfo);
3755  if (rc != SQLITE_OK || !pTableInfo)
3756  goto exit;
3757 
3758  zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
3759  zTmp = appendText(zTmp, zTable, '"');
3760  if (zTmp)
3761  zSelect = appendText(zSelect, zTmp, '\'');
3762  zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
3763  rc = rpmsqlCmd(sql, "step", db,
3764  sqlite3_step(pTableInfo));
3765  while (rc == SQLITE_ROW) {
3766  const char *zText =
3767  (const char *) sqlite3_column_text(pTableInfo, 1);
3768  zSelect = appendText(zSelect, "quote(", 0);
3769  zSelect = appendText(zSelect, zText, '"');
3770  rc = rpmsqlCmd(sql, "step", db,
3771  sqlite3_step(pTableInfo));
3772  if (rc == SQLITE_ROW)
3773  zSelect = appendText(zSelect, ") || ',' || ", 0);
3774  else
3775  zSelect = appendText(zSelect, ") ", 0);
3776  nRow++;
3777  }
3778  rc = rpmsqlCmd(sql, "finalize", db,
3779  sqlite3_finalize(pTableInfo));
3780  if (rc != SQLITE_OK || nRow == 0) {
3781  zSelect = _free(zSelect);
3782  goto exit;
3783  }
3784 
3785  zSelect = appendText(zSelect, "|| ')' FROM ", 0);
3786  zSelect = appendText(zSelect, zTable, '"');
3787 
3788  rc = run_table_dump_query(sql, db, zSelect, zPrepStmt);
3789  if (rc == SQLITE_CORRUPT) {
3790  zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
3791  rc = run_table_dump_query(sql, db, zSelect, NULL);
3792  }
3793  zSelect = _free(zSelect);
3794  }
3795  ec = 0; /* XXX success */
3796 exit:
3797  return ec;
3798 }
3799 
3808 static int run_schema_dump_query(rpmsql sql,
3809  const char *zQuery, char **pzErrMsg)
3810 {
3811  sqlite3 * db = (sqlite3 *) sql->I;
3812  int rc;
3813 
3814 SQLDBG((stderr, "--> %s(%p,%s,%p)\n", __FUNCTION__, sql, zQuery, pzErrMsg));
3815  rc = rpmsqlCmd(sql, "exec", db,
3816  sqlite3_exec(db, zQuery, dump_callback, sql, pzErrMsg));
3817  if (rc == SQLITE_CORRUPT) {
3818  char *zQ2;
3819  if (pzErrMsg)
3820  sqlite3_free(*pzErrMsg);
3821  zQ2 = rpmExpand(zQuery, " ORDER BY rowid DESC", NULL);
3822  rc = rpmsqlCmd(sql, "exec", db,
3823  sqlite3_exec(db, zQ2, dump_callback, sql, pzErrMsg));
3824  zQ2 = _free(zQ2);
3825  }
3826  return rc;
3827 }
3828 
3829 /*
3830  * Text of a help message
3831  */
3832 /*@unchecked@*/
3833 static char zHelp[] =
3834  ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
3835  ".bail ON|OFF Stop after hitting an error. Default OFF\n"
3836  ".databases List names and files of attached databases\n"
3837  ".dump ?TABLE? ... Dump the database in an SQL text format\n"
3838  " If TABLE specified, only dump tables matching\n"
3839  " LIKE pattern TABLE.\n"
3840  ".echo ON|OFF Turn command echo on or off\n"
3841  ".exit Exit this program\n"
3842  ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n"
3843  " With no args, it turns EXPLAIN on.\n"
3844  ".header(s) ON|OFF Turn display of headers on or off\n"
3845  ".help Show this message\n"
3846  ".import FILE TABLE Import data from FILE into TABLE\n"
3847  ".indices ?TABLE? Show names of all indices\n"
3848  " If TABLE specified, only show indices for tables\n"
3849  " matching LIKE pattern TABLE.\n"
3850 #ifdef SQLITE_ENABLE_IOTRACE
3851  ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
3852 #endif
3853  ".load FILE ?ENTRY? Load an extension library\n"
3854  ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
3855  ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
3856  " csv Comma-separated values\n"
3857  " column Left-aligned columns. (See .width)\n"
3858  " html HTML <table> code\n"
3859  " insert SQL insert statements for TABLE\n"
3860  " line One value per line\n"
3861  " list Values delimited by .separator string\n"
3862  " tabs Tab-separated values\n"
3863  " tcl TCL list elements\n"
3864  ".nullvalue STRING Print STRING in place of NULL values\n"
3865  ".output FILENAME Send output to FILENAME\n"
3866  ".output stdout Send output to the screen\n"
3867  ".prompt MAIN CONTINUE Replace the standard prompts\n"
3868  ".quit Exit this program\n"
3869  ".read FILENAME Execute SQL in FILENAME\n"
3870  ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
3871  ".schema ?TABLE? Show the CREATE statements\n"
3872  " If TABLE specified, only show tables matching\n"
3873  " LIKE pattern TABLE.\n"
3874  ".separator STRING Change separator used by output mode and .import\n"
3875  ".show Show the current values for various settings\n"
3876  ".tables ?TABLE? List names of tables\n"
3877  " If TABLE specified, only list tables matching\n"
3878  " LIKE pattern TABLE.\n"
3879  ".timeout MS Try opening locked tables for MS milliseconds\n"
3880  ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n";
3881 
3882 static char zTimerHelp[] =
3883  ".timer ON|OFF Turn the CPU timer measurement on or off\n";
3884 
3894 static void resolve_backslashes(char *z)
3895 {
3896  int i, j;
3897  char c;
3898  for (i = j = 0; (c = z[i]) != 0; i++, j++) {
3899  if (c == '\\') {
3900  c = z[++i];
3901  if (c == 'n') {
3902  c = '\n';
3903  } else if (c == 't') {
3904  c = '\t';
3905  } else if (c == 'r') {
3906  c = '\r';
3907  } else if (c >= '0' && c <= '7') {
3908  c -= '0';
3909  if (z[i + 1] >= '0' && z[i + 1] <= '7') {
3910  i++;
3911  c = (c << 3) + z[i] - '0';
3912  if (z[i + 1] >= '0' && z[i + 1] <= '7') {
3913  i++;
3914  c = (c << 3) + z[i] - '0';
3915  }
3916  }
3917  }
3918  }
3919  z[j] = c;
3920  }
3921  z[j] = 0;
3922 }
3923 
3927 static int booleanValue(const char * zArg)
3928 {
3929  int val = atoi(zArg);
3930  if (!strcasecmp(zArg, "on") || !strcasecmp(zArg, "yes"))
3931  val = 1;
3932 SQLDBG((stderr, "<-- %s(%s) val %d\n", __FUNCTION__, zArg, val));
3933  return val;
3934 }
3935 
3936 /*@unchecked@*/ /*@observer@*/
3937 static const char *modeDescr[] = {
3938  "line",
3939  "column",
3940  "list",
3941  "semi",
3942  "html",
3943  "insert",
3944  "tcl",
3945  "csv",
3946  "explain",
3947 };
3948 
3949 /* forward ref @*/
3950 static int rpmsqlInput(rpmsql sql);
3951 
3952 static int rpmsqlFOpen(const char * fn, FD_t *fdp)
3953  /*@modifies *fdp @*/
3954 {
3955  FD_t fd = *fdp;
3956  int rc = 0;
3957 
3958 SQLDBG((stderr, "--> %s(%s,%p) fd %p\n", __FUNCTION__, fn, fdp, fd));
3959 
3960  if (fd)
3961  (void) Fclose(fd); /* XXX stdout/stderr were dup'd */
3962  fd = NULL;
3963  /* XXX permit numeric fdno's? */
3964  if (fn == NULL)
3965  fd = NULL;
3966  else if (!strcmp(fn, "stdout") || !strcmp(fn, "-"))
3967  fd = fdDup(STDOUT_FILENO);
3968  else if (!strcmp(fn, "stderr"))
3969  fd = fdDup(STDERR_FILENO);
3970  else if (!strcmp(fn, "off"))
3971  fd = NULL;
3972  else {
3973  fd = Fopen(fn, "wb");
3974  if (fd == NULL || Ferror(fd)) {
3975  rpmsql_error(1, _("cannot open \"%s\""), fn);
3976  if (fd) (void) Fclose(fd);
3977  fd = NULL;
3978  rc = 1;
3979  }
3980  }
3981  *fdp = fd;
3982 
3983 SQLDBG((stderr, "<-- %s(%s,%p) fd %p rc %d\n", __FUNCTION__, fn, fdp, fd, rc));
3984 
3985  return rc;
3986 }
3987 
3994 static int rpmsqlMetaCommand(rpmsql sql, char *zLine)
3995 {
3996  sqlite3 * db = (sqlite3 *)sql->I;
3997  int i = 1;
3998  int nArg = 0;
3999  int n, c;
4000  int rc = 0;
4001  char *azArg[50];
4002 
4003 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, zLine));
4004 
4005  /* Parse the input line into tokens. */
4006  while (zLine[i] && nArg < ArraySize(azArg)) {
4007  while (xisspace((unsigned char) zLine[i]))
4008  i++;
4009  if (zLine[i] == '\0')
4010  break;
4011  if (zLine[i] == '\'' || zLine[i] == '"') {
4012  int delim = zLine[i++];
4013  azArg[nArg++] = &zLine[i];
4014  while (zLine[i] && zLine[i] != delim)
4015  i++;
4016  if (zLine[i] == delim)
4017  zLine[i++] = '\0';
4018  if (delim == '"')
4019  resolve_backslashes(azArg[nArg - 1]);
4020  } else {
4021  azArg[nArg++] = &zLine[i];
4022  while (zLine[i] && !xisspace((unsigned char) zLine[i]))
4023  i++;
4024  if (zLine[i])
4025  zLine[i++] = 0;
4026  resolve_backslashes(azArg[nArg - 1]);
4027  }
4028  }
4029 
4030  /* Process the input line. */
4031  if (nArg == 0)
4032  return 0; /* no tokens, no error */
4033  n = strlen30(azArg[0]);
4034  c = azArg[0][0];
4035  if (c == 'b' && n >= 3 && !strncmp(azArg[0], "backup", n)
4036  && nArg > 1 && nArg < 4) {
4037  const char *zDestFile;
4038  const char *zDb;
4039  sqlite3 * pDest;
4040  sqlite3_backup *pBackup;
4041  if (nArg == 2) {
4042  zDestFile = azArg[1];
4043  zDb = "main";
4044  } else {
4045  zDestFile = azArg[2];
4046  zDb = azArg[1];
4047  }
4048  rc = rpmsqlCmd(sql, "open", pDest,
4049  sqlite3_open(zDestFile, &pDest));
4050  if (rc) {
4051 #ifdef DYING
4052  rpmsql_error(1, _("cannot open \"%s\""), zDestFile);
4053 #endif
4054  (void) rpmsqlCmd(sql, "close", pDest,
4055  sqlite3_close(pDest));
4056  return 1;
4057  }
4058  _rpmsqlOpenDB(sql);
4059  db = (sqlite3 *)sql->I;
4060  pBackup = sqlite3_backup_init(pDest, "main", db, zDb);
4061  if (pBackup == NULL) {
4062  rpmsql_error(1, "%s", sqlite3_errmsg(pDest));
4063  (void) rpmsqlCmd(sql, "close", pDest,
4064  sqlite3_close(pDest));
4065  return 1;
4066  }
4067  while ((rc = rpmsqlCmd(sql, "backup_step", db,
4068  sqlite3_backup_step(pBackup, 100))) == SQLITE_OK)
4069  ;
4070  (void) rpmsqlCmd(sql, "backup_finish", pBackup,
4071  sqlite3_backup_finish(pBackup));
4072  if (rc == SQLITE_DONE) {
4073  rc = 0;
4074  } else {
4075  rpmsql_error(1, "%s", sqlite3_errmsg(pDest));
4076  rc = 1;
4077  }
4078  (void) rpmsqlCmd(sql, "close", pDest,
4079  sqlite3_close(pDest));
4080  } else
4081  if (c == 'b' && n >= 3 && !strncmp(azArg[0], "bail", n)
4082  && nArg > 1 && nArg < 3) {
4083  if (booleanValue(azArg[1]))
4084  sql->flags |= RPMSQL_FLAGS_BAIL;
4085  else
4086  sql->flags &= ~RPMSQL_FLAGS_BAIL;
4087  } else
4088  if (c == 'd' && n > 1 && !strncmp(azArg[0], "databases", n) && nArg == 1) {
4089  /* XXX recursion b0rkage lies here. */
4090  uint32_t _flags = sql->flags;
4091  uint32_t _mode = sql->mode;
4092  int _cnt = sql->cnt;;
4093  int _colWidth[3];
4094  char *zErrMsg = NULL;
4095  memcpy(_colWidth, sql->colWidth, sizeof(_colWidth));
4096  _rpmsqlOpenDB(sql);
4097  db = (sqlite3 *)sql->I;
4098  sql->flags |= RPMSQL_FLAGS_SHOWHDR;
4099  sql->mode = RPMSQL_MODE_COLUMN;
4100  sql->colWidth[0] = 3;
4101  sql->colWidth[1] = 15;
4102  sql->colWidth[2] = 58;
4103  sql->cnt = 0;
4104  (void) rpmsqlCmd(sql, "exec", db,
4105  sqlite3_exec(db, "PRAGMA database_list;", callback, sql, &zErrMsg));
4106  if (zErrMsg) {
4107  rpmsql_error(1, "%s", zErrMsg);
4108  sqlite3_free(zErrMsg);
4109  rc = 1;
4110  }
4111  memcpy(sql->colWidth, _colWidth, sizeof(_colWidth));
4112  sql->cnt = _cnt;
4113  sql->mode = _mode;
4114  sql->flags = _flags;
4115  } else
4116  if (c == 'd' && !strncmp(azArg[0], "dump", n) && nArg < 3) {
4117  char * t;
4118  _rpmsqlOpenDB(sql);
4119  db = (sqlite3 *)sql->I;
4120  /* When playing back a "dump", the content might appear in an order
4121  ** which causes immediate foreign key constraints to be violated.
4122  ** So disable foreign-key constraint enforcement to prevent problems. */
4123  rpmsqlFprintf(sql, "PRAGMA foreign_keys=OFF;\n");
4124  rpmsqlFprintf(sql, "BEGIN TRANSACTION;\n");
4125  sql->flags &= ~RPMSQL_FLAGS_WRITABLE;
4126  (void) rpmsqlCmd(sql, "exec", db,
4127  sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0));
4128  if (nArg == 1) {
4129  t = rpmExpand("SELECT name, type, sql FROM sqlite_master"
4130  " WHERE sql NOT NULL AND type=='table'"
4131  " AND name!='sqlite_sequence'", NULL);
4132  run_schema_dump_query(sql, t, NULL);
4133  t = _free(t);
4134  t = rpmExpand("SELECT name, type, sql FROM sqlite_master"
4135  " WHERE name=='sqlite_sequence'", NULL);
4136  run_schema_dump_query(sql, t, NULL);
4137  t = _free(t);
4138  t = rpmExpand("SELECT sql FROM sqlite_master"
4139  " WHERE sql NOT NULL AND type IN ('index','trigger','view')", NULL);
4140  run_table_dump_query(sql, db, t, NULL);
4141  t = _free(t);
4142  } else {
4143  int i;
4144  for (i = 1; i < nArg; i++) {
4145  t = rpmExpand( "SELECT name, type, sql FROM sqlite_master"
4146  " WHERE tbl_name LIKE '", azArg[i], "'"
4147  " AND type=='table' AND sql NOT NULL", NULL);
4148  run_schema_dump_query(sql, t, NULL);
4149  t = _free(t);
4150  t = rpmExpand( "SELECT sql FROM sqlite_master"
4151  " WHERE sql NOT NULL"
4152  " AND type IN ('index','trigger','view')"
4153  " AND tbl_name LIKE '", azArg[i], "'", NULL);
4154  run_table_dump_query(sql, db, t, NULL);
4155  t = _free(t);
4156  }
4157  }
4158  if (F_ISSET(sql, WRITABLE)) {
4159  rpmsqlFprintf(sql, "PRAGMA writable_schema=OFF;\n");
4160  sql->flags &= ~RPMSQL_FLAGS_WRITABLE;
4161  }
4162  (void) rpmsqlCmd(sql, "exec", db,
4163  sqlite3_exec(db, "PRAGMA writable_schema=OFF", 0, 0, 0));
4164  rpmsqlFprintf(sql, "COMMIT;\n");
4165  } else
4166  if (c == 'e' && !strncmp(azArg[0], "echo", n) && nArg > 1 && nArg < 3) {
4167  if (booleanValue(azArg[1]))
4168  sql->flags |= RPMSQL_FLAGS_ECHO;
4169  else
4170  sql->flags &= ~RPMSQL_FLAGS_ECHO;
4171  } else
4172  if (c == 'e' && !strncmp(azArg[0], "exit", n) && nArg == 1) {
4173  rc = 2;
4174  } else
4175  if (c == 'e' && !strncmp(azArg[0], "explain", n) && nArg < 3) {
4176  int val = nArg >= 2 ? booleanValue(azArg[1]) : 1;
4177  if (val == 1) {
4178  if (!sql->explainPrev.valid) {
4179  sql->explainPrev.valid = 1;
4180  sql->explainPrev.mode = sql->mode;
4181  sql->explainPrev.flags = sql->flags;
4182  memcpy(sql->explainPrev.colWidth, sql->colWidth,
4183  sizeof(sql->colWidth));
4184  }
4185  /* We could put this code under the !p->explainValid
4186  ** condition so that it does not execute if we are already in
4187  ** explain mode. However, always executing it allows us an easy
4188  ** way to reset to explain mode in case the user previously
4189  ** did an .explain followed by a .width, .mode or .header
4190  ** command.
4191  */
4192  sql->mode = RPMSQL_MODE_EXPLAIN;
4193  sql->flags |= RPMSQL_FLAGS_SHOWHDR;
4194  memset(sql->colWidth, 0, ArraySize(sql->colWidth));
4195  sql->colWidth[0] = 4; /* addr */
4196  sql->colWidth[1] = 13; /* opcode */
4197  sql->colWidth[2] = 4; /* P1 */
4198  sql->colWidth[3] = 4; /* P2 */
4199  sql->colWidth[4] = 4; /* P3 */
4200  sql->colWidth[5] = 13; /* P4 */
4201  sql->colWidth[6] = 2; /* P5 */
4202  sql->colWidth[7] = 13; /* Comment */
4203  } else if (sql->explainPrev.valid) {
4204  sql->explainPrev.valid = 0;
4205  sql->mode = sql->explainPrev.mode;
4206  sql->flags = sql->explainPrev.flags;
4207  memcpy(sql->colWidth, sql->explainPrev.colWidth,
4208  sizeof(sql->colWidth));
4209  }
4210  } else
4211  if (c == 'h'
4212  && (!strncmp(azArg[0], "header", n) || !strncmp(azArg[0], "headers", n))
4213  && nArg > 1 && nArg < 3)
4214  {
4215  if (booleanValue(azArg[1]))
4216  sql->flags |= RPMSQL_FLAGS_SHOWHDR;
4217  else
4218  sql->flags &= ~RPMSQL_FLAGS_SHOWHDR;
4219  } else
4220  if (c == 'h' && !strncmp(azArg[0], "help", n)) {
4221  rpmsql_error(0, "%s", zHelp);
4222  if (HAS_TIMER)
4223  rpmsql_error(0, "%s", zTimerHelp);
4224  } else
4225  if (c == 'i' && !strncmp(azArg[0], "import", n) && nArg == 3) {
4226  char *zTable = azArg[2]; /* Insert data into this table */
4227  char *zFile = azArg[1]; /* The file from which to extract data */
4228  sqlite3_stmt * pStmt = NULL;/* A statement */
4229  int nCol; /* Number of columns in the table */
4230  int nByte; /* Number of bytes in an SQL string */
4231  int i, j; /* Loop counters */
4232  int nSep; /* Number of bytes in sql->separator[] */
4233  char *zSql; /* An SQL statement */
4234  char *zLine; /* A single line of input from the file */
4235  char **azCol; /* zLine[] broken up into columns */
4236  char *zCommit; /* How to commit changes */
4237  int lineno = 0; /* Line number of input file */
4238 
4239  _rpmsqlOpenDB(sql);
4240  db = (sqlite3 *)sql->I;
4241  nSep = strlen30(sql->separator);
4242  if (nSep == 0) {
4243  rpmsql_error(1, _("non-null separator required for import"));
4244  return 1;
4245  }
4246  zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
4247 assert(zSql != NULL);
4248  nByte = strlen30(zSql);
4249  rc = rpmsqlCmd(sql, "prepare", db,
4250  sqlite3_prepare(db, zSql, -1, &pStmt, 0));
4251  sqlite3_free(zSql);
4252  if (rc) {
4253 #ifdef DYING
4254  sqlite3 * db = (sqlite3 *)sql->I;
4255  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4256 #endif
4257  if (pStmt)
4258  (void) rpmsqlCmd(sql, "finalize", db,
4259  sqlite3_finalize(pStmt));
4260  return 1;
4261  }
4262  nCol = sqlite3_column_count(pStmt);
4263  (void) rpmsqlCmd(sql, "finalize", db,
4264  sqlite3_finalize(pStmt));
4265  pStmt = 0;
4266  if (nCol == 0)
4267  return 0; /* no columns, no error */
4268  zSql = xmalloc(nByte + 20 + nCol * 2);
4269  sqlite3_snprintf(nByte + 20, zSql, "INSERT INTO '%q' VALUES(?",
4270  zTable);
4271  j = strlen30(zSql);
4272  for (i = 1; i < nCol; i++) {
4273  zSql[j++] = ',';
4274  zSql[j++] = '?';
4275  }
4276  zSql[j++] = ')';
4277  zSql[j] = 0;
4278  rc = rpmsqlCmd(sql, "prepare", db,
4279  sqlite3_prepare(db, zSql, -1, &pStmt, 0));
4280  zSql = _free(zSql);
4281  if (rc) {
4282 #ifdef DYING
4283  sqlite3 * db = (sqlite3 *)sql->I;
4284  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4285 #endif
4286  if (pStmt)
4287  (void) rpmsqlCmd(sql, "finalize", db,
4288  sqlite3_finalize(pStmt));
4289  return 1;
4290  }
4291 assert(sql->ifd == NULL);
4292  sql->ifd = Fopen(zFile, "rb.fpio");
4293  if (sql->ifd == NULL || Ferror(sql->ifd)) {
4294  rpmsql_error(1, _("cannot open \"%s\""), zFile);
4295  (void) rpmsqlCmd(sql, "finalize", db,
4296  sqlite3_finalize(pStmt));
4297  if (sql->ifd) (void) Fclose(sql->ifd);
4298  sql->ifd = NULL;
4299  return 1;
4300  }
4301 assert(sql->buf == NULL);
4302 sql->nbuf = BUFSIZ;
4303 sql->buf = xmalloc(sql->nbuf);
4304  azCol = malloc(sizeof(azCol[0]) * (nCol + 1));
4305  if (azCol == NULL) {
4306  if (sql->ifd) (void) Fclose(sql->ifd);
4307  sql->ifd = NULL;
4308  (void) rpmsqlCmd(sql, "finalize", db,
4309  sqlite3_finalize(pStmt));
4310 assert(azCol);
4311  }
4312  (void) rpmsqlCmd(sql, "exec", db,
4313  sqlite3_exec(db, "BEGIN", 0, 0, 0));
4314  zCommit = "COMMIT";
4315  while ((zLine = local_getline(sql, NULL)) != NULL) {
4316  char *z;
4317  i = 0;
4318  lineno++;
4319  azCol[0] = zLine;
4320  for (i = 0, z = zLine; *z && *z != '\n' && *z != '\r'; z++) {
4321  if (*z == sql->separator[0] && !strncmp(z, sql->separator, nSep)) {
4322  *z = '\0';
4323  i++;
4324  if (i < nCol) {
4325  azCol[i] = &z[nSep];
4326  z += nSep - 1;
4327  }
4328  }
4329  } /* end for */
4330  *z = '\0';
4331  if (i + 1 != nCol) {
4332  rpmsql_error(1,
4333  _("%s line %d: expected %d columns of data but found %d"),
4334  zFile, lineno, nCol, i + 1);
4335  zCommit = "ROLLBACK";
4336  rc = 1;
4337  break; /* from while */
4338  }
4339  for (i = 0; i < nCol; i++)
4340  rc = rpmsqlCmd(sql, "bind_text", db,
4341  sqlite3_bind_text(pStmt, i + 1, azCol[i], -1, SQLITE_STATIC));
4342  rc = rpmsqlCmd(sql, "step", db,
4343  sqlite3_step(pStmt));
4344  rc = rpmsqlCmd(sql, "reset", db,
4345  sqlite3_reset(pStmt));
4346  if (rc) {
4347 #ifdef DYING
4348  sqlite3 * db = (sqlite3 *)sql->I;
4349  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4350 #endif
4351  zCommit = "ROLLBACK";
4352  rc = 1;
4353  break; /* from while */
4354  }
4355  } /* end while */
4356  azCol = _free(azCol);
4357  if (sql->ifd) (void) Fclose(sql->ifd);
4358  sql->ifd = NULL;
4359 sql->buf = _free(sql->buf);
4360 sql->nbuf = 0;
4361  (void) rpmsqlCmd(sql, "finalize", db,
4362  sqlite3_finalize(pStmt));
4363  (void) rpmsqlCmd(sql, "exec", db,
4364  sqlite3_exec(db, zCommit, 0, 0, 0));
4365  } else
4366  if (c == 'i' && !strncmp(azArg[0], "indices", n) && nArg < 3) {
4367  /* XXX recursion b0rkage lies here. */
4368  uint32_t _flags = sql->flags;
4369  uint32_t _mode = sql->mode;
4370  char * t;
4371  char *zErrMsg = NULL;
4372  _rpmsqlOpenDB(sql);
4373  db = (sqlite3 *)sql->I;
4374  sql->flags &= ~RPMSQL_FLAGS_SHOWHDR;
4375  sql->mode = RPMSQL_MODE_LIST;
4376  if (nArg == 1) {
4377  t = rpmExpand("SELECT name FROM sqlite_master"
4378  " WHERE type='index' AND name NOT LIKE 'sqlite_%'"
4379  " UNION ALL "
4380  "SELECT name FROM sqlite_temp_master"
4381  " WHERE type='index'"
4382  " ORDER BY 1", NULL);
4383  rc = rpmsqlCmd(sql, "exec", db,
4384  sqlite3_exec(db, t, callback, sql, &zErrMsg));
4385  t = _free(t);
4386  } else {
4387  t = rpmExpand("SELECT name FROM sqlite_master"
4388  " WHERE type='index' AND tbl_name LIKE '", azArg[1], "'",
4389  " UNION ALL "
4390  "SELECT name FROM sqlite_temp_master"
4391  " WHERE type='index' AND tbl_name LIKE '", azArg[1], "'",
4392  " ORDER BY 1", NULL);
4393  rc = rpmsqlCmd(sql, "exec", db,
4394  sqlite3_exec(db, t, callback, sql, &zErrMsg));
4395  t = _free(t);
4396  }
4397  if (zErrMsg) {
4398  rpmsql_error(1, "%s", zErrMsg);
4399  sqlite3_free(zErrMsg);
4400  rc = 1;
4401  } else if (rc) {
4402 #ifdef DYING
4403  rpmsql_error(1, _("querying sqlite_master and sqlite_temp_master"));
4404 #endif
4405  rc = 1;
4406  }
4407  sql->mode = _mode;
4408  sql->flags = _flags;
4409  } else
4410 
4411 #ifdef SQLITE_ENABLE_IOTRACE
4412  if (c == 'i' && !strncmp(azArg[0], "iotrace", n)) {
4413  extern void (*sqlite3IoTrace) (const char *, ...);
4414  rc = rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->tfd);
4415  sqlite3IoTrace = (sql->tfd ? iotracePrintf : NULL);
4416  } else
4417 #endif
4418 
4419  if (c == 'l' && !strncmp(azArg[0], "load", n) && nArg >= 2) {
4420  const char *zFile, *zProc;
4421  char *zErrMsg = 0;
4422  zFile = azArg[1];
4423  zProc = nArg >= 3 ? azArg[2] : 0;
4424  if (!F_ISSET(sql, NOLOAD)) {
4425  _rpmsqlOpenDB(sql);
4426  db = (sqlite3 *)sql->I;
4427  rc = rpmsqlCmd(sql, "load_extension", db,
4428  sqlite3_load_extension(db, zFile, zProc, &zErrMsg));
4429  if (rc) {
4430  rpmsql_error(1, "%s", zErrMsg);
4431  sqlite3_free(zErrMsg);
4432  rc = 1;
4433  }
4434  }
4435  } else
4436 
4437  if (c == 'l' && !strncmp(azArg[0], "log", n) && nArg >= 1) {
4438  /* XXX set rc? */
4439  (void) rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->lfd);
4440  } else
4441  if (c == 'm' && !strncmp(azArg[0], "mode", n) && nArg == 2) {
4442  int n2 = strlen30(azArg[1]);
4443  if ((n2 == 4 && !strncmp(azArg[1], "line", n2))
4444  || (n2 == 5 && !strncmp(azArg[1], "lines", n2))) {
4445  sql->mode = RPMSQL_MODE_LINE;
4446  } else if ((n2 == 6 && !strncmp(azArg[1], "column", n2))
4447  || (n2 == 7 && !strncmp(azArg[1], "columns", n2))) {
4448  sql->mode = RPMSQL_MODE_COLUMN;
4449  } else if (n2 == 4 && !strncmp(azArg[1], "list", n2)) {
4450  sql->mode = RPMSQL_MODE_LIST;
4451  } else if (n2 == 4 && !strncmp(azArg[1], "html", n2)) {
4452  sql->mode = RPMSQL_MODE_HTML;
4453  } else if (n2 == 3 && !strncmp(azArg[1], "tcl", n2)) {
4454  sql->mode = RPMSQL_MODE_TCL;
4455  } else if (n2 == 3 && !strncmp(azArg[1], "csv", n2)) {
4456  sql->mode = RPMSQL_MODE_CSV;
4457  (void) stpcpy(sql->separator, ",");
4458  } else if (n2 == 4 && !strncmp(azArg[1], "tabs", n2)) {
4459  sql->mode = RPMSQL_MODE_LIST;
4460  (void) stpcpy(sql->separator, "\t");
4461  } else if (n2 == 6 && !strncmp(azArg[1], "insert", n2)) {
4462  sql->mode = RPMSQL_MODE_INSERT;
4463  set_table_name(sql, "table");
4464  } else {
4465  rpmsql_error(1, _("mode should be one of: %s"),
4466  "column csv html insert line list tabs tcl");
4467  rc = 1;
4468  }
4469  } else
4470  if (c == 'm' && !strncmp(azArg[0], "mode", n) && nArg == 3) {
4471  int n2 = strlen30(azArg[1]);
4472  if (n2 == 6 && !strncmp(azArg[1], "insert", n2)) {
4473  sql->mode = RPMSQL_MODE_INSERT;
4474  set_table_name(sql, azArg[2]);
4475  } else {
4476  rpmsql_error(1, _("invalid arguments: "
4477  " \"%s\". Enter \".help\" for help"), azArg[2]);
4478  rc = 1;
4479  }
4480  } else
4481  if (c == 'n' && !strncmp(azArg[0], "nullvalue", n) && nArg == 2) {
4482  (void) stpncpy(sql->nullvalue, azArg[1], sizeof(sql->nullvalue)-1);
4483  } else
4484  if (c == 'o' && !strncmp(azArg[0], "output", n) && nArg == 2) {
4485  rc = rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->ofd);
4486 
4487  /* Make sure sql->ofd squirts _SOMEWHERE_. Save the name too. */
4488  sql->outfile = _free(sql->outfile);
4489  if (sql->ofd)
4490  sql->outfile = xstrdup(azArg[1]);
4491  else {
4492  sql->ofd = fdDup(STDOUT_FILENO);
4493  sql->outfile = xstrdup("stdout");
4494  }
4495  } else
4496  if (c == 'p' && !strncmp(azArg[0], "prompt", n)
4497  && (nArg == 2 || nArg == 3)) {
4498  if (nArg >= 2) {
4499  sql->zPrompt = _free(sql->zPrompt);
4500  sql->zPrompt = xstrdup(azArg[1]);
4501  }
4502  if (nArg >= 3) {
4503  sql->zContinue = _free(sql->zContinue);
4504  sql->zContinue = xstrdup(azArg[2]);
4505  }
4506  } else
4507  if (c == 'q' && !strncmp(azArg[0], "quit", n) && nArg == 1) {
4508  rc = 2;
4509  } else
4510  if (c == 'r' && n >= 3 && !strncmp(azArg[0], "read", n)
4511  && nArg == 2) {
4512  FD_t _ifd = sql->ifd;
4513  sql->ifd = Fopen(azArg[1], "rb.fpio");
4514  if (sql->ifd == NULL || Ferror(sql->ifd)) {
4515  rpmsql_error(1, _("cannot open \"%s\""), azArg[1]);
4516  rc = 1;
4517  } else {
4518  /* XXX .read assumes .echo off? */
4519  rc = rpmsqlInput(sql);
4520  }
4521  if (sql->ifd) (void) Fclose(sql->ifd);
4522  sql->ifd = _ifd;
4523  } else
4524  if (c == 'r' && n >= 3 && !strncmp(azArg[0], "restore", n)
4525  && nArg > 1 && nArg < 4) {
4526  const char *zSrcFile;
4527  const char *zDb;
4528  sqlite3 * pSrc;
4529  sqlite3_backup *pBackup;
4530  int nTimeout = 0;
4531 
4532  if (nArg == 2) {
4533  zSrcFile = azArg[1];
4534  zDb = "main";
4535  } else {
4536  zSrcFile = azArg[2];
4537  zDb = azArg[1];
4538  }
4539  rc = rpmsqlCmd(sql, "open", pSrc, /* XXX watchout: arg order */
4540  sqlite3_open(zSrcFile, &pSrc));
4541  if (rc) {
4542 #ifdef DYING
4543  rpmsql_error(1, _("cannot open \"%s\""), zSrcFile);
4544 #endif
4545  (void) rpmsqlCmd(sql, "close", pSrc,
4546  sqlite3_close(pSrc));
4547  return 1;
4548  }
4549  _rpmsqlOpenDB(sql);
4550  db = (sqlite3 *)sql->I;
4551  pBackup = sqlite3_backup_init(db, zDb, pSrc, "main");
4552  if (pBackup == 0) {
4553  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4554  (void) rpmsqlCmd(sql, "close", db,
4555  sqlite3_close(pSrc));
4556  return 1;
4557  }
4558  while ((rc = sqlite3_backup_step(pBackup, 100)) == SQLITE_OK
4559  || rc == SQLITE_BUSY)
4560  {
4561  if (rc == SQLITE_BUSY) {
4562  if (nTimeout++ >= 3)
4563  break;
4564  sqlite3_sleep(100);
4565  }
4566  }
4567  sqlite3_backup_finish(pBackup);
4568  switch (rc) {
4569  case SQLITE_DONE:
4570  rc = 0;
4571  break;
4572  case SQLITE_BUSY:
4573  case SQLITE_LOCKED:
4574  rpmsql_error(1, _("source database is busy"));
4575  rc = 1;
4576  break;
4577  default:
4578  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4579  rc = 1;
4580  break;
4581  }
4582  (void) rpmsqlCmd(sql, "close", pSrc,
4583  sqlite3_close(pSrc));
4584  } else
4585  if (c == 's' && !strncmp(azArg[0], "schema", n) && nArg < 3) {
4586  /* XXX recursion b0rkage lies here. */
4587  uint32_t _flags = sql->flags;
4588  uint32_t _mode = sql->mode;
4589  char *zErrMsg = 0;
4590  _rpmsqlOpenDB(sql);
4591  db = (sqlite3 *)sql->I;
4592  sql->flags &= ~RPMSQL_FLAGS_SHOWHDR;
4593  sql->mode = RPMSQL_MODE_SEMI;
4594  if (nArg > 1) {
4595  int i;
4596  for (i = 0; azArg[1][i]; i++)
4597  azArg[1][i] = (char) tolower(azArg[1][i]);
4598  if (!strcmp(azArg[1], "sqlite_master")) {
4599  char *new_argv[2], *new_colv[2];
4600  new_argv[0] = "CREATE TABLE sqlite_master (\n"
4601  " type text,\n"
4602  " name text,\n"
4603  " tbl_name text,\n"
4604  " rootpage integer,\n" " sql text\n" ")";
4605  new_argv[1] = 0;
4606  new_colv[0] = "sql";
4607  new_colv[1] = 0;
4608  callback(sql, 1, new_argv, new_colv);
4609  rc = SQLITE_OK;
4610  } else if (!strcmp(azArg[1], "sqlite_temp_master")) {
4611  char *new_argv[2], *new_colv[2];
4612  new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
4613  " type text,\n"
4614  " name text,\n"
4615  " tbl_name text,\n"
4616  " rootpage integer,\n" " sql text\n" ")";
4617  new_argv[1] = 0;
4618  new_colv[0] = "sql";
4619  new_colv[1] = 0;
4620  callback(sql, 1, new_argv, new_colv);
4621  rc = SQLITE_OK;
4622  } else {
4623  char * t;
4624  t = rpmExpand( "SELECT sql FROM "
4625  " (SELECT sql sql, type type, tbl_name tbl_name, name name"
4626  " FROM sqlite_master UNION ALL"
4627  " SELECT sql, type, tbl_name, name FROM sqlite_temp_master)"
4628  " WHERE tbl_name LIKE '", azArg[1], "'"
4629  " AND type!='meta' AND sql NOTNULL "
4630  "ORDER BY substr(type,2,1), name", NULL);
4631  rc = rpmsqlCmd(sql, "exec", db,
4632  sqlite3_exec(db, t, callback, sql, &zErrMsg));
4633  t = _free(t);
4634  }
4635  sql->mode = _mode;
4636  sql->flags = _flags;
4637  } else {
4638  rc = rpmsqlCmd(sql, "exec", db,
4639  sqlite3_exec(db,
4640  "SELECT sql FROM "
4641  " (SELECT sql sql, type type, tbl_name tbl_name, name name"
4642  " FROM sqlite_master UNION ALL"
4643  " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
4644  "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
4645  "ORDER BY substr(type,2,1), name",
4646  callback, sql, &zErrMsg));
4647  }
4648  if (zErrMsg) {
4649  rpmsql_error(1, "%s", zErrMsg);
4650  sqlite3_free(zErrMsg);
4651  rc = 1;
4652  } else if (rc != SQLITE_OK) {
4653  rpmsql_error(1, _("querying schema information"));
4654  rc = 1;
4655  } else {
4656  rc = 0;
4657  }
4658  } else
4659  if (c == 's' && !strncmp(azArg[0], "separator", n) && nArg == 2) {
4660  (void) stpncpy(sql->separator, azArg[1], sizeof(sql->separator)-1);
4661  } else
4662  if (c == 's' && !strncmp(azArg[0], "show", n) && nArg == 1) {
4663  int i;
4664  rpmsqlFprintf(sql, "%9.9s: %s\n", "echo", F_ISSET(sql, ECHO) ? "on" : "off");
4665  rpmsqlFprintf(sql, "%9.9s: %s\n", "explain",
4666  sql->explainPrev.valid ? "on" : "off");
4667  rpmsqlFprintf(sql, "%9.9s: %s\n", "headers",
4668  F_ISSET(sql, SHOWHDR) ? "on" : "off");
4669  rpmsqlFprintf(sql, "%9.9s: %s\n", "mode", modeDescr[sql->mode]);
4670  rpmsqlFprintf(sql, "%9.9s: ", "nullvalue");
4671  output_c_string(sql, sql->nullvalue);
4672  rpmsqlFprintf(sql, "\n");
4673  rpmsqlFprintf(sql, "%9.9s: %s\n", "output",
4674  (sql->outfile ? sql->outfile : "stdout"));
4675  rpmsqlFprintf(sql, "%9.9s: ", "separator");
4676  output_c_string(sql, sql->separator);
4677  rpmsqlFprintf(sql, "\n");
4678  rpmsqlFprintf(sql, "%9.9s: ", "width");
4679  for (i = 0;
4680  i < (int) ArraySize(sql->colWidth) && sql->colWidth[i] != 0;
4681  i++)
4682  {
4683  rpmsqlFprintf(sql, "%d ", sql->colWidth[i]);
4684  }
4685  rpmsqlFprintf(sql, "\n");
4686  } else
4687  if (c == 't' && n > 1 && !strncmp(azArg[0], "tables", n) && nArg < 3) {
4688  char **azResult;
4689  int nRow;
4690  char *zErrMsg;
4691  _rpmsqlOpenDB(sql);
4692  db = (sqlite3 *)sql->I;
4693  if (nArg == 1) {
4694  rc = rpmsqlCmd(sql, "get_table", db,
4695  sqlite3_get_table(db,
4696  "SELECT name FROM sqlite_master "
4697  "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
4698  "UNION ALL "
4699  "SELECT name FROM sqlite_temp_master "
4700  "WHERE type IN ('table','view') "
4701  "ORDER BY 1",
4702  &azResult, &nRow, 0, &zErrMsg));
4703  } else {
4704  char * t;
4705  t = rpmExpand("SELECT name FROM sqlite_master "
4706  " WHERE type IN ('table','view') AND name LIKE '", azArg[1], "'"
4707  " UNION ALL "
4708  "SELECT name FROM sqlite_temp_master"
4709  " WHERE type IN ('table','view') AND name LIKE '", azArg[1], "'"
4710  "ORDER BY 1", NULL);
4711  rc = rpmsqlCmd(sql, "get_table", db,
4712  sqlite3_get_table(db, t, &azResult, &nRow, 0,&zErrMsg));
4713  t = _free(t);
4714  }
4715  if (zErrMsg) {
4716  rpmsql_error(1, "%s", zErrMsg);
4717  sqlite3_free(zErrMsg);
4718  rc = 1;
4719  } else if (rc) {
4720  rpmsql_error(1, _("querying sqlite_master and sqlite_temp_master"));
4721  rc = 1;
4722  } else {
4723  int len, maxlen = 0;
4724  int i, j;
4725  int nPrintCol, nPrintRow;
4726  for (i = 1; i <= nRow; i++) {
4727  if (azResult[i] == 0)
4728  continue;
4729  len = strlen30(azResult[i]);
4730  if (len > maxlen)
4731  maxlen = len;
4732  }
4733  nPrintCol = 80 / (maxlen + 2);
4734  if (nPrintCol < 1)
4735  nPrintCol = 1;
4736  nPrintRow = (nRow + nPrintCol - 1) / nPrintCol;
4737  for (i = 0; i < nPrintRow; i++) {
4738  for (j = i + 1; j <= nRow; j += nPrintRow) {
4739  char *zSp = j <= nPrintRow ? "" : " ";
4740  rpmsqlFprintf(sql, "%s%-*s", zSp, maxlen,
4741  azResult[j] ? azResult[j] : "");
4742  }
4743  rpmsqlFprintf(sql, "\n");
4744  }
4745  }
4746  sqlite3_free_table(azResult);
4747  } else
4748  if (c == 't' && n > 4 && !strncmp(azArg[0], "timeout", n) && nArg == 2) {
4749  _rpmsqlOpenDB(sql);
4750  db = (sqlite3 *)sql->I;
4751  (void) rpmsqlCmd(sql, "busy_timeout", db,
4752  sqlite3_busy_timeout(db, atoi(azArg[1])));
4753  } else
4754  if (HAS_TIMER && c == 't' && n >= 5
4755  && !strncmp(azArg[0], "timer", n) && nArg == 2) {
4756  sql->enableTimer = booleanValue(azArg[1]);
4757  } else
4758  if (c == 'w' && !strncmp(azArg[0], "width", n) && nArg > 1) {
4759  int j;
4760 assert(nArg <= ArraySize(azArg));
4761  for (j = 1; j < nArg && j < ArraySize(sql->colWidth); j++)
4762  sql->colWidth[j - 1] = atoi(azArg[j]);
4763  } else
4764  {
4765  rpmsql_error(1, _("unknown command or invalid arguments: "
4766  " \"%s\". Enter \".help\" for help"), azArg[0]);
4767  rc = 1;
4768  }
4769 
4770  return rc;
4771 }
4772 
4773 #endif /* defined(WITH_SQLITE) */
4774 
4775 /*==============================================================*/
4776 
4777 #if defined(WITH_SQLITE)
4778 
4783 static int _contains_semicolon(const char *z, int N)
4784 {
4785  int rc = 0;
4786  int i;
4787  for (i = 0; i < N; i++) {
4788  if (z[i] != ';')
4789  continue;
4790  rc = 1;
4791  break;
4792  }
4793 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, z, rc));
4794  return rc;
4795 }
4796 
4800 static int _all_whitespace(const char *z)
4801 {
4802  int rc = 1;
4803 
4804  for (; *z; z++) {
4805  if (xisspace(*(unsigned char *) z))
4806  continue;
4807  if (*z == '/' && z[1] == '*') {
4808  z += 2;
4809  while (*z && (*z != '*' || z[1] != '/'))
4810  z++;
4811  if (*z == '\0') {
4812  rc = 0;
4813  break;
4814  }
4815  z++;
4816  continue;
4817  }
4818  if (*z == '-' && z[1] == '-') {
4819  z += 2;
4820  while (*z && *z != '\n')
4821  z++;
4822  if (*z == '\0')
4823  break;
4824  continue;
4825  }
4826  rc = 0;
4827  break;
4828  }
4829 
4830 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, z, rc));
4831  return rc;
4832 }
4833 
4839 static int _is_command_terminator(const char *zLine)
4840 {
4841  int rc = 1;
4842 
4843  while (xisspace(*(unsigned char *) zLine))
4844  zLine++;
4845  if (zLine[0] == '/' && _all_whitespace(&zLine[1]))
4846  goto exit; /* Oracle */
4847  if (xtolower(zLine[0]) == 'g' && xtolower(zLine[1]) == 'o'
4848  && _all_whitespace(&zLine[2]))
4849  goto exit; /* SQL Server */
4850  rc = 0;
4851 exit:
4852 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, zLine, rc));
4853  return rc;
4854 }
4855 
4860 static int _is_complete(char *zSql, int nSql)
4861 {
4862  int rc = 1;
4863  if (zSql == NULL)
4864  goto exit;
4865  zSql[nSql] = ';';
4866  zSql[nSql + 1] = '\0';
4867  rc = sqlite3_complete(zSql);
4868  zSql[nSql] = '\0';
4869 exit:
4870 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, zSql, rc));
4871  return rc;
4872 }
4873 
4884 static int rpmsqlInput(rpmsql sql)
4885 {
4886  sqlite3 * db = (sqlite3 *) sql->I;
4887  char *zLine = 0;
4888  char *zSql = 0;
4889  int nSql = 0;
4890  int nSqlPrior = 0;
4891  char *zErrMsg;
4892  int rc;
4893  int errCnt = 0;
4894  int lineno = 0;
4895  int startline = 0;
4896 
4897 char * _buf = sql->buf;
4898 size_t _nbuf = sql->nbuf;
4899 
4900 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, sql));
4901 if (_rpmsql_debug < 0)
4902 rpmsqlDebugDump(sql);
4903 
4904 sql->nbuf = BUFSIZ;
4905 sql->buf = xmalloc(sql->nbuf);
4906 
4907  while (errCnt == 0 || !F_ISSET(sql, BAIL) || F_ISSET(sql, PROMPT))
4908  {
4909  if (sql->ofd) Fflush(sql->ofd);
4910  zLine = rpmsqlInputOneLine(sql, zSql);
4911  if (zLine == NULL)
4912  break; /* We have reached EOF */
4913  if (_rpmsqlSeenInterrupt) {
4914  if (!F_ISSET(sql, PROMPT))
4915  break;
4917  }
4918  lineno++;
4919  if ((zSql == NULL || zSql[0] == '\0') && _all_whitespace(zLine))
4920  continue;
4921  if (zLine && zLine[0] == '.' && nSql == 0) {
4922  if (F_ISSET(sql, ECHO))
4923  rpmsqlFprintf(sql, "%s\n", zLine);
4924  rc = rpmsqlMetaCommand(sql, zLine);
4925  if (rc == 2) /* exit requested */
4926  break;
4927  else if (rc)
4928  errCnt++;
4929  continue;
4930  }
4931  if (_is_command_terminator(zLine) && _is_complete(zSql, nSql))
4932  memcpy(zLine, ";", 2);
4933  nSqlPrior = nSql;
4934  if (zSql == NULL) {
4935  int i;
4936  for (i = 0; zLine[i] && xisspace((unsigned char) zLine[i]); i++)
4937  ;
4938  if (zLine[i] != '\0') {
4939  nSql = strlen30(zLine);
4940  zSql = xmalloc(nSql + 3);
4941  memcpy(zSql, zLine, nSql + 1);
4942  startline = lineno;
4943  }
4944  } else {
4945  int len = strlen30(zLine);
4946  zSql = xrealloc(zSql, nSql + len + 4);
4947  zSql[nSql++] = '\n';
4948  memcpy(&zSql[nSql], zLine, len + 1);
4949  nSql += len;
4950  }
4951  if (zSql && _contains_semicolon(&zSql[nSqlPrior], nSql - nSqlPrior)
4952  && sqlite3_complete(zSql)) {
4953  sql->cnt = 0;
4954  _rpmsqlOpenDB(sql);
4955  db = (sqlite3 *)sql->I;
4956  BEGIN_TIMER(sql);
4957  rc = _rpmsqlShellExec(sql, zSql, _rpmsqlShellCallback, &zErrMsg);
4958  END_TIMER(sql);
4959  if (rc || zErrMsg) {
4960  char zPrefix[100];
4961  if (!F_ISSET(sql, PROMPT) || !F_ISSET(sql, INTERACTIVE))
4962  snprintf(zPrefix, sizeof(zPrefix),
4963  "near line %d: ", startline);
4964  else
4965  zPrefix[0] = '\0';
4966  rpmsql_error(1, "%s%s", zPrefix,
4967  zErrMsg ? zErrMsg : sqlite3_errmsg(db));
4968  zErrMsg = _free(zErrMsg);
4969  errCnt++;
4970  }
4971  zSql = _free(zSql);
4972  nSql = 0;
4973  }
4974  }
4975  if (zSql) {
4976  if (!_all_whitespace(zSql))
4977  rpmsql_error(1, _("incomplete SQL: %s"), zSql);
4978  zSql = _free(zSql);
4979  }
4980 
4981 sql->buf = _free(sql->buf);
4982 sql->buf = _buf;
4983 sql->nbuf = _nbuf;
4984 
4985 SQLDBG((stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, sql, errCnt));
4986 
4987  return errCnt;
4988 }
4989 
4997 static int rpmsqlInitRC(rpmsql sql, const char *sqliterc)
4998 {
4999  int rc = 0;
5000 
5001 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, sqliterc));
5002 if (_rpmsql_debug < 0)
5003 rpmsqlDebugDump(sql);
5004 
5005  if (sqliterc == NULL)
5006  sqliterc = sql->zInitrc;
5007  if (sqliterc) {
5008  FD_t _ifd = sql->ifd;
5009  sql->ifd = Fopen(sqliterc, "rb.fpio");
5010  if (!(sql->ifd == NULL || Ferror(sql->ifd))) {
5011  if (F_ISSET(sql, INTERACTIVE))
5012  rpmsql_error(0, "-- Loading resources from %s", sqliterc);
5013  rc = rpmsqlInput(sql);
5014  }
5015  if (sql->ifd) (void) Fclose(sql->ifd);
5016  sql->ifd = _ifd;
5017  }
5018 
5019 SQLDBG((stderr, "<-- %s(%p,%s) rc %d\n", __FUNCTION__, sql, sqliterc, rc));
5020 
5021  return rc;
5022 }
5023 
5024 #endif /* defined(WITH_SQLITE) */
5025 
5026 /*==============================================================*/
5027 
5028 #if defined(WITH_SQLITE)
5029 
5032 static void rpmsqlArgCallback(poptContext con,
5033  /*@unused@ */ enum poptCallbackReason reason,
5034  const struct poptOption *opt,
5035  const char *arg,
5036  /*@unused@ */ void *_data)
5037  /*@ */
5038 {
5039  rpmsql sql = &_sql;
5040 
5041  /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
5042  if (opt->arg == NULL)
5043  switch (opt->val) {
5044  case 'S': /* -separator x */
5045 assert(arg != NULL);
5046  (void) stpncpy(sql->separator, arg, sizeof(sql->separator)-1);
5047  break;
5048  case 'N': /* -nullvalue text */
5049 assert(arg != NULL);
5050  (void) stpncpy(sql->nullvalue, arg, sizeof(sql->nullvalue)-1);
5051  break;
5052  case 'V': /* -version */
5053  printf("%s\n", sqlite3_libversion());
5054  /*@-exitarg@ */ exit(0); /*@=exitarg@ */
5055  /*@notreached@ */ break;
5056  default:
5057  /* XXX fprintf(stderr, ...)? */
5058  rpmsql_error(0, _("%s: Unknown callback(0x%x)\n"),
5059  __FUNCTION__, (unsigned) opt->val);
5060  poptPrintUsage(con, stderr, 0);
5061  /*@-exitarg@ */ exit(2); /*@=exitarg@ */
5062  /*@notreached@ */ break;
5063  }
5064 }
5065 
5066 /*@unchecked@*/ /*@observer@*/
5067 static struct poptOption _rpmsqlOptions[] = {
5068  /*@-type@*//* FIX: cast? */
5069  {NULL, '\0',
5070  POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
5071  rpmsqlArgCallback, 0, NULL, NULL},
5072 /*@=type@*/
5073 
5074  { "debug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH|POPT_ARGFLAG_DOC_HIDDEN, &_rpmsql_debug, -1,
5075  N_("Debug embedded SQL interpreter"), NULL},
5076  { "create", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH|POPT_ARGFLAG_DOC_HIDDEN, &_sql.flags, RPMSQL_FLAGS_CREATE,
5077  N_("create database if not exists"), NULL},
5078 
5079  { "init", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, &_sql.zInitFile, 0,
5080  N_("read/process named FILE"), N_("FILE") },
5081  { "echo", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_ECHO,
5082  N_("print commands before execution"), NULL },
5083 
5084  { "load", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_NOLOAD,
5085  N_("disable extension loading (normally enabled)"), NULL },
5086  { "header", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_SHOWHDR,
5087  N_("turn headers on or off"), NULL },
5088 
5089  { "bail", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_BAIL,
5090  N_("stop after hitting an error"), NULL },
5091 
5092  { "interactive", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_INTERACTIVE,
5093  N_("force interactive I/O"), NULL },
5094  { "batch", '\0', POPT_BIT_CLR|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_INTERACTIVE,
5095  N_("force batch I/O"), NULL },
5096 
5097  { "column", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_COLUMN,
5098  N_("set output mode to 'column'"), NULL },
5099  { "csv", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_CSV,
5100  N_("set output mode to 'csv'"), NULL },
5101  { "html", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_HTML,
5102  N_("set output mode to HTML"), NULL },
5103  { "line", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_LINE,
5104  N_("set output mode to 'line'"), NULL },
5105  { "list", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_LIST,
5106  N_("set output mode to 'list'"), NULL },
5107  { "separator", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, 0, 'S',
5108  N_("set output field separator (|)"), N_("CHAR") },
5109  { "nullvalue", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, 0, 'N',
5110  N_("set text string for NULL values"), N_("TEXT") },
5111 
5112  { "version", '\0', POPT_ARG_NONE|POPT_ARGFLAG_ONEDASH, 0, 'V',
5113  N_("show SQLite version"), NULL},
5114 
5115 #ifdef NOTYET
5116  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
5117  N_("Common options for all rpmio executables:"), NULL},
5118 #endif
5119 
5120  POPT_AUTOHELP
5121  { NULL, (char) -1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
5122  N_("\
5123 Usage: dbsql [OPTIONS] FILENAME [SQL]\n\
5124 FILENAME is the name of an SQLite database. A new database is created\n\
5125 if the file does not previously exist.\n\
5126 \n\
5127 OPTIONS include:\n\
5128  -help show this message\n\
5129  -init filename read/process named file\n\
5130  -echo print commands before execution\n\
5131  -[no]header turn headers on or off\n\
5132  -bail stop after hitting an error\n\
5133  -interactive force interactive I/O\n\
5134  -batch force batch I/O\n\
5135  -column set output mode to 'column'\n\
5136  -csv set output mode to 'csv'\n\
5137  -html set output mode to HTML\n\
5138  -line set output mode to 'line'\n\
5139  -list set output mode to 'list'\n\
5140  -separator 'x' set output field separator (|)\n\
5141  -nullvalue 'text' set text string for NULL values\n\
5142  -version show SQLite version\n\
5143 "), NULL},
5144 
5145  POPT_TABLEEND
5146 };
5147 
5148 #endif /* defined(WITH_SQLITE) */
5149 
5150 /*==============================================================*/
5151 
5155 static void rpmsqlFini(void * _sql)
5156  /*@globals fileSystem @*/
5157  /*@modifies *_sql, fileSystem @*/
5158 {
5159  rpmsql sql = _sql;
5160 
5161 SQLDBG((stderr, "==> %s(%p)\n", __FUNCTION__, sql));
5162 
5163  sql->zDestTable = _free(sql->zDestTable);
5164 
5165  if (sql->ifd)
5166  (void) Fclose(sql->ifd); /* XXX stdin dup'd */
5167  sql->ifd = NULL;
5168  if (sql->ofd)
5169  (void) Fclose(sql->ofd); /* XXX stdout/stderr were dup'd */
5170  sql->ofd = NULL;
5171  if (sql->lfd)
5172  (void) Fclose(sql->lfd);
5173  sql->lfd = NULL;
5174  if (sql->tfd)
5175  (void) Fclose(sql->tfd);
5176  sql->tfd = NULL;
5177 
5178  sql->buf = _free(sql->buf);
5179  sql->buf = sql->b = NULL;
5180  sql->nbuf = sql->nb = 0;
5181 
5182  /* XXX INTERACTIVE cruft. */
5183  sql->zHome = _free(sql->zHome);
5184  sql->zInitrc = _free(sql->zInitrc);
5185  sql->zHistory = _free(sql->zHistory);
5186  sql->zPrompt = _free(sql->zPrompt);
5187  sql->zContinue = _free(sql->zContinue);
5188 
5189  sql->outfile = _free(sql->outfile);
5190 
5191  sql->zDbFilename = _free(sql->zDbFilename);
5192  sql->zInitFile = _free(sql->zInitFile);
5193  sql->av = argvFree(sql->av);
5194 #if defined(WITH_SQLITE)
5195  if (sql->I) {
5196  sqlite3 * db = (sqlite3 *)sql->I;
5197  (void) rpmsqlCmd(sql, "close", db,
5198  sqlite3_close(db));
5199  }
5200 #endif
5201  sql->I = NULL;
5202  (void) rpmiobFree(sql->iob);
5203  sql->iob = NULL;
5204 }
5205 
5206 /*@unchecked@*/ /*@only@*/ /*@null@*/
5208 
5209 static rpmsql rpmsqlGetPool(/*@null@*/ rpmioPool pool)
5210  /*@globals _rpmsqlPool, fileSystem @*/
5211  /*@modifies pool, _rpmsqlPool, fileSystem @*/
5212 {
5213  rpmsql sql;
5214 
5215  if (_rpmsqlPool == NULL) {
5216  _rpmsqlPool = rpmioNewPool("sql", sizeof(*sql), -1, _rpmsql_debug,
5217  NULL, NULL, rpmsqlFini);
5218  pool = _rpmsqlPool;
5219  }
5220  sql = (rpmsql) rpmioGetPool(pool, sizeof(*sql));
5221  memset(((char *)sql)+sizeof(sql->_item), 0, sizeof(*sql)-sizeof(sql->_item));
5222  return sql;
5223 }
5224 
5225 const char ** rpmsqlArgv(rpmsql sql, int * argcp)
5226 {
5227  const char ** av = sql->av;
5228 
5229  if (argcp)
5230  *argcp = argvCount(av);
5231  return av;
5232 }
5233 
5234 #if defined(WITH_SQLITE)
5235 
5239 static void rpmsqlInitPopt(rpmsql sql, int ac, char ** av, poptOption tbl)
5240  /*@modifies sql @*/
5241 {
5242  poptContext con;
5243  int rc;
5244 
5245  if (av == NULL || av[0] == NULL || av[1] == NULL)
5246  goto exit;
5247 
5248  con = poptGetContext(av[0], ac, (const char **)av, tbl, 0);
5249 
5250  /* Process all options into _sql, whine if unknown options. */
5251  while ((rc = poptGetNextOpt(con)) > 0) {
5252  const char * arg = poptGetOptArg(con);
5253  arg = _free(arg);
5254  switch (rc) {
5255  default:
5256  /* XXX fprintf(stderr, ...)? */
5257  rpmsql_error(0, _("%s: option table misconfigured (%d)\n"),
5258  __FUNCTION__, rc);
5259  break;
5260  }
5261  }
5262  /* XXX FIXME: arrange error return iff rc < -1. */
5263 if (rc)
5264 SQLDBG((stderr, "%s: poptGetNextOpt rc(%d): %s\n", __FUNCTION__, rc, poptStrerror(rc)));
5265 
5266  /* Move the POPT parsed values into the current rpmsql object. */
5267  sql->flags = _sql.flags;
5268  sql->mode = _sql.mode;
5269  if (_sql.zInitFile) {
5270  sql->zInitFile = _free(sql->zInitFile);
5271  sql->zInitFile = _sql.zInitFile;
5272  _sql.zInitFile = NULL;
5273  }
5274  memcpy(sql->separator, _sql.separator, sizeof(sql->separator));
5275  memcpy(sql->nullvalue, _sql.nullvalue, sizeof(sql->nullvalue));
5276 
5277  sql->av = argvFree(sql->av);
5278  rc = argvAppend(&sql->av, poptGetArgs(con));
5279 
5280  con = poptFreeContext(con);
5281 
5282 exit:
5283  /* If not overridden, set the separator according to mode. */
5284  if (sql->separator[0] == '\0')
5285  switch (sql->mode) {
5286  default:
5287  case RPMSQL_MODE_LIST: (void)stpcpy(sql->separator, "|"); break;
5288  case RPMSQL_MODE_CSV: (void)stpcpy(sql->separator, ","); break;
5289  }
5290 
5291 SQLDBG((stderr, "<== %s(%p, %p[%u], %p)\n", __FUNCTION__, sql, av, (unsigned)ac, tbl));
5292 }
5293 #endif /* defined(WITH_SQLITE) */
5294 
5295 rpmsql rpmsqlNew(char ** av, uint32_t flags)
5296 {
5297  rpmsql sql =
5298  (flags & 0x80000000) ? rpmsqlI() :
5299  rpmsqlGetPool(_rpmsqlPool);
5300  int ac = argvCount((ARGV_t)av);
5301 
5302 SQLDBG((stderr, "==> %s(%p[%u], 0x%x)\n", __FUNCTION__, av, (unsigned)ac, flags));
5303 if (av && _rpmsql_debug < 0)
5304 argvPrint("av", (ARGV_t)av, NULL);
5305 
5306  sql->flags = flags; /* XXX useful? */
5307 
5308 #if defined(WITH_SQLITE)
5309  /* XXX Avoid initialization on global interpreter creation path. */
5310  if (av) {
5311  static int _oneshot;
5312  sqlite3 * db = NULL;
5313  int xx;
5314 
5315  if (!_oneshot) {
5316 #if defined(SQLITE_CONFIG_LOG)
5317  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, sql);
5318 #endif
5319  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
5320  _oneshot++;
5321  }
5322 
5323  /* Initialize defaults for popt parsing. */
5324  memset(&_sql, 0, sizeof(_sql));
5325  sql->flags = _sql.flags = flags; /* XXX INTERACTIVE defaulted here. */
5326  sql->mode = _sql.mode = RPMSQL_MODE_LIST;
5327 
5328  rpmsqlInitPopt(sql, ac, av, (poptOption) _rpmsqlOptions);
5329 
5330  /* The 1st argument is the database to open (or :memory: default). */
5331  if (sql->av && sql->av[0]) {
5332  sql->zDbFilename = xstrdup(sql->av[0]); /* XXX strdup? */
5333  /* If requested or database already exists, open immediately. */
5334  if (F_ISSET(sql, CREATE) || !Access(sql->zDbFilename, R_OK)) {
5335  xx = rpmsqlCmd(sql, "open", db, /* XXX watchout: arg order */
5336  sqlite3_open(sql->zDbFilename, &db));
5337  sql->I = (void *) db;
5338  }
5339  } else
5340  sql->zDbFilename = xstrdup(":memory:");
5341 
5342  /* Read ~/.sqliterc (if specified), then reparse options. */
5343  if (sql->zInitFile || F_ISSET(sql, INTERACTIVE)) {
5344  sql->ofd = fdDup(STDOUT_FILENO);
5345  xx = rpmsqlInitRC(sql, sql->zInitFile);
5346  if (sql->ofd) (void) Fclose(sql->ofd);
5347  sql->ofd = NULL;
5348  rpmsqlInitPopt(sql, ac, av, (poptOption) _rpmsqlOptions);
5349  }
5350 
5351  }
5352 
5353  { /* XXX INTERACTIVE cruft. */
5354  static const char _zInitrc[] = "/.sqliterc";
5355  static const char _zHistory[] = "/.sqlite_history";
5356  /* XXX getpwuid? */
5357 sql->zHome = _free(sql->zHome);
5358  sql->zHome = xstrdup(getenv("HOME"));
5359 sql->zInitrc = _free(sql->zInitrc);
5360  sql->zInitrc = rpmGetPath(sql->zHome, _zInitrc, NULL);
5361 sql->zHistory = _free(sql->zHistory);
5362  sql->zHistory = rpmGetPath(sql->zHome, _zHistory, NULL);
5363  /*
5364  ** Prompt strings. Initialized in main. Settable with
5365  ** .prompt main continue
5366  */
5367  /* Initialize the prompt from basename(argv[0]). */
5368  if (sql->zPrompt == NULL) { /* XXX this test is useless */
5369  char * t = xstrdup((av && av[0] ? av[0] : "sql"));
5370  char * bn = basename(t);
5371 sql->zPrompt = _free(sql->zPrompt);
5372  sql->zPrompt = rpmExpand(bn, "> ", NULL);
5373  t = _free(t);
5374 sql->zContinue = _free(sql->zContinue);
5375  sql->zContinue = t = xstrdup(sql->zPrompt);
5376  while (*t && *t != '>')
5377  *t++ = '-';
5378  }
5379  }
5380 #else /* WITH_SQLITE */
5381  if (av)
5382  (void) argvAppend(&sql->av, (ARGV_t) av); /* XXX useful? */
5383 #endif /* WITH_SQLITE */
5384 
5385  /* Set sane defaults for output sink(s) dependent on INTERACTIVE. */
5386  if (F_ISSET(sql, INTERACTIVE)) {
5387  if (sql->ofd == NULL)
5388  sql->ofd = fdDup(STDOUT_FILENO);
5389  } else {
5390  if (sql->iob == NULL)
5391  sql->iob = rpmiobNew(0);
5392  }
5393 
5394  return rpmsqlLink(sql);
5395 }
5396 
5397 rpmRC rpmsqlRun(rpmsql sql, const char * str, const char ** resultp)
5398 {
5399  rpmRC rc = RPMRC_FAIL;
5400 
5401 SQLDBG((stderr, "==> %s(%p,%p[%u]) \"%s\"\n", __FUNCTION__, sql, str, (unsigned)(str ? strlen(str) : 0), str));
5402 SQLDBG((stderr, "==========>\n%s\n<==========\n", str));
5403 
5404  if (sql == NULL) sql = rpmsqlI();
5405 
5406 #if defined(WITH_SQLITE)
5407  if (str != NULL) {
5408  const char * s = str;
5409 
5410  /* Ignore leading whitespace. */
5411  while (*s && xisspace((int)*s))
5412  s++;
5413 
5414  /* Perform the SQL operation(s). */
5415  if (*s == '\0') { /* INTERACTIVE */
5416  static int oneshot;
5417  uint32_t _flags = sql->flags;
5418  FD_t _ofd = sql->ofd;
5419  FD_t _ifd = sql->ifd;
5420 
5421 SQLDBG((stderr, "*** %s: INTERACTIVE\n", __FUNCTION__));
5422  sql->flags |= RPMSQL_FLAGS_INTERACTIVE;
5423  if (sql->ofd == NULL)
5424  sql->ofd = fdDup(STDOUT_FILENO);
5425  if (!oneshot) {
5426 #ifdef REFERENCE
5427  extern char *db_full_version(int *, int *, int *, int *, int *);
5428  fprintf(sql->out, "%s\n"
5429  "Enter \".help\" for instructions\n"
5430  "Enter SQL statements terminated with a \";\"\n",
5431  db_full_version(NULL, NULL, NULL, NULL, NULL));
5432 #endif
5433  size_t nb;
5434  size_t nw;
5435  char * t = rpmExpand(
5436  "SQLite version ", sqlite3_libversion(), "\n",
5437 #if SQLITE_VERSION_NUMBER > 3006015
5438  "\t(", sqlite3_sourceid(), ")\n",
5439 #endif
5440  "Enter \".help\" for instructions\n",
5441  "Enter SQL statements terminated with a \";\"\n", NULL);
5442  nb = strlen(t);
5443  nw = Fwrite(t, 1, nb, sql->ofd);
5444  (void) Fflush(sql->ofd);
5445 assert(nb == nw);
5446  t = _free(t);
5447 #if defined(HAVE_READLINE) && HAVE_READLINE==1
5448  if (sql->zHistory)
5449  read_history(sql->zHistory);
5450 #endif
5451  oneshot++;
5452  }
5453 
5454  sql->ifd = Fdopen(fdDup(fileno(stdin)), "rb.fpio");
5455 assert(sql->ifd);
5456 
5457 sql->flags |= RPMSQL_FLAGS_PROMPT;
5458  rc = rpmsqlInput(sql);
5459 sql->flags &= ~RPMSQL_FLAGS_PROMPT;
5460 
5461  if (sql->ifd) (void) Fclose(sql->ifd);
5462  sql->ifd = _ifd;
5463 
5464  if (sql->zHistory) {
5465  stifle_history(100);
5466  write_history(sql->zHistory);
5467  }
5468  if (_ofd == NULL)
5469  (void) Fclose(sql->ofd);
5470  sql->ofd = _ofd;
5471  sql->flags = _flags;
5472  if (rc != 0) rc = RPMRC_FAIL;
5473  } else
5474  if (!strcmp(s, "-") || !strcmp(s, "stdin")) { /* STDIN */
5475 FD_t _ofd = sql->ofd;
5476 SQLDBG((stderr, "*** %s: STDIN\n", __FUNCTION__));
5477 
5478 if (sql->ofd == NULL) sql->ofd = fdDup(STDOUT_FILENO);
5479 assert(sql->ofd);
5480 
5481 assert(sql->ifd == NULL);
5482  sql->ifd = Fdopen(fdDup(fileno(stdin)), "rb.fpio");
5483 assert(sql->ifd);
5484 
5485  rc = rpmsqlInput(sql);
5486 
5487  if (sql->ifd) (void) Fclose(sql->ifd);
5488  sql->ifd = NULL;
5489 
5490 if (_ofd == NULL) (void) Fclose(sql->ofd);
5491  sql->ofd = _ofd;
5492 
5493  if (rc != 0) rc = RPMRC_FAIL;
5494  } else
5495  if (*s == '/') { /* FILE */
5496  FD_t _ifd = sql->ifd;
5497 SQLDBG((stderr, "*** %s: FILE\n", __FUNCTION__));
5498  sql->ifd = Fopen(s, "rb.fpio");
5499  if (!(sql->ifd == NULL || Ferror(sql->ifd))) {
5500  rc = rpmsqlInput(sql);
5501  }
5502  if (sql->ifd) (void) Fclose(sql->ifd);
5503  sql->ifd = _ifd;
5504  if (rc != 0) rc = RPMRC_FAIL;
5505  } else { /* STRING */
5506 SQLDBG((stderr, "*** %s: STRING\n", __FUNCTION__));
5507  if (*s == '.') {
5508  char * t = xstrdup(s);
5509  rc = rpmsqlMetaCommand(sql, t);
5510  t = _free(t);
5511  } else {
5512  sqlite3 * db;
5513  char * zErrMsg = NULL;
5514  _rpmsqlOpenDB(sql);
5515  db = (sqlite3 *)sql->I;
5516  rc = _rpmsqlShellExec(sql, s, _rpmsqlShellCallback, &zErrMsg);
5517  if (zErrMsg) {
5518  rpmsql_error(1, "%s", zErrMsg);
5519  zErrMsg = _free(zErrMsg);
5520  if (rc == 0) rc = RPMRC_FAIL;
5521  } else if (rc != 0) {
5522  rpmsql_error(1, _("unable to process SQL \"%s\""), s);
5523  rc = RPMRC_FAIL;
5524  }
5525  }
5526  }
5527 
5528  /* Return the SQL output. */
5529  if (sql->iob) {
5530  (void) rpmiobRTrim(sql->iob);
5531 SQLDBG((stderr, "==========>\n%s\n<==========\n", rpmiobStr(sql->iob)));
5532  if (resultp)
5533  *resultp = rpmiobStr(sql->iob); /* XXX strdup? */
5534  }
5535 
5536  }
5537 #endif /* WITH_SQLITE */
5538 
5539 SQLDBG((stderr, "<== %s(%p,%p[%u]) rc %d\n", __FUNCTION__, sql, str, (unsigned)(str ? strlen(str) : 0), rc));
5540 
5541  return rc;
5542 }
rpmiob rpmiobRTrim(rpmiob iob)
Trim trailing white space.
Definition: rpmiob.c:67
int mireSetEOptions(miRE mire, int *offsets, int noffsets)
Initialize pattern execute options (PCRE only).
Definition: mire.c:156
miRE mireNew(rpmMireMode mode, int tag)
Create pattern container.
Definition: mire.c:113
rpmioPool _rpmsqlPool
Definition: rpmsql.c:5207
#define VCDBG(_vc, _l)
Definition: rpmsql.c:577
char * getenv(const char *name)
rpmioPool _rpmvcPool
Definition: rpmsql.c:597
int _rpmvt_debug
Definition: rpmsql.c:46
static int xtoupper(int c)
Definition: rpmiotypes.h:468
#define EXIT_FAILURE
static int xisalnum(int c)
Definition: rpmiotypes.h:440
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
fwrite(3) clone.
Definition: rpmio.c:2434
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
size_t rpmiobLen(rpmiob iob)
Return I/O buffer len.
Definition: rpmiob.c:123
#define rpmsqlDebugDump(_sql)
Definition: rpmsql.c:854
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
struct rpmsql_s * rpmsql
Definition: rpmsql.h:18
Definition: db3.c:181
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3310
int Access(const char *path, int amode)
access(2) clone.
Definition: rpmrpc.c:2196
int mireRegcomp(miRE mire, const char *pattern)
Compile pattern match.
Definition: mire.c:334
int mireSetCOptions(miRE mire, rpmMireMode mode, int tag, int options, const unsigned char *table)
Initialize pattern compile options.
Definition: mire.c:121
rpmioPool _rpmvtPool
Definition: rpmsql.c:90
int argvAppend(ARGV_t *argvp, ARGV_t av)
Append one argv array to another.
Definition: argv.c:216
#define R_OK
Definition: system.h:219
int rpmsqlCmd(rpmsql sql, const char *msg, void *_db, int rc)
Check sqlite3 return code, displaying error messages.
static rpmsql rpmsqlI(void)
Return the global interpreter, creating laziliy if needed.
Definition: rpmsql.c:974
struct rpmvd_s * rpmvd
Definition: rpmsql.h:14
int Fflush(FD_t fd)
fflush(3) clone.
Definition: rpmio.c:2916
char ** environ
rpmsql rpmsqlLink(rpmsql sql)
Reference a sql interpreter instance.
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
static int xisalpha(int c)
Definition: rpmiotypes.h:434
FD_t fdDup(int fdno)
Definition: rpmio.c:264
rpmiob rpmiobAppend(rpmiob iob, const char *s, size_t nl)
Append string to I/O buffer.
Definition: rpmiob.c:78
static rpmsql rpmsqlGetPool(rpmioPool pool)
Definition: rpmsql.c:5209
int rpmiobSlurp(const char *fn, rpmiob *iobp)
Definition: rpmiob.c:130
#define add_history(X)
Definition: rpmsql.c:35
int flags
rpmsql rpmsqlNew(char **av, uint32_t flags)
Create and load a sql interpreter.
Definition: rpmsql.c:5295
static int xtolower(int c)
Definition: rpmiotypes.h:465
char * alloca()
int rpmGlob(const char *patterns, int *argcPtr, const char ***argvPtr)
Return URL path(s) from a (URL prefixed) pattern glob.
Definition: macro.c:2509
miRE mireFree(miRE mire)
Free pattern container.
#define fdGetFILE(_fd)
Definition: rpmio.c:157
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:301
struct rpmvt_s * rpmvt
Definition: rpmsql.h:17
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:221
static void rpmsqlFini(void *_sql)
rpmsql pool destructor.
Definition: rpmsql.c:5155
#define N_(Text)
Definition: system.h:490
rpmvt rpmvtNew(void *db, void *pModule, const char *const *argv, rpmvd vd)
Definition: rpmsql.c:108
RPM pattern matching.
volatile int _rpmsqlSeenInterrupt
Definition: rpmsql.c:55
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
char * stpncpy(char *dest, const char *src, size_t n)
int Lstat(const char *path, struct stat *st)
lstat(2) clone.
Definition: rpmrpc.c:1401
#define POPT_ARGFLAG_TOGGLE
Definition: poptIO.c:68
#define VTDBGNOISY(_vt, _l)
Definition: rpmsql.c:65
static int xisspace(int c)
Definition: rpmiotypes.h:446
int _rpmvc_debug
Definition: rpmsql.c:49
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
struct miRE_s * miRE
Definition: mire.h:60
uint32_t v
Definition: db3.c:182
int Glob_pattern_p(const char *pattern, int quote)
glob_pattern_p(3) clone.
Definition: rpmrpc.c:2231
The FD_t File Handle data structure.
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
int mireRegexec(miRE mire, const char *val, size_t vallen)
Execute pattern match.
Definition: mire.c:398
#define VCDBGNOISY(_vc, _l)
Definition: rpmsql.c:578
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
#define stifle_history(X)
Definition: rpmsql.c:38
#define VTDBG(_vt, _l)
Definition: rpmsql.c:64
#define readline(sql, p)
Definition: rpmsql.c:34
#define dirent
Definition: system.h:230
static rpmvt rpmvtGetPool(rpmioPool pool)
Definition: rpmsql.c:92
rpmsql _rpmsqlI
Definition: rpmsql.c:52
#define F_ISSET(_psm, _FLAG)
Definition: psm.c:49
static void _rpmsqlDebugDump(rpmsql sql, const char *_func, const char *_fn, unsigned _ln)
Definition: rpmsql.c:814
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
rpmiob rpmiobNew(size_t len)
Create an I/O buffer.
Definition: rpmiob.c:44
void argvPrint(const char *msg, ARGV_t argv, FILE *fp)
Print argv array elements.
Definition: argv.c:19
static void rpmvtFini(void *_VT)
rpmvt pool destructor.
Definition: rpmsql.c:70
enum rpmRC_e rpmRC
RPM return codes.
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:113
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:429
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
struct key_s KEY
static void rpmvcFini(void *_VC)
rpmvc pool destructor.
Definition: rpmsql.c:583
static const char * prefix[]
Tables for prefixing and suffixing patterns, according to the -w, -x, and -F options.
Definition: rpmgrep.c:183
static int vsnprintf(char *buf, int nb, const char *fmt, va_list ap)
Definition: rpmps.c:212
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:110
char * stpcpy(char *dest, const char *src)
rpmvc rpmvcNew(rpmvt vt, int nrows)
Definition: rpmsql.c:615
#define write_history(X)
Definition: rpmsql.c:37
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:57
FD_t Fdopen(FD_t ofd, const char *fmode)
Definition: rpmio.c:2718
rpmRC rpmsqlRun(rpmsql sql, const char *str, const char **resultp)
Execute sql from STRING | FILE | STDIN | INTERACTIVE.
Definition: rpmsql.c:5397
int argvSplit(ARGV_t *argvp, const char *str, const char *seps)
Split a string into an argv array.
Definition: argv.c:233
static int xisblank(int c)
Definition: rpmiotypes.h:443
int Fileno(FD_t fd)
fileno(3) clone.
Definition: rpmio.c:2991
#define read_history(X)
Definition: rpmsql.c:36
#define _(Text)
Definition: system.h:30
#define xmalloc
Definition: system.h:33
int _rpmsql_debug
Definition: rpmsql.c:43
ARGstr_t * ARGV_t
Definition: argv.h:9
struct poptOption rpmioAllPoptTable[]
Definition: poptIO.c:551
const char * n
Definition: db3.c:184
void * rpmvArg
Definition: rpmsql.h:12
struct rpmvc_s * rpmvc
Definition: rpmsql.h:16
#define xrealloc
Definition: system.h:36
static rpmvc rpmvcGetPool(rpmioPool pool)
Definition: rpmsql.c:599
const char ** rpmsqlArgv(rpmsql sql, int *argcp)
Return arguments from a sql interpreter.
Definition: rpmsql.c:5225
rpmuint32_t value
Definition: hdrfmt.c:4378
#define iseol(_c)
Definition: macro.c:11