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