rpm  5.4.14
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)
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 
991 /*@printflike@*/
992 static int rpmsqlFprintf(rpmsql sql, const char *fmt, ...)
993 #if defined(__GNUC__) && __GNUC__ >= 2
994  __attribute__((format (printf, 2, 3)))
995 #endif
996  /*@*/;
997 static int rpmsqlFprintf(rpmsql sql, const char *fmt, ...)
998 {
999  char b[BUFSIZ];
1000  size_t nb = sizeof(b);
1001  int rc;
1002  va_list ap;
1003 
1004  if (sql == NULL) sql = rpmsqlI();
1005 assert(sql);
1006 
1007  /* Format the output */
1008  va_start(ap, fmt);
1009  rc = vsnprintf(b, nb, fmt, ap);
1010  va_end(ap);
1011  /* XXX just in case */
1012  if (!(rc >= 0 && rc < (int)nb))
1013  rc = nb - 1;
1014  b[rc] = '\0';
1015 
1016  /* Dispose of the output. */
1017  if (sql->ofd) {
1018  size_t nw = Fwrite(b, 1, rc, sql->ofd);
1019 assert((int)nw == rc);
1020  }
1021  if (sql->iob)
1022  (void) rpmiobAppend(sql->iob, b, 0);
1023 
1024  return rc;
1025 }
1026 
1033 #ifdef SQLITE_ENABLE_IOTRACE
1034 static void iotracePrintf(const char *zFormat, ...)
1035 {
1036  char * z;
1037  size_t nz;
1038  size_t nw;
1039  va_list ap;
1040 
1041  if (_rpmsqlI == NULL || _rpmsqlI->tfd == NULL)
1042  return;
1043  va_start(ap, zFormat);
1044  z = sqlite3_vmprintf(zFormat, ap);
1045  va_end(ap);
1046  nz = strlen(z);
1047  nw = Fwrite(z, 1, nz, sql->tfd);
1048 assert(nz == nw);
1049  sqlite3_free(z);
1050 }
1051 #endif
1052 
1053 #if defined(SQLITE_CONFIG_LOG)
1054 
1058 static void shellLog(void *_sql, int iErrCode, const char *zMsg)
1059 {
1060  rpmsql sql = (rpmsql) _sql;
1061  if (sql && sql->lfd) {
1062  char num[32];
1063  int xx = snprintf(num, sizeof(num), "(%d) ", iErrCode);
1064  const char * t = rpmExpand(num, zMsg, "\n", NULL);
1065  size_t nt = strlen(t);
1066  size_t nw = Fwrite(t, 1, nt, sql->lfd);
1067 assert(nt == nw);
1068  xx = Fflush(sql->lfd);
1069  }
1070 }
1071 #endif
1072 
1073 /*==============================================================*/
1079 #ifdef NOTYET /* XXX figger multibyte char's. */
1080 #define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
1081 #define sqliteCharVal(X) sqlite3ReadUtf8(X)
1082 #else
1083 #define sqliteNextChar(X) while( ( *++(X)) ) break
1084 #define sqliteCharVal(X) (int)(*(X))
1085 #endif
1086 
1087 #include <math.h>
1088 
1103 #define GEN_MATH_WRAP_DOUBLE_1(name, function, domain) \
1104 static void name(sqlite3_context *context, int argc, sqlite3_value **argv) {\
1105  double rVal = 0.0;\
1106 assert(argc==1);\
1107  switch (sqlite3_value_type(argv[0])) {\
1108  case SQLITE_NULL:\
1109  sqlite3_result_null(context);\
1110  break;\
1111  default:\
1112  rVal = sqlite3_value_double(argv[0]);\
1113  if (domain)\
1114  sqlite3_result_error(context, "domain error", -1);\
1115  else\
1116  sqlite3_result_double(context, function(rVal));\
1117  break;\
1118  }\
1119 }
1120 
1126 GEN_MATH_WRAP_DOUBLE_1(sqrtFunc, sqrt, rVal < 0)
1127 
1128 /* trignometric functions */
1129 GEN_MATH_WRAP_DOUBLE_1(acosFunc, acos, rVal < -1.0 || rVal > 1.0)
1130 GEN_MATH_WRAP_DOUBLE_1(asinFunc, asin, rVal < -1.0 || rVal > 1.0)
1131 GEN_MATH_WRAP_DOUBLE_1(atanFunc, atan, 0)
1132 
1138 #ifdef REFERENCE
1139 static double acosh(double x)
1140 {
1141  return log(x + sqrt(x * x - 1.0));
1142 }
1143 #endif
1144 
1145 GEN_MATH_WRAP_DOUBLE_1(acoshFunc, acosh, rVal < 1)
1146 #ifdef REFERENCE
1147 static double asinh(double x)
1148 {
1149  return log(x + sqrt(x * x + 1.0));
1150 }
1151 #endif
1152 
1153 GEN_MATH_WRAP_DOUBLE_1(asinhFunc, asinh, 0)
1154 #ifdef REFERENCE
1155 static double atanh(double x)
1156 {
1157  return (1.0 / 2.0) * log((1 + x) / (1 - x));
1158 }
1159 #endif
1160 
1161 GEN_MATH_WRAP_DOUBLE_1(atanhFunc, atanh, rVal > 1.0 || rVal < -1.0)
1162 
1163 
1166 static double cot(double x)
1167 {
1168  return 1.0 / tan(x);
1169 }
1170 
1171 GEN_MATH_WRAP_DOUBLE_1(sinFunc, sin, 0)
1172 GEN_MATH_WRAP_DOUBLE_1(cosFunc, cos, 0)
1173 GEN_MATH_WRAP_DOUBLE_1(tanFunc, tan, 0) /* XXX DOMAIN */
1174 GEN_MATH_WRAP_DOUBLE_1(cotFunc, cot, 0) /* XXX DOMAIN */
1175 
1176 static double coth(double x)
1177 {
1178  return 1.0 / tanh(x);
1179 }
1180 
1185 #ifdef REFERENCE
1186 static double sinh(double x)
1187 {
1188  return (exp(x) - exp(-x)) / 2.0;
1189 }
1190 #endif
1191 GEN_MATH_WRAP_DOUBLE_1(sinhFunc, sinh, 0)
1192 
1193 #ifdef REFERENCE
1194 static double cosh(double x)
1195 {
1196  return (exp(x) + exp(-x)) / 2.0;
1197 }
1198 #endif
1199 GEN_MATH_WRAP_DOUBLE_1(coshFunc, cosh, 0)
1200 
1201 #ifdef REFERENCE
1202 static double tanh(double x)
1203 {
1204  return sinh(x) / cosh(x);
1205 }
1206 #endif
1207 GEN_MATH_WRAP_DOUBLE_1(tanhFunc, tanh, 0)
1208 GEN_MATH_WRAP_DOUBLE_1(cothFunc, coth, 0) /* XXX DOMAIN */
1209 
1213 #ifdef REFERENCE
1214 static double log10(double x)
1215 {
1216  static double l10 = -1.0;
1217  if (l10 < 0.0) {
1218  l10 = log(10.0);
1219  }
1220  return log(x) / l10;
1221 }
1222 #endif
1223 GEN_MATH_WRAP_DOUBLE_1(logFunc, log, rVal <= 0.0)
1224 GEN_MATH_WRAP_DOUBLE_1(log10Func, log10, rVal <= 0.0)
1225 GEN_MATH_WRAP_DOUBLE_1(expFunc, exp, 0)
1226 
1230 #ifndef M_PI
1231 
1235 #define M_PI 3.14159265358979323846
1236 #endif
1237 
1241 static double deg2rad(double x)
1242 {
1243  return x * M_PI / 180.0;
1244 }
1245 
1249 static double rad2deg(double x)
1250 {
1251  return 180.0 * x / M_PI;
1252 }
1253 GEN_MATH_WRAP_DOUBLE_1(rad2degFunc, rad2deg, 0)
1254 GEN_MATH_WRAP_DOUBLE_1(deg2radFunc, deg2rad, 0)
1255 
1259 static void piFunc(sqlite3_context * context,
1260  int argc, sqlite3_value ** argv)
1261 {
1262  sqlite3_result_double(context, M_PI);
1263 }
1264 
1270 static void squareFunc(sqlite3_context * context,
1271  int argc, sqlite3_value ** argv)
1272 {
1273  double rVal = 0.0;
1274  int64_t iVal;
1275 
1276 assert(argc == 2);
1277  switch (sqlite3_value_type(argv[0])) {
1278  case SQLITE_INTEGER:
1279  iVal = sqlite3_value_int64(argv[0]);
1280  sqlite3_result_int64(context, iVal * iVal);
1281  break;
1282  case SQLITE_NULL:
1283  sqlite3_result_null(context);
1284  break;
1285  default:
1286  rVal = sqlite3_value_double(argv[0]);
1287  sqlite3_result_double(context, rVal * rVal);
1288  break;
1289  }
1290 }
1291 
1297 static void powerFunc(sqlite3_context * context,
1298  int argc, sqlite3_value ** argv)
1299 {
1300  double r1 = 0.0;
1301  double r2 = 0.0;
1302 
1303 assert(argc == 2);
1304 
1305  if (sqlite3_value_type(argv[0]) == SQLITE_NULL
1306  || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
1307  sqlite3_result_null(context);
1308  } else {
1309  r1 = sqlite3_value_double(argv[0]);
1310  r2 = sqlite3_value_double(argv[1]);
1311  if (r1 <= 0.0) {
1312  /* base must be positive */
1313  sqlite3_result_error(context, "domain error", -1);
1314  } else {
1315  sqlite3_result_double(context, pow(r1, r2));
1316  }
1317  }
1318 }
1319 
1323 static void atn2Func(sqlite3_context * context,
1324  int argc, sqlite3_value ** argv)
1325 {
1326  double r1 = 0.0;
1327  double r2 = 0.0;
1328 
1329 assert(argc == 2);
1330 
1331  if (sqlite3_value_type(argv[0]) == SQLITE_NULL
1332  || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
1333  sqlite3_result_null(context);
1334  } else {
1335  r1 = sqlite3_value_double(argv[0]);
1336  r2 = sqlite3_value_double(argv[1]);
1337  sqlite3_result_double(context, atan2(r1, r2));
1338  }
1339 }
1340 
1347 static void signFunc(sqlite3_context * context,
1348  int argc, sqlite3_value ** argv)
1349 {
1350  double rVal = 0.0;
1351  int64_t iVal;
1352 
1353 assert(argc == 1);
1354  switch (sqlite3_value_type(argv[0])) {
1355  case SQLITE_INTEGER:
1356  iVal = sqlite3_value_int64(argv[0]);
1357  iVal = (iVal > 0) ? 1 : (iVal < 0) ? -1 : 0;
1358  sqlite3_result_int64(context, iVal);
1359  break;
1360  case SQLITE_NULL:
1361  sqlite3_result_null(context);
1362  break;
1363  default:
1364  /* 2nd change below. Line for abs was: if( rVal<0 ) rVal = rVal * -1.0; */
1365 
1366  rVal = sqlite3_value_double(argv[0]);
1367  rVal = (rVal > 0) ? 1 : (rVal < 0) ? -1 : 0;
1368  sqlite3_result_double(context, rVal);
1369  break;
1370  }
1371 }
1372 
1376 static void ceilFunc(sqlite3_context * context,
1377  int argc, sqlite3_value ** argv)
1378 {
1379  double rVal = 0.0;
1380  int64_t iVal;
1381 
1382 assert(argc == 1);
1383  switch (sqlite3_value_type(argv[0])) {
1384  case SQLITE_INTEGER:
1385  iVal = sqlite3_value_int64(argv[0]);
1386  sqlite3_result_int64(context, iVal);
1387  break;
1388  case SQLITE_NULL:
1389  sqlite3_result_null(context);
1390  break;
1391  default:
1392  rVal = sqlite3_value_double(argv[0]);
1393  sqlite3_result_int64(context, ceil(rVal));
1394  break;
1395  }
1396 }
1397 
1401 static void floorFunc(sqlite3_context * context,
1402  int argc, sqlite3_value ** argv)
1403 {
1404  double rVal = 0.0;
1405  int64_t iVal;
1406 
1407 assert(argc == 1);
1408  switch (sqlite3_value_type(argv[0])) {
1409  case SQLITE_INTEGER:
1410  iVal = sqlite3_value_int64(argv[0]);
1411  sqlite3_result_int64(context, iVal);
1412  break;
1413  case SQLITE_NULL:
1414  sqlite3_result_null(context);
1415  break;
1416  default:
1417  rVal = sqlite3_value_double(argv[0]);
1418  sqlite3_result_int64(context, floor(rVal));
1419  break;
1420  }
1421 }
1422 
1427 static void replicateFunc(sqlite3_context * context,
1428  int argc, sqlite3_value ** argv)
1429 {
1430  unsigned char *z; /* input string */
1431  unsigned char *zo; /* result string */
1432  int iCount; /* times to repeat */
1433  size_t nLen; /* length of the input string (no multibyte considerations) */
1434  size_t nTLen; /* length of the result string (no multibyte considerations) */
1435  int i = 0;
1436 
1437  if (argc != 2 || SQLITE_NULL == sqlite3_value_type(argv[0]))
1438  return;
1439 
1440  iCount = sqlite3_value_int64(argv[1]);
1441 
1442  if (iCount < 0) {
1443  sqlite3_result_error(context, "domain error", -1);
1444  } else {
1445  nLen = sqlite3_value_bytes(argv[0]);
1446  nTLen = nLen * iCount;
1447  z = xmalloc(nTLen + 1);
1448  zo = xmalloc(nLen + 1);
1449  strcpy((char *) zo, (char *) sqlite3_value_text(argv[0]));
1450 
1451  for (i = 0; i < iCount; ++i)
1452  strcpy((char *) (z + i * nLen), (char *) zo);
1453 
1454  sqlite3_result_text(context, (char *) z, -1, free);
1455  zo = _free(zo);
1456  }
1457 }
1458 
1459 static void properFunc(sqlite3_context * context,
1460  int argc, sqlite3_value ** argv)
1461 {
1462  const unsigned char *z; /* input string */
1463  unsigned char *zo; /* output string */
1464  unsigned char *zt; /* iterator */
1465  char r;
1466  int c = 1;
1467 
1468 assert(argc == 1);
1469  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1470  sqlite3_result_null(context);
1471  return;
1472  }
1473 
1474  z = sqlite3_value_text(argv[0]);
1475  zo = (unsigned char *) xstrdup((const char *)z);
1476  zt = zo;
1477 
1478  while ((r = *(z++)) != 0) {
1479  if (xisblank(r)) {
1480  c = 1;
1481  } else {
1482  r = (c == 1) ? xtoupper(r) : xtolower(r);
1483  c = 0;
1484  }
1485  *(zt++) = r;
1486  }
1487  *zt = '\0';
1488 
1489  sqlite3_result_text(context, (char *) zo, -1, free);
1490 }
1491 
1492 #ifdef NOTYET /* XXX figger multibyte char's. */
1493 
1499 static void padlFunc(sqlite3_context * context,
1500  int argc, sqlite3_value ** argv)
1501 {
1502  size_t ilen; /* length to pad to */
1503  size_t zl; /* length of the input string (UTF-8 chars) */
1504  size_t i;
1505  const char *zi; /* input string */
1506  char *zo; /* output string */
1507  char *zt;
1508 
1509 assert(argc == 2);
1510  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
1511  sqlite3_result_null(context);
1512  } else {
1513  zi = (const char *) sqlite3_value_text(argv[0]);
1514  ilen = sqlite3_value_int64(argv[1]);
1515  /* check domain */
1516  if (ilen < 0) {
1517  sqlite3_result_error(context, "domain error", -1);
1518  return;
1519  }
1520  zl = sqlite3utf8CharLen(zi, -1);
1521  if (zl >= ilen) {
1522  /* string is longer than the requested pad length, return the same string (dup it) */
1523  sqlite3_result_text(context, xstrdup(zi), -1, free);
1524  } else {
1525  zo = xmalloc(strlen(zi) + ilen - zl + 1);
1526  zt = zo;
1527  for (i = 1; i + zl <= ilen; ++i)
1528  *(zt++) = ' ';
1529  /* no need to take UTF-8 into consideration here */
1530  strcpy(zt, zi);
1531  sqlite3_result_text(context, zo, -1, free);
1532  }
1533  }
1534 }
1535 
1542 static void padrFunc(sqlite3_context * context,
1543  int argc, sqlite3_value ** argv)
1544 {
1545  size_t ilen; /* length to pad to */
1546  size_t zl; /* length of the input string (UTF-8 chars) */
1547  size_t zll; /* length of the input string (bytes) */
1548  size_t i;
1549  const char *zi; /* input string */
1550  char *zo; /* output string */
1551  char *zt;
1552 
1553 assert(argc == 2);
1554  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
1555  sqlite3_result_null(context);
1556  } else {
1557  int64_t _ilen;
1558  zi = (const char *) sqlite3_value_text(argv[0]);
1559  _ilen = sqlite3_value_int64(argv[1]);
1560  /* check domain */
1561  if (_ilen < 0) {
1562  sqlite3_result_error(context, "domain error", -1);
1563  return;
1564  }
1565  ilen = _ilen;
1566  zl = sqlite3utf8CharLen(zi, -1);
1567  if (zl >= ilen) {
1568  /* string is longer than the requested pad length, return the same string (dup it) */
1569  sqlite3_result_text(context, xstrdup(zi), -1, free);
1570  } else {
1571  zll = strlen(zi);
1572  zo = xmalloc(zll + ilen - zl + 1);
1573  zt = strcpy(zo, zi) + zll;
1574  for (i = 1; i + zl <= ilen; ++i)
1575  *(zt++) = ' ';
1576  *zt = '\0';
1577  sqlite3_result_text(context, zo, -1, free);
1578  }
1579  }
1580 }
1581 
1589 static void padcFunc(sqlite3_context * context,
1590  int argc, sqlite3_value ** argv)
1591 {
1592  size_t ilen; /* length to pad to */
1593  size_t zl; /* length of the input string (UTF-8 chars) */
1594  size_t zll; /* length of the input string (bytes) */
1595  size_t i;
1596  const char *zi; /* input string */
1597  char *zo; /* output string */
1598  char *zt;
1599 
1600 assert(argc == 2);
1601  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
1602  sqlite3_result_null(context);
1603  } else {
1604  int64_t _ilen;
1605  zi = (const char *) sqlite3_value_text(argv[0]);
1606  _ilen = sqlite3_value_int64(argv[1]);
1607  /* check domain */
1608  if (_ilen < 0) {
1609  sqlite3_result_error(context, "domain error", -1);
1610  return;
1611  }
1612  ilen = _ilen;
1613  zl = sqlite3utf8CharLen(zi, -1);
1614  if (zl >= ilen) {
1615  /* string is longer than the requested pad length, return the same string (dup it) */
1616  sqlite3_result_text(context, xstrdup(zi), -1, free);
1617  } else {
1618  zll = strlen(zi);
1619  zo = xmalloc(zll + ilen - zl + 1);
1620  zt = zo;
1621  for (i = 1; 2 * i + zl <= ilen; ++i)
1622  *(zt++) = ' ';
1623  strcpy(zt, zi);
1624  zt += zll;
1625  for (; i + zl <= ilen; ++i)
1626  *(zt++) = ' ';
1627  *zt = '\0';
1628  sqlite3_result_text(context, zo, -1, free);
1629  }
1630  }
1631 }
1632 #endif
1633 
1638 static void strfilterFunc(sqlite3_context * context,
1639  int argc, sqlite3_value ** argv)
1640 {
1641  const char *zi1; /* first parameter string (searched string) */
1642  const char *zi2; /* second parameter string (vcontains valid characters) */
1643  const char *z1;
1644  const char *z21;
1645  const char *z22;
1646  char *zo; /* output string */
1647  char *zot;
1648  int c1;
1649  int c2;
1650 
1651 assert(argc == 2);
1652 
1653  if (sqlite3_value_type(argv[0]) == SQLITE_NULL
1654  || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
1655  sqlite3_result_null(context);
1656  } else {
1657  zi1 = (const char *) sqlite3_value_text(argv[0]);
1658  zi2 = (const char *) sqlite3_value_text(argv[1]);
1659  zo = xmalloc(strlen(zi1) + 1);
1660  zot = zo;
1661  z1 = zi1;
1662  while ((c1 = sqliteCharVal(z1)) != 0) {
1663  z21 = zi2;
1664  while ((c2 = sqliteCharVal(z21)) != 0 && c2 != c1)
1665  sqliteNextChar(z21);
1666  if (c2 != 0) {
1667  z22 = z21;
1668  sqliteNextChar(z22);
1669  strncpy(zot, z21, z22 - z21);
1670  zot += z22 - z21;
1671  }
1672  sqliteNextChar(z1);
1673  }
1674  *zot = '\0';
1675 
1676  sqlite3_result_text(context, zo, -1, free);
1677  }
1678 }
1679 
1687 static int _substr(const char *z1, const char *z2, int s, const char **p)
1688 {
1689  int c = 0;
1690  int rVal = -1;
1691  const char *zt1;
1692  const char *zt2;
1693  int c1;
1694  int c2;
1695 
1696  if (*z1 == '\0')
1697  return -1;
1698 
1699  while ((sqliteCharVal(z2) != 0) && (c++) < s)
1700  sqliteNextChar(z2);
1701 
1702  c = 0;
1703  while ((sqliteCharVal(z2)) != 0) {
1704  zt1 = z1;
1705  zt2 = z2;
1706 
1707  do {
1708  c1 = sqliteCharVal(zt1);
1709  c2 = sqliteCharVal(zt2);
1710  sqliteNextChar(zt1);
1711  sqliteNextChar(zt2);
1712  } while (c1 == c2 && c1 != 0 && c2 != 0);
1713 
1714  if (c1 == 0) {
1715  rVal = c;
1716  break;
1717  }
1718 
1719  sqliteNextChar(z2);
1720  ++c;
1721  }
1722  if (p)
1723  *p = z2;
1724  return rVal >= 0 ? rVal + s : rVal;
1725 }
1726 
1734 static void charindexFunc(sqlite3_context * context,
1735  int argc, sqlite3_value ** argv)
1736 {
1737  const char *z1; /* s1 string */
1738  const char *z2; /* s2 string */
1739  int s = 0;
1740  int rVal = 0;
1741 
1742 assert(argc == 2 || argc == 3);
1743  if (SQLITE_NULL == sqlite3_value_type(argv[0])
1744  || SQLITE_NULL == sqlite3_value_type(argv[1])) {
1745  sqlite3_result_null(context);
1746  return;
1747  }
1748 
1749  z1 = (const char *) sqlite3_value_text(argv[0]);
1750  z2 = (const char *) sqlite3_value_text(argv[1]);
1751  if (argc == 3) {
1752  s = sqlite3_value_int(argv[2]) - 1;
1753  if (s < 0)
1754  s = 0;
1755  } else {
1756  s = 0;
1757  }
1758 
1759  rVal = _substr(z1, z2, s, NULL);
1760  sqlite3_result_int(context, rVal + 1);
1761 }
1762 
1767 static void leftFunc(sqlite3_context * context,
1768  int argc, sqlite3_value ** argv)
1769 {
1770  int c = 0;
1771  int cc = 0;
1772  int l = 0;
1773  const unsigned char *z; /* input string */
1774  const unsigned char *zt;
1775  unsigned char *rz; /* output string */
1776 
1777 assert(argc == 2);
1778  if (SQLITE_NULL == sqlite3_value_type(argv[0])
1779  || SQLITE_NULL == sqlite3_value_type(argv[1])) {
1780  sqlite3_result_null(context);
1781  return;
1782  }
1783 
1784  z = sqlite3_value_text(argv[0]);
1785  l = sqlite3_value_int(argv[1]);
1786  zt = z;
1787 
1788  while (sqliteCharVal(zt) && c++ < l)
1789  sqliteNextChar(zt);
1790 
1791  cc = zt - z;
1792 
1793  rz = xmalloc(zt - z + 1);
1794  strncpy((char *) rz, (char *) z, zt - z);
1795  *(rz + cc) = '\0';
1796  sqlite3_result_text(context, (char *) rz, -1, free);
1797 }
1798 
1803 static void rightFunc(sqlite3_context * context,
1804  int argc, sqlite3_value ** argv)
1805 {
1806  int l = 0;
1807  int c = 0;
1808  int cc = 0;
1809  const char *z;
1810  const char *zt;
1811  const char *ze;
1812  char *rz;
1813 
1814 assert(argc == 2);
1815  if (SQLITE_NULL == sqlite3_value_type(argv[0])
1816  || SQLITE_NULL == sqlite3_value_type(argv[1])) {
1817  sqlite3_result_null(context);
1818  return;
1819  }
1820 
1821  z = (const char *) sqlite3_value_text(argv[0]);
1822  l = sqlite3_value_int(argv[1]);
1823  zt = z;
1824 
1825  while (sqliteCharVal(zt) != 0) {
1826  sqliteNextChar(zt);
1827  ++c;
1828  }
1829 
1830  ze = zt;
1831  zt = z;
1832 
1833  cc = c - l;
1834  if (cc < 0)
1835  cc = 0;
1836 
1837  while (cc-- > 0) {
1838  sqliteNextChar(zt);
1839  }
1840 
1841  rz = xmalloc(ze - zt + 1);
1842  strcpy((char *) rz, (char *) (zt));
1843  sqlite3_result_text(context, (char *) rz, -1, free);
1844 }
1845 
1849 static const char * ltrim(const char *s)
1850 {
1851  while (*s == ' ')
1852  ++s;
1853  return s;
1854 }
1855 
1860 static const char * rtrim(char *s)
1861 {
1862  char *ss = s + strlen(s) - 1;
1863  while (ss >= s && *ss == ' ')
1864  --ss;
1865  *(ss + 1) = '\0';
1866  return s;
1867 }
1868 
1872 static void ltrimFunc(sqlite3_context * context,
1873  int argc, sqlite3_value ** argv)
1874 {
1875  const char *z;
1876 
1877 assert(argc == 1);
1878  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1879  sqlite3_result_null(context);
1880  return;
1881  }
1882  z = (const char *) sqlite3_value_text(argv[0]);
1883  sqlite3_result_text(context, xstrdup(ltrim(z)), -1, free);
1884 }
1885 
1889 static void rtrimFunc(sqlite3_context * context,
1890  int argc, sqlite3_value ** argv)
1891 {
1892  const char *z;
1893 
1894 assert(argc == 1);
1895  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1896  sqlite3_result_null(context);
1897  return;
1898  }
1899  z = (const char *) sqlite3_value_text(argv[0]);
1900  sqlite3_result_text(context, rtrim(xstrdup(z)), -1, free);
1901 }
1902 
1906 static void trimFunc(sqlite3_context * context,
1907  int argc, sqlite3_value ** argv)
1908 {
1909  const char *z;
1910 
1911 assert(argc == 1);
1912  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1913  sqlite3_result_null(context);
1914  return;
1915  }
1916  z = (const char *) sqlite3_value_text(argv[0]);
1917  sqlite3_result_text(context, rtrim(xstrdup(ltrim(z))), -1, free);
1918 }
1919 
1926 static void _append(char **s1, int l1, const char *s2, int l2)
1927 {
1928  *s1 = xrealloc(*s1, (l1 + l2 + 1) * sizeof(char));
1929  strncpy((*s1) + l1, s2, l2);
1930  *(*(s1) + l1 + l2) = '\0';
1931 }
1932 
1936 static void replaceFunc(sqlite3_context * context,
1937  int argc, sqlite3_value ** argv)
1938 {
1939  const char *z1; /* string s (first parameter) */
1940  const char *z2; /* string s1 (second parameter) string to look for */
1941  const char *z3; /* string s2 (third parameter) string to replace occurrences of s1 with */
1942  size_t lz1;
1943  size_t lz2;
1944  size_t lz3;
1945  int lzo = 0;
1946  char *zo = 0;
1947  int ret = 0;
1948  const char *zt1;
1949  const char *zt2;
1950 
1951 assert(argc == 3);
1952  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
1953  sqlite3_result_null(context);
1954  return;
1955  }
1956 
1957  z1 = (const char *)sqlite3_value_text(argv[0]);
1958  z2 = (const char *)sqlite3_value_text(argv[1]);
1959  z3 = (const char *)sqlite3_value_text(argv[2]);
1960  /* handle possible null values */
1961  if (z2 == NULL)
1962  z2 = "";
1963  if (z3 == NULL)
1964  z3 = "";
1965 
1966  lz1 = strlen(z1);
1967  lz2 = strlen(z2);
1968  lz3 = strlen(z3);
1969 
1970 #if 0
1971  /* special case when z2 is empty (or null) nothing will be changed */
1972  if (0 == lz2) {
1973  sqlite3_result_text(context, xstrdup(z1), -1, free);
1974  return;
1975  }
1976 #endif
1977 
1978  zt1 = z1;
1979  zt2 = z1;
1980 
1981  while (1) {
1982  ret = _substr(z2, zt1, 0, &zt2);
1983 
1984  if (ret < 0)
1985  break;
1986 
1987  _append(&zo, lzo, zt1, zt2 - zt1);
1988  lzo += zt2 - zt1;
1989  _append(&zo, lzo, z3, lz3);
1990  lzo += lz3;
1991 
1992  zt1 = zt2 + lz2;
1993  }
1994  _append(&zo, lzo, zt1, lz1 - (zt1 - z1));
1995  sqlite3_result_text(context, zo, -1, free);
1996 }
1997 
2001 static void reverseFunc(sqlite3_context * context,
2002  int argc, sqlite3_value ** argv)
2003 {
2004  const char *z;
2005  const char *zt;
2006  char *rz;
2007  char *rzt;
2008  size_t l;
2009  int i;
2010 
2011 assert(argc == 1);
2012  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
2013  sqlite3_result_null(context);
2014  return;
2015  }
2016  z = (const char *)sqlite3_value_text(argv[0]);
2017  l = strlen(z);
2018  rz = xmalloc(l + 1);
2019  rzt = rz + l;
2020  *(rzt--) = '\0';
2021 
2022  zt = z;
2023  while (sqliteCharVal(zt) != 0) {
2024  z = zt;
2025  sqliteNextChar(zt);
2026  for (i = 1; zt - i >= z; ++i)
2027  *(rzt--) = *(zt - i);
2028  }
2029 
2030  sqlite3_result_text(context, rz, -1, free);
2031 }
2032 
2033 #ifdef NOTYET /* XXX needs the sqlite3 map function */
2034 
2040 typedef struct StdevCtx StdevCtx;
2041 struct StdevCtx {
2042  double rM;
2043  double rS;
2044  int64_t cnt; /* number of elements */
2045 };
2046 
2055 typedef struct ModeCtx ModeCtx;
2056 struct ModeCtx {
2057  int64_t riM; /* integer value found so far */
2058  double rdM; /* double value found so far */
2059  int64_t cnt; /* number of elements so far */
2060  double pcnt; /* number of elements smaller than a percentile */
2061  int64_t mcnt; /* maximum number of occurrences (for mode) */
2062  int64_t mn; /* number of occurrences (for mode and percentiles) */
2063  int64_t is_double; /* whether the computation is being done for doubles (>0) or integers (=0) */
2064  map *m; /* map structure used for the computation */
2065  int done; /* whether the answer has been found */
2066 };
2067 
2071 static void varianceStep(sqlite3_context * context,
2072  int argc, sqlite3_value ** argv)
2073 {
2074  StdevCtx *p;
2075  double delta;
2076  double x;
2077 
2078 assert(argc == 1);
2079  p = sqlite3_aggregate_context(context, sizeof(*p));
2080  /* only consider non-null values */
2081  if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) {
2082  p->cnt++;
2083  x = sqlite3_value_double(argv[0]);
2084  delta = (x - p->rM);
2085  p->rM += delta / p->cnt;
2086  p->rS += delta * (x - p->rM);
2087  }
2088 }
2089 
2093 static void modeStep(sqlite3_context * context,
2094  int argc, sqlite3_value ** argv)
2095 {
2096  ModeCtx *p;
2097  int64_t xi = 0;
2098  double xd = 0.0;
2099  int64_t *iptr;
2100  double *dptr;
2101  int type;
2102 
2103 assert(argc == 1);
2104  type = sqlite3_value_numeric_type(argv[0]);
2105 
2106  if (type == SQLITE_NULL)
2107  return;
2108 
2109  p = sqlite3_aggregate_context(context, sizeof(*p));
2110 
2111  if (0 == (p->m)) {
2112  p->m = calloc(1, sizeof(map));
2113  if (type == SQLITE_INTEGER) {
2114  /* map will be used for integers */
2115  *(p->m) = map_make(int_cmp);
2116  p->is_double = 0;
2117  } else {
2118  p->is_double = 1;
2119  /* map will be used for doubles */
2120  *(p->m) = map_make(double_cmp);
2121  }
2122  }
2123 
2124  ++(p->cnt);
2125 
2126  if (0 == p->is_double) {
2127  xi = sqlite3_value_int64(argv[0]);
2128  iptr = (int64_t *) calloc(1, sizeof(int64_t));
2129  *iptr = xi;
2130  map_insert(p->m, iptr);
2131  } else {
2132  xd = sqlite3_value_double(argv[0]);
2133  dptr = (double *) calloc(1, sizeof(double));
2134  *dptr = xd;
2135  map_insert(p->m, dptr);
2136  }
2137 }
2138 
2143 static void modeIterate(void *e, int64_t c, void *pp)
2144 {
2145  int64_t ei;
2146  double ed;
2147  ModeCtx *p = (ModeCtx *) pp;
2148 
2149  if (0 == p->is_double) {
2150  ei = *(int *) (e);
2151 
2152  if (p->mcnt == c) {
2153  ++p->mn;
2154  } else if (p->mcnt < c) {
2155  p->riM = ei;
2156  p->mcnt = c;
2157  p->mn = 1;
2158  }
2159  } else {
2160  ed = *(double *) (e);
2161 
2162  if (p->mcnt == c) {
2163  ++p->mn;
2164  } else if (p->mcnt < c) {
2165  p->rdM = ed;
2166  p->mcnt = c;
2167  p->mn = 1;
2168  }
2169  }
2170 }
2171 
2177 static void medianIterate(void *e, int64_t c, void *pp)
2178 {
2179  int64_t ei;
2180  double ed;
2181  double iL;
2182  double iR;
2183  int il;
2184  int ir;
2185  ModeCtx *p = (ModeCtx *) pp;
2186 
2187  if (p->done > 0)
2188  return;
2189 
2190  iL = p->pcnt;
2191  iR = p->cnt - p->pcnt;
2192  il = p->mcnt + c;
2193  ir = p->cnt - p->mcnt;
2194 
2195  if (il >= iL) {
2196  if (ir >= iR) {
2197  ++p->mn;
2198  if (0 == p->is_double) {
2199  ei = *(int *) (e);
2200  p->riM += ei;
2201  } else {
2202  ed = *(double *) (e);
2203  p->rdM += ed;
2204  }
2205  } else {
2206  p->done = 1;
2207  }
2208  }
2209  p->mcnt += c;
2210 }
2211 
2215 static void modeFinalize(sqlite3_context * context)
2216 {
2217  ModeCtx *p = sqlite3_aggregate_context(context, 0);
2218  if (p && p->m) {
2219  map_iterate(p->m, modeIterate, p);
2220  map_destroy(p->m);
2221  free(p->m);
2222 
2223  if (1 == p->mn) {
2224  if (0 == p->is_double)
2225  sqlite3_result_int64(context, p->riM);
2226  else
2227  sqlite3_result_double(context, p->rdM);
2228  }
2229  }
2230 }
2231 
2235 static void _medianFinalize(sqlite3_context * context)
2236 {
2237  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2238  if (p && p->m) {
2239  p->done = 0;
2240  map_iterate(p->m, medianIterate, p);
2241  map_destroy(p->m);
2242  free(p->m);
2243 
2244  if (0 == p->is_double)
2245  if (1 == p->mn)
2246  sqlite3_result_int64(context, p->riM);
2247  else
2248  sqlite3_result_double(context, p->riM * 1.0 / p->mn);
2249  else
2250  sqlite3_result_double(context, p->rdM / p->mn);
2251  }
2252 }
2253 
2257 static void medianFinalize(sqlite3_context * context)
2258 {
2259  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2260  if (p != NULL) {
2261  p->pcnt = (p->cnt) / 2.0;
2262  _medianFinalize(context);
2263  }
2264 }
2265 
2269 static void lower_quartileFinalize(sqlite3_context * context)
2270 {
2271  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2272  if (p != NULL) {
2273  p->pcnt = (p->cnt) / 4.0;
2274  _medianFinalize(context);
2275  }
2276 }
2277 
2281 static void upper_quartileFinalize(sqlite3_context * context)
2282 {
2283  ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0);
2284  if (p != NULL) {
2285  p->pcnt = (p->cnt) * 3 / 4.0;
2286  _medianFinalize(context);
2287  }
2288 }
2289 
2293 static void stdevFinalize(sqlite3_context * context)
2294 {
2295  StdevCtx *p = sqlite3_aggregate_context(context, 0);
2296  if (p && p->cnt > 1)
2297  sqlite3_result_double(context, sqrt(p->rS / (p->cnt - 1)));
2298  else
2299  sqlite3_result_double(context, 0.0);
2300 }
2301 
2305 static void varianceFinalize(sqlite3_context * context)
2306 {
2307  StdevCtx *p = sqlite3_aggregate_context(context, 0);
2308  if (p && p->cnt > 1)
2309  sqlite3_result_double(context, p->rS / (p->cnt - 1));
2310  else
2311  sqlite3_result_double(context, 0.0);
2312 }
2313 #endif
2314 
2318 static void expandFunc(sqlite3_context * context,
2319  int argc, sqlite3_value ** argv)
2320 {
2321  sqlite3_result_text(context,
2322  rpmExpand((const char *)sqlite3_value_text(argv[0]), NULL), -1, free);
2323 }
2324 
2328 static void regexpFunc(sqlite3_context* context,
2329  int argc, sqlite3_value** argv)
2330 {
2331  const char * value = (const char *) sqlite3_value_text(argv[0]);
2332  const char * pattern = (const char *) sqlite3_value_text(argv[1]);
2333  miRE mire = mireNew(RPMMIRE_REGEX, 0);
2334  int rc = mireRegcomp(mire, pattern);
2335 
2336  rc = mireRegexec(mire, value, strlen(value));
2337  switch (rc) {
2338  case 0:
2339  case 1:
2340  sqlite3_result_int(context, rc);
2341  break;
2342  default:
2343  sqlite3_result_error(context, "invalid pattern", -1);
2344  break;
2345  }
2346  mire = mireFree(mire);
2347 }
2348 
2349 static struct rpmsqlCF_s __CF[] = {
2350  /* math.h extensions */
2351  { "acos", 1, 0, SQLITE_UTF8, 0, acosFunc, NULL, NULL },
2352  { "asin", 1, 0, SQLITE_UTF8, 0, asinFunc, NULL, NULL },
2353  { "atan", 1, 0, SQLITE_UTF8, 0, atanFunc, NULL, NULL },
2354  { "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func, NULL, NULL },
2355  /* XXX alias */
2356  { "atan2", 2, 0, SQLITE_UTF8, 0, atn2Func, NULL, NULL },
2357  { "acosh", 1, 0, SQLITE_UTF8, 0, acoshFunc, NULL, NULL },
2358  { "asinh", 1, 0, SQLITE_UTF8, 0, asinhFunc, NULL, NULL },
2359  { "atanh", 1, 0, SQLITE_UTF8, 0, atanhFunc, NULL, NULL },
2360 
2361 #ifdef NOTYET
2362  { "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc, NULL, NULL },
2363 #endif
2364  { "degrees", 1, 0, SQLITE_UTF8, 0, rad2degFunc, NULL, NULL },
2365  { "radians", 1, 0, SQLITE_UTF8, 0, deg2radFunc, NULL, NULL },
2366 
2367  { "cos", 1, 0, SQLITE_UTF8, 0, cosFunc, NULL, NULL },
2368  { "sin", 1, 0, SQLITE_UTF8, 0, sinFunc, NULL, NULL },
2369  { "tan", 1, 0, SQLITE_UTF8, 0, tanFunc, NULL, NULL },
2370  { "cot", 1, 0, SQLITE_UTF8, 0, cotFunc, NULL, NULL },
2371  { "cosh", 1, 0, SQLITE_UTF8, 0, coshFunc, NULL, NULL },
2372  { "sinh", 1, 0, SQLITE_UTF8, 0, sinhFunc, NULL, NULL },
2373  { "tanh", 1, 0, SQLITE_UTF8, 0, tanhFunc, NULL, NULL },
2374  { "coth", 1, 0, SQLITE_UTF8, 0, cothFunc, NULL, NULL },
2375 
2376  { "exp", 1, 0, SQLITE_UTF8, 0, expFunc, NULL, NULL },
2377  { "log", 1, 0, SQLITE_UTF8, 0, logFunc, NULL, NULL },
2378  { "log10", 1, 0, SQLITE_UTF8, 0, log10Func, NULL, NULL },
2379  { "power", 2, 0, SQLITE_UTF8, 0, powerFunc, NULL, NULL },
2380  { "sign", 1, 0, SQLITE_UTF8, 0, signFunc, NULL, NULL },
2381  { "sqrt", 1, 0, SQLITE_UTF8, 0, sqrtFunc, NULL, NULL },
2382  { "square", 1, 0, SQLITE_UTF8, 0, squareFunc, NULL, NULL },
2383 
2384  { "ceil", 1, 0, SQLITE_UTF8, 0, ceilFunc, NULL, NULL },
2385  { "floor", 1, 0, SQLITE_UTF8, 0, floorFunc, NULL, NULL },
2386 
2387  { "pi", 0, 0, SQLITE_UTF8, 1, piFunc, NULL, NULL },
2388 
2389  /* string extensions */
2390  { "replicate", 2, 0, SQLITE_UTF8, 0, replicateFunc, NULL, NULL },
2391  { "charindex", 2, 0, SQLITE_UTF8, 0, charindexFunc, NULL, NULL },
2392  { "charindex", 3, 0, SQLITE_UTF8, 0, charindexFunc, NULL, NULL },
2393  { "leftstr", 2, 0, SQLITE_UTF8, 0, leftFunc, NULL, NULL },
2394  { "rightstr", 2, 0, SQLITE_UTF8, 0, rightFunc, NULL, NULL },
2395  { "ltrim", 1, 0, SQLITE_UTF8, 0, ltrimFunc, NULL, NULL },
2396  { "rtrim", 1, 0, SQLITE_UTF8, 0, rtrimFunc, NULL, NULL },
2397  { "trim", 1, 0, SQLITE_UTF8, 0, trimFunc, NULL, NULL },
2398  { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc, NULL, NULL },
2399  { "reverse", 1, 0, SQLITE_UTF8, 0, reverseFunc, NULL, NULL },
2400  { "proper", 1, 0, SQLITE_UTF8, 0, properFunc, NULL, NULL },
2401 #ifdef NOTYET /* XXX figger multibyte char's. */
2402  { "padl", 2, 0, SQLITE_UTF8, 0, padlFunc, NULL, NULL },
2403  { "padr", 2, 0, SQLITE_UTF8, 0, padrFunc, NULL, NULL },
2404  { "padc", 2, 0, SQLITE_UTF8, 0, padcFunc, NULL, NULL },
2405 #endif
2406  { "strfilter", 2, 0, SQLITE_UTF8, 0, strfilterFunc, NULL, NULL },
2407 
2408  /* statistical aggregate extensions */
2409 #ifdef NOTYET /* XXX needs the sqlite3 map function */
2410  { "stdev", 1, 0, SQLITE_UTF8, 0, NULL, varianceStep, stdevFinalize },
2411  { "variance", 1, 0, SQLITE_UTF8, 0, NULL, varianceStep, varianceFinalize },
2412  { "mode", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, modeFinalize },
2413  { "median", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, medianFinalize },
2414  { "lower_quartile", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, lower_quartileFinalize },
2415  { "upper_quartile", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, upper_quartileFinalize },
2416 #endif
2417 
2418  /* RPM extensions. */
2419  { "expand", 1, 0, SQLITE_UTF8, 0, expandFunc, NULL, NULL },
2420  { "regexp", 2, 0, SQLITE_UTF8, 0, regexpFunc, NULL, NULL },
2421  { NULL, 0, 0, 0, 0, NULL, NULL, NULL }
2422 };
2423 
2424 rpmsqlCF _rpmsqlCFT = __CF;
2425 
2426 int _rpmsqlLoadCFT(rpmsql sql, void * _CF)
2427 {
2428  sqlite3 * db = (sqlite3 *)sql->I;
2429  rpmsqlCF CF;
2430  int rc = 0;
2431 
2432 SQLDBG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, sql, _CF));
2433  if (_CF == NULL)
2434  _CF = _rpmsqlCFT;
2435  if (_CF)
2436  for (CF = (rpmsqlCF) _CF; CF->zName != NULL; CF++) {
2437  void * _pApp = NULL;
2438  int xx;
2439 
2440  switch (CF->argType) {
2441  default:
2442  case 0: _pApp = NULL; break;
2443  case 1: _pApp = (void *)db; break;
2444  case 2: _pApp = (void *)-1; break;
2445  }
2446 
2447  xx = rpmsqlCmd(sql, "create_function", db,
2448  sqlite3_create_function(db, CF->zName, CF->nArg, CF->eTextRep,
2449  _pApp, CF->xFunc, CF->xStep, CF->xFinal));
2450 SQLDBG((stderr, "\t%s(%s) xx %d\n", "sqlite3_create_function", CF->zName, xx));
2451  if (xx && rc == 0)
2452  rc = xx;
2453 
2454 #ifdef NOTYET
2455  if (CF->needColSeq) {
2456  FuncDef *pFunc = sqlite3FindFunction(db, CF->zName,
2457  strlen(CF_>zName), CF->nArg, CF->eTextRep, 0);
2458  if (pFunc) pFunc->needCollSeq = 1;
2459  }
2460 #endif
2461 
2462  }
2463 SQLDBG((stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, sql, rc));
2464  return rc;
2465 }
2466 
2467 /*==============================================================*/
2468 
2469 static struct rpmvd_s _envVD = {
2470  .split = "=",
2471  .parse = "key=val",
2472  .regex = "^([^=]+)=(.*)$",
2473  .idx = 1,
2474 };
2475 
2476 static int envCreateConnect(void * _db, void * pAux,
2477  int argc, const char *const * argv,
2478  rpmvt * vtp, char ** pzErr)
2479 {
2480  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_envVD), vtp);
2481 }
2482 
2483 struct sqlite3_module envModule = {
2484  .xCreate = (void *) envCreateConnect,
2485  .xConnect = (void *) envCreateConnect,
2486 };
2487 
2488 /*==============================================================*/
2489 
2490 static struct rpmvd_s _grdbVD = {
2491  .prefix = "%{?_etc_group}%{!?_etc_group:/etc/group}",
2492  .split = ":",
2493  /* XXX "group" is a reserved keyword. */
2494  .parse = "_group:passwd:gid:groups",
2495  .regex = "^([^:]*):([^:]*):([^:]*):([^:]*)$",
2496  .idx = 3,
2497 };
2498 
2499 static int grdbCreateConnect(void * _db, void * pAux,
2500  int argc, const char *const * argv,
2501  rpmvt * vtp, char ** pzErr)
2502 {
2503  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_grdbVD), vtp);
2504 }
2505 
2506 struct sqlite3_module grdbModule = {
2507  .xCreate = (void *) grdbCreateConnect,
2508  .xConnect = (void *) grdbCreateConnect,
2509 };
2510 
2511 /*==============================================================*/
2512 
2513 static struct rpmvd_s _procdbVD = {
2514  .prefix = "%{?_procdb}%{!?_procdb:/proc/[0-9]}",
2515  .split = "/-",
2516  .parse = "dir/pid/*",
2517  .regex = "^(.+/)([0-9]+)$",
2518  .idx = 2,
2519 };
2520 
2521 static int procdbCreateConnect(void * _db, void * pAux,
2522  int argc, const char *const * argv,
2523  rpmvt * vtp, char ** pzErr)
2524 {
2525  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_procdbVD), vtp);
2526 }
2527 
2528 struct sqlite3_module procdbModule = {
2529  .xCreate = (void *) procdbCreateConnect,
2530  .xConnect = (void *) procdbCreateConnect,
2531 };
2532 
2533 /*==============================================================*/
2534 
2535 static struct rpmvd_s _pwdbVD = {
2536  .prefix = "%{?_etc_passwd}%{!?_etc_passwd:/etc/passwd}",
2537  .split = ":",
2538  .parse = "user:passwd:uid:gid:gecos:dir:shell",
2539  .regex = "^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)$",
2540  .idx = 3,
2541 };
2542 
2543 static int pwdbCreateConnect(void * _db, void * pAux,
2544  int argc, const char *const * argv,
2545  rpmvt * vtp, char ** pzErr)
2546 {
2547  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_pwdbVD), vtp);
2548 }
2549 
2550 struct sqlite3_module pwdbModule = {
2551  .xCreate = (void *) pwdbCreateConnect,
2552  .xConnect = (void *) pwdbCreateConnect,
2553 };
2554 
2555 /*==============================================================*/
2556 
2557 static struct rpmvd_s _repodbVD = {
2558  /* XXX where to map the default? */
2559  .prefix = "%{?_repodb}%{!?_repodb:/X/popt/}",
2560  .split = "/-.",
2561  .parse = "dir/file-NVRA-N-V-R.A",
2562  .regex = "^(.+/)(((.*)-([^-]+)-([^-]+)\\.([^.]+))\\.rpm)$",
2563  .idx = 2,
2564 };
2565 
2566 static int repodbCreateConnect(void * _db, void * pAux,
2567  int argc, const char *const * argv,
2568  rpmvt * vtp, char ** pzErr)
2569 {
2570  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_repodbVD), vtp);
2571 }
2572 
2573 struct sqlite3_module repodbModule = {
2574  .xCreate = (void *) repodbCreateConnect,
2575  .xConnect = (void *) repodbCreateConnect,
2576 };
2577 
2578 /*==============================================================*/
2579 
2580 static int _stat_debug = 0;
2581 
2582 static struct rpmvd_s _statVD = {
2583  .split = " ,",
2584  .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",
2585 };
2586 
2587 static int statCreateConnect(void * _db, void * pAux,
2588  int argc, const char *const * argv,
2589  rpmvt * vtp, char ** pzErr)
2590 {
2591  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_statVD), vtp);
2592 }
2593 
2594 static int statColumn(rpmvc vc, void * _pContext, int colx)
2595 {
2596  sqlite3_context * pContext = (sqlite3_context *) _pContext;
2597  rpmvt vt = vc->vt;
2598  const char * path = vt->av[vc->ix];
2599  const char * col = vt->cols[colx];
2600  struct stat sb, *st = &sb; /* XXX move to rpmvcNext for performance */
2601  int ret = Lstat(path, &sb);
2602  int rc = SQLITE_OK;
2603 
2604 if (_stat_debug < 0)
2605 fprintf(stderr, "--> %s(%p,%p,%d)\n", __FUNCTION__, vc, pContext, colx);
2606 
2607 
2608  if (!strcmp(col, "path"))
2609  sqlite3_result_text(pContext, path, -1, SQLITE_STATIC);
2610  else if (!strcmp(col, "st_dev") && !ret)
2611  sqlite3_result_int64(pContext, st->st_dev);
2612  else if (!strcmp(col, "st_ino") && !ret)
2613  sqlite3_result_int64(pContext, st->st_ino);
2614  else if (!strcmp(col, "st_mode") && !ret)
2615  sqlite3_result_int64(pContext, st->st_mode);
2616  else if (!strcmp(col, "st_nlink") && !ret)
2617  sqlite3_result_int64(pContext, st->st_nlink);
2618  else if (!strcmp(col, "st_uid") && !ret)
2619  sqlite3_result_int64(pContext, st->st_uid);
2620  else if (!strcmp(col, "st_gid") && !ret)
2621  sqlite3_result_int64(pContext, st->st_gid);
2622  else if (!strcmp(col, "st_rdev") && !ret)
2623  sqlite3_result_int64(pContext, st->st_rdev);
2624  else if (!strcmp(col, "st_size") && !ret)
2625  sqlite3_result_int64(pContext, st->st_size);
2626  else if (!strcmp(col, "st_blksize") && !ret)
2627  sqlite3_result_int64(pContext, st->st_blksize);
2628  else if (!strcmp(col, "st_blocks") && !ret)
2629  sqlite3_result_int64(pContext, st->st_blocks);
2630  else if (!strcmp(col, "st_atime") && !ret)
2631  sqlite3_result_int64(pContext, st->st_atime);
2632  else if (!strcmp(col, "st_mtime") && !ret)
2633  sqlite3_result_int64(pContext, st->st_mtime);
2634  else if (!strcmp(col, "st_ctime") && !ret)
2635  sqlite3_result_int64(pContext, st->st_ctime);
2636  /* XXX pick up *BSD derangements */
2637  else
2638  sqlite3_result_null(pContext);
2639 
2640 if (_stat_debug < 0)
2641 fprintf(stderr, "<-- %s(%p,%p,%d) rc %d\n", __FUNCTION__, vc, pContext, colx, rc);
2642 
2643  return rc;
2644 }
2645 
2646 struct sqlite3_module statModule = {
2647  .xCreate = (void *) statCreateConnect,
2648  .xConnect = (void *) statCreateConnect,
2649  .xColumn = (void *) statColumn,
2650 };
2651 
2652 /*==============================================================*/
2653 
2654 static struct rpmvd_s _yumdbVD = {
2655  .prefix = "%{?_yumdb}%{!?_yumdb:/var/lib/yum/yumdb}/",
2656  .split = "/-",
2657  .parse = "dir/hash-NVRA-N-V-R-A/*",
2658  .regex = "^(.+/)([^-]+)-((.*)-([^-]+)-([^-]+)-([^-]+))$",
2659  .idx = 2,
2660 };
2661 
2662 static int yumdbCreateConnect(void * _db, void * pAux,
2663  int argc, const char *const * argv,
2664  rpmvt * vtp, char ** pzErr)
2665 {
2666  return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_yumdbVD), vtp);
2667 }
2668 
2669 struct sqlite3_module yumdbModule = {
2670  .xCreate = (void *) yumdbCreateConnect,
2671  .xConnect = (void *) yumdbCreateConnect,
2672 };
2673 
2674 /*==============================================================*/
2675 
2676 struct sqlite3_module _rpmvmTemplate = {
2677  .xCreate = (void *) rpmvtCreate,
2678  .xConnect = (void *) rpmvtConnect,
2679  .xBestIndex = (void *) rpmvtBestIndex,
2680  .xDisconnect = (void *) rpmvtDisconnect,
2681  .xDestroy = (void *) rpmvtDestroy,
2682  .xOpen = (void *) rpmvcOpen,
2683  .xClose = (void *) rpmvcClose,
2684  .xFilter = (void *) rpmvcFilter,
2685  .xNext = (void *) rpmvcNext,
2686  .xEof = (void *) rpmvcEof,
2687  .xColumn = (void *) rpmvcColumn,
2688  .xRowid = (void *) rpmvcRowid,
2689  .xUpdate = (void *) rpmvtUpdate,
2690  .xBegin = (void *) rpmvtBegin,
2691  .xSync = (void *) rpmvtSync,
2692  .xCommit = (void *) rpmvtCommit,
2693  .xRollback = (void *) rpmvtRollback,
2694  .xFindFunction = (void *) rpmvtFindFunction,
2695  .xRename = (void *) rpmvtRename
2696 };
2697 
2698 static struct rpmsqlVMT_s __VMT[] = {
2699  { "Argv", NULL, NULL },
2700  { "Env", &envModule, NULL },
2701  { "Grdb", &grdbModule, NULL },
2702  { "Procdb", &procdbModule, NULL },
2703  { "Pwdb", &pwdbModule, NULL },
2704  { "Repodb", &repodbModule, NULL },
2705  { "Stat", &statModule, NULL },
2706  { "Yumdb", &yumdbModule, NULL },
2707  { NULL, NULL, NULL }
2708 };
2709 
2710 static void rpmsqlVMFree(void * _VM)
2711  /*@*/
2712 {
2713 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, _VM));
2714  if (_VM)
2715  free(_VM);
2716 }
2717 
2718 #ifdef UNUSED
2719 static void dumpVM(const char * msg, const rpmsqlVM s)
2720 {
2721 fprintf(stderr, "--------------------- %s\n", (msg ? msg : ""));
2722 #define VMPRT(f) if (s->f) fprintf(stderr, "%20s: %p\n", #f, s->f)
2723  VMPRT(xCreate);
2724  VMPRT(xConnect);
2725  VMPRT(xBestIndex);
2726  VMPRT(xDisconnect);
2727  VMPRT(xDestroy);
2728  VMPRT(xOpen);
2729  VMPRT(xClose);
2730  VMPRT(xFilter);
2731  VMPRT(xNext);
2732  VMPRT(xEof);
2733  VMPRT(xColumn);
2734  VMPRT(xRowid);
2735  VMPRT(xUpdate);
2736  VMPRT(xBegin);
2737  VMPRT(xSync);
2738  VMPRT(xCommit);
2739  VMPRT(xRollback);
2740  VMPRT(xFindFunction);
2741  VMPRT(xRename);
2742 #undef VMPRT
2743 }
2744 #endif
2745 
2746 static /*@only@*/ rpmsqlVM rpmsqlVMNew(/*@null@*/ const rpmsqlVM s)
2747 {
2748  rpmsqlVM t = xcalloc(1, sizeof(*t));
2749 
2750 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, s));
2751  *t = _rpmvmTemplate; /* structure assignment */
2752 
2753  if (s) {
2754  if (s->iVersion) t->iVersion = s->iVersion;
2755 #define VMCPY(f) if (s->f) t->f = ((s->f != (void *)-1) ? s->f : NULL)
2756  VMCPY(xCreate);
2757  VMCPY(xConnect);
2758  VMCPY(xBestIndex);
2759  VMCPY(xDisconnect);
2760  VMCPY(xDestroy);
2761  VMCPY(xOpen);
2762  VMCPY(xClose);
2763  VMCPY(xFilter);
2764  VMCPY(xNext);
2765  VMCPY(xEof);
2766  VMCPY(xColumn);
2767  VMCPY(xRowid);
2768  VMCPY(xUpdate);
2769  VMCPY(xBegin);
2770  VMCPY(xSync);
2771  VMCPY(xCommit);
2772  VMCPY(xRollback);
2773  VMCPY(xFindFunction);
2774  VMCPY(xRename);
2775 #undef VMCPY
2776  }
2777 SQLDBG((stderr, "<-- %s(%p) %p\n", __FUNCTION__, s, t));
2778  return t;
2779 }
2780 
2781 int _rpmsqlLoadVMT(void * _db, const rpmsqlVMT _VMT)
2782 {
2783  sqlite3 * db = (sqlite3 *) _db;
2784  rpmsqlVMT VMT;
2785  int rc = 0;
2786 
2787 SQLDBG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, _db, _VMT));
2788  for (VMT = (rpmsqlVMT)_VMT; VMT->zName != NULL; VMT++) {
2789  int xx;
2790 
2791  xx = rpmsqlCmd(_rpmsqlI, "create_module_v2", db,
2792  sqlite3_create_module_v2(db, VMT->zName,
2793  rpmsqlVMNew(VMT->module), VMT->data, rpmsqlVMFree));
2794 SQLDBG((stderr, "\t%s(%s) xx %d\n", "sqlite3_create_module_v2", VMT->zName, xx));
2795  if (xx && rc == 0)
2796  rc = xx;
2797 
2798  }
2799 SQLDBG((stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, _db, _VMT, rc));
2800  return rc;
2801 }
2802 
2803 /*==============================================================*/
2804 /* XXX HACK: AWOL in -lsqlite3 on CM14 */
2805 #if SQLITE_VERSION_NUMBER <= 3006015
2806 #define sqlite3_enable_load_extension(db, onoff) SQLITE_OK
2807 #define sqlite3_load_extension(db, zFile, zProc, pzErrMsg) SQLITE_OK
2808 #endif
2809 
2815 static int _rpmsqlOpenDB(rpmsql sql)
2816 {
2817  int rc = -1; /* assume failure */
2818  sqlite3 * db;
2819 
2820 assert(sql);
2821 
2822  db = (sqlite3 *)sql->I;
2823  if (db == NULL) {
2824  int rc;
2825  rc = rpmsqlCmd(sql, "open", db, /* XXX watchout: arg order */
2826  sqlite3_open(sql->zDbFilename, &db));
2827  sql->I = db;
2828 
2829  if (db && rc == SQLITE_OK) {
2830  (void) _rpmsqlLoadCFT(sql, _rpmsqlCFT);
2831  (void) _rpmsqlLoadVMT(db, __VMT);
2832  }
2833 
2834  if (db == NULL || sqlite3_errcode(db) != SQLITE_OK) {
2835  /* XXX rpmlog */
2836  rpmsql_error(1, _("unable to open database \"%s\": %s"),
2837  sql->zDbFilename, sqlite3_errmsg(db));
2838  goto exit;
2839  }
2840  /* Enable extension loading (if not disabled). */
2841  if (!F_ISSET(sql, NOLOAD))
2842  (void) rpmsqlCmd(sql, "enable_load_extension", db,
2843  sqlite3_enable_load_extension(db, 1));
2844  }
2845  rc = 0;
2846 
2847 exit:
2848 SQLDBG((stderr, "<-- %s(%p) rc %d %s\n", __FUNCTION__, sql, rc, sql->zDbFilename));
2849  return rc;
2850 }
2851 
2852 #endif /* defined(WITH_SQLITE) */
2853 
2854 /*==============================================================*/
2855 
2856 #if defined(WITH_SQLITE)
2857 
2860 static int isNumber(const char *z, int *realnum)
2861 {
2862  if (*z == '-' || *z == '+')
2863  z++;
2864  if (!isdigit(*z))
2865  return 0;
2866  z++;
2867  if (realnum)
2868  *realnum = 0;
2869  while (isdigit(*z))
2870  z++;
2871  if (*z == '.') {
2872  z++;
2873  if (!isdigit(*z))
2874  return 0;
2875  while (isdigit(*z))
2876  z++;
2877  if (realnum)
2878  *realnum = 1;
2879  }
2880  if (*z == 'e' || *z == 'E') {
2881  z++;
2882  if (*z == '+' || *z == '-')
2883  z++;
2884  if (!isdigit(*z))
2885  return 0;
2886  while (isdigit(*z))
2887  z++;
2888  if (realnum)
2889  *realnum = 1;
2890  }
2891  return *z == 0;
2892 }
2893 
2898 static int strlen30(const char *z)
2899 {
2900  const char *z2 = z;
2901  while (*z2)
2902  z2++;
2903  return 0x3fffffff & (int) (z2 - z);
2904 }
2905 #endif /* defined(WITH_SQLITE) */
2906 
2907 /*==============================================================*/
2908 #if defined(WITH_SQLITE)
2909 
2913 static void output_hex_blob(rpmsql sql, const void *pBlob, int nBlob)
2914 {
2915  char *zBlob = (char *) pBlob;
2916  int i;
2917 
2918 SQLDBG((stderr, "--> %s(%p,%p[%u])\n", __FUNCTION__, sql, pBlob, (unsigned)nBlob));
2919  rpmsqlFprintf(sql, "X'");
2920  for (i = 0; i < nBlob; i++)
2921  rpmsqlFprintf(sql, "%02x", zBlob[i]);
2922  rpmsqlFprintf(sql, "'");
2923 }
2924 
2929 static void output_quoted_string(rpmsql sql, const char *z)
2930 {
2931  int i;
2932  int nSingle = 0;
2933 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z));
2934  for (i = 0; z[i]; i++) {
2935  if (z[i] == '\'')
2936  nSingle++;
2937  }
2938  if (nSingle == 0) {
2939  rpmsqlFprintf(sql, "'%s'", z);
2940  } else {
2941  rpmsqlFprintf(sql, "'");
2942  while (*z) {
2943  for (i = 0; z[i] && z[i] != '\''; i++)
2944  ;
2945  if (i == 0) {
2946  rpmsqlFprintf(sql, "''");
2947  z++;
2948  } else if (z[i] == '\'') {
2949  rpmsqlFprintf(sql, "%.*s''", i, z);
2950  z += i + 1;
2951  } else {
2952  rpmsqlFprintf(sql, "%s", z);
2953  break;
2954  }
2955  }
2956  rpmsqlFprintf(sql, "'");
2957  }
2958 }
2959 
2964 static void output_c_string(rpmsql sql, const char *z)
2965 {
2966  unsigned int c;
2967 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z));
2968  rpmsqlFprintf(sql, "\"");
2969  while ((c = *(z++)) != 0) {
2970  if (c == '\\')
2971  rpmsqlFprintf(sql, "\\\\");
2972  else if (c == '\t')
2973  rpmsqlFprintf(sql, "\\t");
2974  else if (c == '\n')
2975  rpmsqlFprintf(sql, "\\n");
2976  else if (c == '\r')
2977  rpmsqlFprintf(sql, "\\r");
2978  else if (!isprint(c))
2979  rpmsqlFprintf(sql, "\\%03o", c & 0xff);
2980  else
2981  rpmsqlFprintf(sql, "%c", c);
2982  }
2983  rpmsqlFprintf(sql, "\"");
2984 }
2985 
2991 static void output_html_string(rpmsql sql, const char *z)
2992 {
2993  int i;
2994 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z));
2995  while (*z) {
2996  for (i = 0; z[i]
2997  && z[i] != '<'
2998  && z[i] != '&'
2999  && z[i] != '>' && z[i] != '\"' && z[i] != '\''; i++) {
3000  }
3001  if (i > 0)
3002  rpmsqlFprintf(sql, "%.*s", i, z);
3003  if (z[i] == '<')
3004  rpmsqlFprintf(sql, "&lt;");
3005  else if (z[i] == '&')
3006  rpmsqlFprintf(sql, "&amp;");
3007  else if (z[i] == '>')
3008  rpmsqlFprintf(sql, "&gt;");
3009  else if (z[i] == '\"')
3010  rpmsqlFprintf(sql, "&quot;");
3011  else if (z[i] == '\'')
3012  rpmsqlFprintf(sql, "&#39;");
3013  else
3014  break;
3015  z += i + 1;
3016  }
3017 }
3018 
3023 /*@unchecked@*/
3024 static const char needCsvQuote[] = {
3025  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3026  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3027  1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
3028  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3029  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3030  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3031  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3032  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
3033  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3034  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3035  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3036  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3037  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3038  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3039  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3040  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3041 };
3042 
3050 static void output_csv(rpmsql sql, const char *z, int bSep)
3051 {
3052 SQLDBG((stderr, "--> %s(%p,%s,0x%x)\n", __FUNCTION__, sql, z, bSep));
3053  if (z == 0) {
3054  rpmsqlFprintf(sql, "%s", sql->nullvalue);
3055  } else {
3056  int i;
3057  int nSep = strlen30(sql->separator);
3058  for (i = 0; z[i]; i++) {
3059  if (needCsvQuote[((unsigned char *) z)[i]]
3060  || (z[i] == sql->separator[0] &&
3061  (nSep == 1 || memcmp(z, sql->separator, nSep) == 0))) {
3062  i = 0;
3063  break;
3064  }
3065  }
3066  if (i == 0) {
3067  rpmsqlFprintf(sql, "\"");
3068  for (i = 0; z[i]; i++) {
3069  if (z[i] == '"')
3070  rpmsqlFprintf(sql, "\"");
3071  rpmsqlFprintf(sql, "%c", z[i]);
3072  }
3073  rpmsqlFprintf(sql, "\"");
3074  } else {
3075  rpmsqlFprintf(sql, "%s", z);
3076  }
3077  }
3078  if (bSep)
3079  rpmsqlFprintf(sql, "%s", sql->separator);
3080 }
3081 
3087 static int _rpmsqlShellCallback(void * _sql, int nArg, char **azArg, char **azCol,
3088  int *aiType)
3089 {
3090  rpmsql sql = (rpmsql) _sql;
3091  int w;
3092  int i;
3093 
3094 SQLDBG((stderr, "--> %s(%p,%d,%p,%p,%p)\n", __FUNCTION__, _sql, nArg, azArg, azCol, aiType));
3095  switch (sql->mode) {
3096  case RPMSQL_MODE_LINE:
3097  w = 5;
3098  if (azArg == 0)
3099  break;
3100  for (i = 0; i < nArg; i++) {
3101  int len = strlen30(azCol[i] ? azCol[i] : "");
3102  if (len > w)
3103  w = len;
3104  }
3105  if (sql->cnt++ > 0)
3106  rpmsqlFprintf(sql, "\n");
3107  for (i = 0; i < nArg; i++)
3108  rpmsqlFprintf(sql, "%*s = %s\n", w, azCol[i],
3109  azArg[i] ? azArg[i] : sql->nullvalue);
3110  break;
3111  case RPMSQL_MODE_EXPLAIN:
3112  case RPMSQL_MODE_COLUMN:
3113  if (sql->cnt++ == 0) {
3114  for (i = 0; i < nArg; i++) {
3115  int n;
3116  w = (i < ArraySize(sql->colWidth) ? sql->colWidth[i] : 0);
3117 
3118  if (w <= 0) {
3119  w = strlen30(azCol[i] ? azCol[i] : "");
3120  if (w < 10)
3121  w = 10;
3122  n = strlen30(azArg && azArg[i]
3123  ? azArg[i] : sql-> nullvalue);
3124  if (w < n)
3125  w = n;
3126  }
3127  if (i < ArraySize(sql->actualWidth))
3128  sql->actualWidth[i] = w;
3129  if (F_ISSET(sql, SHOWHDR)) {
3130  rpmsqlFprintf(sql, "%-*.*s%s", w, w, azCol[i],
3131  i == nArg - 1 ? "\n" : " ");
3132  }
3133  }
3134  if (F_ISSET(sql, SHOWHDR)) {
3135  for (i = 0; i < nArg; i++) {
3136  w = (i < ArraySize(sql->actualWidth)
3137  ? sql->actualWidth[i] : 10);
3138 
3139  rpmsqlFprintf(sql, "%-*.*s%s", w, w,
3140  "-----------------------------------"
3141  "----------------------------------------------------------",
3142  i == nArg - 1 ? "\n" : " ");
3143  }
3144  }
3145  }
3146  if (azArg == 0)
3147  break;
3148  for (i = 0; i < nArg; i++) {
3149  w = (i < ArraySize(sql->actualWidth) ? sql->actualWidth[i] : 10);
3150  if (sql->mode == RPMSQL_MODE_EXPLAIN && azArg[i] &&
3151  strlen30(azArg[i]) > w) {
3152  w = strlen30(azArg[i]);
3153  }
3154  rpmsqlFprintf(sql, "%-*.*s%s", w, w,
3155  azArg[i] ? azArg[i] : sql->nullvalue,
3156  i == nArg - 1 ? "\n" : " ");
3157  }
3158  break;
3159  case RPMSQL_MODE_SEMI:
3160  case RPMSQL_MODE_LIST:
3161  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3162  for (i = 0; i < nArg; i++)
3163  rpmsqlFprintf(sql, "%s%s", azCol[i],
3164  i == nArg - 1 ? "\n" : sql->separator);
3165  }
3166 
3167  if (azArg == 0)
3168  break;
3169  for (i = 0; i < nArg; i++) {
3170  char *z = azArg[i];
3171  if (z == 0)
3172  z = sql->nullvalue;
3173  rpmsqlFprintf(sql, "%s", z);
3174  if (i < nArg - 1)
3175  rpmsqlFprintf(sql, "%s", sql->separator);
3176  else if (sql->mode == RPMSQL_MODE_SEMI)
3177  rpmsqlFprintf(sql, ";\n");
3178  else
3179  rpmsqlFprintf(sql, "\n");
3180  }
3181  break;
3182  case RPMSQL_MODE_HTML:
3183  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3184  rpmsqlFprintf(sql, "<TR>");
3185  for (i = 0; i < nArg; i++) {
3186  rpmsqlFprintf(sql, "<TH>");
3187  output_html_string(sql, azCol[i]);
3188  rpmsqlFprintf(sql, "</TH>\n");
3189  }
3190  rpmsqlFprintf(sql, "</TR>\n");
3191  }
3192  if (azArg == 0)
3193  break;
3194  rpmsqlFprintf(sql, "<TR>");
3195  for (i = 0; i < nArg; i++) {
3196  rpmsqlFprintf(sql, "<TD>");
3197  output_html_string(sql, azArg[i] ? azArg[i] : sql->nullvalue);
3198  rpmsqlFprintf(sql, "</TD>\n");
3199  }
3200  rpmsqlFprintf(sql, "</TR>\n");
3201  break;
3202  case RPMSQL_MODE_TCL:
3203  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3204  for (i = 0; i < nArg; i++) {
3205  output_c_string(sql, azCol[i] ? azCol[i] : "");
3206  rpmsqlFprintf(sql, "%s", sql->separator);
3207  }
3208  rpmsqlFprintf(sql, "\n");
3209  }
3210  if (azArg == 0)
3211  break;
3212  for (i = 0; i < nArg; i++) {
3213  output_c_string(sql, azArg[i] ? azArg[i] : sql->nullvalue);
3214  rpmsqlFprintf(sql, "%s", sql->separator);
3215  }
3216  rpmsqlFprintf(sql, "\n");
3217  break;
3218  case RPMSQL_MODE_CSV:
3219  if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) {
3220  for (i = 0; i < nArg; i++)
3221  output_csv(sql, azCol[i] ? azCol[i] : "", i < nArg - 1);
3222  rpmsqlFprintf(sql, "\n");
3223  }
3224  if (azArg == 0)
3225  break;
3226  for (i = 0; i < nArg; i++)
3227  output_csv(sql, azArg[i], i < nArg - 1);
3228  rpmsqlFprintf(sql, "\n");
3229  break;
3230  case RPMSQL_MODE_INSERT:
3231  sql->cnt++;
3232  if (azArg == 0)
3233  break;
3234  rpmsqlFprintf(sql, "INSERT INTO %s VALUES(", sql->zDestTable);
3235  for (i = 0; i < nArg; i++) {
3236  char *zSep = i > 0 ? "," : "";
3237  if ((azArg[i] == 0) || (aiType && aiType[i] == SQLITE_NULL)) {
3238  rpmsqlFprintf(sql, "%sNULL", zSep);
3239  } else if (aiType && aiType[i] == SQLITE_TEXT) {
3240  if (zSep[0])
3241  rpmsqlFprintf(sql, "%s", zSep);
3242  output_quoted_string(sql, azArg[i]);
3243  } else if (aiType
3244  && (aiType[i] == SQLITE_INTEGER
3245  || aiType[i] == SQLITE_FLOAT)) {
3246  rpmsqlFprintf(sql, "%s%s", zSep, azArg[i]);
3247  } else if (aiType && aiType[i] == SQLITE_BLOB && sql->S) {
3248  sqlite3_stmt * pStmt = (sqlite3_stmt *)sql->S;
3249  const void *pBlob = sqlite3_column_blob(pStmt, i);
3250  int nBlob = sqlite3_column_bytes(pStmt, i);
3251  if (zSep[0])
3252  rpmsqlFprintf(sql, "%s", zSep);
3253  output_hex_blob(sql, pBlob, nBlob);
3254  } else if (isNumber(azArg[i], 0)) {
3255  rpmsqlFprintf(sql, "%s%s", zSep, azArg[i]);
3256  } else {
3257  if (zSep[0])
3258  rpmsqlFprintf(sql, "%s", zSep);
3259  output_quoted_string(sql, azArg[i]);
3260  }
3261  }
3262  rpmsqlFprintf(sql, ");\n");
3263  break;
3264  }
3265  return 0;
3266 }
3267 
3273 static int callback(void *_sql, int nArg, char **azArg, char **azCol)
3274 {
3275  /* since we don't have type info, call the _rpmsqlShellCallback with a NULL value */
3276  return _rpmsqlShellCallback(_sql, nArg, azArg, azCol, NULL);
3277 }
3278 
3285 static void set_table_name(rpmsql sql, const char *zName)
3286 {
3287  int i, n;
3288  int needQuote;
3289  char *z;
3290 
3291 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, zName));
3292  sql->zDestTable = _free(sql->zDestTable);
3293  if (zName == NULL)
3294  return;
3295  needQuote = !xisalpha((unsigned char) *zName) && *zName != '_';
3296  for (i = n = 0; zName[i]; i++, n++) {
3297  if (!xisalnum((unsigned char) zName[i]) && zName[i] != '_') {
3298  needQuote = 1;
3299  if (zName[i] == '\'')
3300  n++;
3301  }
3302  }
3303  if (needQuote)
3304  n += 2;
3305  sql->zDestTable = z = xmalloc(n + 1);
3306  n = 0;
3307  if (needQuote)
3308  z[n++] = '\'';
3309  for (i = 0; zName[i]; i++) {
3310  z[n++] = zName[i];
3311  if (zName[i] == '\'')
3312  z[n++] = '\'';
3313  }
3314  if (needQuote)
3315  z[n++] = '\'';
3316  z[n] = 0;
3317 }
3318 
3328 static char *appendText(char *zIn, char const *zAppend, char quote)
3329 {
3330  int len;
3331  int i;
3332  int nAppend = strlen30(zAppend);
3333  int nIn = (zIn ? strlen30(zIn) : 0);
3334 
3335 SQLDBG((stderr, "--> %s(%s,%s,0x%02x)\n", __FUNCTION__, zIn, zAppend, quote));
3336  len = nAppend + nIn + 1;
3337  if (quote) {
3338  len += 2;
3339  for (i = 0; i < nAppend; i++) {
3340  if (zAppend[i] == quote)
3341  len++;
3342  }
3343  }
3344 
3345  zIn = (char *) xrealloc(zIn, len);
3346 
3347  if (quote) {
3348  char *zCsr = &zIn[nIn];
3349  *zCsr++ = quote;
3350  for (i = 0; i < nAppend; i++) {
3351  *zCsr++ = zAppend[i];
3352  if (zAppend[i] == quote)
3353  *zCsr++ = quote;
3354  }
3355  *zCsr++ = quote;
3356  *zCsr++ = '\0';
3357 assert((zCsr - zIn) == len);
3358  } else {
3359  memcpy(&zIn[nIn], zAppend, nAppend);
3360  zIn[len - 1] = '\0';
3361  }
3362 
3363  return zIn;
3364 }
3365 
3366 
3375 static int run_table_dump_query(rpmsql sql, sqlite3 * db,
3376  const char *zSelect, const char *zFirstRow)
3377 {
3378  sqlite3_stmt * pSelect;
3379  int rc;
3380 SQLDBG((stderr, "--> %s(%p,%p,%s,%s)\n", __FUNCTION__, sql, db, zSelect, zFirstRow));
3381  rc = rpmsqlCmd(sql, "prepare", db,
3382  sqlite3_prepare(db, zSelect, -1, &pSelect, 0));
3383  if (rc || pSelect == NULL)
3384  return rc;
3385 
3386  while ((rc = rpmsqlCmd(sql, "step", db,
3387  sqlite3_step(pSelect))) == SQLITE_ROW)
3388  {
3389  if (zFirstRow) {
3390  rpmsqlFprintf(sql, "%s", zFirstRow);
3391  zFirstRow = NULL;
3392  }
3393  rpmsqlFprintf(sql, "%s;\n", sqlite3_column_text(pSelect, 0));
3394  }
3395 
3396  return rpmsqlCmd(sql, "finalize", db,
3397  sqlite3_finalize(pSelect));
3398 }
3399 #endif /* defined(WITH_SQLITE) */
3400 
3401 /*==============================================================*/
3402 
3403 #if defined(WITH_SQLITE)
3404 #define iseol(_c) ((char)(_c) == '\n' || (char)(_c) == '\r')
3405 
3413 /*@null@*/
3414 static char *
3415 rpmsqlFgets(/*@returned@*/ char * buf, size_t nbuf, rpmsql sql)
3416  /*@globals fileSystem @*/
3417  /*@modifies buf, fileSystem @*/
3418 {
3419  FD_t ifd = sql->ifd;
3420 /* XXX sadly, fgets(3) cannot be used against a LIBIO wrapped .fpio FD_t */
3421 FILE * ifp = (!F_ISSET(sql, PROMPT) ? fdGetFILE(ifd) : stdin);
3422  char *q = buf - 1; /* initialize just before buffer. */
3423  size_t nb = 0;
3424  size_t nr = 0;
3425  int pc = 0, bc = 0;
3426  char *p = buf;
3427 
3428 #ifdef NOISY /* XXX obliterates CLI input */
3429 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)));
3430 #endif /* NOISY */
3431 assert(ifp != NULL);
3432 
3433  if (ifp != NULL)
3434  do {
3435  *(++q) = '\0'; /* terminate and move forward. */
3436  if (fgets(q, (int)nbuf, ifp) == NULL) /* read next line. */
3437  break;
3438  nb = strlen(q);
3439  nr += nb; /* trim trailing \r and \n */
3440  for (q += nb - 1; nb > 0 && iseol(*q); q--)
3441  nb--;
3442  for (; p <= q; p++) {
3443  switch (*p) {
3444  case '\\':
3445  switch (*(p+1)) {
3446  case '\r': /*@switchbreak@*/ break;
3447  case '\n': /*@switchbreak@*/ break;
3448  case '\0': /*@switchbreak@*/ break;
3449  default: p++; /*@switchbreak@*/ break;
3450  }
3451  /*@switchbreak@*/ break;
3452  case '%':
3453  switch (*(p+1)) {
3454  case '{': p++, bc++; /*@switchbreak@*/ break;
3455  case '(': p++, pc++; /*@switchbreak@*/ break;
3456  case '%': p++; /*@switchbreak@*/ break;
3457  }
3458  /*@switchbreak@*/ break;
3459  case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
3460  case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
3461  case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
3462  case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
3463  }
3464  }
3465  if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
3466  *(++q) = '\0'; /* trim trailing \r, \n */
3467  break;
3468  }
3469  q++; p++; nb++; /* copy newline too */
3470  nbuf -= nb;
3471  if (*q == '\r') /* XXX avoid \r madness */
3472  *q = '\n';
3473  } while (nbuf > 0);
3474 
3475 SQLDBG((stderr, "<-- %s(%p[%u],%p) nr %u\n", __FUNCTION__, buf, (unsigned)nbuf, sql, (unsigned)nr));
3476 
3477  return (nr > 0 ? buf : NULL);
3478 }
3479 
3490 static char *local_getline(rpmsql sql, /*@null@*/const char *zPrompt)
3491 {
3492  char * t;
3493 
3494 SQLDBG((stderr, "--> %s(%s) ofd %p\n", __FUNCTION__, zPrompt, sql->ofd));
3495 
3496  if (sql->ofd && zPrompt && *zPrompt) {
3497  size_t nb = strlen(zPrompt);
3498  size_t nw = Fwrite(zPrompt, 1, nb, sql->ofd);
3499 assert(nb == nw);
3500  (void) Fflush(sql->ofd);
3501  }
3502 
3503 assert(sql->ifd != NULL);
3504  t = rpmsqlFgets(sql->buf, sql->nbuf, sql);
3505 
3506 SQLDBG((stderr, "<-- %s(%s) ofd %p\n", __FUNCTION__, zPrompt, sql->ofd));
3507 
3508  return t;
3509 }
3510 
3518 static char *rpmsqlInputOneLine(rpmsql sql, const char *zPrior)
3519 {
3520  const char *zPrompt;
3521  char *zResult;
3522 
3523 SQLDBG((stderr, "--> %s(%s)\n", __FUNCTION__, zPrior));
3524 
3525 assert(sql->buf != NULL);
3526 assert(sql->ifd != NULL);
3527 
3528  if (!F_ISSET(sql, PROMPT)) {
3529  zResult = local_getline(sql, NULL);
3530  } else {
3531  zPrompt = (zPrior && zPrior[0]) ? sql->zContinue : sql->zPrompt;
3532  zResult = readline(sql, zPrompt);
3533  if (zResult) {
3534 #if defined(HAVE_READLINE) && HAVE_READLINE==1
3535  if (*zResult)
3536  add_history(zResult);
3537  /* XXX readline returns malloc'd memory. copy & free. */
3538  if (zResult != sql->buf) {
3539  strncpy(sql->buf, zResult, sql->nbuf);
3540  zResult = _free(zResult);
3541  zResult = sql->buf;
3542  }
3543 #endif
3544  }
3545  }
3546 
3547 SQLDBG((stderr, "<-- %s(%s)\n", __FUNCTION__, zPrior));
3548 
3549  return zResult;
3550 }
3551 
3552 #endif /* defined(WITH_SQLITE) */
3553 
3554 /*==============================================================*/
3555 
3556 #if defined(WITH_SQLITE)
3557 
3560 static char *save_err_msg(sqlite3 * db)
3561 {
3562  const char * s = sqlite3_errmsg(db);
3563  int nb = strlen30(s) + 1;
3564  return memcpy(xmalloc(nb), s, nb);
3565 }
3566 
3577 static int _rpmsqlShellExec(rpmsql sql, const char *zSql,
3578  int (*xCallback) (void *, int, char **, char **, int *),
3579  char **pzErrMsg
3580  )
3581 {
3582  sqlite3 * db = (sqlite3 *) sql->I;
3583  sqlite3_stmt * pStmt = NULL; /* Statement to execute. */
3584  int rc = SQLITE_OK; /* Return Code */
3585  const char *zLeftover; /* Tail of unprocessed SQL */
3586 
3587 SQLDBG((stderr, "--> %s(%p,%s,%p,%p)\n", __FUNCTION__, sql, zSql, xCallback, pzErrMsg));
3588  if (pzErrMsg)
3589  *pzErrMsg = NULL;
3590 
3591  while (zSql[0] && rc == SQLITE_OK) {
3592  rc = rpmsqlCmd(sql, "prepare_v2", db,
3593  sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover));
3594  if (rc)
3595  goto bottom;
3596 
3597  /* this happens for a comment or white-space */
3598  if (pStmt == NULL)
3599  goto bottom;
3600 
3601  /* echo the sql statement if echo on */
3602  if (sql->ofd && F_ISSET(sql, ECHO)) {
3603  const char *zStmtSql = sqlite3_sql(pStmt);
3604  rpmsqlFprintf(sql, "%s\n", zStmtSql ? zStmtSql : zSql);
3605  (void) Fflush(sql->ofd);
3606  }
3607 
3608  /* perform the first step. this will tell us if we
3609  ** have a result set or not and how wide it is.
3610  */
3611  rc = rpmsqlCmd(sql, "step", db,
3612  sqlite3_step(pStmt));
3613  /* if we have a result set... */
3614  if (rc == SQLITE_ROW) {
3615  /* if we have a callback... */
3616  if (xCallback) {
3617  /* allocate space for col name ptr, value ptr, and type */
3618  int nCol = sqlite3_column_count(pStmt);
3619  size_t nb = 3 * nCol * sizeof(const char *) + 1;
3620  char ** azCols = xmalloc(nb); /* Result names */
3621  char ** azVals = &azCols[nCol]; /* Result values */
3622  int * aiTypes = (int *) &azVals[nCol]; /* Result types */
3623  int i;
3624 
3625  /* save off ptrs to column names */
3626  for (i = 0; i < nCol; i++)
3627  azCols[i] = (char *) sqlite3_column_name(pStmt, i);
3628 
3629  /* save off the prepared statement handle and reset row count */
3630  sql->S = (void *) pStmt;
3631  sql->cnt = 0;
3632  do {
3633  /* extract the data and data types */
3634  for (i = 0; i < nCol; i++) {
3635  azVals[i] = (char *) sqlite3_column_text(pStmt, i);
3636  aiTypes[i] = sqlite3_column_type(pStmt, i);
3637  if (!azVals[i] && (aiTypes[i] != SQLITE_NULL)) {
3638  rc = SQLITE_NOMEM;
3639  break; /* from for */
3640  }
3641  } /* end for */
3642 
3643  /* if data and types extraction failed... */
3644  if (rc != SQLITE_ROW)
3645  break;
3646 
3647  /* call the supplied callback with the result row data */
3648  if (xCallback (sql, nCol, azVals, azCols, aiTypes)) {
3649  rc = SQLITE_ABORT;
3650  break;
3651  }
3652  rc = rpmsqlCmd(sql, "step", db,
3653  sqlite3_step(pStmt));
3654  } while (rc == SQLITE_ROW);
3655  azCols = _free(azCols);
3656  sql->S = NULL;
3657  } else {
3658  do {
3659  rc = rpmsqlCmd(sql, "step", db,
3660  sqlite3_step(pStmt));
3661  } while (rc == SQLITE_ROW);
3662  }
3663  }
3664 
3665  /* Finalize the statement just executed. If this fails, save a
3666  ** copy of the error message. Otherwise, set zSql to point to the
3667  ** next statement to execute. */
3668  rc = rpmsqlCmd(sql, "finalize", db,
3669  sqlite3_finalize(pStmt));
3670 
3671 bottom:
3672  /* On error, retrieve message and exit. */
3673  if (rc) {
3674  if (pzErrMsg)
3675  *pzErrMsg = save_err_msg(db);
3676  break;
3677  }
3678 
3679  /* Move to next sql statement */
3680  zSql = zLeftover;
3681  while (xisspace(zSql[0]))
3682  zSql++;
3683  } /* end while */
3684 
3685  return rc;
3686 }
3687 #endif /* defined(WITH_SQLITE) */
3688 
3689 /*==============================================================*/
3690 
3691 #if defined(WITH_SQLITE)
3692 
3700 static int dump_callback(void *_sql, int nArg, char **azArg, char **azCol)
3701 {
3702  rpmsql sql = (rpmsql) _sql;
3703  sqlite3 * db = (sqlite3 *) sql->I;
3704  int rc;
3705  const char *zTable;
3706  const char *zType;
3707  const char *zSql;
3708  const char *zPrepStmt = 0;
3709  int ec = 1; /* assume failure */
3710 
3711 SQLDBG((stderr, "--> %s(%p,%d,%p,%p)\n", __FUNCTION__, _sql, nArg, azArg, azCol));
3712  azCol = azCol;
3713  if (nArg != 3)
3714  goto exit;
3715  zTable = azArg[0];
3716  zType = azArg[1];
3717  zSql = azArg[2];
3718 
3719  if (!strcmp(zTable, "sqlite_sequence")) {
3720  zPrepStmt = "DELETE FROM sqlite_sequence;\n";
3721  } else if (!strcmp(zTable, "sqlite_stat1")) {
3722  rpmsqlFprintf(sql, "ANALYZE sqlite_master;\n");
3723  } else if (!strncmp(zTable, "sqlite_", 7)) {
3724  ec = 0; /* XXX success */
3725  goto exit;
3726  } else if (!strncmp(zSql, "CREATE VIRTUAL TABLE", 20)) {
3727  char *zIns;
3728  if (!F_ISSET(sql, WRITABLE)) {
3729  rpmsqlFprintf(sql, "PRAGMA writable_schema=ON;\n");
3730  sql->flags |= RPMSQL_FLAGS_WRITABLE;
3731  }
3732  zIns =
3733  sqlite3_mprintf
3734  ("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
3735  "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql);
3736  rpmsqlFprintf(sql, "%s\n", zIns);
3737  sqlite3_free(zIns);
3738  ec = 0; /* XXX success */
3739  goto exit;
3740  } else
3741  rpmsqlFprintf(sql, "%s;\n", zSql);
3742 
3743  if (!strcmp(zType, "table")) {
3744  sqlite3_stmt * pTableInfo = NULL;
3745  char *zSelect = 0;
3746  char *zTableInfo = 0;
3747  char *zTmp = 0;
3748  int nRow = 0;
3749 
3750  zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
3751  zTableInfo = appendText(zTableInfo, zTable, '"');
3752  zTableInfo = appendText(zTableInfo, ");", 0);
3753 
3754  rc = rpmsqlCmd(sql, "prepare", db,
3755  sqlite3_prepare(db, zTableInfo, -1, &pTableInfo, 0));
3756  zTableInfo = _free(zTableInfo);
3757  if (rc != SQLITE_OK || !pTableInfo)
3758  goto exit;
3759 
3760  zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
3761 
3762  zTmp = appendText(zTmp, zTable, '"');
3763  if (zTmp)
3764  zSelect = appendText(zSelect, zTmp, '\'');
3765  zTmp = _free(zTmp); /* XXX coverity #1035922 */
3766 
3767  zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
3768  rc = rpmsqlCmd(sql, "step", db,
3769  sqlite3_step(pTableInfo));
3770  while (rc == SQLITE_ROW) {
3771  const char *zText =
3772  (const char *) sqlite3_column_text(pTableInfo, 1);
3773  zSelect = appendText(zSelect, "quote(", 0);
3774  zSelect = appendText(zSelect, zText, '"');
3775  rc = rpmsqlCmd(sql, "step", db,
3776  sqlite3_step(pTableInfo));
3777  if (rc == SQLITE_ROW)
3778  zSelect = appendText(zSelect, ") || ',' || ", 0);
3779  else
3780  zSelect = appendText(zSelect, ") ", 0);
3781  nRow++;
3782  }
3783  rc = rpmsqlCmd(sql, "finalize", db,
3784  sqlite3_finalize(pTableInfo));
3785  if (rc != SQLITE_OK || nRow == 0) {
3786  zSelect = _free(zSelect);
3787  goto exit;
3788  }
3789 
3790  zSelect = appendText(zSelect, "|| ')' FROM ", 0);
3791  zSelect = appendText(zSelect, zTable, '"');
3792 
3793  rc = run_table_dump_query(sql, db, zSelect, zPrepStmt);
3794  if (rc == SQLITE_CORRUPT) {
3795  zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
3796  rc = run_table_dump_query(sql, db, zSelect, NULL);
3797  }
3798  zSelect = _free(zSelect);
3799  }
3800  ec = 0; /* XXX success */
3801 exit:
3802  return ec;
3803 }
3804 
3813 static int run_schema_dump_query(rpmsql sql,
3814  const char *zQuery, char **pzErrMsg)
3815 {
3816  sqlite3 * db = (sqlite3 *) sql->I;
3817  int rc;
3818 
3819 SQLDBG((stderr, "--> %s(%p,%s,%p)\n", __FUNCTION__, sql, zQuery, pzErrMsg));
3820  rc = rpmsqlCmd(sql, "exec", db,
3821  sqlite3_exec(db, zQuery, dump_callback, sql, pzErrMsg));
3822  if (rc == SQLITE_CORRUPT) {
3823  char *zQ2;
3824  if (pzErrMsg)
3825  sqlite3_free(*pzErrMsg);
3826  zQ2 = rpmExpand(zQuery, " ORDER BY rowid DESC", NULL);
3827  rc = rpmsqlCmd(sql, "exec", db,
3828  sqlite3_exec(db, zQ2, dump_callback, sql, pzErrMsg));
3829  zQ2 = _free(zQ2);
3830  }
3831  return rc;
3832 }
3833 
3834 /*
3835  * Text of a help message
3836  */
3837 /*@unchecked@*/
3838 static char zHelp[] =
3839  ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
3840  ".bail ON|OFF Stop after hitting an error. Default OFF\n"
3841  ".databases List names and files of attached databases\n"
3842  ".dump ?TABLE? ... Dump the database in an SQL text format\n"
3843  " If TABLE specified, only dump tables matching\n"
3844  " LIKE pattern TABLE.\n"
3845  ".echo ON|OFF Turn command echo on or off\n"
3846  ".exit Exit this program\n"
3847  ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n"
3848  " With no args, it turns EXPLAIN on.\n"
3849  ".header(s) ON|OFF Turn display of headers on or off\n"
3850  ".help Show this message\n"
3851  ".import FILE TABLE Import data from FILE into TABLE\n"
3852  ".indices ?TABLE? Show names of all indices\n"
3853  " If TABLE specified, only show indices for tables\n"
3854  " matching LIKE pattern TABLE.\n"
3855 #ifdef SQLITE_ENABLE_IOTRACE
3856  ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
3857 #endif
3858  ".load FILE ?ENTRY? Load an extension library\n"
3859  ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
3860  ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
3861  " csv Comma-separated values\n"
3862  " column Left-aligned columns. (See .width)\n"
3863  " html HTML <table> code\n"
3864  " insert SQL insert statements for TABLE\n"
3865  " line One value per line\n"
3866  " list Values delimited by .separator string\n"
3867  " tabs Tab-separated values\n"
3868  " tcl TCL list elements\n"
3869  ".nullvalue STRING Print STRING in place of NULL values\n"
3870  ".output FILENAME Send output to FILENAME\n"
3871  ".output stdout Send output to the screen\n"
3872  ".prompt MAIN CONTINUE Replace the standard prompts\n"
3873  ".quit Exit this program\n"
3874  ".read FILENAME Execute SQL in FILENAME\n"
3875  ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
3876  ".schema ?TABLE? Show the CREATE statements\n"
3877  " If TABLE specified, only show tables matching\n"
3878  " LIKE pattern TABLE.\n"
3879  ".separator STRING Change separator used by output mode and .import\n"
3880  ".show Show the current values for various settings\n"
3881  ".tables ?TABLE? List names of tables\n"
3882  " If TABLE specified, only list tables matching\n"
3883  " LIKE pattern TABLE.\n"
3884  ".timeout MS Try opening locked tables for MS milliseconds\n"
3885  ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n";
3886 
3887 static char zTimerHelp[] =
3888  ".timer ON|OFF Turn the CPU timer measurement on or off\n";
3889 
3899 static void resolve_backslashes(char *z)
3900 {
3901  int i, j;
3902  char c;
3903  for (i = j = 0; (c = z[i]) != 0; i++, j++) {
3904  if (c == '\\') {
3905  c = z[++i];
3906  if (c == 'n') {
3907  c = '\n';
3908  } else if (c == 't') {
3909  c = '\t';
3910  } else if (c == 'r') {
3911  c = '\r';
3912  } else if (c >= '0' && c <= '7') {
3913  c -= '0';
3914  if (z[i + 1] >= '0' && z[i + 1] <= '7') {
3915  i++;
3916  c = (c << 3) + z[i] - '0';
3917  if (z[i + 1] >= '0' && z[i + 1] <= '7') {
3918  i++;
3919  c = (c << 3) + z[i] - '0';
3920  }
3921  }
3922  }
3923  }
3924  z[j] = c;
3925  }
3926  z[j] = 0;
3927 }
3928 
3932 static int booleanValue(const char * zArg)
3933 {
3934  int val = atoi(zArg);
3935  if (!strcasecmp(zArg, "on") || !strcasecmp(zArg, "yes"))
3936  val = 1;
3937 SQLDBG((stderr, "<-- %s(%s) val %d\n", __FUNCTION__, zArg, val));
3938  return val;
3939 }
3940 
3941 /*@unchecked@*/ /*@observer@*/
3942 static const char *modeDescr[] = {
3943  "line",
3944  "column",
3945  "list",
3946  "semi",
3947  "html",
3948  "insert",
3949  "tcl",
3950  "csv",
3951  "explain",
3952 };
3953 
3954 /* forward ref @*/
3955 static int rpmsqlInput(rpmsql sql);
3956 
3957 static int rpmsqlFOpen(const char * fn, FD_t *fdp)
3958  /*@modifies *fdp @*/
3959 {
3960  FD_t fd = *fdp;
3961  int rc = 0;
3962 
3963 SQLDBG((stderr, "--> %s(%s,%p) fd %p\n", __FUNCTION__, fn, fdp, fd));
3964 
3965  if (fd)
3966  (void) Fclose(fd); /* XXX stdout/stderr were dup'd */
3967  fd = NULL;
3968  /* XXX permit numeric fdno's? */
3969  if (fn == NULL)
3970  fd = NULL;
3971  else if (!strcmp(fn, "stdout") || !strcmp(fn, "-"))
3972  fd = fdDup(STDOUT_FILENO);
3973  else if (!strcmp(fn, "stderr"))
3974  fd = fdDup(STDERR_FILENO);
3975  else if (!strcmp(fn, "off"))
3976  fd = NULL;
3977  else {
3978  fd = Fopen(fn, "wb");
3979  if (fd == NULL || Ferror(fd)) {
3980  rpmsql_error(1, _("cannot open \"%s\""), fn);
3981  if (fd) (void) Fclose(fd);
3982  fd = NULL;
3983  rc = 1;
3984  }
3985  }
3986  *fdp = fd;
3987 
3988 SQLDBG((stderr, "<-- %s(%s,%p) fd %p rc %d\n", __FUNCTION__, fn, fdp, fd, rc));
3989 
3990  return rc;
3991 }
3992 
3999 static int rpmsqlMetaCommand(rpmsql sql, char *zLine)
4000 {
4001  sqlite3 * db = (sqlite3 *)sql->I;
4002  int i = 1;
4003  int nArg = 0;
4004  int n, c;
4005  int rc = 0;
4006  char *azArg[50];
4007 
4008 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, zLine));
4009 
4010  /* Parse the input line into tokens. */
4011  while (zLine[i] && nArg < ArraySize(azArg)) {
4012  while (xisspace((unsigned char) zLine[i]))
4013  i++;
4014  if (zLine[i] == '\0')
4015  break;
4016  if (zLine[i] == '\'' || zLine[i] == '"') {
4017  int delim = zLine[i++];
4018  azArg[nArg++] = &zLine[i];
4019  while (zLine[i] && zLine[i] != delim)
4020  i++;
4021  if (zLine[i] == delim)
4022  zLine[i++] = '\0';
4023  if (delim == '"')
4024  resolve_backslashes(azArg[nArg - 1]);
4025  } else {
4026  azArg[nArg++] = &zLine[i];
4027  while (zLine[i] && !xisspace((unsigned char) zLine[i]))
4028  i++;
4029  if (zLine[i])
4030  zLine[i++] = 0;
4031  resolve_backslashes(azArg[nArg - 1]);
4032  }
4033  }
4034 
4035  /* Process the input line. */
4036  if (nArg == 0)
4037  return 0; /* no tokens, no error */
4038  n = strlen30(azArg[0]);
4039  c = azArg[0][0];
4040  if (c == 'b' && n >= 3 && !strncmp(azArg[0], "backup", n)
4041  && nArg > 1 && nArg < 4) {
4042  const char *zDestFile;
4043  const char *zDb;
4044  sqlite3 * pDest;
4045  sqlite3_backup *pBackup;
4046  if (nArg == 2) {
4047  zDestFile = azArg[1];
4048  zDb = "main";
4049  } else {
4050  zDestFile = azArg[2];
4051  zDb = azArg[1];
4052  }
4053  rc = rpmsqlCmd(sql, "open", pDest,
4054  sqlite3_open(zDestFile, &pDest));
4055  if (rc) {
4056 #ifdef DYING
4057  rpmsql_error(1, _("cannot open \"%s\""), zDestFile);
4058 #endif
4059  (void) rpmsqlCmd(sql, "close", pDest,
4060  sqlite3_close(pDest));
4061  return 1;
4062  }
4063  _rpmsqlOpenDB(sql);
4064  db = (sqlite3 *)sql->I;
4065  pBackup = sqlite3_backup_init(pDest, "main", db, zDb);
4066  if (pBackup == NULL) {
4067  rpmsql_error(1, "%s", sqlite3_errmsg(pDest));
4068  (void) rpmsqlCmd(sql, "close", pDest,
4069  sqlite3_close(pDest));
4070  return 1;
4071  }
4072  while ((rc = rpmsqlCmd(sql, "backup_step", db,
4073  sqlite3_backup_step(pBackup, 100))) == SQLITE_OK)
4074  ;
4075  (void) rpmsqlCmd(sql, "backup_finish", pBackup,
4076  sqlite3_backup_finish(pBackup));
4077  if (rc == SQLITE_DONE) {
4078  rc = 0;
4079  } else {
4080  rpmsql_error(1, "%s", sqlite3_errmsg(pDest));
4081  rc = 1;
4082  }
4083  (void) rpmsqlCmd(sql, "close", pDest,
4084  sqlite3_close(pDest));
4085  } else
4086  if (c == 'b' && n >= 3 && !strncmp(azArg[0], "bail", n)
4087  && nArg > 1 && nArg < 3) {
4088  if (booleanValue(azArg[1]))
4089  sql->flags |= RPMSQL_FLAGS_BAIL;
4090  else
4091  sql->flags &= ~RPMSQL_FLAGS_BAIL;
4092  } else
4093  if (c == 'd' && n > 1 && !strncmp(azArg[0], "databases", n) && nArg == 1) {
4094  /* XXX recursion b0rkage lies here. */
4095  uint32_t _flags = sql->flags;
4096  uint32_t _mode = sql->mode;
4097  int _cnt = sql->cnt;;
4098  int _colWidth[3];
4099  char *zErrMsg = NULL;
4100  memcpy(_colWidth, sql->colWidth, sizeof(_colWidth));
4101  _rpmsqlOpenDB(sql);
4102  db = (sqlite3 *)sql->I;
4103  sql->flags |= RPMSQL_FLAGS_SHOWHDR;
4104  sql->mode = RPMSQL_MODE_COLUMN;
4105  sql->colWidth[0] = 3;
4106  sql->colWidth[1] = 15;
4107  sql->colWidth[2] = 58;
4108  sql->cnt = 0;
4109  (void) rpmsqlCmd(sql, "exec", db,
4110  sqlite3_exec(db, "PRAGMA database_list;", callback, sql, &zErrMsg));
4111  if (zErrMsg) {
4112  rpmsql_error(1, "%s", zErrMsg);
4113  sqlite3_free(zErrMsg);
4114  rc = 1;
4115  }
4116  memcpy(sql->colWidth, _colWidth, sizeof(_colWidth));
4117  sql->cnt = _cnt;
4118  sql->mode = _mode;
4119  sql->flags = _flags;
4120  } else
4121  if (c == 'd' && !strncmp(azArg[0], "dump", n) && nArg < 3) {
4122  char * t;
4123  _rpmsqlOpenDB(sql);
4124  db = (sqlite3 *)sql->I;
4125  /* When playing back a "dump", the content might appear in an order
4126  ** which causes immediate foreign key constraints to be violated.
4127  ** So disable foreign-key constraint enforcement to prevent problems. */
4128  rpmsqlFprintf(sql, "PRAGMA foreign_keys=OFF;\n");
4129  rpmsqlFprintf(sql, "BEGIN TRANSACTION;\n");
4130  sql->flags &= ~RPMSQL_FLAGS_WRITABLE;
4131  (void) rpmsqlCmd(sql, "exec", db,
4132  sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0));
4133  if (nArg == 1) {
4134  t = rpmExpand("SELECT name, type, sql FROM sqlite_master"
4135  " WHERE sql NOT NULL AND type=='table'"
4136  " AND name!='sqlite_sequence'", NULL);
4137  run_schema_dump_query(sql, t, NULL);
4138  t = _free(t);
4139  t = rpmExpand("SELECT name, type, sql FROM sqlite_master"
4140  " WHERE name=='sqlite_sequence'", NULL);
4141  run_schema_dump_query(sql, t, NULL);
4142  t = _free(t);
4143  t = rpmExpand("SELECT sql FROM sqlite_master"
4144  " WHERE sql NOT NULL AND type IN ('index','trigger','view')", NULL);
4145  run_table_dump_query(sql, db, t, NULL);
4146  t = _free(t);
4147  } else {
4148  int i;
4149  for (i = 1; i < nArg; i++) {
4150  t = rpmExpand( "SELECT name, type, sql FROM sqlite_master"
4151  " WHERE tbl_name LIKE '", azArg[i], "'"
4152  " AND type=='table' AND sql NOT NULL", NULL);
4153  run_schema_dump_query(sql, t, NULL);
4154  t = _free(t);
4155  t = rpmExpand( "SELECT sql FROM sqlite_master"
4156  " WHERE sql NOT NULL"
4157  " AND type IN ('index','trigger','view')"
4158  " AND tbl_name LIKE '", azArg[i], "'", NULL);
4159  run_table_dump_query(sql, db, t, NULL);
4160  t = _free(t);
4161  }
4162  }
4163  if (F_ISSET(sql, WRITABLE)) {
4164  rpmsqlFprintf(sql, "PRAGMA writable_schema=OFF;\n");
4165  sql->flags &= ~RPMSQL_FLAGS_WRITABLE;
4166  }
4167  (void) rpmsqlCmd(sql, "exec", db,
4168  sqlite3_exec(db, "PRAGMA writable_schema=OFF", 0, 0, 0));
4169  rpmsqlFprintf(sql, "COMMIT;\n");
4170  } else
4171  if (c == 'e' && !strncmp(azArg[0], "echo", n) && nArg > 1 && nArg < 3) {
4172  if (booleanValue(azArg[1]))
4173  sql->flags |= RPMSQL_FLAGS_ECHO;
4174  else
4175  sql->flags &= ~RPMSQL_FLAGS_ECHO;
4176  } else
4177  if (c == 'e' && !strncmp(azArg[0], "exit", n) && nArg == 1) {
4178  rc = 2;
4179  } else
4180  if (c == 'e' && !strncmp(azArg[0], "explain", n) && nArg < 3) {
4181  int val = nArg >= 2 ? booleanValue(azArg[1]) : 1;
4182  if (val == 1) {
4183  if (!sql->explainPrev.valid) {
4184  sql->explainPrev.valid = 1;
4185  sql->explainPrev.mode = sql->mode;
4186  sql->explainPrev.flags = sql->flags;
4187  memcpy(sql->explainPrev.colWidth, sql->colWidth,
4188  sizeof(sql->colWidth));
4189  }
4190  /* We could put this code under the !p->explainValid
4191  ** condition so that it does not execute if we are already in
4192  ** explain mode. However, always executing it allows us an easy
4193  ** way to reset to explain mode in case the user previously
4194  ** did an .explain followed by a .width, .mode or .header
4195  ** command.
4196  */
4197  sql->mode = RPMSQL_MODE_EXPLAIN;
4198  sql->flags |= RPMSQL_FLAGS_SHOWHDR;
4199  memset(sql->colWidth, 0, ArraySize(sql->colWidth));
4200  sql->colWidth[0] = 4; /* addr */
4201  sql->colWidth[1] = 13; /* opcode */
4202  sql->colWidth[2] = 4; /* P1 */
4203  sql->colWidth[3] = 4; /* P2 */
4204  sql->colWidth[4] = 4; /* P3 */
4205  sql->colWidth[5] = 13; /* P4 */
4206  sql->colWidth[6] = 2; /* P5 */
4207  sql->colWidth[7] = 13; /* Comment */
4208  } else if (sql->explainPrev.valid) {
4209  sql->explainPrev.valid = 0;
4210  sql->mode = sql->explainPrev.mode;
4211  sql->flags = sql->explainPrev.flags;
4212  memcpy(sql->colWidth, sql->explainPrev.colWidth,
4213  sizeof(sql->colWidth));
4214  }
4215  } else
4216  if (c == 'h'
4217  && (!strncmp(azArg[0], "header", n) || !strncmp(azArg[0], "headers", n))
4218  && nArg > 1 && nArg < 3)
4219  {
4220  if (booleanValue(azArg[1]))
4221  sql->flags |= RPMSQL_FLAGS_SHOWHDR;
4222  else
4223  sql->flags &= ~RPMSQL_FLAGS_SHOWHDR;
4224  } else
4225  if (c == 'h' && !strncmp(azArg[0], "help", n)) {
4226  rpmsql_error(0, "%s", zHelp);
4227  if (HAS_TIMER)
4228  rpmsql_error(0, "%s", zTimerHelp);
4229  } else
4230  if (c == 'i' && !strncmp(azArg[0], "import", n) && nArg == 3) {
4231  char *zTable = azArg[2]; /* Insert data into this table */
4232  char *zFile = azArg[1]; /* The file from which to extract data */
4233  sqlite3_stmt * pStmt = NULL;/* A statement */
4234  int nCol; /* Number of columns in the table */
4235  int nByte; /* Number of bytes in an SQL string */
4236  int i, j; /* Loop counters */
4237  int nSep; /* Number of bytes in sql->separator[] */
4238  char *zSql; /* An SQL statement */
4239  char *zLine; /* A single line of input from the file */
4240  char **azCol; /* zLine[] broken up into columns */
4241  char *zCommit; /* How to commit changes */
4242  int lineno = 0; /* Line number of input file */
4243 
4244  _rpmsqlOpenDB(sql);
4245  db = (sqlite3 *)sql->I;
4246  nSep = strlen30(sql->separator);
4247  if (nSep == 0) {
4248  rpmsql_error(1, _("non-null separator required for import"));
4249  return 1;
4250  }
4251  zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
4252 assert(zSql != NULL);
4253  nByte = strlen30(zSql);
4254  rc = rpmsqlCmd(sql, "prepare", db,
4255  sqlite3_prepare(db, zSql, -1, &pStmt, 0));
4256  sqlite3_free(zSql);
4257  if (rc) {
4258 #ifdef DYING
4259  sqlite3 * db = (sqlite3 *)sql->I;
4260  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4261 #endif
4262  if (pStmt)
4263  (void) rpmsqlCmd(sql, "finalize", db,
4264  sqlite3_finalize(pStmt));
4265  return 1;
4266  }
4267  nCol = sqlite3_column_count(pStmt);
4268  (void) rpmsqlCmd(sql, "finalize", db,
4269  sqlite3_finalize(pStmt));
4270  pStmt = 0;
4271  if (nCol == 0)
4272  return 0; /* no columns, no error */
4273  zSql = xmalloc(nByte + 20 + nCol * 2);
4274  sqlite3_snprintf(nByte + 20, zSql, "INSERT INTO '%q' VALUES(?",
4275  zTable);
4276  j = strlen30(zSql);
4277  for (i = 1; i < nCol; i++) {
4278  zSql[j++] = ',';
4279  zSql[j++] = '?';
4280  }
4281  zSql[j++] = ')';
4282  zSql[j] = 0;
4283  rc = rpmsqlCmd(sql, "prepare", db,
4284  sqlite3_prepare(db, zSql, -1, &pStmt, 0));
4285  zSql = _free(zSql);
4286  if (rc) {
4287 #ifdef DYING
4288  sqlite3 * db = (sqlite3 *)sql->I;
4289  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4290 #endif
4291  if (pStmt)
4292  (void) rpmsqlCmd(sql, "finalize", db,
4293  sqlite3_finalize(pStmt));
4294  return 1;
4295  }
4296 assert(sql->ifd == NULL);
4297  sql->ifd = Fopen(zFile, "rb.fpio");
4298  if (sql->ifd == NULL || Ferror(sql->ifd)) {
4299  rpmsql_error(1, _("cannot open \"%s\""), zFile);
4300  (void) rpmsqlCmd(sql, "finalize", db,
4301  sqlite3_finalize(pStmt));
4302  if (sql->ifd) (void) Fclose(sql->ifd);
4303  sql->ifd = NULL;
4304  return 1;
4305  }
4306 assert(sql->buf == NULL);
4307 sql->nbuf = BUFSIZ;
4308 sql->buf = xmalloc(sql->nbuf);
4309  azCol = malloc(sizeof(azCol[0]) * (nCol + 1));
4310  if (azCol == NULL) {
4311  if (sql->ifd) (void) Fclose(sql->ifd);
4312  sql->ifd = NULL;
4313  (void) rpmsqlCmd(sql, "finalize", db,
4314  sqlite3_finalize(pStmt));
4315 assert(azCol);
4316  }
4317  (void) rpmsqlCmd(sql, "exec", db,
4318  sqlite3_exec(db, "BEGIN", 0, 0, 0));
4319  zCommit = "COMMIT";
4320  while ((zLine = local_getline(sql, NULL)) != NULL) {
4321  char *z;
4322  i = 0;
4323  lineno++;
4324  azCol[0] = zLine;
4325  for (i = 0, z = zLine; *z && *z != '\n' && *z != '\r'; z++) {
4326  if (*z == sql->separator[0] && !strncmp(z, sql->separator, nSep)) {
4327  *z = '\0';
4328  i++;
4329  if (i < nCol) {
4330  azCol[i] = &z[nSep];
4331  z += nSep - 1;
4332  }
4333  }
4334  } /* end for */
4335  *z = '\0';
4336  if (i + 1 != nCol) {
4337  rpmsql_error(1,
4338  _("%s line %d: expected %d columns of data but found %d"),
4339  zFile, lineno, nCol, i + 1);
4340  zCommit = "ROLLBACK";
4341  rc = 1;
4342  break; /* from while */
4343  }
4344  for (i = 0; i < nCol; i++)
4345  rc = rpmsqlCmd(sql, "bind_text", db,
4346  sqlite3_bind_text(pStmt, i + 1, azCol[i], -1, SQLITE_STATIC));
4347  rc = rpmsqlCmd(sql, "step", db,
4348  sqlite3_step(pStmt));
4349  rc = rpmsqlCmd(sql, "reset", db,
4350  sqlite3_reset(pStmt));
4351  if (rc) {
4352 #ifdef DYING
4353  sqlite3 * db = (sqlite3 *)sql->I;
4354  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4355 #endif
4356  zCommit = "ROLLBACK";
4357  rc = 1;
4358  break; /* from while */
4359  }
4360  } /* end while */
4361  azCol = _free(azCol);
4362  if (sql->ifd) (void) Fclose(sql->ifd);
4363  sql->ifd = NULL;
4364 sql->buf = _free(sql->buf);
4365 sql->nbuf = 0;
4366  (void) rpmsqlCmd(sql, "finalize", db,
4367  sqlite3_finalize(pStmt));
4368  (void) rpmsqlCmd(sql, "exec", db,
4369  sqlite3_exec(db, zCommit, 0, 0, 0));
4370  } else
4371  if (c == 'i' && !strncmp(azArg[0], "indices", n) && nArg < 3) {
4372  /* XXX recursion b0rkage lies here. */
4373  uint32_t _flags = sql->flags;
4374  uint32_t _mode = sql->mode;
4375  char * t;
4376  char *zErrMsg = NULL;
4377  _rpmsqlOpenDB(sql);
4378  db = (sqlite3 *)sql->I;
4379  sql->flags &= ~RPMSQL_FLAGS_SHOWHDR;
4380  sql->mode = RPMSQL_MODE_LIST;
4381  if (nArg == 1) {
4382  t = rpmExpand("SELECT name FROM sqlite_master"
4383  " WHERE type='index' AND name NOT LIKE 'sqlite_%'"
4384  " UNION ALL "
4385  "SELECT name FROM sqlite_temp_master"
4386  " WHERE type='index'"
4387  " ORDER BY 1", NULL);
4388  rc = rpmsqlCmd(sql, "exec", db,
4389  sqlite3_exec(db, t, callback, sql, &zErrMsg));
4390  t = _free(t);
4391  } else {
4392  t = rpmExpand("SELECT name FROM sqlite_master"
4393  " WHERE type='index' AND tbl_name LIKE '", azArg[1], "'",
4394  " UNION ALL "
4395  "SELECT name FROM sqlite_temp_master"
4396  " WHERE type='index' AND tbl_name LIKE '", azArg[1], "'",
4397  " ORDER BY 1", NULL);
4398  rc = rpmsqlCmd(sql, "exec", db,
4399  sqlite3_exec(db, t, callback, sql, &zErrMsg));
4400  t = _free(t);
4401  }
4402  if (zErrMsg) {
4403  rpmsql_error(1, "%s", zErrMsg);
4404  sqlite3_free(zErrMsg);
4405  rc = 1;
4406  } else if (rc) {
4407 #ifdef DYING
4408  rpmsql_error(1, _("querying sqlite_master and sqlite_temp_master"));
4409 #endif
4410  rc = 1;
4411  }
4412  sql->mode = _mode;
4413  sql->flags = _flags;
4414  } else
4415 
4416 #ifdef SQLITE_ENABLE_IOTRACE
4417  if (c == 'i' && !strncmp(azArg[0], "iotrace", n)) {
4418  extern void (*sqlite3IoTrace) (const char *, ...);
4419  rc = rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->tfd);
4420  sqlite3IoTrace = (sql->tfd ? iotracePrintf : NULL);
4421  } else
4422 #endif
4423 
4424  if (c == 'l' && !strncmp(azArg[0], "load", n) && nArg >= 2) {
4425  const char *zFile, *zProc;
4426  char *zErrMsg = 0;
4427  zFile = azArg[1];
4428  zProc = nArg >= 3 ? azArg[2] : 0;
4429  if (!F_ISSET(sql, NOLOAD)) {
4430  _rpmsqlOpenDB(sql);
4431  db = (sqlite3 *)sql->I;
4432  rc = rpmsqlCmd(sql, "load_extension", db,
4433  sqlite3_load_extension(db, zFile, zProc, &zErrMsg));
4434  if (rc) {
4435  rpmsql_error(1, "%s", zErrMsg);
4436  sqlite3_free(zErrMsg);
4437  rc = 1;
4438  }
4439  }
4440  } else
4441 
4442  if (c == 'l' && !strncmp(azArg[0], "log", n) && nArg >= 1) {
4443  /* XXX set rc? */
4444  (void) rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->lfd);
4445  } else
4446  if (c == 'm' && !strncmp(azArg[0], "mode", n) && nArg == 2) {
4447  int n2 = strlen30(azArg[1]);
4448  if ((n2 == 4 && !strncmp(azArg[1], "line", n2))
4449  || (n2 == 5 && !strncmp(azArg[1], "lines", n2))) {
4450  sql->mode = RPMSQL_MODE_LINE;
4451  } else if ((n2 == 6 && !strncmp(azArg[1], "column", n2))
4452  || (n2 == 7 && !strncmp(azArg[1], "columns", n2))) {
4453  sql->mode = RPMSQL_MODE_COLUMN;
4454  } else if (n2 == 4 && !strncmp(azArg[1], "list", n2)) {
4455  sql->mode = RPMSQL_MODE_LIST;
4456  } else if (n2 == 4 && !strncmp(azArg[1], "html", n2)) {
4457  sql->mode = RPMSQL_MODE_HTML;
4458  } else if (n2 == 3 && !strncmp(azArg[1], "tcl", n2)) {
4459  sql->mode = RPMSQL_MODE_TCL;
4460  } else if (n2 == 3 && !strncmp(azArg[1], "csv", n2)) {
4461  sql->mode = RPMSQL_MODE_CSV;
4462  (void) stpcpy(sql->separator, ",");
4463  } else if (n2 == 4 && !strncmp(azArg[1], "tabs", n2)) {
4464  sql->mode = RPMSQL_MODE_LIST;
4465  (void) stpcpy(sql->separator, "\t");
4466  } else if (n2 == 6 && !strncmp(azArg[1], "insert", n2)) {
4467  sql->mode = RPMSQL_MODE_INSERT;
4468  set_table_name(sql, "table");
4469  } else {
4470  rpmsql_error(1, _("mode should be one of: %s"),
4471  "column csv html insert line list tabs tcl");
4472  rc = 1;
4473  }
4474  } else
4475  if (c == 'm' && !strncmp(azArg[0], "mode", n) && nArg == 3) {
4476  int n2 = strlen30(azArg[1]);
4477  if (n2 == 6 && !strncmp(azArg[1], "insert", n2)) {
4478  sql->mode = RPMSQL_MODE_INSERT;
4479  set_table_name(sql, azArg[2]);
4480  } else {
4481  rpmsql_error(1, _("invalid arguments: "
4482  " \"%s\". Enter \".help\" for help"), azArg[2]);
4483  rc = 1;
4484  }
4485  } else
4486  if (c == 'n' && !strncmp(azArg[0], "nullvalue", n) && nArg == 2) {
4487  (void) stpncpy(sql->nullvalue, azArg[1], sizeof(sql->nullvalue)-1);
4488  } else
4489  if (c == 'o' && !strncmp(azArg[0], "output", n) && nArg == 2) {
4490  rc = rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->ofd);
4491 
4492  /* Make sure sql->ofd squirts _SOMEWHERE_. Save the name too. */
4493  sql->outfile = _free(sql->outfile);
4494  if (sql->ofd)
4495  sql->outfile = xstrdup(azArg[1]);
4496  else {
4497  sql->ofd = fdDup(STDOUT_FILENO);
4498  sql->outfile = xstrdup("stdout");
4499  }
4500  } else
4501  if (c == 'p' && !strncmp(azArg[0], "prompt", n)
4502  && (nArg == 2 || nArg == 3)) {
4503  if (nArg >= 2) {
4504  sql->zPrompt = _free(sql->zPrompt);
4505  sql->zPrompt = xstrdup(azArg[1]);
4506  }
4507  if (nArg >= 3) {
4508  sql->zContinue = _free(sql->zContinue);
4509  sql->zContinue = xstrdup(azArg[2]);
4510  }
4511  } else
4512  if (c == 'q' && !strncmp(azArg[0], "quit", n) && nArg == 1) {
4513  rc = 2;
4514  } else
4515  if (c == 'r' && n >= 3 && !strncmp(azArg[0], "read", n)
4516  && nArg == 2) {
4517  FD_t _ifd = sql->ifd;
4518  sql->ifd = Fopen(azArg[1], "rb.fpio");
4519  if (sql->ifd == NULL || Ferror(sql->ifd)) {
4520  rpmsql_error(1, _("cannot open \"%s\""), azArg[1]);
4521  rc = 1;
4522  } else {
4523  /* XXX .read assumes .echo off? */
4524  rc = rpmsqlInput(sql);
4525  }
4526  if (sql->ifd) (void) Fclose(sql->ifd);
4527  sql->ifd = _ifd;
4528  } else
4529  if (c == 'r' && n >= 3 && !strncmp(azArg[0], "restore", n)
4530  && nArg > 1 && nArg < 4) {
4531  const char *zSrcFile;
4532  const char *zDb;
4533  sqlite3 * pSrc;
4534  sqlite3_backup *pBackup;
4535  int nTimeout = 0;
4536 
4537  if (nArg == 2) {
4538  zSrcFile = azArg[1];
4539  zDb = "main";
4540  } else {
4541  zSrcFile = azArg[2];
4542  zDb = azArg[1];
4543  }
4544  rc = rpmsqlCmd(sql, "open", pSrc, /* XXX watchout: arg order */
4545  sqlite3_open(zSrcFile, &pSrc));
4546  if (rc) {
4547 #ifdef DYING
4548  rpmsql_error(1, _("cannot open \"%s\""), zSrcFile);
4549 #endif
4550  (void) rpmsqlCmd(sql, "close", pSrc,
4551  sqlite3_close(pSrc));
4552  return 1;
4553  }
4554  _rpmsqlOpenDB(sql);
4555  db = (sqlite3 *)sql->I;
4556  pBackup = sqlite3_backup_init(db, zDb, pSrc, "main");
4557  if (pBackup == 0) {
4558  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4559  (void) rpmsqlCmd(sql, "close", db,
4560  sqlite3_close(pSrc));
4561  return 1;
4562  }
4563  while ((rc = sqlite3_backup_step(pBackup, 100)) == SQLITE_OK
4564  || rc == SQLITE_BUSY)
4565  {
4566  if (rc == SQLITE_BUSY) {
4567  if (nTimeout++ >= 3)
4568  break;
4569  sqlite3_sleep(100);
4570  }
4571  }
4572  sqlite3_backup_finish(pBackup);
4573  switch (rc) {
4574  case SQLITE_DONE:
4575  rc = 0;
4576  break;
4577  case SQLITE_BUSY:
4578  case SQLITE_LOCKED:
4579  rpmsql_error(1, _("source database is busy"));
4580  rc = 1;
4581  break;
4582  default:
4583  rpmsql_error(1, "%s", sqlite3_errmsg(db));
4584  rc = 1;
4585  break;
4586  }
4587  (void) rpmsqlCmd(sql, "close", pSrc,
4588  sqlite3_close(pSrc));
4589  } else
4590  if (c == 's' && !strncmp(azArg[0], "schema", n) && nArg < 3) {
4591  /* XXX recursion b0rkage lies here. */
4592  uint32_t _flags = sql->flags;
4593  uint32_t _mode = sql->mode;
4594  char *zErrMsg = 0;
4595  _rpmsqlOpenDB(sql);
4596  db = (sqlite3 *)sql->I;
4597  sql->flags &= ~RPMSQL_FLAGS_SHOWHDR;
4598  sql->mode = RPMSQL_MODE_SEMI;
4599  if (nArg > 1) {
4600  int i;
4601  for (i = 0; azArg[1][i]; i++)
4602  azArg[1][i] = (char) tolower(azArg[1][i]);
4603  if (!strcmp(azArg[1], "sqlite_master")) {
4604  char *new_argv[2], *new_colv[2];
4605  new_argv[0] = "CREATE TABLE sqlite_master (\n"
4606  " type text,\n"
4607  " name text,\n"
4608  " tbl_name text,\n"
4609  " rootpage integer,\n" " sql text\n" ")";
4610  new_argv[1] = 0;
4611  new_colv[0] = "sql";
4612  new_colv[1] = 0;
4613  callback(sql, 1, new_argv, new_colv);
4614  rc = SQLITE_OK;
4615  } else if (!strcmp(azArg[1], "sqlite_temp_master")) {
4616  char *new_argv[2], *new_colv[2];
4617  new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
4618  " type text,\n"
4619  " name text,\n"
4620  " tbl_name text,\n"
4621  " rootpage integer,\n" " sql text\n" ")";
4622  new_argv[1] = 0;
4623  new_colv[0] = "sql";
4624  new_colv[1] = 0;
4625  callback(sql, 1, new_argv, new_colv);
4626  rc = SQLITE_OK;
4627  } else {
4628  char * t;
4629  t = rpmExpand( "SELECT sql FROM "
4630  " (SELECT sql sql, type type, tbl_name tbl_name, name name"
4631  " FROM sqlite_master UNION ALL"
4632  " SELECT sql, type, tbl_name, name FROM sqlite_temp_master)"
4633  " WHERE tbl_name LIKE '", azArg[1], "'"
4634  " AND type!='meta' AND sql NOTNULL "
4635  "ORDER BY substr(type,2,1), name", NULL);
4636  rc = rpmsqlCmd(sql, "exec", db,
4637  sqlite3_exec(db, t, callback, sql, &zErrMsg));
4638  t = _free(t);
4639  }
4640  sql->mode = _mode;
4641  sql->flags = _flags;
4642  } else {
4643  rc = rpmsqlCmd(sql, "exec", db,
4644  sqlite3_exec(db,
4645  "SELECT sql FROM "
4646  " (SELECT sql sql, type type, tbl_name tbl_name, name name"
4647  " FROM sqlite_master UNION ALL"
4648  " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
4649  "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
4650  "ORDER BY substr(type,2,1), name",
4651  callback, sql, &zErrMsg));
4652  }
4653  if (zErrMsg) {
4654  rpmsql_error(1, "%s", zErrMsg);
4655  sqlite3_free(zErrMsg);
4656  rc = 1;
4657  } else if (rc != SQLITE_OK) {
4658  rpmsql_error(1, _("querying schema information"));
4659  rc = 1;
4660  } else {
4661  rc = 0;
4662  }
4663  } else
4664  if (c == 's' && !strncmp(azArg[0], "separator", n) && nArg == 2) {
4665  (void) stpncpy(sql->separator, azArg[1], sizeof(sql->separator)-1);
4666  } else
4667  if (c == 's' && !strncmp(azArg[0], "show", n) && nArg == 1) {
4668  int i;
4669  rpmsqlFprintf(sql, "%9.9s: %s\n", "echo", F_ISSET(sql, ECHO) ? "on" : "off");
4670  rpmsqlFprintf(sql, "%9.9s: %s\n", "explain",
4671  sql->explainPrev.valid ? "on" : "off");
4672  rpmsqlFprintf(sql, "%9.9s: %s\n", "headers",
4673  F_ISSET(sql, SHOWHDR) ? "on" : "off");
4674  rpmsqlFprintf(sql, "%9.9s: %s\n", "mode", modeDescr[sql->mode]);
4675  rpmsqlFprintf(sql, "%9.9s: ", "nullvalue");
4676  output_c_string(sql, sql->nullvalue);
4677  rpmsqlFprintf(sql, "\n");
4678  rpmsqlFprintf(sql, "%9.9s: %s\n", "output",
4679  (sql->outfile ? sql->outfile : "stdout"));
4680  rpmsqlFprintf(sql, "%9.9s: ", "separator");
4681  output_c_string(sql, sql->separator);
4682  rpmsqlFprintf(sql, "\n");
4683  rpmsqlFprintf(sql, "%9.9s: ", "width");
4684  for (i = 0;
4685  i < (int) ArraySize(sql->colWidth) && sql->colWidth[i] != 0;
4686  i++)
4687  {
4688  rpmsqlFprintf(sql, "%d ", sql->colWidth[i]);
4689  }
4690  rpmsqlFprintf(sql, "\n");
4691  } else
4692  if (c == 't' && n > 1 && !strncmp(azArg[0], "tables", n) && nArg < 3) {
4693  char **azResult;
4694  int nRow;
4695  char *zErrMsg;
4696  _rpmsqlOpenDB(sql);
4697  db = (sqlite3 *)sql->I;
4698  if (nArg == 1) {
4699  rc = rpmsqlCmd(sql, "get_table", db,
4700  sqlite3_get_table(db,
4701  "SELECT name FROM sqlite_master "
4702  "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
4703  "UNION ALL "
4704  "SELECT name FROM sqlite_temp_master "
4705  "WHERE type IN ('table','view') "
4706  "ORDER BY 1",
4707  &azResult, &nRow, 0, &zErrMsg));
4708  } else {
4709  char * t;
4710  t = rpmExpand("SELECT name FROM sqlite_master "
4711  " WHERE type IN ('table','view') AND name LIKE '", azArg[1], "'"
4712  " UNION ALL "
4713  "SELECT name FROM sqlite_temp_master"
4714  " WHERE type IN ('table','view') AND name LIKE '", azArg[1], "'"
4715  "ORDER BY 1", NULL);
4716  rc = rpmsqlCmd(sql, "get_table", db,
4717  sqlite3_get_table(db, t, &azResult, &nRow, 0,&zErrMsg));
4718  t = _free(t);
4719  }
4720  if (zErrMsg) {
4721  rpmsql_error(1, "%s", zErrMsg);
4722  sqlite3_free(zErrMsg);
4723  rc = 1;
4724  } else if (rc) {
4725  rpmsql_error(1, _("querying sqlite_master and sqlite_temp_master"));
4726  rc = 1;
4727  } else {
4728  int len, maxlen = 0;
4729  int i, j;
4730  int nPrintCol, nPrintRow;
4731  for (i = 1; i <= nRow; i++) {
4732  if (azResult[i] == 0)
4733  continue;
4734  len = strlen30(azResult[i]);
4735  if (len > maxlen)
4736  maxlen = len;
4737  }
4738  nPrintCol = 80 / (maxlen + 2);
4739  if (nPrintCol < 1)
4740  nPrintCol = 1;
4741  nPrintRow = (nRow + nPrintCol - 1) / nPrintCol;
4742  for (i = 0; i < nPrintRow; i++) {
4743  for (j = i + 1; j <= nRow; j += nPrintRow) {
4744  char *zSp = j <= nPrintRow ? "" : " ";
4745  rpmsqlFprintf(sql, "%s%-*s", zSp, maxlen,
4746  azResult[j] ? azResult[j] : "");
4747  }
4748  rpmsqlFprintf(sql, "\n");
4749  }
4750  }
4751  sqlite3_free_table(azResult);
4752  } else
4753  if (c == 't' && n > 4 && !strncmp(azArg[0], "timeout", n) && nArg == 2) {
4754  _rpmsqlOpenDB(sql);
4755  db = (sqlite3 *)sql->I;
4756  (void) rpmsqlCmd(sql, "busy_timeout", db,
4757  sqlite3_busy_timeout(db, atoi(azArg[1])));
4758  } else
4759  if (HAS_TIMER && c == 't' && n >= 5
4760  && !strncmp(azArg[0], "timer", n) && nArg == 2) {
4761  sql->enableTimer = booleanValue(azArg[1]);
4762  } else
4763  if (c == 'w' && !strncmp(azArg[0], "width", n) && nArg > 1) {
4764  int j;
4765 assert(nArg <= ArraySize(azArg));
4766  for (j = 1; j < nArg && j < ArraySize(sql->colWidth); j++)
4767  sql->colWidth[j - 1] = atoi(azArg[j]);
4768  } else
4769  {
4770  rpmsql_error(1, _("unknown command or invalid arguments: "
4771  " \"%s\". Enter \".help\" for help"), azArg[0]);
4772  rc = 1;
4773  }
4774 
4775  return rc;
4776 }
4777 
4778 #endif /* defined(WITH_SQLITE) */
4779 
4780 /*==============================================================*/
4781 
4782 #if defined(WITH_SQLITE)
4783 
4788 static int _contains_semicolon(const char *z, int N)
4789 {
4790  int rc = 0;
4791  int i;
4792  for (i = 0; i < N; i++) {
4793  if (z[i] != ';')
4794  continue;
4795  rc = 1;
4796  break;
4797  }
4798 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, z, rc));
4799  return rc;
4800 }
4801 
4805 static int _all_whitespace(const char *z)
4806 {
4807  int rc = 1;
4808 
4809  for (; *z; z++) {
4810  if (xisspace(*(unsigned char *) z))
4811  continue;
4812  if (*z == '/' && z[1] == '*') {
4813  z += 2;
4814  while (*z && (*z != '*' || z[1] != '/'))
4815  z++;
4816  if (*z == '\0') {
4817  rc = 0;
4818  break;
4819  }
4820  z++;
4821  continue;
4822  }
4823  if (*z == '-' && z[1] == '-') {
4824  z += 2;
4825  while (*z && *z != '\n')
4826  z++;
4827  if (*z == '\0')
4828  break;
4829  continue;
4830  }
4831  rc = 0;
4832  break;
4833  }
4834 
4835 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, z, rc));
4836  return rc;
4837 }
4838 
4844 static int _is_command_terminator(const char *zLine)
4845 {
4846  int rc = 1;
4847 
4848  while (xisspace(*(unsigned char *) zLine))
4849  zLine++;
4850  if (zLine[0] == '/' && _all_whitespace(&zLine[1]))
4851  goto exit; /* Oracle */
4852  if (xtolower(zLine[0]) == 'g' && xtolower(zLine[1]) == 'o'
4853  && _all_whitespace(&zLine[2]))
4854  goto exit; /* SQL Server */
4855  rc = 0;
4856 exit:
4857 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, zLine, rc));
4858  return rc;
4859 }
4860 
4865 static int _is_complete(char *zSql, int nSql)
4866 {
4867  int rc = 1;
4868  if (zSql == NULL)
4869  goto exit;
4870  zSql[nSql] = ';';
4871  zSql[nSql + 1] = '\0';
4872  rc = sqlite3_complete(zSql);
4873  zSql[nSql] = '\0';
4874 exit:
4875 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, zSql, rc));
4876  return rc;
4877 }
4878 
4889 static int rpmsqlInput(rpmsql sql)
4890 {
4891  sqlite3 * db = (sqlite3 *) sql->I;
4892  char *zLine = 0;
4893  char *zSql = 0;
4894  int nSql = 0;
4895  int nSqlPrior = 0;
4896  char *zErrMsg;
4897  int rc;
4898  int errCnt = 0;
4899  int lineno = 0;
4900  int startline = 0;
4901 
4902 char * _buf = sql->buf;
4903 size_t _nbuf = sql->nbuf;
4904 
4905 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, sql));
4906 if (_rpmsql_debug < 0)
4907 rpmsqlDebugDump(sql);
4908 
4909 sql->nbuf = BUFSIZ;
4910 sql->buf = xmalloc(sql->nbuf);
4911 
4912  while (errCnt == 0 || !F_ISSET(sql, BAIL) || F_ISSET(sql, PROMPT))
4913  {
4914  if (sql->ofd) Fflush(sql->ofd);
4915  zLine = rpmsqlInputOneLine(sql, zSql);
4916  if (zLine == NULL)
4917  break; /* We have reached EOF */
4918  if (_rpmsqlSeenInterrupt) {
4919  if (!F_ISSET(sql, PROMPT))
4920  break;
4922  }
4923  lineno++;
4924  if ((zSql == NULL || zSql[0] == '\0') && _all_whitespace(zLine))
4925  continue;
4926  if (zLine && zLine[0] == '.' && nSql == 0) {
4927  if (F_ISSET(sql, ECHO))
4928  rpmsqlFprintf(sql, "%s\n", zLine);
4929  rc = rpmsqlMetaCommand(sql, zLine);
4930  if (rc == 2) /* exit requested */
4931  break;
4932  else if (rc)
4933  errCnt++;
4934  continue;
4935  }
4936  if (_is_command_terminator(zLine) && _is_complete(zSql, nSql))
4937  memcpy(zLine, ";", 2);
4938  nSqlPrior = nSql;
4939  if (zSql == NULL) {
4940  int i;
4941  for (i = 0; zLine[i] && xisspace((unsigned char) zLine[i]); i++)
4942  ;
4943  if (zLine[i] != '\0') {
4944  nSql = strlen30(zLine);
4945  zSql = xmalloc(nSql + 3);
4946  memcpy(zSql, zLine, nSql + 1);
4947  startline = lineno;
4948  }
4949  } else {
4950  int len = strlen30(zLine);
4951  zSql = xrealloc(zSql, nSql + len + 4);
4952  zSql[nSql++] = '\n';
4953  memcpy(&zSql[nSql], zLine, len + 1);
4954  nSql += len;
4955  }
4956  if (zSql && _contains_semicolon(&zSql[nSqlPrior], nSql - nSqlPrior)
4957  && sqlite3_complete(zSql)) {
4958  sql->cnt = 0;
4959  _rpmsqlOpenDB(sql);
4960  db = (sqlite3 *)sql->I;
4961  BEGIN_TIMER(sql);
4962  rc = _rpmsqlShellExec(sql, zSql, _rpmsqlShellCallback, &zErrMsg);
4963  END_TIMER(sql);
4964  if (rc || zErrMsg) {
4965  char zPrefix[100];
4966  if (!F_ISSET(sql, PROMPT) || !F_ISSET(sql, INTERACTIVE))
4967  snprintf(zPrefix, sizeof(zPrefix),
4968  "near line %d: ", startline);
4969  else
4970  zPrefix[0] = '\0';
4971  rpmsql_error(1, "%s%s", zPrefix,
4972  zErrMsg ? zErrMsg : sqlite3_errmsg(db));
4973  zErrMsg = _free(zErrMsg);
4974  errCnt++;
4975  }
4976  zSql = _free(zSql);
4977  nSql = 0;
4978  }
4979  }
4980  if (zSql) {
4981  if (!_all_whitespace(zSql))
4982  rpmsql_error(1, _("incomplete SQL: %s"), zSql);
4983  zSql = _free(zSql);
4984  }
4985 
4986 sql->buf = _free(sql->buf);
4987 sql->buf = _buf;
4988 sql->nbuf = _nbuf;
4989 
4990 SQLDBG((stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, sql, errCnt));
4991 
4992  return errCnt;
4993 }
4994 
5002 static int rpmsqlInitRC(rpmsql sql, const char *sqliterc)
5003 {
5004  int rc = 0;
5005 
5006 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, sqliterc));
5007 if (_rpmsql_debug < 0)
5008 rpmsqlDebugDump(sql);
5009 
5010  if (sqliterc == NULL)
5011  sqliterc = sql->zInitrc;
5012  if (sqliterc) {
5013  FD_t _ifd = sql->ifd;
5014  sql->ifd = Fopen(sqliterc, "rb.fpio");
5015  if (!(sql->ifd == NULL || Ferror(sql->ifd))) {
5016  if (F_ISSET(sql, INTERACTIVE))
5017  rpmsql_error(0, "-- Loading resources from %s", sqliterc);
5018  rc = rpmsqlInput(sql);
5019  }
5020  if (sql->ifd) (void) Fclose(sql->ifd);
5021  sql->ifd = _ifd;
5022  }
5023 
5024 SQLDBG((stderr, "<-- %s(%p,%s) rc %d\n", __FUNCTION__, sql, sqliterc, rc));
5025 
5026  return rc;
5027 }
5028 
5029 #endif /* defined(WITH_SQLITE) */
5030 
5031 /*==============================================================*/
5032 
5033 #if defined(WITH_SQLITE)
5034 
5037 static void rpmsqlArgCallback(poptContext con,
5038  /*@unused@ */ enum poptCallbackReason reason,
5039  const struct poptOption *opt,
5040  const char *arg,
5041  /*@unused@ */ void *_data)
5042  /*@ */
5043 {
5044  rpmsql sql = &_sql;
5045 
5046  /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
5047  if (opt->arg == NULL)
5048  switch (opt->val) {
5049  case 'S': /* -separator x */
5050 assert(arg != NULL);
5051  (void) stpncpy(sql->separator, arg, sizeof(sql->separator)-1);
5052  break;
5053  case 'N': /* -nullvalue text */
5054 assert(arg != NULL);
5055  (void) stpncpy(sql->nullvalue, arg, sizeof(sql->nullvalue)-1);
5056  break;
5057  case 'V': /* -version */
5058  printf("%s\n", sqlite3_libversion());
5059  /*@-exitarg@ */ exit(0); /*@=exitarg@ */
5060  /*@notreached@ */ break;
5061  default:
5062  /* XXX fprintf(stderr, ...)? */
5063  rpmsql_error(0, _("%s: Unknown callback(0x%x)\n"),
5064  __FUNCTION__, (unsigned) opt->val);
5065  poptPrintUsage(con, stderr, 0);
5066  /*@-exitarg@ */ exit(2); /*@=exitarg@ */
5067  /*@notreached@ */ break;
5068  }
5069 }
5070 
5071 /*@unchecked@*/ /*@observer@*/
5072 static struct poptOption _rpmsqlOptions[] = {
5073  /*@-type@*//* FIX: cast? */
5074  {NULL, '\0',
5075  POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
5076  rpmsqlArgCallback, 0, NULL, NULL},
5077 /*@=type@*/
5078 
5079  { "debug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH|POPT_ARGFLAG_DOC_HIDDEN, &_rpmsql_debug, -1,
5080  N_("Debug embedded SQL interpreter"), NULL},
5081  { "create", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH|POPT_ARGFLAG_DOC_HIDDEN, &_sql.flags, RPMSQL_FLAGS_CREATE,
5082  N_("create database if not exists"), NULL},
5083 
5084  { "init", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, &_sql.zInitFile, 0,
5085  N_("read/process named FILE"), N_("FILE") },
5086  { "echo", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_ECHO,
5087  N_("print commands before execution"), NULL },
5088 
5089  { "load", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_NOLOAD,
5090  N_("disable extension loading (normally enabled)"), NULL },
5091  { "header", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_SHOWHDR,
5092  N_("turn headers on or off"), NULL },
5093 
5094  { "bail", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_BAIL,
5095  N_("stop after hitting an error"), NULL },
5096 
5097  { "interactive", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_INTERACTIVE,
5098  N_("force interactive I/O"), NULL },
5099  { "batch", '\0', POPT_BIT_CLR|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_INTERACTIVE,
5100  N_("force batch I/O"), NULL },
5101 
5102  { "column", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_COLUMN,
5103  N_("set output mode to 'column'"), NULL },
5104  { "csv", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_CSV,
5105  N_("set output mode to 'csv'"), NULL },
5106  { "html", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_HTML,
5107  N_("set output mode to HTML"), NULL },
5108  { "line", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_LINE,
5109  N_("set output mode to 'line'"), NULL },
5110  { "list", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_LIST,
5111  N_("set output mode to 'list'"), NULL },
5112  { "separator", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, 0, 'S',
5113  N_("set output field separator (|)"), N_("CHAR") },
5114  { "nullvalue", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, 0, 'N',
5115  N_("set text string for NULL values"), N_("TEXT") },
5116 
5117  { "version", '\0', POPT_ARG_NONE|POPT_ARGFLAG_ONEDASH, 0, 'V',
5118  N_("show SQLite version"), NULL},
5119 
5120 #ifdef NOTYET
5121  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
5122  N_("Common options for all rpmio executables:"), NULL},
5123 #endif
5124 
5125  POPT_AUTOHELP
5126  { NULL, (char) -1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
5127  N_("\
5128 Usage: dbsql [OPTIONS] FILENAME [SQL]\n\
5129 FILENAME is the name of an SQLite database. A new database is created\n\
5130 if the file does not previously exist.\n\
5131 \n\
5132 OPTIONS include:\n\
5133  -help show this message\n\
5134  -init filename read/process named file\n\
5135  -echo print commands before execution\n\
5136  -[no]header turn headers on or off\n\
5137  -bail stop after hitting an error\n\
5138  -interactive force interactive I/O\n\
5139  -batch force batch I/O\n\
5140  -column set output mode to 'column'\n\
5141  -csv set output mode to 'csv'\n\
5142  -html set output mode to HTML\n\
5143  -line set output mode to 'line'\n\
5144  -list set output mode to 'list'\n\
5145  -separator 'x' set output field separator (|)\n\
5146  -nullvalue 'text' set text string for NULL values\n\
5147  -version show SQLite version\n\
5148 "), NULL},
5149 
5150  POPT_TABLEEND
5151 };
5152 
5153 #endif /* defined(WITH_SQLITE) */
5154 
5155 /*==============================================================*/
5156 
5160 static void rpmsqlFini(void * _sql)
5161  /*@globals fileSystem @*/
5162  /*@modifies *_sql, fileSystem @*/
5163 {
5164  rpmsql sql = _sql;
5165 
5166 SQLDBG((stderr, "==> %s(%p)\n", __FUNCTION__, sql));
5167 
5168  sql->zDestTable = _free(sql->zDestTable);
5169 
5170  if (sql->ifd)
5171  (void) Fclose(sql->ifd); /* XXX stdin dup'd */
5172  sql->ifd = NULL;
5173  if (sql->ofd)
5174  (void) Fclose(sql->ofd); /* XXX stdout/stderr were dup'd */
5175  sql->ofd = NULL;
5176  if (sql->lfd)
5177  (void) Fclose(sql->lfd);
5178  sql->lfd = NULL;
5179  if (sql->tfd)
5180  (void) Fclose(sql->tfd);
5181  sql->tfd = NULL;
5182 
5183  sql->buf = _free(sql->buf);
5184  sql->buf = sql->b = NULL;
5185  sql->nbuf = sql->nb = 0;
5186 
5187  /* XXX INTERACTIVE cruft. */
5188  sql->zHome = _free(sql->zHome);
5189  sql->zInitrc = _free(sql->zInitrc);
5190  sql->zHistory = _free(sql->zHistory);
5191  sql->zPrompt = _free(sql->zPrompt);
5192  sql->zContinue = _free(sql->zContinue);
5193 
5194  sql->outfile = _free(sql->outfile);
5195 
5196  sql->zDbFilename = _free(sql->zDbFilename);
5197  sql->zInitFile = _free(sql->zInitFile);
5198  sql->av = argvFree(sql->av);
5199 #if defined(WITH_SQLITE)
5200  if (sql->I) {
5201  sqlite3 * db = (sqlite3 *)sql->I;
5202  (void) rpmsqlCmd(sql, "close", db,
5203  sqlite3_close(db));
5204  }
5205 #endif
5206  sql->I = NULL;
5207  (void) rpmiobFree(sql->iob);
5208  sql->iob = NULL;
5209 }
5210 
5211 /*@unchecked@*/ /*@only@*/ /*@null@*/
5213 
5214 static rpmsql rpmsqlGetPool(/*@null@*/ rpmioPool pool)
5215  /*@globals _rpmsqlPool, fileSystem @*/
5216  /*@modifies pool, _rpmsqlPool, fileSystem @*/
5217 {
5218  rpmsql sql;
5219 
5220  if (_rpmsqlPool == NULL) {
5221  _rpmsqlPool = rpmioNewPool("sql", sizeof(*sql), -1, _rpmsql_debug,
5222  NULL, NULL, rpmsqlFini);
5223  pool = _rpmsqlPool;
5224  }
5225  sql = (rpmsql) rpmioGetPool(pool, sizeof(*sql));
5226  memset(((char *)sql)+sizeof(sql->_item), 0, sizeof(*sql)-sizeof(sql->_item));
5227  return sql;
5228 }
5229 
5230 const char ** rpmsqlArgv(rpmsql sql, int * argcp)
5231 {
5232  const char ** av = sql->av;
5233 
5234  if (argcp)
5235  *argcp = argvCount(av);
5236  return av;
5237 }
5238 
5239 #if defined(WITH_SQLITE)
5240 
5244 static void rpmsqlInitPopt(rpmsql sql, int ac, char ** av, poptOption tbl)
5245  /*@modifies sql @*/
5246 {
5247  poptContext con;
5248  int rc;
5249 
5250  if (av == NULL || av[0] == NULL || av[1] == NULL)
5251  goto exit;
5252 
5253  con = poptGetContext(av[0], ac, (const char **)av, tbl, 0);
5254 
5255  /* Process all options into _sql, whine if unknown options. */
5256  while ((rc = poptGetNextOpt(con)) > 0) {
5257  const char * arg = poptGetOptArg(con);
5258  arg = _free(arg);
5259  switch (rc) {
5260  default:
5261  /* XXX fprintf(stderr, ...)? */
5262  rpmsql_error(0, _("%s: option table misconfigured (%d)\n"),
5263  __FUNCTION__, rc);
5264  break;
5265  }
5266  }
5267  /* XXX FIXME: arrange error return iff rc < -1. */
5268 if (rc < -1)
5269 SQLDBG((stderr, "%s: poptGetNextOpt rc(%d): %s\n", __FUNCTION__, rc, poptStrerror(rc)));
5270 
5271  /* Move the POPT parsed values into the current rpmsql object. */
5272  sql->flags = _sql.flags;
5273  sql->mode = _sql.mode;
5274  if (_sql.zInitFile) {
5275  sql->zInitFile = _free(sql->zInitFile);
5276  sql->zInitFile = _sql.zInitFile;
5277  _sql.zInitFile = NULL;
5278  }
5279  memcpy(sql->separator, _sql.separator, sizeof(sql->separator));
5280  memcpy(sql->nullvalue, _sql.nullvalue, sizeof(sql->nullvalue));
5281 
5282  sql->av = argvFree(sql->av);
5283  rc = argvAppend(&sql->av, poptGetArgs(con));
5284 
5285  con = poptFreeContext(con);
5286 
5287 exit:
5288  /* If not overridden, set the separator according to mode. */
5289  if (sql->separator[0] == '\0')
5290  switch (sql->mode) {
5291  default:
5292  case RPMSQL_MODE_LIST: (void)stpcpy(sql->separator, "|"); break;
5293  case RPMSQL_MODE_CSV: (void)stpcpy(sql->separator, ","); break;
5294  }
5295 
5296 SQLDBG((stderr, "<== %s(%p, %p[%u], %p)\n", __FUNCTION__, sql, av, (unsigned)ac, tbl));
5297 }
5298 #endif /* defined(WITH_SQLITE) */
5299 
5300 rpmsql rpmsqlNew(char ** av, uint32_t flags)
5301 {
5302  rpmsql sql =
5303  (flags & 0x80000000) ? rpmsqlI() :
5304  rpmsqlGetPool(_rpmsqlPool);
5305  int ac = argvCount((ARGV_t)av);
5306 
5307 SQLDBG((stderr, "==> %s(%p[%u], 0x%x)\n", __FUNCTION__, av, (unsigned)ac, flags));
5308 if (av && _rpmsql_debug < 0)
5309 argvPrint("av", (ARGV_t)av, NULL);
5310 
5311  sql->flags = flags; /* XXX useful? */
5312 
5313 #if defined(WITH_SQLITE)
5314  /* XXX Avoid initialization on global interpreter creation path. */
5315  if (av) {
5316  static int _oneshot;
5317  sqlite3 * db = NULL;
5318  int xx;
5319 
5320  if (!_oneshot) {
5321 #if defined(SQLITE_CONFIG_LOG)
5322  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, sql);
5323 #endif
5324  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
5325  _oneshot++;
5326  }
5327 
5328  /* Initialize defaults for popt parsing. */
5329  memset(&_sql, 0, sizeof(_sql));
5330  sql->flags = _sql.flags = flags; /* XXX INTERACTIVE defaulted here. */
5331  sql->mode = _sql.mode = RPMSQL_MODE_LIST;
5332 
5333  rpmsqlInitPopt(sql, ac, av, (poptOption) _rpmsqlOptions);
5334 
5335  /* The 1st argument is the database to open (or :memory: default). */
5336  if (sql->av && sql->av[0]) {
5337  sql->zDbFilename = xstrdup(sql->av[0]); /* XXX strdup? */
5338  /* If requested or database already exists, open immediately. */
5339  if (F_ISSET(sql, CREATE) || !Access(sql->zDbFilename, R_OK)) {
5340  xx = rpmsqlCmd(sql, "open", db, /* XXX watchout: arg order */
5341  sqlite3_open(sql->zDbFilename, &db));
5342  sql->I = (void *) db;
5343  }
5344  } else
5345  sql->zDbFilename = xstrdup(":memory:");
5346 
5347  /* Read ~/.sqliterc (if specified), then reparse options. */
5348  if (sql->zInitFile || F_ISSET(sql, INTERACTIVE)) {
5349  sql->ofd = fdDup(STDOUT_FILENO);
5350  xx = rpmsqlInitRC(sql, sql->zInitFile);
5351  if (sql->ofd) (void) Fclose(sql->ofd);
5352  sql->ofd = NULL;
5353  rpmsqlInitPopt(sql, ac, av, (poptOption) _rpmsqlOptions);
5354  }
5355 
5356  }
5357 
5358  { /* XXX INTERACTIVE cruft. */
5359  static const char _zInitrc[] = "/.sqliterc";
5360  static const char _zHistory[] = "/.sqlite_history";
5361  /* XXX getpwuid? */
5362 sql->zHome = _free(sql->zHome);
5363  { char * t = getenv("HOME");
5364  sql->zHome = xstrdup((t ? t : "/"));
5365  }
5366 sql->zInitrc = _free(sql->zInitrc);
5367  sql->zInitrc = rpmGetPath(sql->zHome, _zInitrc, NULL);
5368 sql->zHistory = _free(sql->zHistory);
5369  sql->zHistory = rpmGetPath(sql->zHome, _zHistory, NULL);
5370  /*
5371  ** Prompt strings. Initialized in main. Settable with
5372  ** .prompt main continue
5373  */
5374  /* Initialize the prompt from basename(argv[0]). */
5375  if (sql->zPrompt == NULL) { /* XXX this test is useless */
5376  char * t = xstrdup((av && av[0] ? av[0] : "sql"));
5377  char * bn = basename(t);
5378 sql->zPrompt = _free(sql->zPrompt);
5379  sql->zPrompt = rpmExpand(bn, "> ", NULL);
5380  t = _free(t);
5381 sql->zContinue = _free(sql->zContinue);
5382  sql->zContinue = t = xstrdup(sql->zPrompt);
5383  while (*t && *t != '>')
5384  *t++ = '-';
5385  }
5386  }
5387 #else /* WITH_SQLITE */
5388  if (av)
5389  (void) argvAppend(&sql->av, (ARGV_t) av); /* XXX useful? */
5390 #endif /* WITH_SQLITE */
5391 
5392  /* Set sane defaults for output sink(s) dependent on INTERACTIVE. */
5393  if (F_ISSET(sql, INTERACTIVE)) {
5394  if (sql->ofd == NULL)
5395  sql->ofd = fdDup(STDOUT_FILENO);
5396  } else {
5397  if (sql->iob == NULL)
5398  sql->iob = rpmiobNew(0);
5399  }
5400 
5401  return rpmsqlLink(sql);
5402 }
5403 
5404 rpmRC rpmsqlRun(rpmsql sql, const char * str, const char ** resultp)
5405 {
5406  rpmRC rc = RPMRC_FAIL;
5407 
5408 SQLDBG((stderr, "==> %s(%p,%p[%u]) \"%s\"\n", __FUNCTION__, sql, str, (unsigned)(str ? strlen(str) : 0), str));
5409 SQLDBG((stderr, "==========>\n%s\n<==========\n", str));
5410 
5411  if (sql == NULL) sql = rpmsqlI();
5412 
5413 #if defined(WITH_SQLITE)
5414  if (str != NULL) {
5415  const char * s = str;
5416 
5417  /* Ignore leading whitespace. */
5418  while (*s && xisspace((int)*s))
5419  s++;
5420 
5421  /* Perform the SQL operation(s). */
5422  if (*s == '\0') { /* INTERACTIVE */
5423  static int oneshot;
5424  uint32_t _flags = sql->flags;
5425  FD_t _ofd = sql->ofd;
5426  FD_t _ifd = sql->ifd;
5427 
5428 SQLDBG((stderr, "*** %s: INTERACTIVE\n", __FUNCTION__));
5429  sql->flags |= RPMSQL_FLAGS_INTERACTIVE;
5430  if (sql->ofd == NULL)
5431  sql->ofd = fdDup(STDOUT_FILENO);
5432  if (!oneshot) {
5433 #ifdef REFERENCE
5434  extern char *db_full_version(int *, int *, int *, int *, int *);
5435  fprintf(sql->out, "%s\n"
5436  "Enter \".help\" for instructions\n"
5437  "Enter SQL statements terminated with a \";\"\n",
5438  db_full_version(NULL, NULL, NULL, NULL, NULL));
5439 #endif
5440  size_t nb;
5441  size_t nw;
5442  char * t = rpmExpand(
5443  "SQLite version ", sqlite3_libversion(), "\n",
5444 #if SQLITE_VERSION_NUMBER > 3006015
5445  "\t(", sqlite3_sourceid(), ")\n",
5446 #endif
5447  "Enter \".help\" for instructions\n",
5448  "Enter SQL statements terminated with a \";\"\n", NULL);
5449  nb = strlen(t);
5450  nw = Fwrite(t, 1, nb, sql->ofd);
5451  (void) Fflush(sql->ofd);
5452 assert(nb == nw);
5453  t = _free(t);
5454 #if defined(HAVE_READLINE) && HAVE_READLINE==1
5455  if (sql->zHistory)
5456  read_history(sql->zHistory);
5457 #endif
5458  oneshot++;
5459  }
5460 
5461  sql->ifd = Fdopen(fdDup(fileno(stdin)), "rb.fpio");
5462 assert(sql->ifd);
5463 
5464 sql->flags |= RPMSQL_FLAGS_PROMPT;
5465  rc = rpmsqlInput(sql);
5466 sql->flags &= ~RPMSQL_FLAGS_PROMPT;
5467 
5468  if (sql->ifd) (void) Fclose(sql->ifd);
5469  sql->ifd = _ifd;
5470 
5471  if (sql->zHistory) {
5472  stifle_history(100);
5473  write_history(sql->zHistory);
5474  }
5475  if (_ofd == NULL)
5476  (void) Fclose(sql->ofd);
5477  sql->ofd = _ofd;
5478  sql->flags = _flags;
5479  if (rc != 0) rc = RPMRC_FAIL;
5480  } else
5481  if (!strcmp(s, "-") || !strcmp(s, "stdin")) { /* STDIN */
5482 FD_t _ofd = sql->ofd;
5483 SQLDBG((stderr, "*** %s: STDIN\n", __FUNCTION__));
5484 
5485 if (sql->ofd == NULL) sql->ofd = fdDup(STDOUT_FILENO);
5486 assert(sql->ofd);
5487 
5488 assert(sql->ifd == NULL);
5489  sql->ifd = Fdopen(fdDup(fileno(stdin)), "rb.fpio");
5490 assert(sql->ifd);
5491 
5492  rc = rpmsqlInput(sql);
5493 
5494  if (sql->ifd) (void) Fclose(sql->ifd);
5495  sql->ifd = NULL;
5496 
5497 if (_ofd == NULL) (void) Fclose(sql->ofd);
5498  sql->ofd = _ofd;
5499 
5500  if (rc != 0) rc = RPMRC_FAIL;
5501  } else
5502  if (*s == '/') { /* FILE */
5503  FD_t _ifd = sql->ifd;
5504 SQLDBG((stderr, "*** %s: FILE\n", __FUNCTION__));
5505  sql->ifd = Fopen(s, "rb.fpio");
5506  if (!(sql->ifd == NULL || Ferror(sql->ifd))) {
5507  rc = rpmsqlInput(sql);
5508  }
5509  if (sql->ifd) (void) Fclose(sql->ifd);
5510  sql->ifd = _ifd;
5511  if (rc != 0) rc = RPMRC_FAIL;
5512  } else { /* STRING */
5513 SQLDBG((stderr, "*** %s: STRING\n", __FUNCTION__));
5514  if (*s == '.') {
5515  char * t = xstrdup(s);
5516  rc = rpmsqlMetaCommand(sql, t);
5517  t = _free(t);
5518  } else {
5519  sqlite3 * db;
5520  char * zErrMsg = NULL;
5521  _rpmsqlOpenDB(sql);
5522  db = (sqlite3 *)sql->I;
5523  rc = _rpmsqlShellExec(sql, s, _rpmsqlShellCallback, &zErrMsg);
5524  if (zErrMsg) {
5525  rpmsql_error(1, "%s", zErrMsg);
5526  zErrMsg = _free(zErrMsg);
5527  if (rc == 0) rc = RPMRC_FAIL;
5528  } else if (rc != 0) {
5529  rpmsql_error(1, _("unable to process SQL \"%s\""), s);
5530  rc = RPMRC_FAIL;
5531  }
5532  }
5533  }
5534 
5535  /* Return the SQL output. */
5536  if (sql->iob) {
5537  (void) rpmiobRTrim(sql->iob);
5538 SQLDBG((stderr, "==========>\n%s\n<==========\n", rpmiobStr(sql->iob)));
5539  if (resultp)
5540  *resultp = rpmiobStr(sql->iob); /* XXX strdup? */
5541  }
5542 
5543  }
5544 #endif /* WITH_SQLITE */
5545 
5546 SQLDBG((stderr, "<== %s(%p,%p[%u]) rc %d\n", __FUNCTION__, sql, str, (unsigned)(str ? strlen(str) : 0), rc));
5547 
5548  return rc;
5549 }
rpmiob rpmiobRTrim(rpmiob iob)
Trim trailing white space.
Definition: rpmiob.c:67
int xx
Definition: spec.c:744
int mireSetEOptions(miRE mire, int *offsets, int noffsets)
Initialize pattern execute options (PCRE only).
Definition: mire.c:156
format
Definition: hdrfmt.c:5560
miRE mireNew(rpmMireMode mode, int tag)
Create pattern container.
Definition: mire.c:113
rpmioPool _rpmsqlPool
Definition: rpmsql.c:5212
#define VCDBG(_vc, _l)
Definition: rpmsql.c:579
char * getenv(const char *name)
rpmioPool _rpmvcPool
Definition: rpmsql.c:599
return se
Definition: macro.c:897
int _rpmvt_debug
Definition: rpmsql.c:46
q
Definition: macro.c:451
static PyObject *int type
Definition: rpmmi-py.c:151
static int xtoupper(int c)
Definition: rpmiotypes.h:468
#define EXIT_FAILURE
static int xisalnum(int c)
Definition: rpmiotypes.h:440
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
fwrite(3) clone.
Definition: rpmio.c:2432
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:2831
struct rpmsql_s * rpmsql
Definition: rpmsql.h:20
Definition: db3.c:181
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3371
static char *size_t nb
fgets(3) analogue that reads \ continuations.
Definition: macro.c:409
int Access(const char *path, int amode)
access(2) clone.
Definition: rpmrpc.c:2196
int rc
Definition: poptALL.c:670
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
fts m
Definition: rpmmtree.c:3827
struct rpmvd_s * rpmvd
Definition: rpmsql.h:16
int Fflush(FD_t fd)
fflush(3) clone.
Definition: rpmio.c:2914
char ** environ
rpmsql rpmsqlLink(rpmsql sql)
Reference a sql interpreter instance.
long int value
Definition: rpmds.c:2712
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
static int xisalpha(int c)
Definition: rpmiotypes.h:434
FD_t fdDup(int fdno)
Definition: rpmio.c:264
rpmiob rpmiobAppend(rpmiob iob, const char *s, size_t nl)
Append string to I/O buffer.
Definition: rpmiob.c:77
int ac
Definition: rpmgrep.c:1431
Header h
Definition: spec.c:739
argv
Definition: rpmmtree.c:3679
static rpmsql rpmsqlGetPool(rpmioPool pool)
Definition: rpmsql.c:5214
int rpmiobSlurp(const char *fn, rpmiob *iobp)
Definition: rpmiob.c:129
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:60
#define add_history(X)
Definition: rpmsql.c:35
int flags
ret
Definition: macro.c:387
rpmsql rpmsqlNew(char **av, uint32_t flags)
Create and load a sql interpreter.
Definition: rpmsql.c:5300
int const char * pattern
Definition: fnmatch.c:280
static int xtolower(int c)
Definition: rpmiotypes.h:465
const char * N
Definition: rpmds.c:2714
char * alloca()
enum rpmRC_e rpmRC
RPM return codes.
Definition: signature.c:616
goto exit
Definition: db3.c:1903
memset(_r, 0, sizeof(*_r))
size_t ns
Definition: db3.c:1892
int rpmGlob(const char *patterns, int *argcPtr, const char ***argvPtr)
Return URL path(s) from a (URL prefixed) pattern glob.
Definition: macro.c:2547
miRE mireFree(miRE mire)
Free pattern container.
#define fdGetFILE(_fd)
Definition: rpmio.c:157
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
assert(key->size==sizeof(hdrNum))
int ix
Definition: rpmps-py.c:174
char * p
Definition: macro.c:413
size_t nr
Definition: rpmmtree.c:526
struct rpmvt_s * rpmvt
Definition: rpmsql.h:19
HE_t ec
Definition: hdrfmt.c:6710
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:5160
fprintf(stderr,"--> %s(%p,%p,%p) sig %p sigp %p\n", __FUNCTION__, dig, t, rsactx, sig, sigp)
#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.
const char * g
Definition: macro.c:1697
volatile int _rpmsqlSeenInterrupt
Definition: rpmsql.c:55
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
char * stpncpy(char *dest, const char *src, size_t n)
int Lstat(const char *path, struct stat *st)
lstat(2) clone.
Definition: rpmrpc.c:1401
#define POPT_ARGFLAG_TOGGLE
Definition: poptIO.c:68
#define VTDBGNOISY(_vt, _l)
Definition: rpmsql.c:65
static int xisspace(int c)
Definition: rpmiotypes.h:446
int _rpmvc_debug
Definition: rpmsql.c:49
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
struct miRE_s * miRE
Definition: mire.h:60
uint32_t v
Definition: db3.c:182
int Glob_pattern_p(const char *pattern, int quote)
glob_pattern_p(3) clone.
Definition: rpmrpc.c:2231
The FD_t File Handle data structure.
return k val
Definition: rpmmtree.c:401
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&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3178
#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
static rpmvt rpmvtGetPool(rpmioPool pool)
Definition: rpmsql.c:92
node fd
Definition: rpmfd-py.c:124
rpmsql _rpmsqlI
Definition: rpmsql.c:52
#define F_ISSET(_psm, _FLAG)
Definition: psm.c:49
static void _rpmsqlDebugDump(rpmsql sql, const char *_func, const char *_fn, unsigned _ln)
Definition: rpmsql.c:816
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2532
spectags st
Definition: spec.c:741
int j
Definition: spec.c:743
char * n
Definition: macro.c:744
rpmiob rpmiobNew(size_t len)
Create an I/O buffer.
Definition: rpmiob.c:44
void argvPrint(const char *msg, ARGV_t argv, FILE *fp)
Print argv array elements.
Definition: argv.c:19
static const char *char c
Return text between pl and matching pr characters.
Definition: macro.c:470
fts u
Definition: rpmmtree.c:3828
int bc
Definition: macro.c:412
static void rpmvtFini(void *_VT)
rpmvt pool destructor.
Definition: rpmsql.c:70
int pc
Definition: macro.c:412
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2942
char * rpmiobStr(rpmiob iob)
Return I/O buffer (as string).
Definition: rpmiob.c:112
return strcmp(ame->name, bme->name)
const char * s
Definition: poptALL.c:734
char * t
Definition: rpmds.c:2716
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
struct key_s KEY
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
static int vsnprintf(char *buf, int nb, const char *fmt, va_list ap)
Definition: rpmps.c:212
char * path
Definition: poptALL.c:744
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
char * stpcpy(char *dest, const char *src)
rpmvc rpmvcNew(rpmvt vt, int nrows)
Definition: rpmsql.c:617
if(__progname==NULL)
Definition: poptALL.c:683
te
Definition: macro.c:552
#define write_history(X)
Definition: rpmsql.c:37
FD_t Fdopen(FD_t ofd, const char *fmode)
Definition: rpmio.c:2716
int flags
Definition: fnmatch.c:282
const char * msg
Definition: rpmts-py.c:976
rpmRC rpmsqlRun(rpmsql sql, const char *str, const char **resultp)
Execute sql from STRING | FILE | STDIN | INTERACTIVE.
Definition: rpmsql.c:5404
int argvSplit(ARGV_t *argvp, const char *str, const char *seps)
Split a string into an argv array.
Definition: argv.c:233
static int xisblank(int c)
Definition: rpmiotypes.h:443
return NULL
Definition: poptALL.c:613
int Fileno(FD_t fd)
fileno(3) clone.
Definition: rpmio.c:2989
static void
Print copy of spec file, filling in Group/Description/Summary from specspo.
Definition: spec.c:737
#define read_history(X)
Definition: rpmsql.c:36
k
Definition: rpmmtree.c:394
char * buf
Parse (and execute) macro undefinition.
Definition: macro.c:703
#define _(Text)
Definition: system.h:29
char * b
Definition: macro.c:746
int
Save source and expand field into target.
Definition: rpmds.c:2709
#define xmalloc
Definition: system.h:32
int _rpmsql_debug
Definition: rpmsql.c:43
ARGstr_t * ARGV_t
Definition: argv.h:12
struct poptOption rpmioAllPoptTable[]
Definition: poptIO.c:551
poptContext
Definition: poptALL.c:525
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
int i
Definition: spec.c:743
strncpy(sbuf, f, flen)
void * rpmvArg
Definition: rpmsql.h:14
const char ** av
Definition: rpmts-py.c:788
struct rpmvc_s * rpmvc
Definition: rpmsql.h:18
#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:5230
size_t fn
Definition: macro.c:1698
int len
Definition: rpmdb-py.c:119
goto out
Definition: rpmsq.c:804
#define iseol(_c)
Definition: macro.c:11