rpm 5.3.7
|
00001 #include "system.h" 00002 00003 #include <popt.h> 00004 00005 #define _RPMIOB_INTERNAL /* rpmiobSlurp */ 00006 #include "rpmio_internal.h" /* XXX fdGetFILE */ 00007 #include <rpmmacro.h> 00008 #include <rpmdir.h> 00009 #include <rpmurl.h> 00010 #include <mire.h> 00011 00012 #if defined(WITH_DBSQL) 00013 #include <db51/dbsql.h> 00014 #elif defined(WITH_SQLITE) 00015 #define SQLITE_OS_UNIX 1 00016 #define SQLITE_THREADSAFE 1 00017 #define SQLITE_THREAD_OVERRIDE_LOCK -1 00018 #define SQLITE_TEMP_STORE 1 00019 #include <sqlite3.h> 00020 #endif /* WITH_SQLITE */ 00021 00022 #define _RPMSQL_INTERNAL 00023 #define _RPMVT_INTERNAL 00024 #define _RPMVC_INTERNAL 00025 #include <rpmsql.h> 00026 00027 #ifdef NOTYET /* XXX FIXME */ 00028 #include <editline/readline.h> 00029 #elif defined(HAVE_READLINE) && HAVE_READLINE==1 00030 # include <readline/readline.h> 00031 # include <readline/history.h> 00032 #endif 00033 00034 # define readline(sql, p) local_getline(sql, p) 00035 # define add_history(X) 00036 # define read_history(X) 00037 # define write_history(X) 00038 # define stifle_history(X) 00039 00040 #include "debug.h" 00041 00042 /*@unchecked@*/ 00043 int _rpmsql_debug = 0; 00044 00045 /*@unchecked@*/ 00046 int _rpmvt_debug = 0; 00047 00048 /*@unchecked@*/ 00049 int _rpmvc_debug = 0; 00050 00051 /*@unchecked@*/ /*@relnull@*/ 00052 rpmsql _rpmsqlI = NULL; 00053 00054 /*@unchecked@*/ 00055 volatile int _rpmsqlSeenInterrupt; 00056 00057 #if defined(WITH_SQLITE) 00058 /*@unchecked@*/ 00059 static struct rpmsql_s _sql; 00060 #endif /* defined(WITH_SQLITE) */ 00061 00062 /*==============================================================*/ 00063 00064 #define VTDBG(_vt, _l) if ((_vt)->debug) fprintf _l 00065 #define VTDBGNOISY(_vt, _l) if ((_vt)->debug < 0) fprintf _l 00066 00070 static void rpmvtFini(void * _VT) 00071 /*@globals fileSystem @*/ 00072 /*@modifies *_VT, fileSystem @*/ 00073 { 00074 struct rpmVT_s * VT = _VT; 00075 rpmvt vt = &VT->vt; 00076 00077 00078 VTDBGNOISY(vt, (stderr, "==> %s(%p)\n", __FUNCTION__, vt)); 00079 vt->argv = argvFree(vt->argv); 00080 vt->argc = 0; 00081 vt->fields = argvFree(vt->fields); 00082 vt->nfields = 0; 00083 vt->cols = argvFree(vt->cols); 00084 vt->ncols = 0; 00085 vt->av = argvFree(vt->av); 00086 vt->ac = 0; 00087 } 00088 00089 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00090 rpmioPool _rpmvtPool; 00091 00092 static rpmvt rpmvtGetPool(/*@null@*/ rpmioPool pool) 00093 /*@globals _rpmvtPool, fileSystem @*/ 00094 /*@modifies pool, _rpmvtPool, fileSystem @*/ 00095 { 00096 struct rpmVT_s * VT; 00097 00098 if (_rpmvtPool == NULL) { 00099 _rpmvtPool = rpmioNewPool("vt", sizeof(*VT), -1, _rpmvt_debug, 00100 NULL, NULL, rpmvtFini); 00101 pool = _rpmvtPool; 00102 } 00103 VT = (struct rpmVT_s *) rpmioGetPool(pool, sizeof(*VT)); 00104 memset(((char *)VT)+sizeof(VT->_item), 0, sizeof(*VT)-sizeof(VT->_item)); 00105 return &VT->vt; 00106 } 00107 00108 rpmvt rpmvtNew(void * db, void * pModule, const char *const * argv, rpmvd vd) 00109 { 00110 rpmvt vt = rpmvtLink(rpmvtGetPool(_rpmvtPool)); 00111 00112 vt->db = db; 00113 (void) argvAppend(&vt->argv, (ARGV_t) argv); 00114 vt->argc = argvCount(vt->argv); 00115 if (vd->split && vd->parse && *vd->parse) { 00116 char * parse = rpmExpand(vd->parse, NULL); 00117 int xx; 00118 xx = argvSplit(&vt->fields, parse, vd->split); 00119 assert(xx == 0); 00120 vt->nfields = argvCount(vt->fields); 00121 parse = _free(parse); 00122 } 00123 00124 vt->av = NULL; 00125 vt->ac = 0; 00126 00127 vt->vd = vd; 00128 vt->debug = _rpmvt_debug; 00129 00130 VTDBG(vt, (stderr, "\tdbpath: %s\n", vd->dbpath)); 00131 VTDBG(vt, (stderr, "\tprefix: %s\n", vd->prefix)); 00132 VTDBG(vt, (stderr, "\t split: %s\n", vd->split)); 00133 VTDBG(vt, (stderr, "\t parse: %s\n", vd->parse)); 00134 VTDBG(vt, (stderr, "\t regex: %s\n", vd->regex)); 00135 00136 return vt; 00137 } 00138 00139 /*==============================================================*/ 00140 00141 #if defined(WITH_SQLITE) 00142 00143 typedef struct key_s { 00144 const char * k; 00145 uint32_t v; 00146 } KEY; 00147 static KEY sqlTypes[] = { 00148 { "blob", SQLITE_BLOB }, 00149 { "float", SQLITE_FLOAT }, 00150 { "int", SQLITE_INTEGER }, 00151 { "integer",SQLITE_INTEGER }, 00152 { "null", SQLITE_NULL }, 00153 { "text", SQLITE_TEXT }, 00154 }; 00155 static size_t nsqlTypes = sizeof(sqlTypes) / sizeof(sqlTypes[0]); 00156 00157 static const char * hasSqlType(const char * s) 00158 { 00159 int i; 00160 for (i = 0; i < (int)nsqlTypes; i++) { 00161 const char * k = sqlTypes[i].k; 00162 const char * se = strcasestr(s, k); 00163 if (se == NULL || se <= s || se[-1] != ' ') 00164 continue; 00165 se += strlen(k); 00166 if (*se && *se != ' ') 00167 continue; 00168 return se; 00169 } 00170 return NULL; 00171 } 00172 00173 static char * _rpmvtJoin(const char * a, const char ** argv, const char * z) 00174 { 00175 static const char _type[] = " TEXT"; 00176 const char ** av; 00177 size_t na = (sizeof("\t")-1) + (a ? strlen(a) : 0); 00178 size_t nb = 0; 00179 size_t nz = (z ? strlen(z) : 0) + strlen(_type) + (sizeof(",\n")-1); 00180 char *t, *te; 00181 00182 for (av = argv; *av != NULL; av++) 00183 nb += na + strlen(*av) + nz; 00184 00185 te = t = xmalloc(nb + 1); 00186 for (av = argv; *av != NULL; av++) { 00187 *te++ = '\t'; 00188 te = stpcpy(te, a); 00189 te = stpcpy(te, *av); 00190 if (hasSqlType(*av) == NULL) 00191 te = stpcpy(te, _type); 00192 te = stpcpy(te, z); 00193 *te++ = ','; 00194 *te++ = '\n'; 00195 } 00196 *te = '\0'; 00197 00198 return t; 00199 } 00200 00201 static char * _rpmvtAppendCols(rpmvt vt, const char ** av) 00202 { 00203 char * h = _rpmvtJoin("", av, ""); 00204 int xx = argvAppend(&vt->cols, av); 00205 char * u; 00206 char * hu; 00207 /* XXX permit user column overrides w/o a argv[3] selector. */ 00208 rpmvd vd = vt->vd; 00209 int fx = (vd->fx == 3 ? 3 : 4); 00210 00211 av = (const char **) (vt->argc > fx ? &vt->argv[fx] : vt->fields); 00212 assert(av); 00213 u = _rpmvtJoin("", av, ""); 00214 u[strlen(u)-2] = ' '; /* XXX nuke the final comma */ 00215 xx = argvAppend(&vt->cols, av); 00216 00217 #define dbN vt->argv[1] 00218 #define tblN vt->argv[2] 00219 hu = rpmExpand("CREATE TABLE ", dbN, ".", tblN, " (\n", h, u, ");", NULL); 00220 #undef dbN 00221 #undef tblN 00222 00223 u = _free(u); 00224 h = _free(h); 00225 00226 VTDBG(vt, (stderr, "%s\n", hu)); 00227 return hu; 00228 } 00229 00230 int rpmvtLoadArgv(rpmvt vt, rpmvt * vtp) 00231 { 00232 sqlite3 * db = (sqlite3 *) vt->db; 00233 rpmvd vd = vt->vd; 00234 00235 static const char * hidden[] = { "path HIDDEN", "id HIDDEN", NULL }; 00236 const char * hu; 00237 00238 char * uri = NULL; 00239 struct stat sb; 00240 00241 const char * fn = NULL; 00242 00243 int rc = SQLITE_OK; 00244 int xx; 00245 00246 VTDBG(vt, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, vt, vtp)); 00247 if (vt->debug) 00248 argvPrint("vt->argv", (ARGV_t)vt->argv, NULL); 00249 00250 /* Set the columns in the schema. */ 00251 hu = _rpmvtAppendCols(vt, hidden); 00252 rc = rpmsqlCmd(NULL, "declare_vtab", db, 00253 sqlite3_declare_vtab(db, hu)); 00254 hu = _free(hu); 00255 00256 if (vt->argv[3]) { 00257 /* XXX slice out the quotes that sqlite passes through ... */ 00258 static char _quotes[] = "'\""; 00259 int quoted = (strchr(_quotes, *vt->argv[3]) != NULL); 00260 const char * prefix; 00261 const char * path = NULL; 00262 /* XXX Prefer user override to global prefix (if absolute path). */ 00263 (void) urlPath(vt->argv[3]+quoted, &path); 00264 prefix = (*path != '/' && vd->prefix ? vd->prefix : ""); 00265 uri = rpmGetPath(prefix, path, NULL); 00266 uri[strlen(uri)-quoted] = '\0'; 00267 } else 00268 uri = rpmGetPath(vd->prefix, fn, NULL); 00269 00270 (void) urlPath(uri, (const char **) &fn); 00271 00272 if (!strcasecmp(vt->argv[0], "nixdb")) { 00273 const char * out = rpmExpand("%{sql ", vd->dbpath, ":", 00274 "select path from ValidPaths where glob('", fn, "', path);", 00275 "}", NULL); 00276 (void) argvSplit(&vt->av, out, "\n"); 00277 out = _free(out); 00278 } else 00279 00280 if (!strcasecmp(vt->argv[0], "Env")) { 00281 int fx = 4; /* XXX user column overrides? */ 00282 if (vt->debug) 00283 fprintf(stderr, " ENV: getenv(%p[%d])\n", &vt->argv[fx], argvCount(&vt->argv[fx])); 00284 /* XXX permit glob selector filtering from argv[3]? */ 00285 xx = argvAppend(&vt->av, (ARGV_t)environ); 00286 } else 00287 00288 if (fn[0] == '/') { 00289 if (vt->debug) 00290 fprintf(stderr, "*** uri %s fn %s\n", uri, fn); 00291 if (Glob_pattern_p(uri, 0)) { /* XXX uri */ 00292 const char ** av = NULL; 00293 int ac = 0; 00294 00295 xx = rpmGlob(uri, &ac, &av); /* XXX uri */ 00296 if (vt->debug) 00297 fprintf(stderr, "GLOB: %d = Glob(%s) av %p[%d]\n", xx, uri, av, ac); 00298 if (xx) 00299 rc = SQLITE_NOTFOUND; /* XXX */ 00300 else 00301 xx = argvAppend(&vt->av, (ARGV_t)av); 00302 av = argvFree(av); 00303 } else 00304 if (uri[strlen(uri)-1] == '/') { 00305 DIR * dir = Opendir(uri); 00306 struct dirent * dp; 00307 if (vt->debug) 00308 fprintf(stderr, " DIR: %p = Opendir(%s)\n", dir, uri); 00309 if (dir == NULL) 00310 rc = SQLITE_NOTFOUND; /* XXX */ 00311 else 00312 while ((dp = Readdir(dir)) != NULL) { 00313 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 00314 continue; 00315 fn = rpmGetPath(uri, "/", dp->d_name, NULL); 00316 xx = argvAdd(&vt->av, fn); 00317 fn = _free(fn); 00318 } 00319 if (dir) xx = Closedir(dir); 00320 } else 00321 if (!Lstat(uri, &sb)) { 00322 rpmiob iob = NULL; 00323 xx = rpmiobSlurp(uri, &iob); 00324 if (vt->debug) 00325 fprintf(stderr, "FILE: %d = Slurp(%s)\n", xx, uri); 00326 if (!xx) 00327 xx = argvSplit(&vt->av, rpmiobStr(iob), "\n"); 00328 else 00329 rc = SQLITE_NOTFOUND; /* XXX */ 00330 iob = rpmiobFree(iob); 00331 } else 00332 rc = SQLITE_NOTFOUND; /* XXX */ 00333 } else { 00334 xx = argvAppend(&vt->av, (ARGV_t)&vt->argv[3]); 00335 if (vt->debug) 00336 fprintf(stderr, "LIST: %d = Append(%p[%d])\n", xx, &vt->argv[3], argvCount(&vt->argv[3])); 00337 } 00338 00339 vt->ac = argvCount((ARGV_t)vt->av); 00340 00341 uri = _free(uri); 00342 00343 if (vt->debug) 00344 argvPrint("vt->av", (ARGV_t)vt->av, NULL); 00345 00346 if (vtp) { 00347 if (!rc) 00348 *vtp = (rpmvt) vt; 00349 else { 00350 *vtp = NULL; 00351 (void) rpmvtFree(vt); 00352 vt = NULL; 00353 } 00354 } else { 00355 vt = rpmvtFree(vt); 00356 vt = NULL; 00357 } 00358 00359 VTDBG(vt, (stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, vt, vtp, rc)); 00360 00361 return rc; 00362 } 00363 00364 /*==============================================================*/ 00365 00366 static struct rpmvd_s _argVD = { 00367 }; 00368 00369 int rpmvtCreate(void * _db, void * pAux, 00370 int argc, const char *const * argv, 00371 rpmvt * vtp, char ** pzErr) 00372 { 00373 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_argVD), vtp); 00374 } 00375 00376 int rpmvtConnect(void * _db, void * pAux, 00377 int argc, const char *const * argv, 00378 rpmvt * vtp, char ** pzErr) 00379 { 00380 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_argVD), vtp); 00381 } 00382 00383 #ifdef NOTYET 00384 static void dumpInfo(const char * msg, const struct sqlite3_index_info * s) 00385 { 00386 fprintf(stderr, "--------------------- %s\n", (msg ? msg : "")); 00387 #define _PRT(f,v) fprintf(stderr, "%20s: " #f "\n", #v, s->v) 00388 _PRT(%p, aConstraintUsage); 00389 _PRT(%d, idxNum); 00390 _PRT(%s, idxStr); 00391 _PRT(%d, needToFreeIdxStr); 00392 _PRT(%d, orderByConsumed); 00393 _PRT(%g, estimatedCost); 00394 #undef _PRT 00395 } 00396 #endif 00397 00398 int rpmvtBestIndex(rpmvt vt, void * _pInfo) 00399 { 00400 sqlite3_index_info * pInfo = (sqlite3_index_info *) _pInfo; 00401 int rc = SQLITE_OK; 00402 #ifdef NOTYET 00403 int i; 00404 #endif 00405 00406 VTDBG(vt, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, vt, pInfo)); 00407 00408 #ifdef NOTYET 00409 if (pInfo->aConstraint) 00410 for (i = 0; i < pInfo->nConstraint; i++) { 00411 const struct sqlite3_index_constraint * p = pInfo->aConstraint + i; 00412 fprintf(stderr, "\tcol %s(%d) 0x%02x 0x%02x\n", vt->cols[p->iColumn], p->iColumn, 00413 p->op, p->usable); 00414 } 00415 if (pInfo->aOrderBy) 00416 for (i = 0; i < pInfo->nOrderBy; i++) { 00417 const struct sqlite3_index_orderby * p = pInfo->aOrderBy + i; 00418 fprintf(stderr, "\tcol %s(%d) %s\n", vt->cols[p->iColumn], p->iColumn, 00419 (p->desc ? "DESC" : "ASC")); 00420 } 00421 dumpInfo(__FUNCTION__, pInfo); 00422 #endif 00423 00424 VTDBG(vt, (stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, vt, pInfo, rc)); 00425 00426 return rc; 00427 } 00428 00429 int rpmvtDisconnect(rpmvt vt) 00430 { 00431 (void) rpmvtFree(vt); 00432 return 0; /* SQLITE_OK */ 00433 } 00434 00435 int rpmvtDestroy(rpmvt vt) 00436 { 00437 (void) rpmvtFree(vt); 00438 return 0; /* SQLITE_OK */ 00439 } 00440 00441 static const char * dumpArg(rpmvArg _v) 00442 { 00443 static char buf[BUFSIZ]; 00444 char * b = buf; 00445 size_t nb = sizeof(buf); 00446 sqlite3_value * v = (sqlite3_value *) _v; 00447 int vtype = sqlite3_value_type(v); 00448 unsigned long long ll; 00449 double d; 00450 const void * p; 00451 const char * s; 00452 00453 snprintf(b, nb, "%p(%d)", v, vtype); 00454 nb -= strlen(b); 00455 b += strlen(b); 00456 00457 switch (vtype) { 00458 case SQLITE_INTEGER: 00459 ll = (unsigned long long) sqlite3_value_int64(v); 00460 snprintf(b, nb, " INT %lld", ll); 00461 break; 00462 case SQLITE_FLOAT: 00463 d = sqlite3_value_double(v); 00464 snprintf(b, nb, " REAL %g", d); 00465 break; 00466 case SQLITE_BLOB: 00467 p = sqlite3_value_blob(v); 00468 snprintf(b, nb, " BLOB %p", p); 00469 break; 00470 case SQLITE_NULL: 00471 snprintf(b, nb, " NULL"); 00472 break; 00473 case SQLITE_TEXT: 00474 s = (const char *)sqlite3_value_text(v); 00475 snprintf(b, nb, " TEXT \"%s\"", s); 00476 break; 00477 default: 00478 snprintf(b, nb, " UNKNOWN"); 00479 break; 00480 } 00481 00482 return buf; 00483 } 00484 00485 static void dumpArgv(const char * msg, int argc, rpmvArg * _argv) 00486 { 00487 if (argc > 0 && _argv) { 00488 int i; 00489 fprintf(stderr, "--------------------- %s\n", (msg ? msg : "")); 00490 for (i = 0; i < argc; i++) 00491 fprintf(stderr, "\targv[%d] %s\n", i, dumpArg(_argv[i])); 00492 } 00493 } 00494 00495 int rpmvtUpdate(rpmvt vt, int argc, rpmvArg * _argv, int64_t * pRowid) 00496 { 00497 sqlite3_value ** argv = (sqlite3_value **) _argv; 00498 int rc = SQLITE_OK; 00499 00500 VTDBG(vt, (stderr, "--> %s(%p,%p[%u],%p)\n", __FUNCTION__, vt, argv, (unsigned)argc, pRowid)); 00501 00502 if (argc == 0 || argv == NULL) { 00503 if (vt->debug) 00504 dumpArgv("ERROR", argc, _argv); 00505 rc = SQLITE_NOTFOUND; /* XXX */ 00506 } else 00507 if (argc == 1) { 00508 VTDBG(vt, (stderr, "\tDELETE ROW 0x%llx\n", *(unsigned long long *)argv[0])); 00509 } else 00510 if (argv[0] == NULL) { 00511 VTDBG(vt, (stderr, "\tADD ROW 0x%llx\n", *(unsigned long long *)argv[1])); 00512 if (vt->debug) 00513 dumpArgv("ADD ROW", argc, _argv); 00514 } else 00515 if (argv[0] == argv[1]) { 00516 VTDBG(vt, (stderr, "\tUPDATE ROW 0x%llx\n", *(unsigned long long *)argv[1])); 00517 if (vt->debug) 00518 dumpArgv("UPDATE argv", argc-2, _argv+2); 00519 } else { 00520 VTDBG(vt, (stderr, "\tREPLACE ROW 0x%llx from 0x%llx\n", 00521 *(unsigned long long *)argv[0], *(unsigned long long *)argv[1])); 00522 if (vt->debug) 00523 dumpArgv("REPLACE argv", argc-2, _argv+2); 00524 } 00525 00526 VTDBG(vt, (stderr, "<-- %s(%p,%p[%u],%p) rc %d\n", __FUNCTION__, vt, argv, (unsigned)argc, pRowid, rc)); 00527 return rc; 00528 } 00529 00530 int rpmvtBegin(rpmvt vt) 00531 { 00532 int rc = SQLITE_OK; 00533 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc)); 00534 return rc; 00535 } 00536 00537 int rpmvtSync(rpmvt vt) 00538 { 00539 int rc = SQLITE_OK; 00540 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc)); 00541 return rc; 00542 } 00543 00544 int rpmvtCommit(rpmvt vt) 00545 { 00546 int rc = SQLITE_OK; 00547 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc)); 00548 return rc; 00549 } 00550 00551 int rpmvtRollback(rpmvt vt) 00552 { 00553 int rc = SQLITE_OK; 00554 VTDBG(vt, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vt, rc)); 00555 return rc; 00556 } 00557 00558 int rpmvtFindFunction(rpmvt vt, int nArg, const char * zName, 00559 void (**pxFunc)(void *, int, rpmvArg *), 00560 void ** ppArg) 00561 { 00562 int rc = SQLITE_OK; 00563 VTDBG(vt, (stderr, "<-- %s(%p,%d,%s,%p,%p) rc %d\n", __FUNCTION__, vt, nArg, zName, pxFunc, ppArg, rc)); 00564 return rc; 00565 } 00566 00567 int rpmvtRename(rpmvt vt, const char * zNew) 00568 { 00569 int rc = SQLITE_OK; 00570 VTDBG(vt, (stderr, "<-- %s(%p,%s) rc %d\n", __FUNCTION__, vt, zNew, rc)); 00571 return rc; 00572 } 00573 #endif /* defined(WITH_SQLITE) */ 00574 00575 /*==============================================================*/ 00576 00577 #define VCDBG(_vc, _l) if ((_vc)->debug) fprintf _l 00578 #define VCDBGNOISY(_vc, _l) if ((_vc)->debug < 0) fprintf _l 00579 00583 static void rpmvcFini(void * _VC) 00584 /*@globals fileSystem @*/ 00585 /*@modifies *_VC, fileSystem @*/ 00586 { 00587 struct rpmVC_s * VC = _VC; 00588 rpmvc vc = &VC->vc; 00589 00590 VCDBGNOISY(vc, (stderr, "==> %s(%p)\n", __FUNCTION__, vc)); 00591 if (vc->vt) 00592 (void) rpmvtFree(vc->vt); 00593 vc->vt = NULL; 00594 } 00595 00596 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00597 rpmioPool _rpmvcPool; 00598 00599 static rpmvc rpmvcGetPool(/*@null@*/ rpmioPool pool) 00600 /*@globals _rpmvcPool, fileSystem @*/ 00601 /*@modifies pool, _rpmvcPool, fileSystem @*/ 00602 { 00603 struct rpmVC_s * VC; 00604 00605 if (_rpmvcPool == NULL) { 00606 _rpmvcPool = rpmioNewPool("vc", sizeof(*VC), -1, _rpmvc_debug, 00607 NULL, NULL, rpmvcFini); 00608 pool = _rpmvcPool; 00609 } 00610 VC = (struct rpmVC_s *) rpmioGetPool(pool, sizeof(*VC)); 00611 memset(((char *)VC)+sizeof(VC->_item), 0, sizeof(*VC)-sizeof(VC->_item)); 00612 return &VC->vc; 00613 } 00614 00615 rpmvc rpmvcNew(rpmvt vt, int nrows) 00616 { 00617 rpmvc vc = rpmvcLink(rpmvcGetPool(_rpmvcPool)); 00618 00619 vc->vt = rpmvtLink(vt); 00620 vc->ix = -1; 00621 00622 vc->debug = _rpmvc_debug; 00623 vc->nrows = nrows; 00624 vc->vd = NULL; 00625 00626 return vc; 00627 } 00628 00629 /*==============================================================*/ 00630 00631 #if defined(WITH_SQLITE) 00632 00633 int rpmvcOpen(rpmvt vt, rpmvc * vcp) 00634 { 00635 rpmvc vc = rpmvcNew(vt, vt->ac); 00636 int rc = SQLITE_OK; 00637 00638 if (vcp) 00639 *vcp = vc; 00640 else 00641 (void) rpmvcFree(vc); 00642 00643 return rc; 00644 } 00645 00646 int rpmvcClose(rpmvc vc) 00647 { 00648 /* XXX unnecessary but the debug spewage is confusing. */ 00649 if (vc->vt) 00650 (void) rpmvtFree(vc->vt); 00651 vc->vt = NULL; 00652 (void) rpmvcFree(vc); 00653 return 0; /* SQLITE_OK */ 00654 } 00655 00656 int rpmvcFilter(rpmvc vc, int idxNum, const char * idxStr, 00657 int argc, rpmvArg * _argv) 00658 { 00659 sqlite3_value ** argv = (sqlite3_value **) _argv; 00660 int rc = SQLITE_OK; 00661 00662 VCDBGNOISY(vc, (stderr, "--> %s(%p,%d,%s,%p[%u]) [%d:%d]\n", __FUNCTION__, vc, idxNum, idxStr, argv, (unsigned)argc, vc->ix, vc->nrows)); 00663 dumpArgv(__FUNCTION__, argc, _argv); 00664 00665 if (vc->nrows > 0) 00666 vc->ix = 0; 00667 00668 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)); 00669 00670 return rc; 00671 } 00672 00673 int rpmvcNext(rpmvc vc) 00674 { 00675 int rc = SQLITE_OK; 00676 00677 if (vc->ix >= 0 && vc->ix < vc->nrows) /* XXX needed? */ 00678 vc->ix++; 00679 00680 if (!(vc->ix >= 0 && vc->ix < vc->nrows)) 00681 VCDBGNOISY(vc, (stderr, "<-- %s(%p) rc %d (%d:%d)\n", __FUNCTION__, vc, rc, vc->ix, vc->nrows)); 00682 return rc; 00683 } 00684 00685 int rpmvcEof(rpmvc vc) 00686 { 00687 int rc = (vc->ix >= 0 && vc->ix < vc->nrows ? 0 : 1); 00688 00689 if (rc) 00690 VCDBGNOISY(vc, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, vc, rc)); 00691 return rc; 00692 } 00693 00694 /*==============================================================*/ 00695 00696 int rpmvcColumn(rpmvc vc, void * _pContext, int colx) 00697 { 00698 sqlite3_context * pContext = (sqlite3_context *) _pContext; 00699 rpmvt vt = vc->vt; 00700 rpmvd vd = vt->vd; 00701 const char * path = vt->av[vc->ix]; 00702 const char * col = vt->cols[colx]; 00703 int rc = SQLITE_OK; 00704 00705 size_t nb; 00706 miRE mire = NULL; 00707 int noffsets = 0; 00708 int * offsets = NULL; 00709 int xx; 00710 int i; 00711 00712 /* Use a PCRE pattern for parsing column value. */ 00713 if (vd->regex) { 00714 mire = mireNew(RPMMIRE_REGEX, 0); 00715 xx = mireSetCOptions(mire, RPMMIRE_REGEX, 0, 0, NULL); 00716 xx = mireRegcomp(mire, vd->regex); /* XXX move to rpmvtNew */ 00717 00718 noffsets = 10 * 3; 00719 nb = noffsets * sizeof(*offsets); 00720 offsets = memset(alloca(nb), -1, nb); 00721 xx = mireSetEOptions(mire, offsets, noffsets); 00722 00723 nb = strlen(path); 00724 xx = mireRegexec(mire, path, nb); 00725 assert(xx == 0); 00726 00727 for (i = 0; i < noffsets; i += 2) { 00728 if (offsets[i] < 0) 00729 continue; 00730 assert(offsets[i ] >= 0 && offsets[i ] <= (int)nb); 00731 assert(offsets[i+1] >= 0 && offsets[i+1] <= (int)nb); 00732 offsets[i+1] -= offsets[i]; /* XXX convert offset to length */ 00733 VCDBGNOISY(vc, (stderr, "\t%d [%d,%d] %.*s\n", i/2, offsets[i], offsets[i+1], offsets[i+1], path+offsets[i])); 00734 } 00735 00736 } 00737 00738 if (!strcmp(col, "path")) 00739 sqlite3_result_text(pContext, path, -1, SQLITE_STATIC); 00740 else 00741 if (vd->regex) { 00742 /* Use a PCRE pattern for parsing column value. */ 00743 assert(vt->fields); 00744 for (i = 0; i < vt->nfields; i++) { 00745 /* Slurp file contents for unknown field values. */ 00746 /* XXX procdb/yumdb */ 00747 /* XXX uri's? */ 00748 if (path[0] == '/' && !strcmp("*", vt->fields[i])) { 00749 const char * fn = rpmGetPath(path, "/", col, NULL); 00750 if (!Access(fn, R_OK)) { 00751 rpmiob iob = NULL; 00752 xx = rpmiobSlurp(fn, &iob); 00753 sqlite3_result_text(pContext, rpmiobStr(iob), rpmiobLen(iob), SQLITE_TRANSIENT); 00754 iob = rpmiobFree(iob); 00755 } else 00756 sqlite3_result_null(pContext); 00757 break; 00758 } else 00759 if (!strcmp(col, vt->fields[i])) { 00760 int ix = 2 * (i + 1); 00761 const char * s = path + offsets[ix]; 00762 size_t ns = offsets[ix+1]; /* XXX convert offset to length */ 00763 sqlite3_result_text(pContext, s, ns, SQLITE_STATIC); 00764 break; 00765 } 00766 } 00767 if (i == vt->nfields) 00768 sqlite3_result_null(pContext); 00769 } else 00770 if (vd->split && strlen(vd->split) == 1 && vt->nfields > 0) { 00771 /* Simple argv split on a separator char. */ 00772 /* XXX using argvSplit has extra malloc's, needs SQLITE_TRANSIENT */ 00773 ARGV_t av = NULL; /* XXX move to rpmvcNext for performance */ 00774 xx = argvSplit(&av, path, vd->split); 00775 assert(vt->fields); 00776 for (i = 0; i < vt->nfields; i++) { 00777 if (strcmp(col, vt->fields[i])) 00778 continue; 00779 sqlite3_result_text(pContext, av[i], -1, SQLITE_TRANSIENT); 00780 break; 00781 } 00782 if (i == vt->nfields) 00783 sqlite3_result_null(pContext); 00784 av = argvFree(av); 00785 } else 00786 sqlite3_result_null(pContext); /* XXX unnecessary */ 00787 00788 if (mire) { 00789 xx = mireSetEOptions(mire, NULL, 0); 00790 mire = mireFree(mire); 00791 } 00792 00793 if (rc) 00794 VCDBG(vc, (stderr, "<-- %s(%p,%p,%d) rc %d\n", __FUNCTION__, vc, pContext, colx, rc)); 00795 00796 return rc; 00797 } 00798 00799 int rpmvcRowid(rpmvc vc, int64_t * pRowid) 00800 { 00801 int rc = SQLITE_OK; 00802 00803 if (pRowid) 00804 *pRowid = vc->ix; 00805 00806 if (rc) 00807 VCDBG(vc, (stderr, "<-- %s(%p,%p) rc %d rowid 0x%llx\n", __FUNCTION__, vc, pRowid, rc, (unsigned long long)(pRowid ? *pRowid : 0xf00))); 00808 return rc; 00809 } 00810 #endif /* defined(WITH_SQLITE) */ 00811 00812 /*==============================================================*/ 00813 00814 static void _rpmsqlDebugDump(rpmsql sql, 00815 const char * _func, const char * _fn, unsigned _ln) 00816 { 00817 SQLDBG((stderr, "==> %s:%u %s(%p) _rpmsqlI %p\n", _fn, _ln, _func, sql, _rpmsqlI)); 00818 if (sql) { 00819 fprintf(stderr, "\t flags: 0x%x\n", sql->flags); 00820 fprintf(stderr, "\t av: %p[%u]\n", sql->av, (unsigned)argvCount(sql->av)); 00821 fprintf(stderr, "\t I: %p\n", sql->I); 00822 fprintf(stderr, "\t S: %p\n", sql->S); 00823 fprintf(stderr, "\t init: %s\n", sql->zInitFile); 00824 fprintf(stderr, "\t database: %s\n", sql->zDbFilename); 00825 fprintf(stderr, "\t table: %s\n", sql->zDestTable); 00826 00827 fprintf(stderr, "\t mode: 0x%x\n", sql->mode); 00828 fprintf(stderr, "\t cnt: 0x%x\n", sql->cnt); 00829 fprintf(stderr, "\t iob: %p\n", sql->iob); 00830 fprintf(stderr, "\t IN ifd: %p\n", sql->ifd); 00831 fprintf(stderr, "\t OUT ofd: %p\n", sql->ofd); 00832 fprintf(stderr, "\t LOG lfd: %p\n", sql->lfd); 00833 fprintf(stderr, "\tTRACE tfd: %p\n", sql->tfd); 00834 00835 if (sql->explainPrev.valid) { 00836 fprintf(stderr, "\t explain:\n"); 00837 fprintf(stderr, "\t\t mode: 0x%x\n", sql->explainPrev.mode); 00838 fprintf(stderr, "\t\tflags: 0x%x\n", sql->explainPrev.flags); 00839 } 00840 00841 fprintf(stderr, "\tseparator: %.*s\n", (int)sizeof(sql->separator), sql->separator); 00842 fprintf(stderr, "\tnullvalue: %.*s\n", (int)sizeof(sql->nullvalue), sql->nullvalue); 00843 fprintf(stderr, "\t outfile: %s\n", sql->outfile); 00844 fprintf(stderr, "\t home: %s\n", sql->zHome); 00845 fprintf(stderr, "\t initrc: %s\n", sql->zInitrc); 00846 fprintf(stderr, "\t history: %s\n", sql->zHistory); 00847 fprintf(stderr, "\t prompt: %s\n", sql->zPrompt); 00848 fprintf(stderr, "\t continue: %s\n", sql->zContinue); 00849 00850 fprintf(stderr, "\t buf: %p[%u]\n", sql->buf, (unsigned)sql->nbuf); 00851 fprintf(stderr, "\t b: %p[%u]\n", sql->b, (unsigned)sql->nb); 00852 } 00853 } 00854 #define rpmsqlDebugDump(_sql) \ 00855 _rpmsqlDebugDump(_sql, __FUNCTION__, __FILE__, __LINE__) 00856 00857 #if defined(WITH_SQLITE) 00858 00863 /*@mayexit@*/ /*@printflike@*/ 00864 static void rpmsql_error(int lvl, const char *fmt, ...) 00865 #if defined(__GNUC__) && __GNUC__ >= 2 00866 __attribute__((format (printf, 2, 3))) 00867 #endif 00868 /*@globals fileSystem @*/ 00869 /*@modifies fileSystem @*/; 00870 static void 00871 rpmsql_error(int lvl, const char *fmt, ...) 00872 { 00873 va_list ap; 00874 00875 (void) fflush(NULL); 00876 if (lvl >= 1) 00877 (void) fprintf(stderr, "Error: "); 00878 va_start(ap, fmt); 00879 (void) vfprintf(stderr, fmt, ap); 00880 va_end (ap); 00881 (void) fprintf(stderr, "\n"); 00882 if (lvl > 1) 00883 exit(EXIT_FAILURE); 00884 } 00885 00891 int rpmsqlCmd(/*@null@*/ rpmsql sql, const char * msg, void * _db, int rc) 00892 /*@globals fileSystem @*/ 00893 /*@modifies fileSystem @*/ 00894 { 00895 sqlite3 * db; 00896 00897 switch (rc) { 00898 case SQLITE_OK: 00899 case SQLITE_ROW: 00900 case SQLITE_DONE: 00901 /* XXX ignore noisy debug spewage */ 00902 if (1 || !_rpmsql_debug) 00903 break; 00904 /*@fallthrough@*/ 00905 default: 00906 /* XXX system sqlite3 w loadable modules */ 00907 if (sql) 00908 db = (sqlite3 *) (_db ? _db : sql->I); 00909 else 00910 db = (sqlite3 *) _db; 00911 rpmsql_error(0, "sqlite3_%s(%p): rc(%d) %s", msg, db, rc, 00912 sqlite3_errmsg(db)); 00913 break; 00914 } 00915 return rc; 00916 } 00917 #endif /* defined(WITH_SQLITE) */ 00918 00919 /*==============================================================*/ 00920 00921 #if defined(WITH_SQLITE) 00922 00926 static void _rpmsqlBeginTimer(rpmsql sql) 00927 { 00928 if (sql->enableTimer) 00929 getrusage(RUSAGE_SELF, &sql->sBegin); 00930 } 00931 00932 /* Return the difference of two time_structs in seconds */ 00933 static double timeDiff(struct timeval *pStart, struct timeval *pEnd) 00934 { 00935 return (pEnd->tv_usec - pStart->tv_usec) * 0.000001 + 00936 (double) (pEnd->tv_sec - pStart->tv_sec); 00937 } 00938 00943 static void _rpmsqlEndTimer(rpmsql sql) 00944 { 00945 if (sql->enableTimer) { 00946 struct rusage sEnd; 00947 char b[BUFSIZ]; 00948 size_t nb; 00949 size_t nw; 00950 assert(sql->ofd); 00951 getrusage(RUSAGE_SELF, &sEnd); 00952 snprintf(b, sizeof(b), "CPU Time: user %f sys %f\n", 00953 timeDiff(&sql->sBegin.ru_utime, &sEnd.ru_utime), 00954 timeDiff(&sql->sBegin.ru_stime, &sEnd.ru_stime)); 00955 nb = strlen(b); 00956 nw = Fwrite(b, 1, nb, sql->ofd); 00957 assert(nb == nw); 00958 } 00959 } 00960 00961 #define BEGIN_TIMER(_sql) _rpmsqlBeginTimer(_sql) 00962 #define END_TIMER(_sql) _rpmsqlEndTimer(_sql) 00963 #define HAS_TIMER 1 00964 00965 #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) 00966 #endif /* defined(WITH_SQLITE) */ 00967 00968 /*==============================================================*/ 00969 00974 static rpmsql rpmsqlI(void) 00975 /*@globals _rpmsqlI @*/ 00976 /*@modifies _rpmsqlI @*/ 00977 { 00978 if (_rpmsqlI == NULL) 00979 _rpmsqlI = rpmsqlNew(NULL, 0); 00980 SQLDBG((stderr, "<== %s() _rpmsqlI %p\n", __FUNCTION__, _rpmsqlI)); 00981 return _rpmsqlI; 00982 } 00983 00984 #if defined(WITH_SQLITE) 00985 00989 /*@printflike@*/ 00990 static int rpmsqlFprintf(rpmsql sql, const char *fmt, ...) 00991 #if defined(__GNUC__) && __GNUC__ >= 2 00992 __attribute__((format (printf, 2, 3))) 00993 #endif 00994 /*@*/; 00995 static int rpmsqlFprintf(rpmsql sql, const char *fmt, ...) 00996 { 00997 char b[BUFSIZ]; 00998 size_t nb = sizeof(b); 00999 int rc; 01000 va_list ap; 01001 01002 if (sql == NULL) sql = rpmsqlI(); 01003 assert(sql); 01004 01005 /* Format the output */ 01006 va_start(ap, fmt); 01007 rc = vsnprintf(b, nb, fmt, ap); 01008 va_end(ap); 01009 /* XXX just in case */ 01010 if (!(rc >= 0 && rc < (int)nb)) 01011 rc = nb - 1; 01012 b[rc] = '\0'; 01013 01014 /* Dispose of the output. */ 01015 if (sql->ofd) { 01016 size_t nw = Fwrite(b, 1, rc, sql->ofd); 01017 assert((int)nw == rc); 01018 } 01019 if (sql->iob) 01020 (void) rpmiobAppend(sql->iob, b, 0); 01021 01022 return rc; 01023 } 01024 01031 #ifdef SQLITE_ENABLE_IOTRACE 01032 static void iotracePrintf(const char *zFormat, ...) 01033 { 01034 char * z; 01035 size_t nz; 01036 size_t nw; 01037 va_list ap; 01038 01039 if (_rpmsqlI == NULL || _rpmsqlI->tfd == NULL) 01040 return; 01041 va_start(ap, zFormat); 01042 z = sqlite3_vmprintf(zFormat, ap); 01043 va_end(ap); 01044 nz = strlen(z); 01045 nw = Fwrite(z, 1, nz, sql->tfd); 01046 assert(nz == nw); 01047 sqlite3_free(z); 01048 } 01049 #endif 01050 01051 #if defined(SQLITE_CONFIG_LOG) 01052 01056 static void shellLog(void *_sql, int iErrCode, const char *zMsg) 01057 { 01058 rpmsql sql = (rpmsql) _sql; 01059 if (sql && sql->lfd) { 01060 char num[32]; 01061 int xx = snprintf(num, sizeof(num), "(%d) ", iErrCode); 01062 const char * t = rpmExpand(num, zMsg, "\n", NULL); 01063 size_t nt = strlen(t); 01064 size_t nw = Fwrite(t, 1, nt, sql->lfd); 01065 assert(nt == nw); 01066 xx = Fflush(sql->lfd); 01067 } 01068 } 01069 #endif 01070 01071 /*==============================================================*/ 01077 #ifdef NOTYET /* XXX figger multibyte char's. */ 01078 #define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){} 01079 #define sqliteCharVal(X) sqlite3ReadUtf8(X) 01080 #else 01081 #define sqliteNextChar(X) while( ( *++(X)) ) break 01082 #define sqliteCharVal(X) (int)(*(X)) 01083 #endif 01084 01085 #include <math.h> 01086 01101 #define GEN_MATH_WRAP_DOUBLE_1(name, function, domain) \ 01102 static void name(sqlite3_context *context, int argc, sqlite3_value **argv) {\ 01103 double rVal = 0.0;\ 01104 assert(argc==1);\ 01105 switch (sqlite3_value_type(argv[0])) {\ 01106 case SQLITE_NULL:\ 01107 sqlite3_result_null(context);\ 01108 break;\ 01109 default:\ 01110 rVal = sqlite3_value_double(argv[0]);\ 01111 if (domain)\ 01112 sqlite3_result_error(context, "domain error", -1);\ 01113 else\ 01114 sqlite3_result_double(context, function(rVal));\ 01115 break;\ 01116 }\ 01117 } 01118 01124 GEN_MATH_WRAP_DOUBLE_1(sqrtFunc, sqrt, rVal < 0) 01125 01126 /* trignometric functions */ 01127 GEN_MATH_WRAP_DOUBLE_1(acosFunc, acos, rVal < -1.0 || rVal > 1.0) 01128 GEN_MATH_WRAP_DOUBLE_1(asinFunc, asin, rVal < -1.0 || rVal > 1.0) 01129 GEN_MATH_WRAP_DOUBLE_1(atanFunc, atan, 0) 01130 01136 #ifdef REFERENCE 01137 static double acosh(double x) 01138 { 01139 return log(x + sqrt(x * x - 1.0)); 01140 } 01141 #endif 01142 01143 GEN_MATH_WRAP_DOUBLE_1(acoshFunc, acosh, rVal < 1) 01144 #ifdef REFERENCE 01145 static double asinh(double x) 01146 { 01147 return log(x + sqrt(x * x + 1.0)); 01148 } 01149 #endif 01150 01151 GEN_MATH_WRAP_DOUBLE_1(asinhFunc, asinh, 0) 01152 #ifdef REFERENCE 01153 static double atanh(double x) 01154 { 01155 return (1.0 / 2.0) * log((1 + x) / (1 - x)); 01156 } 01157 #endif 01158 01159 GEN_MATH_WRAP_DOUBLE_1(atanhFunc, atanh, rVal > 1.0 || rVal < -1.0) 01160 01161 01164 static double cot(double x) 01165 { 01166 return 1.0 / tan(x); 01167 } 01168 01169 GEN_MATH_WRAP_DOUBLE_1(sinFunc, sin, 0) 01170 GEN_MATH_WRAP_DOUBLE_1(cosFunc, cos, 0) 01171 GEN_MATH_WRAP_DOUBLE_1(tanFunc, tan, 0) /* XXX DOMAIN */ 01172 GEN_MATH_WRAP_DOUBLE_1(cotFunc, cot, 0) /* XXX DOMAIN */ 01173 01174 static double coth(double x) 01175 { 01176 return 1.0 / tanh(x); 01177 } 01178 01183 #ifdef REFERENCE 01184 static double sinh(double x) 01185 { 01186 return (exp(x) - exp(-x)) / 2.0; 01187 } 01188 #endif 01189 GEN_MATH_WRAP_DOUBLE_1(sinhFunc, sinh, 0) 01190 01191 #ifdef REFERENCE 01192 static double cosh(double x) 01193 { 01194 return (exp(x) + exp(-x)) / 2.0; 01195 } 01196 #endif 01197 GEN_MATH_WRAP_DOUBLE_1(coshFunc, cosh, 0) 01198 01199 #ifdef REFERENCE 01200 static double tanh(double x) 01201 { 01202 return sinh(x) / cosh(x); 01203 } 01204 #endif 01205 GEN_MATH_WRAP_DOUBLE_1(tanhFunc, tanh, 0) 01206 GEN_MATH_WRAP_DOUBLE_1(cothFunc, coth, 0) /* XXX DOMAIN */ 01207 01211 #ifdef REFERENCE 01212 static double log10(double x) 01213 { 01214 static double l10 = -1.0; 01215 if (l10 < 0.0) { 01216 l10 = log(10.0); 01217 } 01218 return log(x) / l10; 01219 } 01220 #endif 01221 GEN_MATH_WRAP_DOUBLE_1(logFunc, log, rVal <= 0.0) 01222 GEN_MATH_WRAP_DOUBLE_1(log10Func, log10, rVal <= 0.0) 01223 GEN_MATH_WRAP_DOUBLE_1(expFunc, exp, 0) 01224 01228 #ifndef M_PI 01229 01233 #define M_PI 3.14159265358979323846 01234 #endif 01235 01239 static double deg2rad(double x) 01240 { 01241 return x * M_PI / 180.0; 01242 } 01243 01247 static double rad2deg(double x) 01248 { 01249 return 180.0 * x / M_PI; 01250 } 01251 GEN_MATH_WRAP_DOUBLE_1(rad2degFunc, rad2deg, 0) 01252 GEN_MATH_WRAP_DOUBLE_1(deg2radFunc, deg2rad, 0) 01253 01257 static void piFunc(sqlite3_context * context, 01258 int argc, sqlite3_value ** argv) 01259 { 01260 sqlite3_result_double(context, M_PI); 01261 } 01262 01268 static void squareFunc(sqlite3_context * context, 01269 int argc, sqlite3_value ** argv) 01270 { 01271 double rVal = 0.0; 01272 int64_t iVal; 01273 01274 assert(argc == 2); 01275 switch (sqlite3_value_type(argv[0])) { 01276 case SQLITE_INTEGER: 01277 iVal = sqlite3_value_int64(argv[0]); 01278 sqlite3_result_int64(context, iVal * iVal); 01279 break; 01280 case SQLITE_NULL: 01281 sqlite3_result_null(context); 01282 break; 01283 default: 01284 rVal = sqlite3_value_double(argv[0]); 01285 sqlite3_result_double(context, rVal * rVal); 01286 break; 01287 } 01288 } 01289 01295 static void powerFunc(sqlite3_context * context, 01296 int argc, sqlite3_value ** argv) 01297 { 01298 double r1 = 0.0; 01299 double r2 = 0.0; 01300 01301 assert(argc == 2); 01302 01303 if (sqlite3_value_type(argv[0]) == SQLITE_NULL 01304 || sqlite3_value_type(argv[1]) == SQLITE_NULL) { 01305 sqlite3_result_null(context); 01306 } else { 01307 r1 = sqlite3_value_double(argv[0]); 01308 r2 = sqlite3_value_double(argv[1]); 01309 if (r1 <= 0.0) { 01310 /* base must be positive */ 01311 sqlite3_result_error(context, "domain error", -1); 01312 } else { 01313 sqlite3_result_double(context, pow(r1, r2)); 01314 } 01315 } 01316 } 01317 01321 static void atn2Func(sqlite3_context * context, 01322 int argc, sqlite3_value ** argv) 01323 { 01324 double r1 = 0.0; 01325 double r2 = 0.0; 01326 01327 assert(argc == 2); 01328 01329 if (sqlite3_value_type(argv[0]) == SQLITE_NULL 01330 || sqlite3_value_type(argv[1]) == SQLITE_NULL) { 01331 sqlite3_result_null(context); 01332 } else { 01333 r1 = sqlite3_value_double(argv[0]); 01334 r2 = sqlite3_value_double(argv[1]); 01335 sqlite3_result_double(context, atan2(r1, r2)); 01336 } 01337 } 01338 01345 static void signFunc(sqlite3_context * context, 01346 int argc, sqlite3_value ** argv) 01347 { 01348 double rVal = 0.0; 01349 int64_t iVal; 01350 01351 assert(argc == 1); 01352 switch (sqlite3_value_type(argv[0])) { 01353 case SQLITE_INTEGER: 01354 iVal = sqlite3_value_int64(argv[0]); 01355 iVal = (iVal > 0) ? 1 : (iVal < 0) ? -1 : 0; 01356 sqlite3_result_int64(context, iVal); 01357 break; 01358 case SQLITE_NULL: 01359 sqlite3_result_null(context); 01360 break; 01361 default: 01362 /* 2nd change below. Line for abs was: if( rVal<0 ) rVal = rVal * -1.0; */ 01363 01364 rVal = sqlite3_value_double(argv[0]); 01365 rVal = (rVal > 0) ? 1 : (rVal < 0) ? -1 : 0; 01366 sqlite3_result_double(context, rVal); 01367 break; 01368 } 01369 } 01370 01374 static void ceilFunc(sqlite3_context * context, 01375 int argc, sqlite3_value ** argv) 01376 { 01377 double rVal = 0.0; 01378 int64_t iVal; 01379 01380 assert(argc == 1); 01381 switch (sqlite3_value_type(argv[0])) { 01382 case SQLITE_INTEGER: 01383 iVal = sqlite3_value_int64(argv[0]); 01384 sqlite3_result_int64(context, iVal); 01385 break; 01386 case SQLITE_NULL: 01387 sqlite3_result_null(context); 01388 break; 01389 default: 01390 rVal = sqlite3_value_double(argv[0]); 01391 sqlite3_result_int64(context, ceil(rVal)); 01392 break; 01393 } 01394 } 01395 01399 static void floorFunc(sqlite3_context * context, 01400 int argc, sqlite3_value ** argv) 01401 { 01402 double rVal = 0.0; 01403 int64_t iVal; 01404 01405 assert(argc == 1); 01406 switch (sqlite3_value_type(argv[0])) { 01407 case SQLITE_INTEGER: 01408 iVal = sqlite3_value_int64(argv[0]); 01409 sqlite3_result_int64(context, iVal); 01410 break; 01411 case SQLITE_NULL: 01412 sqlite3_result_null(context); 01413 break; 01414 default: 01415 rVal = sqlite3_value_double(argv[0]); 01416 sqlite3_result_int64(context, floor(rVal)); 01417 break; 01418 } 01419 } 01420 01425 static void replicateFunc(sqlite3_context * context, 01426 int argc, sqlite3_value ** argv) 01427 { 01428 unsigned char *z; /* input string */ 01429 unsigned char *zo; /* result string */ 01430 int iCount; /* times to repeat */ 01431 size_t nLen; /* length of the input string (no multibyte considerations) */ 01432 size_t nTLen; /* length of the result string (no multibyte considerations) */ 01433 int i = 0; 01434 01435 if (argc != 2 || SQLITE_NULL == sqlite3_value_type(argv[0])) 01436 return; 01437 01438 iCount = sqlite3_value_int64(argv[1]); 01439 01440 if (iCount < 0) { 01441 sqlite3_result_error(context, "domain error", -1); 01442 } else { 01443 nLen = sqlite3_value_bytes(argv[0]); 01444 nTLen = nLen * iCount; 01445 z = xmalloc(nTLen + 1); 01446 zo = xmalloc(nLen + 1); 01447 strcpy((char *) zo, (char *) sqlite3_value_text(argv[0])); 01448 01449 for (i = 0; i < iCount; ++i) 01450 strcpy((char *) (z + i * nLen), (char *) zo); 01451 01452 sqlite3_result_text(context, (char *) z, -1, free); 01453 zo = _free(zo); 01454 } 01455 } 01456 01457 static void properFunc(sqlite3_context * context, 01458 int argc, sqlite3_value ** argv) 01459 { 01460 const unsigned char *z; /* input string */ 01461 unsigned char *zo; /* output string */ 01462 unsigned char *zt; /* iterator */ 01463 char r; 01464 int c = 1; 01465 01466 assert(argc == 1); 01467 if (SQLITE_NULL == sqlite3_value_type(argv[0])) { 01468 sqlite3_result_null(context); 01469 return; 01470 } 01471 01472 z = sqlite3_value_text(argv[0]); 01473 zo = (unsigned char *) xstrdup((const char *)z); 01474 zt = zo; 01475 01476 while ((r = *(z++)) != 0) { 01477 if (xisblank(r)) { 01478 c = 1; 01479 } else { 01480 r = (c == 1) ? xtoupper(r) : xtolower(r); 01481 c = 0; 01482 } 01483 *(zt++) = r; 01484 } 01485 *zt = '\0'; 01486 01487 sqlite3_result_text(context, (char *) zo, -1, free); 01488 } 01489 01490 #ifdef NOTYET /* XXX figger multibyte char's. */ 01491 01497 static void padlFunc(sqlite3_context * context, 01498 int argc, sqlite3_value ** argv) 01499 { 01500 size_t ilen; /* length to pad to */ 01501 size_t zl; /* length of the input string (UTF-8 chars) */ 01502 size_t i; 01503 const char *zi; /* input string */ 01504 char *zo; /* output string */ 01505 char *zt; 01506 01507 assert(argc == 2); 01508 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) { 01509 sqlite3_result_null(context); 01510 } else { 01511 zi = (const char *) sqlite3_value_text(argv[0]); 01512 ilen = sqlite3_value_int64(argv[1]); 01513 /* check domain */ 01514 if (ilen < 0) { 01515 sqlite3_result_error(context, "domain error", -1); 01516 return; 01517 } 01518 zl = sqlite3utf8CharLen(zi, -1); 01519 if (zl >= ilen) { 01520 /* string is longer than the requested pad length, return the same string (dup it) */ 01521 sqlite3_result_text(context, xstrdup(zi), -1, free); 01522 } else { 01523 zo = xmalloc(strlen(zi) + ilen - zl + 1); 01524 zt = zo; 01525 for (i = 1; i + zl <= ilen; ++i) 01526 *(zt++) = ' '; 01527 /* no need to take UTF-8 into consideration here */ 01528 strcpy(zt, zi); 01529 sqlite3_result_text(context, zo, -1, free); 01530 } 01531 } 01532 } 01533 01540 static void padrFunc(sqlite3_context * context, 01541 int argc, sqlite3_value ** argv) 01542 { 01543 size_t ilen; /* length to pad to */ 01544 size_t zl; /* length of the input string (UTF-8 chars) */ 01545 size_t zll; /* length of the input string (bytes) */ 01546 size_t i; 01547 const char *zi; /* input string */ 01548 char *zo; /* output string */ 01549 char *zt; 01550 01551 assert(argc == 2); 01552 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) { 01553 sqlite3_result_null(context); 01554 } else { 01555 int64_t _ilen; 01556 zi = (const char *) sqlite3_value_text(argv[0]); 01557 _ilen = sqlite3_value_int64(argv[1]); 01558 /* check domain */ 01559 if (_ilen < 0) { 01560 sqlite3_result_error(context, "domain error", -1); 01561 return; 01562 } 01563 ilen = _ilen; 01564 zl = sqlite3utf8CharLen(zi, -1); 01565 if (zl >= ilen) { 01566 /* string is longer than the requested pad length, return the same string (dup it) */ 01567 sqlite3_result_text(context, xstrdup(zi), -1, free); 01568 } else { 01569 zll = strlen(zi); 01570 zo = xmalloc(zll + ilen - zl + 1); 01571 zt = strcpy(zo, zi) + zll; 01572 for (i = 1; i + zl <= ilen; ++i) 01573 *(zt++) = ' '; 01574 *zt = '\0'; 01575 sqlite3_result_text(context, zo, -1, free); 01576 } 01577 } 01578 } 01579 01587 static void padcFunc(sqlite3_context * context, 01588 int argc, sqlite3_value ** argv) 01589 { 01590 size_t ilen; /* length to pad to */ 01591 size_t zl; /* length of the input string (UTF-8 chars) */ 01592 size_t zll; /* length of the input string (bytes) */ 01593 size_t i; 01594 const char *zi; /* input string */ 01595 char *zo; /* output string */ 01596 char *zt; 01597 01598 assert(argc == 2); 01599 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) { 01600 sqlite3_result_null(context); 01601 } else { 01602 int64_t _ilen; 01603 zi = (const char *) sqlite3_value_text(argv[0]); 01604 _ilen = sqlite3_value_int64(argv[1]); 01605 /* check domain */ 01606 if (_ilen < 0) { 01607 sqlite3_result_error(context, "domain error", -1); 01608 return; 01609 } 01610 ilen = _ilen; 01611 zl = sqlite3utf8CharLen(zi, -1); 01612 if (zl >= ilen) { 01613 /* string is longer than the requested pad length, return the same string (dup it) */ 01614 sqlite3_result_text(context, xstrdup(zi), -1, free); 01615 } else { 01616 zll = strlen(zi); 01617 zo = xmalloc(zll + ilen - zl + 1); 01618 zt = zo; 01619 for (i = 1; 2 * i + zl <= ilen; ++i) 01620 *(zt++) = ' '; 01621 strcpy(zt, zi); 01622 zt += zll; 01623 for (; i + zl <= ilen; ++i) 01624 *(zt++) = ' '; 01625 *zt = '\0'; 01626 sqlite3_result_text(context, zo, -1, free); 01627 } 01628 } 01629 } 01630 #endif 01631 01636 static void strfilterFunc(sqlite3_context * context, 01637 int argc, sqlite3_value ** argv) 01638 { 01639 const char *zi1; /* first parameter string (searched string) */ 01640 const char *zi2; /* second parameter string (vcontains valid characters) */ 01641 const char *z1; 01642 const char *z21; 01643 const char *z22; 01644 char *zo; /* output string */ 01645 char *zot; 01646 int c1; 01647 int c2; 01648 01649 assert(argc == 2); 01650 01651 if (sqlite3_value_type(argv[0]) == SQLITE_NULL 01652 || sqlite3_value_type(argv[1]) == SQLITE_NULL) { 01653 sqlite3_result_null(context); 01654 } else { 01655 zi1 = (const char *) sqlite3_value_text(argv[0]); 01656 zi2 = (const char *) sqlite3_value_text(argv[1]); 01657 zo = xmalloc(strlen(zi1) + 1); 01658 zot = zo; 01659 z1 = zi1; 01660 while ((c1 = sqliteCharVal(z1)) != 0) { 01661 z21 = zi2; 01662 while ((c2 = sqliteCharVal(z21)) != 0 && c2 != c1) 01663 sqliteNextChar(z21); 01664 if (c2 != 0) { 01665 z22 = z21; 01666 sqliteNextChar(z22); 01667 strncpy(zot, z21, z22 - z21); 01668 zot += z22 - z21; 01669 } 01670 sqliteNextChar(z1); 01671 } 01672 *zot = '\0'; 01673 01674 sqlite3_result_text(context, zo, -1, free); 01675 } 01676 } 01677 01685 static int _substr(const char *z1, const char *z2, int s, const char **p) 01686 { 01687 int c = 0; 01688 int rVal = -1; 01689 const char *zt1; 01690 const char *zt2; 01691 int c1; 01692 int c2; 01693 01694 if (*z1 == '\0') 01695 return -1; 01696 01697 while ((sqliteCharVal(z2) != 0) && (c++) < s) 01698 sqliteNextChar(z2); 01699 01700 c = 0; 01701 while ((sqliteCharVal(z2)) != 0) { 01702 zt1 = z1; 01703 zt2 = z2; 01704 01705 do { 01706 c1 = sqliteCharVal(zt1); 01707 c2 = sqliteCharVal(zt2); 01708 sqliteNextChar(zt1); 01709 sqliteNextChar(zt2); 01710 } while (c1 == c2 && c1 != 0 && c2 != 0); 01711 01712 if (c1 == 0) { 01713 rVal = c; 01714 break; 01715 } 01716 01717 sqliteNextChar(z2); 01718 ++c; 01719 } 01720 if (p) 01721 *p = z2; 01722 return rVal >= 0 ? rVal + s : rVal; 01723 } 01724 01732 static void charindexFunc(sqlite3_context * context, 01733 int argc, sqlite3_value ** argv) 01734 { 01735 const char *z1; /* s1 string */ 01736 const char *z2; /* s2 string */ 01737 int s = 0; 01738 int rVal = 0; 01739 01740 assert(argc == 2 || argc == 3); 01741 if (SQLITE_NULL == sqlite3_value_type(argv[0]) 01742 || SQLITE_NULL == sqlite3_value_type(argv[1])) { 01743 sqlite3_result_null(context); 01744 return; 01745 } 01746 01747 z1 = (const char *) sqlite3_value_text(argv[0]); 01748 z2 = (const char *) sqlite3_value_text(argv[1]); 01749 if (argc == 3) { 01750 s = sqlite3_value_int(argv[2]) - 1; 01751 if (s < 0) 01752 s = 0; 01753 } else { 01754 s = 0; 01755 } 01756 01757 rVal = _substr(z1, z2, s, NULL); 01758 sqlite3_result_int(context, rVal + 1); 01759 } 01760 01765 static void leftFunc(sqlite3_context * context, 01766 int argc, sqlite3_value ** argv) 01767 { 01768 int c = 0; 01769 int cc = 0; 01770 int l = 0; 01771 const unsigned char *z; /* input string */ 01772 const unsigned char *zt; 01773 unsigned char *rz; /* output string */ 01774 01775 assert(argc == 2); 01776 if (SQLITE_NULL == sqlite3_value_type(argv[0]) 01777 || SQLITE_NULL == sqlite3_value_type(argv[1])) { 01778 sqlite3_result_null(context); 01779 return; 01780 } 01781 01782 z = sqlite3_value_text(argv[0]); 01783 l = sqlite3_value_int(argv[1]); 01784 zt = z; 01785 01786 while (sqliteCharVal(zt) && c++ < l) 01787 sqliteNextChar(zt); 01788 01789 cc = zt - z; 01790 01791 rz = xmalloc(zt - z + 1); 01792 strncpy((char *) rz, (char *) z, zt - z); 01793 *(rz + cc) = '\0'; 01794 sqlite3_result_text(context, (char *) rz, -1, free); 01795 } 01796 01801 static void rightFunc(sqlite3_context * context, 01802 int argc, sqlite3_value ** argv) 01803 { 01804 int l = 0; 01805 int c = 0; 01806 int cc = 0; 01807 const char *z; 01808 const char *zt; 01809 const char *ze; 01810 char *rz; 01811 01812 assert(argc == 2); 01813 if (SQLITE_NULL == sqlite3_value_type(argv[0]) 01814 || SQLITE_NULL == sqlite3_value_type(argv[1])) { 01815 sqlite3_result_null(context); 01816 return; 01817 } 01818 01819 z = (const char *) sqlite3_value_text(argv[0]); 01820 l = sqlite3_value_int(argv[1]); 01821 zt = z; 01822 01823 while (sqliteCharVal(zt) != 0) { 01824 sqliteNextChar(zt); 01825 ++c; 01826 } 01827 01828 ze = zt; 01829 zt = z; 01830 01831 cc = c - l; 01832 if (cc < 0) 01833 cc = 0; 01834 01835 while (cc-- > 0) { 01836 sqliteNextChar(zt); 01837 } 01838 01839 rz = xmalloc(ze - zt + 1); 01840 strcpy((char *) rz, (char *) (zt)); 01841 sqlite3_result_text(context, (char *) rz, -1, free); 01842 } 01843 01847 static const char * ltrim(const char *s) 01848 { 01849 while (*s == ' ') 01850 ++s; 01851 return s; 01852 } 01853 01858 static const char * rtrim(char *s) 01859 { 01860 char *ss = s + strlen(s) - 1; 01861 while (ss >= s && *ss == ' ') 01862 --ss; 01863 *(ss + 1) = '\0'; 01864 return s; 01865 } 01866 01870 static void ltrimFunc(sqlite3_context * context, 01871 int argc, sqlite3_value ** argv) 01872 { 01873 const char *z; 01874 01875 assert(argc == 1); 01876 if (SQLITE_NULL == sqlite3_value_type(argv[0])) { 01877 sqlite3_result_null(context); 01878 return; 01879 } 01880 z = (const char *) sqlite3_value_text(argv[0]); 01881 sqlite3_result_text(context, xstrdup(ltrim(z)), -1, free); 01882 } 01883 01887 static void rtrimFunc(sqlite3_context * context, 01888 int argc, sqlite3_value ** argv) 01889 { 01890 const char *z; 01891 01892 assert(argc == 1); 01893 if (SQLITE_NULL == sqlite3_value_type(argv[0])) { 01894 sqlite3_result_null(context); 01895 return; 01896 } 01897 z = (const char *) sqlite3_value_text(argv[0]); 01898 sqlite3_result_text(context, rtrim(xstrdup(z)), -1, free); 01899 } 01900 01904 static void trimFunc(sqlite3_context * context, 01905 int argc, sqlite3_value ** argv) 01906 { 01907 const char *z; 01908 01909 assert(argc == 1); 01910 if (SQLITE_NULL == sqlite3_value_type(argv[0])) { 01911 sqlite3_result_null(context); 01912 return; 01913 } 01914 z = (const char *) sqlite3_value_text(argv[0]); 01915 sqlite3_result_text(context, rtrim(xstrdup(ltrim(z))), -1, free); 01916 } 01917 01924 static void _append(char **s1, int l1, const char *s2, int l2) 01925 { 01926 *s1 = xrealloc(*s1, (l1 + l2 + 1) * sizeof(char)); 01927 strncpy((*s1) + l1, s2, l2); 01928 *(*(s1) + l1 + l2) = '\0'; 01929 } 01930 01934 static void replaceFunc(sqlite3_context * context, 01935 int argc, sqlite3_value ** argv) 01936 { 01937 const char *z1; /* string s (first parameter) */ 01938 const char *z2; /* string s1 (second parameter) string to look for */ 01939 const char *z3; /* string s2 (third parameter) string to replace occurrences of s1 with */ 01940 size_t lz1; 01941 size_t lz2; 01942 size_t lz3; 01943 int lzo = 0; 01944 char *zo = 0; 01945 int ret = 0; 01946 const char *zt1; 01947 const char *zt2; 01948 01949 assert(argc == 3); 01950 if (SQLITE_NULL == sqlite3_value_type(argv[0])) { 01951 sqlite3_result_null(context); 01952 return; 01953 } 01954 01955 z1 = (const char *)sqlite3_value_text(argv[0]); 01956 z2 = (const char *)sqlite3_value_text(argv[1]); 01957 z3 = (const char *)sqlite3_value_text(argv[2]); 01958 /* handle possible null values */ 01959 if (z2 == NULL) 01960 z2 = ""; 01961 if (z3 == NULL) 01962 z3 = ""; 01963 01964 lz1 = strlen(z1); 01965 lz2 = strlen(z2); 01966 lz3 = strlen(z3); 01967 01968 #if 0 01969 /* special case when z2 is empty (or null) nothing will be changed */ 01970 if (0 == lz2) { 01971 sqlite3_result_text(context, xstrdup(z1), -1, free); 01972 return; 01973 } 01974 #endif 01975 01976 zt1 = z1; 01977 zt2 = z1; 01978 01979 while (1) { 01980 ret = _substr(z2, zt1, 0, &zt2); 01981 01982 if (ret < 0) 01983 break; 01984 01985 _append(&zo, lzo, zt1, zt2 - zt1); 01986 lzo += zt2 - zt1; 01987 _append(&zo, lzo, z3, lz3); 01988 lzo += lz3; 01989 01990 zt1 = zt2 + lz2; 01991 } 01992 _append(&zo, lzo, zt1, lz1 - (zt1 - z1)); 01993 sqlite3_result_text(context, zo, -1, free); 01994 } 01995 01999 static void reverseFunc(sqlite3_context * context, 02000 int argc, sqlite3_value ** argv) 02001 { 02002 const char *z; 02003 const char *zt; 02004 char *rz; 02005 char *rzt; 02006 size_t l; 02007 int i; 02008 02009 assert(argc == 1); 02010 if (SQLITE_NULL == sqlite3_value_type(argv[0])) { 02011 sqlite3_result_null(context); 02012 return; 02013 } 02014 z = (const char *)sqlite3_value_text(argv[0]); 02015 l = strlen(z); 02016 rz = xmalloc(l + 1); 02017 rzt = rz + l; 02018 *(rzt--) = '\0'; 02019 02020 zt = z; 02021 while (sqliteCharVal(zt) != 0) { 02022 z = zt; 02023 sqliteNextChar(zt); 02024 for (i = 1; zt - i >= z; ++i) 02025 *(rzt--) = *(zt - i); 02026 } 02027 02028 sqlite3_result_text(context, rz, -1, free); 02029 } 02030 02031 #ifdef NOTYET /* XXX needs the sqlite3 map function */ 02032 02038 typedef struct StdevCtx StdevCtx; 02039 struct StdevCtx { 02040 double rM; 02041 double rS; 02042 int64_t cnt; /* number of elements */ 02043 }; 02044 02053 typedef struct ModeCtx ModeCtx; 02054 struct ModeCtx { 02055 int64_t riM; /* integer value found so far */ 02056 double rdM; /* double value found so far */ 02057 int64_t cnt; /* number of elements so far */ 02058 double pcnt; /* number of elements smaller than a percentile */ 02059 int64_t mcnt; /* maximum number of occurrences (for mode) */ 02060 int64_t mn; /* number of occurrences (for mode and percentiles) */ 02061 int64_t is_double; /* whether the computation is being done for doubles (>0) or integers (=0) */ 02062 map *m; /* map structure used for the computation */ 02063 int done; /* whether the answer has been found */ 02064 }; 02065 02069 static void varianceStep(sqlite3_context * context, 02070 int argc, sqlite3_value ** argv) 02071 { 02072 StdevCtx *p; 02073 double delta; 02074 double x; 02075 02076 assert(argc == 1); 02077 p = sqlite3_aggregate_context(context, sizeof(*p)); 02078 /* only consider non-null values */ 02079 if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) { 02080 p->cnt++; 02081 x = sqlite3_value_double(argv[0]); 02082 delta = (x - p->rM); 02083 p->rM += delta / p->cnt; 02084 p->rS += delta * (x - p->rM); 02085 } 02086 } 02087 02091 static void modeStep(sqlite3_context * context, 02092 int argc, sqlite3_value ** argv) 02093 { 02094 ModeCtx *p; 02095 int64_t xi = 0; 02096 double xd = 0.0; 02097 int64_t *iptr; 02098 double *dptr; 02099 int type; 02100 02101 assert(argc == 1); 02102 type = sqlite3_value_numeric_type(argv[0]); 02103 02104 if (type == SQLITE_NULL) 02105 return; 02106 02107 p = sqlite3_aggregate_context(context, sizeof(*p)); 02108 02109 if (0 == (p->m)) { 02110 p->m = calloc(1, sizeof(map)); 02111 if (type == SQLITE_INTEGER) { 02112 /* map will be used for integers */ 02113 *(p->m) = map_make(int_cmp); 02114 p->is_double = 0; 02115 } else { 02116 p->is_double = 1; 02117 /* map will be used for doubles */ 02118 *(p->m) = map_make(double_cmp); 02119 } 02120 } 02121 02122 ++(p->cnt); 02123 02124 if (0 == p->is_double) { 02125 xi = sqlite3_value_int64(argv[0]); 02126 iptr = (int64_t *) calloc(1, sizeof(int64_t)); 02127 *iptr = xi; 02128 map_insert(p->m, iptr); 02129 } else { 02130 xd = sqlite3_value_double(argv[0]); 02131 dptr = (double *) calloc(1, sizeof(double)); 02132 *dptr = xd; 02133 map_insert(p->m, dptr); 02134 } 02135 } 02136 02141 static void modeIterate(void *e, int64_t c, void *pp) 02142 { 02143 int64_t ei; 02144 double ed; 02145 ModeCtx *p = (ModeCtx *) pp; 02146 02147 if (0 == p->is_double) { 02148 ei = *(int *) (e); 02149 02150 if (p->mcnt == c) { 02151 ++p->mn; 02152 } else if (p->mcnt < c) { 02153 p->riM = ei; 02154 p->mcnt = c; 02155 p->mn = 1; 02156 } 02157 } else { 02158 ed = *(double *) (e); 02159 02160 if (p->mcnt == c) { 02161 ++p->mn; 02162 } else if (p->mcnt < c) { 02163 p->rdM = ed; 02164 p->mcnt = c; 02165 p->mn = 1; 02166 } 02167 } 02168 } 02169 02175 static void medianIterate(void *e, int64_t c, void *pp) 02176 { 02177 int64_t ei; 02178 double ed; 02179 double iL; 02180 double iR; 02181 int il; 02182 int ir; 02183 ModeCtx *p = (ModeCtx *) pp; 02184 02185 if (p->done > 0) 02186 return; 02187 02188 iL = p->pcnt; 02189 iR = p->cnt - p->pcnt; 02190 il = p->mcnt + c; 02191 ir = p->cnt - p->mcnt; 02192 02193 if (il >= iL) { 02194 if (ir >= iR) { 02195 ++p->mn; 02196 if (0 == p->is_double) { 02197 ei = *(int *) (e); 02198 p->riM += ei; 02199 } else { 02200 ed = *(double *) (e); 02201 p->rdM += ed; 02202 } 02203 } else { 02204 p->done = 1; 02205 } 02206 } 02207 p->mcnt += c; 02208 } 02209 02213 static void modeFinalize(sqlite3_context * context) 02214 { 02215 ModeCtx *p = sqlite3_aggregate_context(context, 0); 02216 if (p && p->m) { 02217 map_iterate(p->m, modeIterate, p); 02218 map_destroy(p->m); 02219 free(p->m); 02220 02221 if (1 == p->mn) { 02222 if (0 == p->is_double) 02223 sqlite3_result_int64(context, p->riM); 02224 else 02225 sqlite3_result_double(context, p->rdM); 02226 } 02227 } 02228 } 02229 02233 static void _medianFinalize(sqlite3_context * context) 02234 { 02235 ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0); 02236 if (p && p->m) { 02237 p->done = 0; 02238 map_iterate(p->m, medianIterate, p); 02239 map_destroy(p->m); 02240 free(p->m); 02241 02242 if (0 == p->is_double) 02243 if (1 == p->mn) 02244 sqlite3_result_int64(context, p->riM); 02245 else 02246 sqlite3_result_double(context, p->riM * 1.0 / p->mn); 02247 else 02248 sqlite3_result_double(context, p->rdM / p->mn); 02249 } 02250 } 02251 02255 static void medianFinalize(sqlite3_context * context) 02256 { 02257 ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0); 02258 if (p != NULL) { 02259 p->pcnt = (p->cnt) / 2.0; 02260 _medianFinalize(context); 02261 } 02262 } 02263 02267 static void lower_quartileFinalize(sqlite3_context * context) 02268 { 02269 ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0); 02270 if (p != NULL) { 02271 p->pcnt = (p->cnt) / 4.0; 02272 _medianFinalize(context); 02273 } 02274 } 02275 02279 static void upper_quartileFinalize(sqlite3_context * context) 02280 { 02281 ModeCtx *p = (ModeCtx *) sqlite3_aggregate_context(context, 0); 02282 if (p != NULL) { 02283 p->pcnt = (p->cnt) * 3 / 4.0; 02284 _medianFinalize(context); 02285 } 02286 } 02287 02291 static void stdevFinalize(sqlite3_context * context) 02292 { 02293 StdevCtx *p = sqlite3_aggregate_context(context, 0); 02294 if (p && p->cnt > 1) 02295 sqlite3_result_double(context, sqrt(p->rS / (p->cnt - 1))); 02296 else 02297 sqlite3_result_double(context, 0.0); 02298 } 02299 02303 static void varianceFinalize(sqlite3_context * context) 02304 { 02305 StdevCtx *p = sqlite3_aggregate_context(context, 0); 02306 if (p && p->cnt > 1) 02307 sqlite3_result_double(context, p->rS / (p->cnt - 1)); 02308 else 02309 sqlite3_result_double(context, 0.0); 02310 } 02311 #endif 02312 02316 static void expandFunc(sqlite3_context * context, 02317 int argc, sqlite3_value ** argv) 02318 { 02319 sqlite3_result_text(context, 02320 rpmExpand((const char *)sqlite3_value_text(argv[0]), NULL), -1, free); 02321 } 02322 02326 static void regexpFunc(sqlite3_context* context, 02327 int argc, sqlite3_value** argv) 02328 { 02329 const char * value = (const char *) sqlite3_value_text(argv[0]); 02330 const char * pattern = (const char *) sqlite3_value_text(argv[1]); 02331 miRE mire = mireNew(RPMMIRE_REGEX, 0); 02332 int rc = mireRegcomp(mire, pattern); 02333 02334 rc = mireRegexec(mire, value, strlen(value)); 02335 switch (rc) { 02336 case 0: 02337 case 1: 02338 sqlite3_result_int(context, rc); 02339 break; 02340 default: 02341 sqlite3_result_error(context, "invalid pattern", -1); 02342 break; 02343 } 02344 mire = mireFree(mire); 02345 } 02346 02347 typedef struct rpmsqlCF_s * rpmsqlCF; 02348 struct rpmsqlCF_s { 02349 const char * zName; 02350 int8_t nArg; 02351 uint8_t argType; /* 0: none. 1: db 2: (-1) */ 02352 uint8_t eTextRep; /* SQLITE_UTF8 or SQLITE_UTF16 */ 02353 uint8_t needCollSeq; 02354 void (*xFunc) (sqlite3_context *, int, sqlite3_value **); 02355 void (*xStep) (sqlite3_context *, int, sqlite3_value **); 02356 void (*xFinal) (sqlite3_context *); 02357 }; 02358 02359 static struct rpmsqlCF_s __CF[] = { 02360 /* math.h extensions */ 02361 { "acos", 1, 0, SQLITE_UTF8, 0, acosFunc, NULL, NULL }, 02362 { "asin", 1, 0, SQLITE_UTF8, 0, asinFunc, NULL, NULL }, 02363 { "atan", 1, 0, SQLITE_UTF8, 0, atanFunc, NULL, NULL }, 02364 { "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func, NULL, NULL }, 02365 /* XXX alias */ 02366 { "atan2", 2, 0, SQLITE_UTF8, 0, atn2Func, NULL, NULL }, 02367 { "acosh", 1, 0, SQLITE_UTF8, 0, acoshFunc, NULL, NULL }, 02368 { "asinh", 1, 0, SQLITE_UTF8, 0, asinhFunc, NULL, NULL }, 02369 { "atanh", 1, 0, SQLITE_UTF8, 0, atanhFunc, NULL, NULL }, 02370 02371 #ifdef NOTYET 02372 { "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc, NULL, NULL }, 02373 #endif 02374 { "degrees", 1, 0, SQLITE_UTF8, 0, rad2degFunc, NULL, NULL }, 02375 { "radians", 1, 0, SQLITE_UTF8, 0, deg2radFunc, NULL, NULL }, 02376 02377 { "cos", 1, 0, SQLITE_UTF8, 0, cosFunc, NULL, NULL }, 02378 { "sin", 1, 0, SQLITE_UTF8, 0, sinFunc, NULL, NULL }, 02379 { "tan", 1, 0, SQLITE_UTF8, 0, tanFunc, NULL, NULL }, 02380 { "cot", 1, 0, SQLITE_UTF8, 0, cotFunc, NULL, NULL }, 02381 { "cosh", 1, 0, SQLITE_UTF8, 0, coshFunc, NULL, NULL }, 02382 { "sinh", 1, 0, SQLITE_UTF8, 0, sinhFunc, NULL, NULL }, 02383 { "tanh", 1, 0, SQLITE_UTF8, 0, tanhFunc, NULL, NULL }, 02384 { "coth", 1, 0, SQLITE_UTF8, 0, cothFunc, NULL, NULL }, 02385 02386 { "exp", 1, 0, SQLITE_UTF8, 0, expFunc, NULL, NULL }, 02387 { "log", 1, 0, SQLITE_UTF8, 0, logFunc, NULL, NULL }, 02388 { "log10", 1, 0, SQLITE_UTF8, 0, log10Func, NULL, NULL }, 02389 { "power", 2, 0, SQLITE_UTF8, 0, powerFunc, NULL, NULL }, 02390 { "sign", 1, 0, SQLITE_UTF8, 0, signFunc, NULL, NULL }, 02391 { "sqrt", 1, 0, SQLITE_UTF8, 0, sqrtFunc, NULL, NULL }, 02392 { "square", 1, 0, SQLITE_UTF8, 0, squareFunc, NULL, NULL }, 02393 02394 { "ceil", 1, 0, SQLITE_UTF8, 0, ceilFunc, NULL, NULL }, 02395 { "floor", 1, 0, SQLITE_UTF8, 0, floorFunc, NULL, NULL }, 02396 02397 { "pi", 0, 0, SQLITE_UTF8, 1, piFunc, NULL, NULL }, 02398 02399 /* string extensions */ 02400 { "replicate", 2, 0, SQLITE_UTF8, 0, replicateFunc, NULL, NULL }, 02401 { "charindex", 2, 0, SQLITE_UTF8, 0, charindexFunc, NULL, NULL }, 02402 { "charindex", 3, 0, SQLITE_UTF8, 0, charindexFunc, NULL, NULL }, 02403 { "leftstr", 2, 0, SQLITE_UTF8, 0, leftFunc, NULL, NULL }, 02404 { "rightstr", 2, 0, SQLITE_UTF8, 0, rightFunc, NULL, NULL }, 02405 { "ltrim", 1, 0, SQLITE_UTF8, 0, ltrimFunc, NULL, NULL }, 02406 { "rtrim", 1, 0, SQLITE_UTF8, 0, rtrimFunc, NULL, NULL }, 02407 { "trim", 1, 0, SQLITE_UTF8, 0, trimFunc, NULL, NULL }, 02408 { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc, NULL, NULL }, 02409 { "reverse", 1, 0, SQLITE_UTF8, 0, reverseFunc, NULL, NULL }, 02410 { "proper", 1, 0, SQLITE_UTF8, 0, properFunc, NULL, NULL }, 02411 #ifdef NOTYET /* XXX figger multibyte char's. */ 02412 { "padl", 2, 0, SQLITE_UTF8, 0, padlFunc, NULL, NULL }, 02413 { "padr", 2, 0, SQLITE_UTF8, 0, padrFunc, NULL, NULL }, 02414 { "padc", 2, 0, SQLITE_UTF8, 0, padcFunc, NULL, NULL }, 02415 #endif 02416 { "strfilter", 2, 0, SQLITE_UTF8, 0, strfilterFunc, NULL, NULL }, 02417 02418 /* statistical aggregate extensions */ 02419 #ifdef NOTYET /* XXX needs the sqlite3 map function */ 02420 { "stdev", 1, 0, SQLITE_UTF8, 0, NULL, varianceStep, stdevFinalize }, 02421 { "variance", 1, 0, SQLITE_UTF8, 0, NULL, varianceStep, varianceFinalize }, 02422 { "mode", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, modeFinalize }, 02423 { "median", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, medianFinalize }, 02424 { "lower_quartile", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, lower_quartileFinalize }, 02425 { "upper_quartile", 1, 0, SQLITE_UTF8, 0, NULL, modeStep, upper_quartileFinalize }, 02426 #endif 02427 02428 /* RPM extensions. */ 02429 { "expand", 1, 0, SQLITE_UTF8, 0, expandFunc, NULL, NULL }, 02430 { "regexp", 2, 0, SQLITE_UTF8, 0, regexpFunc, NULL, NULL }, 02431 { NULL, 0, 0, 0, 0, NULL, NULL, NULL } 02432 }; 02433 static rpmsqlCF _CF = __CF; 02434 02439 static int _rpmsqlLoadCF(rpmsql sql) 02440 { 02441 sqlite3 * db = (sqlite3 *)sql->I; 02442 rpmsqlCF CF; 02443 int rc = 0; 02444 02445 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, sql)); 02446 for (CF = _CF; CF->zName != NULL; CF++) { 02447 void * _pApp = NULL; 02448 int xx; 02449 02450 switch (CF->argType) { 02451 default: 02452 case 0: _pApp = NULL; break; 02453 case 1: _pApp = (void *)db; break; 02454 case 2: _pApp = (void *)-1; break; 02455 } 02456 02457 xx = rpmsqlCmd(sql, "create_function", db, 02458 sqlite3_create_function(db, CF->zName, CF->nArg, CF->eTextRep, 02459 _pApp, CF->xFunc, CF->xStep, CF->xFinal)); 02460 SQLDBG((stderr, "\t%s(%s) xx %d\n", "sqlite3_create_function", CF->zName, xx)); 02461 if (xx && rc == 0) 02462 rc = xx; 02463 02464 #ifdef NOTYET 02465 if (CF->needColSeq) { 02466 FuncDef *pFunc = sqlite3FindFunction(db, CF->zName, 02467 strlen(CF_>zName), CF->nArg, CF->eTextRep, 0); 02468 if (pFunc) pFunc->needCollSeq = 1; 02469 } 02470 #endif 02471 02472 } 02473 SQLDBG((stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, sql, rc)); 02474 return rc; 02475 } 02476 02477 /*==============================================================*/ 02478 02479 static struct rpmvd_s _envVD = { 02480 .split = "=", 02481 .parse = "key=val", 02482 .regex = "^([^=]+)=(.*)$", 02483 .idx = 1, 02484 }; 02485 02486 static int envCreateConnect(void * _db, void * pAux, 02487 int argc, const char *const * argv, 02488 rpmvt * vtp, char ** pzErr) 02489 { 02490 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_envVD), vtp); 02491 } 02492 02493 struct sqlite3_module envModule = { 02494 .xCreate = (void *) envCreateConnect, 02495 .xConnect = (void *) envCreateConnect, 02496 }; 02497 02498 /*==============================================================*/ 02499 02500 static struct rpmvd_s _grdbVD = { 02501 .prefix = "%{?_etc_group}%{!?_etc_group:/etc/group}", 02502 .split = ":", 02503 /* XXX "group" is a reserved keyword. */ 02504 .parse = "_group:passwd:gid:groups", 02505 .regex = "^([^:]*):([^:]*):([^:]*):([^:]*)$", 02506 .idx = 3, 02507 }; 02508 02509 static int grdbCreateConnect(void * _db, void * pAux, 02510 int argc, const char *const * argv, 02511 rpmvt * vtp, char ** pzErr) 02512 { 02513 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_grdbVD), vtp); 02514 } 02515 02516 struct sqlite3_module grdbModule = { 02517 .xCreate = (void *) grdbCreateConnect, 02518 .xConnect = (void *) grdbCreateConnect, 02519 }; 02520 02521 /*==============================================================*/ 02522 02523 static struct rpmvd_s _procdbVD = { 02524 .prefix = "%{?_procdb}%{!?_procdb:/proc/[0-9]}", 02525 .split = "/-", 02526 .parse = "dir/pid/*", 02527 .regex = "^(.+/)([0-9]+)$", 02528 .idx = 2, 02529 }; 02530 02531 static int procdbCreateConnect(void * _db, void * pAux, 02532 int argc, const char *const * argv, 02533 rpmvt * vtp, char ** pzErr) 02534 { 02535 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_procdbVD), vtp); 02536 } 02537 02538 struct sqlite3_module procdbModule = { 02539 .xCreate = (void *) procdbCreateConnect, 02540 .xConnect = (void *) procdbCreateConnect, 02541 }; 02542 02543 /*==============================================================*/ 02544 02545 static struct rpmvd_s _pwdbVD = { 02546 .prefix = "%{?_etc_passwd}%{!?_etc_passwd:/etc/passwd}", 02547 .split = ":", 02548 .parse = "user:passwd:uid:gid:gecos:dir:shell", 02549 .regex = "^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)$", 02550 .idx = 3, 02551 }; 02552 02553 static int pwdbCreateConnect(void * _db, void * pAux, 02554 int argc, const char *const * argv, 02555 rpmvt * vtp, char ** pzErr) 02556 { 02557 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_pwdbVD), vtp); 02558 } 02559 02560 struct sqlite3_module pwdbModule = { 02561 .xCreate = (void *) pwdbCreateConnect, 02562 .xConnect = (void *) pwdbCreateConnect, 02563 }; 02564 02565 /*==============================================================*/ 02566 02567 static struct rpmvd_s _repodbVD = { 02568 /* XXX where to map the default? */ 02569 .prefix = "%{?_repodb}%{!?_repodb:/X/popt/}", 02570 .split = "/-.", 02571 .parse = "dir/file-NVRA-N-V-R.A", 02572 .regex = "^(.+/)(((.*)-([^-]+)-([^-]+)\\.([^.]+))\\.rpm)$", 02573 .idx = 2, 02574 }; 02575 02576 static int repodbCreateConnect(void * _db, void * pAux, 02577 int argc, const char *const * argv, 02578 rpmvt * vtp, char ** pzErr) 02579 { 02580 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_repodbVD), vtp); 02581 } 02582 02583 struct sqlite3_module repodbModule = { 02584 .xCreate = (void *) repodbCreateConnect, 02585 .xConnect = (void *) repodbCreateConnect, 02586 }; 02587 02588 /*==============================================================*/ 02589 02590 static int _stat_debug = 0; 02591 02592 static struct rpmvd_s _statVD = { 02593 .split = " ,", 02594 .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", 02595 }; 02596 02597 static int statCreateConnect(void * _db, void * pAux, 02598 int argc, const char *const * argv, 02599 rpmvt * vtp, char ** pzErr) 02600 { 02601 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_statVD), vtp); 02602 } 02603 02604 static int statColumn(rpmvc vc, void * _pContext, int colx) 02605 { 02606 sqlite3_context * pContext = (sqlite3_context *) _pContext; 02607 rpmvt vt = vc->vt; 02608 const char * path = vt->av[vc->ix]; 02609 const char * col = vt->cols[colx]; 02610 struct stat sb, *st = &sb; /* XXX move to rpmvcNext for performance */ 02611 int ret = Lstat(path, &sb); 02612 int rc = SQLITE_OK; 02613 02614 if (_stat_debug < 0) 02615 fprintf(stderr, "--> %s(%p,%p,%d)\n", __FUNCTION__, vc, pContext, colx); 02616 02617 02618 if (!strcmp(col, "path")) 02619 sqlite3_result_text(pContext, path, -1, SQLITE_STATIC); 02620 else if (!strcmp(col, "st_dev") && !ret) 02621 sqlite3_result_int64(pContext, st->st_dev); 02622 else if (!strcmp(col, "st_ino") && !ret) 02623 sqlite3_result_int64(pContext, st->st_ino); 02624 else if (!strcmp(col, "st_mode") && !ret) 02625 sqlite3_result_int64(pContext, st->st_mode); 02626 else if (!strcmp(col, "st_nlink") && !ret) 02627 sqlite3_result_int64(pContext, st->st_nlink); 02628 else if (!strcmp(col, "st_uid") && !ret) 02629 sqlite3_result_int64(pContext, st->st_uid); 02630 else if (!strcmp(col, "st_gid") && !ret) 02631 sqlite3_result_int64(pContext, st->st_gid); 02632 else if (!strcmp(col, "st_rdev") && !ret) 02633 sqlite3_result_int64(pContext, st->st_rdev); 02634 else if (!strcmp(col, "st_size") && !ret) 02635 sqlite3_result_int64(pContext, st->st_size); 02636 else if (!strcmp(col, "st_blksize") && !ret) 02637 sqlite3_result_int64(pContext, st->st_blksize); 02638 else if (!strcmp(col, "st_blocks") && !ret) 02639 sqlite3_result_int64(pContext, st->st_blocks); 02640 else if (!strcmp(col, "st_atime") && !ret) 02641 sqlite3_result_int64(pContext, st->st_atime); 02642 else if (!strcmp(col, "st_mtime") && !ret) 02643 sqlite3_result_int64(pContext, st->st_mtime); 02644 else if (!strcmp(col, "st_ctime") && !ret) 02645 sqlite3_result_int64(pContext, st->st_ctime); 02646 /* XXX pick up *BSD derangements */ 02647 else 02648 sqlite3_result_null(pContext); 02649 02650 if (_stat_debug < 0) 02651 fprintf(stderr, "<-- %s(%p,%p,%d) rc %d\n", __FUNCTION__, vc, pContext, colx, rc); 02652 02653 return rc; 02654 } 02655 02656 struct sqlite3_module statModule = { 02657 .xCreate = (void *) statCreateConnect, 02658 .xConnect = (void *) statCreateConnect, 02659 .xColumn = (void *) statColumn, 02660 }; 02661 02662 /*==============================================================*/ 02663 02664 static struct rpmvd_s _yumdbVD = { 02665 .prefix = "%{?_yumdb}%{!?_yumdb:/var/lib/yum/yumdb}/", 02666 .split = "/-", 02667 .parse = "dir/hash-NVRA-N-V-R-A/*", 02668 .regex = "^(.+/)([^-]+)-((.*)-([^-]+)-([^-]+)-([^-]+))$", 02669 .idx = 2, 02670 }; 02671 02672 static int yumdbCreateConnect(void * _db, void * pAux, 02673 int argc, const char *const * argv, 02674 rpmvt * vtp, char ** pzErr) 02675 { 02676 return rpmvtLoadArgv(rpmvtNew(_db, pAux, argv, &_yumdbVD), vtp); 02677 } 02678 02679 struct sqlite3_module yumdbModule = { 02680 .xCreate = (void *) yumdbCreateConnect, 02681 .xConnect = (void *) yumdbCreateConnect, 02682 }; 02683 02684 /*==============================================================*/ 02685 02686 struct sqlite3_module _rpmvmTemplate = { 02687 .xCreate = (void *) rpmvtCreate, 02688 .xConnect = (void *) rpmvtConnect, 02689 .xBestIndex = (void *) rpmvtBestIndex, 02690 .xDisconnect = (void *) rpmvtDisconnect, 02691 .xDestroy = (void *) rpmvtDestroy, 02692 .xOpen = (void *) rpmvcOpen, 02693 .xClose = (void *) rpmvcClose, 02694 .xFilter = (void *) rpmvcFilter, 02695 .xNext = (void *) rpmvcNext, 02696 .xEof = (void *) rpmvcEof, 02697 .xColumn = (void *) rpmvcColumn, 02698 .xRowid = (void *) rpmvcRowid, 02699 .xUpdate = (void *) rpmvtUpdate, 02700 .xBegin = (void *) rpmvtBegin, 02701 .xSync = (void *) rpmvtSync, 02702 .xCommit = (void *) rpmvtCommit, 02703 .xRollback = (void *) rpmvtRollback, 02704 .xFindFunction = (void *) rpmvtFindFunction, 02705 .xRename = (void *) rpmvtRename 02706 }; 02707 02708 static struct rpmsqlVMT_s __VMT[] = { 02709 { "Argv", NULL, NULL }, 02710 { "Env", &envModule, NULL }, 02711 { "Grdb", &grdbModule, NULL }, 02712 { "Procdb", &procdbModule, NULL }, 02713 { "Pwdb", &pwdbModule, NULL }, 02714 { "Repodb", &repodbModule, NULL }, 02715 { "Stat", &statModule, NULL }, 02716 { "Yumdb", &yumdbModule, NULL }, 02717 { NULL, NULL, NULL } 02718 }; 02719 02720 static void rpmsqlVMFree(void * _VM) 02721 /*@*/ 02722 { 02723 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, _VM)); 02724 if (_VM) 02725 free(_VM); 02726 } 02727 02728 #ifdef UNUSED 02729 static void dumpVM(const char * msg, const rpmsqlVM s) 02730 { 02731 fprintf(stderr, "--------------------- %s\n", (msg ? msg : "")); 02732 #define VMPRT(f) if (s->f) fprintf(stderr, "%20s: %p\n", #f, s->f) 02733 VMPRT(xCreate); 02734 VMPRT(xConnect); 02735 VMPRT(xBestIndex); 02736 VMPRT(xDisconnect); 02737 VMPRT(xDestroy); 02738 VMPRT(xOpen); 02739 VMPRT(xClose); 02740 VMPRT(xFilter); 02741 VMPRT(xNext); 02742 VMPRT(xEof); 02743 VMPRT(xColumn); 02744 VMPRT(xRowid); 02745 VMPRT(xUpdate); 02746 VMPRT(xBegin); 02747 VMPRT(xSync); 02748 VMPRT(xCommit); 02749 VMPRT(xRollback); 02750 VMPRT(xFindFunction); 02751 VMPRT(xRename); 02752 #undef VMPRT 02753 } 02754 #endif 02755 02756 static /*@only@*/ rpmsqlVM rpmsqlVMNew(/*@null@*/ const rpmsqlVM s) 02757 { 02758 rpmsqlVM t = xcalloc(1, sizeof(*t)); 02759 02760 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, s)); 02761 *t = _rpmvmTemplate; /* structure assignment */ 02762 02763 if (s) { 02764 if (s->iVersion) t->iVersion = s->iVersion; 02765 #define VMCPY(f) if (s->f) t->f = ((s->f != (void *)-1) ? s->f : NULL) 02766 VMCPY(xCreate); 02767 VMCPY(xConnect); 02768 VMCPY(xBestIndex); 02769 VMCPY(xDisconnect); 02770 VMCPY(xDestroy); 02771 VMCPY(xOpen); 02772 VMCPY(xClose); 02773 VMCPY(xFilter); 02774 VMCPY(xNext); 02775 VMCPY(xEof); 02776 VMCPY(xColumn); 02777 VMCPY(xRowid); 02778 VMCPY(xUpdate); 02779 VMCPY(xBegin); 02780 VMCPY(xSync); 02781 VMCPY(xCommit); 02782 VMCPY(xRollback); 02783 VMCPY(xFindFunction); 02784 VMCPY(xRename); 02785 #undef VMCPY 02786 } 02787 SQLDBG((stderr, "<-- %s(%p) %p\n", __FUNCTION__, s, t)); 02788 return t; 02789 } 02790 02791 int _rpmsqlLoadVMT(void * _db, const rpmsqlVMT _VMT) 02792 { 02793 sqlite3 * db = (sqlite3 *) _db; 02794 rpmsqlVMT VMT; 02795 int rc = 0; 02796 02797 SQLDBG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, _db, _VMT)); 02798 for (VMT = (rpmsqlVMT)_VMT; VMT->zName != NULL; VMT++) { 02799 int xx; 02800 02801 xx = rpmsqlCmd(_rpmsqlI, "create_module_v2", db, 02802 sqlite3_create_module_v2(db, VMT->zName, 02803 rpmsqlVMNew(VMT->module), VMT->data, rpmsqlVMFree)); 02804 SQLDBG((stderr, "\t%s(%s) xx %d\n", "sqlite3_create_module_v2", VMT->zName, xx)); 02805 if (xx && rc == 0) 02806 rc = xx; 02807 02808 } 02809 SQLDBG((stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, _db, _VMT, rc)); 02810 return rc; 02811 } 02812 02813 /*==============================================================*/ 02814 /* XXX HACK: AWOL in -lsqlite3 on CM14 */ 02815 #if SQLITE_VERSION_NUMBER <= 3006015 02816 #define sqlite3_enable_load_extension(db, onoff) SQLITE_OK 02817 #define sqlite3_load_extension(db, zFile, zProc, pzErrMsg) SQLITE_OK 02818 #endif 02819 02825 static int _rpmsqlOpenDB(rpmsql sql) 02826 { 02827 int rc = -1; /* assume failure */ 02828 sqlite3 * db; 02829 02830 assert(sql); 02831 02832 db = (sqlite3 *)sql->I; 02833 if (db == NULL) { 02834 int rc; 02835 rc = rpmsqlCmd(sql, "open", db, /* XXX watchout: arg order */ 02836 sqlite3_open(sql->zDbFilename, &db)); 02837 sql->I = db; 02838 02839 if (db && rc == SQLITE_OK) { 02840 (void) _rpmsqlLoadCF(sql); 02841 (void) _rpmsqlLoadVMT(db, __VMT); 02842 } 02843 02844 if (db == NULL || sqlite3_errcode(db) != SQLITE_OK) { 02845 /* XXX rpmlog */ 02846 rpmsql_error(1, _("unable to open database \"%s\": %s"), 02847 sql->zDbFilename, sqlite3_errmsg(db)); 02848 goto exit; 02849 } 02850 /* Enable extension loading (if not disabled). */ 02851 if (!F_ISSET(sql, NOLOAD)) 02852 (void) rpmsqlCmd(sql, "enable_load_extension", db, 02853 sqlite3_enable_load_extension(db, 1)); 02854 } 02855 rc = 0; 02856 02857 exit: 02858 SQLDBG((stderr, "<-- %s(%p) rc %d %s\n", __FUNCTION__, sql, rc, sql->zDbFilename)); 02859 return rc; 02860 } 02861 02862 #endif /* defined(WITH_SQLITE) */ 02863 02864 /*==============================================================*/ 02865 02866 #if defined(WITH_SQLITE) 02867 02870 static int isNumber(const char *z, int *realnum) 02871 { 02872 if (*z == '-' || *z == '+') 02873 z++; 02874 if (!isdigit(*z)) 02875 return 0; 02876 z++; 02877 if (realnum) 02878 *realnum = 0; 02879 while (isdigit(*z)) 02880 z++; 02881 if (*z == '.') { 02882 z++; 02883 if (!isdigit(*z)) 02884 return 0; 02885 while (isdigit(*z)) 02886 z++; 02887 if (realnum) 02888 *realnum = 1; 02889 } 02890 if (*z == 'e' || *z == 'E') { 02891 z++; 02892 if (*z == '+' || *z == '-') 02893 z++; 02894 if (!isdigit(*z)) 02895 return 0; 02896 while (isdigit(*z)) 02897 z++; 02898 if (realnum) 02899 *realnum = 1; 02900 } 02901 return *z == 0; 02902 } 02903 02908 static int strlen30(const char *z) 02909 { 02910 const char *z2 = z; 02911 while (*z2) 02912 z2++; 02913 return 0x3fffffff & (int) (z2 - z); 02914 } 02915 #endif /* defined(WITH_SQLITE) */ 02916 02917 /*==============================================================*/ 02918 #if defined(WITH_SQLITE) 02919 02923 static void output_hex_blob(rpmsql sql, const void *pBlob, int nBlob) 02924 { 02925 char *zBlob = (char *) pBlob; 02926 int i; 02927 02928 SQLDBG((stderr, "--> %s(%p,%p[%u])\n", __FUNCTION__, sql, pBlob, (unsigned)nBlob)); 02929 rpmsqlFprintf(sql, "X'"); 02930 for (i = 0; i < nBlob; i++) 02931 rpmsqlFprintf(sql, "%02x", zBlob[i]); 02932 rpmsqlFprintf(sql, "'"); 02933 } 02934 02939 static void output_quoted_string(rpmsql sql, const char *z) 02940 { 02941 int i; 02942 int nSingle = 0; 02943 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z)); 02944 for (i = 0; z[i]; i++) { 02945 if (z[i] == '\'') 02946 nSingle++; 02947 } 02948 if (nSingle == 0) { 02949 rpmsqlFprintf(sql, "'%s'", z); 02950 } else { 02951 rpmsqlFprintf(sql, "'"); 02952 while (*z) { 02953 for (i = 0; z[i] && z[i] != '\''; i++) 02954 ; 02955 if (i == 0) { 02956 rpmsqlFprintf(sql, "''"); 02957 z++; 02958 } else if (z[i] == '\'') { 02959 rpmsqlFprintf(sql, "%.*s''", i, z); 02960 z += i + 1; 02961 } else { 02962 rpmsqlFprintf(sql, "%s", z); 02963 break; 02964 } 02965 } 02966 rpmsqlFprintf(sql, "'"); 02967 } 02968 } 02969 02974 static void output_c_string(rpmsql sql, const char *z) 02975 { 02976 unsigned int c; 02977 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z)); 02978 rpmsqlFprintf(sql, "\""); 02979 while ((c = *(z++)) != 0) { 02980 if (c == '\\') 02981 rpmsqlFprintf(sql, "\\\\"); 02982 else if (c == '\t') 02983 rpmsqlFprintf(sql, "\\t"); 02984 else if (c == '\n') 02985 rpmsqlFprintf(sql, "\\n"); 02986 else if (c == '\r') 02987 rpmsqlFprintf(sql, "\\r"); 02988 else if (!isprint(c)) 02989 rpmsqlFprintf(sql, "\\%03o", c & 0xff); 02990 else 02991 rpmsqlFprintf(sql, "%c", c); 02992 } 02993 rpmsqlFprintf(sql, "\""); 02994 } 02995 03001 static void output_html_string(rpmsql sql, const char *z) 03002 { 03003 int i; 03004 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, z)); 03005 while (*z) { 03006 for (i = 0; z[i] 03007 && z[i] != '<' 03008 && z[i] != '&' 03009 && z[i] != '>' && z[i] != '\"' && z[i] != '\''; i++) { 03010 } 03011 if (i > 0) 03012 rpmsqlFprintf(sql, "%.*s", i, z); 03013 if (z[i] == '<') 03014 rpmsqlFprintf(sql, "<"); 03015 else if (z[i] == '&') 03016 rpmsqlFprintf(sql, "&"); 03017 else if (z[i] == '>') 03018 rpmsqlFprintf(sql, ">"); 03019 else if (z[i] == '\"') 03020 rpmsqlFprintf(sql, """); 03021 else if (z[i] == '\'') 03022 rpmsqlFprintf(sql, "'"); 03023 else 03024 break; 03025 z += i + 1; 03026 } 03027 } 03028 03033 /*@unchecked@*/ 03034 static const char needCsvQuote[] = { 03035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03036 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03037 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 03038 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 03039 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 03040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 03041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 03042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 03043 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03044 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03045 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03046 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03047 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03048 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03049 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03050 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 03051 }; 03052 03060 static void output_csv(rpmsql sql, const char *z, int bSep) 03061 { 03062 SQLDBG((stderr, "--> %s(%p,%s,0x%x)\n", __FUNCTION__, sql, z, bSep)); 03063 if (z == 0) { 03064 rpmsqlFprintf(sql, "%s", sql->nullvalue); 03065 } else { 03066 int i; 03067 int nSep = strlen30(sql->separator); 03068 for (i = 0; z[i]; i++) { 03069 if (needCsvQuote[((unsigned char *) z)[i]] 03070 || (z[i] == sql->separator[0] && 03071 (nSep == 1 || memcmp(z, sql->separator, nSep) == 0))) { 03072 i = 0; 03073 break; 03074 } 03075 } 03076 if (i == 0) { 03077 rpmsqlFprintf(sql, "\""); 03078 for (i = 0; z[i]; i++) { 03079 if (z[i] == '"') 03080 rpmsqlFprintf(sql, "\""); 03081 rpmsqlFprintf(sql, "%c", z[i]); 03082 } 03083 rpmsqlFprintf(sql, "\""); 03084 } else { 03085 rpmsqlFprintf(sql, "%s", z); 03086 } 03087 } 03088 if (bSep) 03089 rpmsqlFprintf(sql, "%s", sql->separator); 03090 } 03091 03097 static int _rpmsqlShellCallback(void * _sql, int nArg, char **azArg, char **azCol, 03098 int *aiType) 03099 { 03100 rpmsql sql = (rpmsql) _sql; 03101 int w; 03102 int i; 03103 03104 SQLDBG((stderr, "--> %s(%p,%d,%p,%p,%p)\n", __FUNCTION__, _sql, nArg, azArg, azCol, aiType)); 03105 switch (sql->mode) { 03106 case RPMSQL_MODE_LINE: 03107 w = 5; 03108 if (azArg == 0) 03109 break; 03110 for (i = 0; i < nArg; i++) { 03111 int len = strlen30(azCol[i] ? azCol[i] : ""); 03112 if (len > w) 03113 w = len; 03114 } 03115 if (sql->cnt++ > 0) 03116 rpmsqlFprintf(sql, "\n"); 03117 for (i = 0; i < nArg; i++) 03118 rpmsqlFprintf(sql, "%*s = %s\n", w, azCol[i], 03119 azArg[i] ? azArg[i] : sql->nullvalue); 03120 break; 03121 case RPMSQL_MODE_EXPLAIN: 03122 case RPMSQL_MODE_COLUMN: 03123 if (sql->cnt++ == 0) { 03124 for (i = 0; i < nArg; i++) { 03125 int n; 03126 w = (i < ArraySize(sql->colWidth) ? sql->colWidth[i] : 0); 03127 03128 if (w <= 0) { 03129 w = strlen30(azCol[i] ? azCol[i] : ""); 03130 if (w < 10) 03131 w = 10; 03132 n = strlen30(azArg && azArg[i] 03133 ? azArg[i] : sql-> nullvalue); 03134 if (w < n) 03135 w = n; 03136 } 03137 if (i < ArraySize(sql->actualWidth)) 03138 sql->actualWidth[i] = w; 03139 if (F_ISSET(sql, SHOWHDR)) { 03140 rpmsqlFprintf(sql, "%-*.*s%s", w, w, azCol[i], 03141 i == nArg - 1 ? "\n" : " "); 03142 } 03143 } 03144 if (F_ISSET(sql, SHOWHDR)) { 03145 for (i = 0; i < nArg; i++) { 03146 w = (i < ArraySize(sql->actualWidth) 03147 ? sql->actualWidth[i] : 10); 03148 03149 rpmsqlFprintf(sql, "%-*.*s%s", w, w, 03150 "-----------------------------------" 03151 "----------------------------------------------------------", 03152 i == nArg - 1 ? "\n" : " "); 03153 } 03154 } 03155 } 03156 if (azArg == 0) 03157 break; 03158 for (i = 0; i < nArg; i++) { 03159 w = (i < ArraySize(sql->actualWidth) ? sql->actualWidth[i] : 10); 03160 if (sql->mode == RPMSQL_MODE_EXPLAIN && azArg[i] && 03161 strlen30(azArg[i]) > w) { 03162 w = strlen30(azArg[i]); 03163 } 03164 rpmsqlFprintf(sql, "%-*.*s%s", w, w, 03165 azArg[i] ? azArg[i] : sql->nullvalue, 03166 i == nArg - 1 ? "\n" : " "); 03167 } 03168 break; 03169 case RPMSQL_MODE_SEMI: 03170 case RPMSQL_MODE_LIST: 03171 if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) { 03172 for (i = 0; i < nArg; i++) 03173 rpmsqlFprintf(sql, "%s%s", azCol[i], 03174 i == nArg - 1 ? "\n" : sql->separator); 03175 } 03176 03177 if (azArg == 0) 03178 break; 03179 for (i = 0; i < nArg; i++) { 03180 char *z = azArg[i]; 03181 if (z == 0) 03182 z = sql->nullvalue; 03183 rpmsqlFprintf(sql, "%s", z); 03184 if (i < nArg - 1) 03185 rpmsqlFprintf(sql, "%s", sql->separator); 03186 else if (sql->mode == RPMSQL_MODE_SEMI) 03187 rpmsqlFprintf(sql, ";\n"); 03188 else 03189 rpmsqlFprintf(sql, "\n"); 03190 } 03191 break; 03192 case RPMSQL_MODE_HTML: 03193 if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) { 03194 rpmsqlFprintf(sql, "<TR>"); 03195 for (i = 0; i < nArg; i++) { 03196 rpmsqlFprintf(sql, "<TH>"); 03197 output_html_string(sql, azCol[i]); 03198 rpmsqlFprintf(sql, "</TH>\n"); 03199 } 03200 rpmsqlFprintf(sql, "</TR>\n"); 03201 } 03202 if (azArg == 0) 03203 break; 03204 rpmsqlFprintf(sql, "<TR>"); 03205 for (i = 0; i < nArg; i++) { 03206 rpmsqlFprintf(sql, "<TD>"); 03207 output_html_string(sql, azArg[i] ? azArg[i] : sql->nullvalue); 03208 rpmsqlFprintf(sql, "</TD>\n"); 03209 } 03210 rpmsqlFprintf(sql, "</TR>\n"); 03211 break; 03212 case RPMSQL_MODE_TCL: 03213 if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) { 03214 for (i = 0; i < nArg; i++) { 03215 output_c_string(sql, azCol[i] ? azCol[i] : ""); 03216 rpmsqlFprintf(sql, "%s", sql->separator); 03217 } 03218 rpmsqlFprintf(sql, "\n"); 03219 } 03220 if (azArg == 0) 03221 break; 03222 for (i = 0; i < nArg; i++) { 03223 output_c_string(sql, azArg[i] ? azArg[i] : sql->nullvalue); 03224 rpmsqlFprintf(sql, "%s", sql->separator); 03225 } 03226 rpmsqlFprintf(sql, "\n"); 03227 break; 03228 case RPMSQL_MODE_CSV: 03229 if (sql->cnt++ == 0 && F_ISSET(sql, SHOWHDR)) { 03230 for (i = 0; i < nArg; i++) 03231 output_csv(sql, azCol[i] ? azCol[i] : "", i < nArg - 1); 03232 rpmsqlFprintf(sql, "\n"); 03233 } 03234 if (azArg == 0) 03235 break; 03236 for (i = 0; i < nArg; i++) 03237 output_csv(sql, azArg[i], i < nArg - 1); 03238 rpmsqlFprintf(sql, "\n"); 03239 break; 03240 case RPMSQL_MODE_INSERT: 03241 sql->cnt++; 03242 if (azArg == 0) 03243 break; 03244 rpmsqlFprintf(sql, "INSERT INTO %s VALUES(", sql->zDestTable); 03245 for (i = 0; i < nArg; i++) { 03246 char *zSep = i > 0 ? "," : ""; 03247 if ((azArg[i] == 0) || (aiType && aiType[i] == SQLITE_NULL)) { 03248 rpmsqlFprintf(sql, "%sNULL", zSep); 03249 } else if (aiType && aiType[i] == SQLITE_TEXT) { 03250 if (zSep[0]) 03251 rpmsqlFprintf(sql, "%s", zSep); 03252 output_quoted_string(sql, azArg[i]); 03253 } else if (aiType 03254 && (aiType[i] == SQLITE_INTEGER 03255 || aiType[i] == SQLITE_FLOAT)) { 03256 rpmsqlFprintf(sql, "%s%s", zSep, azArg[i]); 03257 } else if (aiType && aiType[i] == SQLITE_BLOB && sql->S) { 03258 sqlite3_stmt * pStmt = (sqlite3_stmt *)sql->S; 03259 const void *pBlob = sqlite3_column_blob(pStmt, i); 03260 int nBlob = sqlite3_column_bytes(pStmt, i); 03261 if (zSep[0]) 03262 rpmsqlFprintf(sql, "%s", zSep); 03263 output_hex_blob(sql, pBlob, nBlob); 03264 } else if (isNumber(azArg[i], 0)) { 03265 rpmsqlFprintf(sql, "%s%s", zSep, azArg[i]); 03266 } else { 03267 if (zSep[0]) 03268 rpmsqlFprintf(sql, "%s", zSep); 03269 output_quoted_string(sql, azArg[i]); 03270 } 03271 } 03272 rpmsqlFprintf(sql, ");\n"); 03273 break; 03274 } 03275 return 0; 03276 } 03277 03283 static int callback(void *_sql, int nArg, char **azArg, char **azCol) 03284 { 03285 /* since we don't have type info, call the _rpmsqlShellCallback with a NULL value */ 03286 return _rpmsqlShellCallback(_sql, nArg, azArg, azCol, NULL); 03287 } 03288 03295 static void set_table_name(rpmsql sql, const char *zName) 03296 { 03297 int i, n; 03298 int needQuote; 03299 char *z; 03300 03301 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, zName)); 03302 sql->zDestTable = _free(sql->zDestTable); 03303 if (zName == NULL) 03304 return; 03305 needQuote = !xisalpha((unsigned char) *zName) && *zName != '_'; 03306 for (i = n = 0; zName[i]; i++, n++) { 03307 if (!xisalnum((unsigned char) zName[i]) && zName[i] != '_') { 03308 needQuote = 1; 03309 if (zName[i] == '\'') 03310 n++; 03311 } 03312 } 03313 if (needQuote) 03314 n += 2; 03315 sql->zDestTable = z = xmalloc(n + 1); 03316 n = 0; 03317 if (needQuote) 03318 z[n++] = '\''; 03319 for (i = 0; zName[i]; i++) { 03320 z[n++] = zName[i]; 03321 if (zName[i] == '\'') 03322 z[n++] = '\''; 03323 } 03324 if (needQuote) 03325 z[n++] = '\''; 03326 z[n] = 0; 03327 } 03328 03338 static char *appendText(char *zIn, char const *zAppend, char quote) 03339 { 03340 int len; 03341 int i; 03342 int nAppend = strlen30(zAppend); 03343 int nIn = (zIn ? strlen30(zIn) : 0); 03344 03345 SQLDBG((stderr, "--> %s(%s,%s,0x%02x)\n", __FUNCTION__, zIn, zAppend, quote)); 03346 len = nAppend + nIn + 1; 03347 if (quote) { 03348 len += 2; 03349 for (i = 0; i < nAppend; i++) { 03350 if (zAppend[i] == quote) 03351 len++; 03352 } 03353 } 03354 03355 zIn = (char *) xrealloc(zIn, len); 03356 03357 if (quote) { 03358 char *zCsr = &zIn[nIn]; 03359 *zCsr++ = quote; 03360 for (i = 0; i < nAppend; i++) { 03361 *zCsr++ = zAppend[i]; 03362 if (zAppend[i] == quote) 03363 *zCsr++ = quote; 03364 } 03365 *zCsr++ = quote; 03366 *zCsr++ = '\0'; 03367 assert((zCsr - zIn) == len); 03368 } else { 03369 memcpy(&zIn[nIn], zAppend, nAppend); 03370 zIn[len - 1] = '\0'; 03371 } 03372 03373 return zIn; 03374 } 03375 03376 03385 static int run_table_dump_query(rpmsql sql, sqlite3 * db, 03386 const char *zSelect, const char *zFirstRow) 03387 { 03388 sqlite3_stmt * pSelect; 03389 int rc; 03390 SQLDBG((stderr, "--> %s(%p,%p,%s,%s)\n", __FUNCTION__, sql, db, zSelect, zFirstRow)); 03391 rc = rpmsqlCmd(sql, "prepare", db, 03392 sqlite3_prepare(db, zSelect, -1, &pSelect, 0)); 03393 if (rc || pSelect == NULL) 03394 return rc; 03395 03396 while ((rc = rpmsqlCmd(sql, "step", db, 03397 sqlite3_step(pSelect))) == SQLITE_ROW) 03398 { 03399 if (zFirstRow) { 03400 rpmsqlFprintf(sql, "%s", zFirstRow); 03401 zFirstRow = NULL; 03402 } 03403 rpmsqlFprintf(sql, "%s;\n", sqlite3_column_text(pSelect, 0)); 03404 } 03405 03406 return rpmsqlCmd(sql, "finalize", db, 03407 sqlite3_finalize(pSelect)); 03408 } 03409 #endif /* defined(WITH_SQLITE) */ 03410 03411 /*==============================================================*/ 03412 03413 #if defined(WITH_SQLITE) 03414 #define iseol(_c) ((char)(_c) == '\n' || (char)(_c) == '\r') 03415 03423 /*@null@*/ 03424 static char * 03425 rpmsqlFgets(/*@returned@*/ char * buf, size_t nbuf, rpmsql sql) 03426 /*@globals fileSystem @*/ 03427 /*@modifies buf, fileSystem @*/ 03428 { 03429 FD_t ifd = sql->ifd; 03430 /* XXX sadly, fgets(3) cannot be used against a LIBIO wrapped .fpio FD_t */ 03431 FILE * ifp = (!F_ISSET(sql, PROMPT) ? fdGetFILE(ifd) : stdin); 03432 char *q = buf - 1; /* initialize just before buffer. */ 03433 size_t nb = 0; 03434 size_t nr = 0; 03435 int pc = 0, bc = 0; 03436 char *p = buf; 03437 03438 #ifdef NOISY /* XXX obliterates CLI input */ 03439 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))); 03440 #endif /* NOISY */ 03441 assert(ifp != NULL); 03442 03443 if (ifp != NULL) 03444 do { 03445 *(++q) = '\0'; /* terminate and move forward. */ 03446 if (fgets(q, (int)nbuf, ifp) == NULL) /* read next line. */ 03447 break; 03448 nb = strlen(q); 03449 nr += nb; /* trim trailing \r and \n */ 03450 for (q += nb - 1; nb > 0 && iseol(*q); q--) 03451 nb--; 03452 for (; p <= q; p++) { 03453 switch (*p) { 03454 case '\\': 03455 switch (*(p+1)) { 03456 case '\r': /*@switchbreak@*/ break; 03457 case '\n': /*@switchbreak@*/ break; 03458 case '\0': /*@switchbreak@*/ break; 03459 default: p++; /*@switchbreak@*/ break; 03460 } 03461 /*@switchbreak@*/ break; 03462 case '%': 03463 switch (*(p+1)) { 03464 case '{': p++, bc++; /*@switchbreak@*/ break; 03465 case '(': p++, pc++; /*@switchbreak@*/ break; 03466 case '%': p++; /*@switchbreak@*/ break; 03467 } 03468 /*@switchbreak@*/ break; 03469 case '{': if (bc > 0) bc++; /*@switchbreak@*/ break; 03470 case '}': if (bc > 0) bc--; /*@switchbreak@*/ break; 03471 case '(': if (pc > 0) pc++; /*@switchbreak@*/ break; 03472 case ')': if (pc > 0) pc--; /*@switchbreak@*/ break; 03473 } 03474 } 03475 if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') { 03476 *(++q) = '\0'; /* trim trailing \r, \n */ 03477 break; 03478 } 03479 q++; p++; nb++; /* copy newline too */ 03480 nbuf -= nb; 03481 if (*q == '\r') /* XXX avoid \r madness */ 03482 *q = '\n'; 03483 } while (nbuf > 0); 03484 03485 SQLDBG((stderr, "<-- %s(%p[%u],%p) nr %u\n", __FUNCTION__, buf, (unsigned)nbuf, sql, (unsigned)nr)); 03486 03487 return (nr > 0 ? buf : NULL); 03488 } 03489 03500 static char *local_getline(rpmsql sql, /*@null@*/const char *zPrompt) 03501 { 03502 char * t; 03503 03504 SQLDBG((stderr, "--> %s(%s) ofd %p\n", __FUNCTION__, zPrompt, sql->ofd)); 03505 03506 if (sql->ofd && zPrompt && *zPrompt) { 03507 size_t nb = strlen(zPrompt); 03508 size_t nw = Fwrite(zPrompt, 1, nb, sql->ofd); 03509 assert(nb == nw); 03510 (void) Fflush(sql->ofd); 03511 } 03512 03513 assert(sql->ifd != NULL); 03514 t = rpmsqlFgets(sql->buf, sql->nbuf, sql); 03515 03516 SQLDBG((stderr, "<-- %s(%s) ofd %p\n", __FUNCTION__, zPrompt, sql->ofd)); 03517 03518 return t; 03519 } 03520 03528 static char *rpmsqlInputOneLine(rpmsql sql, const char *zPrior) 03529 { 03530 const char *zPrompt; 03531 char *zResult; 03532 03533 SQLDBG((stderr, "--> %s(%s)\n", __FUNCTION__, zPrior)); 03534 03535 assert(sql->buf != NULL); 03536 assert(sql->ifd != NULL); 03537 03538 if (!F_ISSET(sql, PROMPT)) { 03539 zResult = local_getline(sql, NULL); 03540 } else { 03541 zPrompt = (zPrior && zPrior[0]) ? sql->zContinue : sql->zPrompt; 03542 zResult = readline(sql, zPrompt); 03543 if (zResult) { 03544 #if defined(HAVE_READLINE) && HAVE_READLINE==1 03545 if (*zResult) 03546 add_history(zResult); 03547 /* XXX readline returns malloc'd memory. copy & free. */ 03548 if (zResult != sql->buf) { 03549 strncpy(sql->buf, zResult, sql->nbuf); 03550 zResult = _free(zResult); 03551 zResult = sql->buf; 03552 } 03553 #endif 03554 } 03555 } 03556 03557 SQLDBG((stderr, "<-- %s(%s)\n", __FUNCTION__, zPrior)); 03558 03559 return zResult; 03560 } 03561 03562 #endif /* defined(WITH_SQLITE) */ 03563 03564 /*==============================================================*/ 03565 03566 #if defined(WITH_SQLITE) 03567 03570 static char *save_err_msg(sqlite3 * db) 03571 { 03572 const char * s = sqlite3_errmsg(db); 03573 int nb = strlen30(s) + 1; 03574 return memcpy(xmalloc(nb), s, nb); 03575 } 03576 03587 static int _rpmsqlShellExec(rpmsql sql, const char *zSql, 03588 int (*xCallback) (void *, int, char **, char **, int *), 03589 char **pzErrMsg 03590 ) 03591 { 03592 sqlite3 * db = (sqlite3 *) sql->I; 03593 sqlite3_stmt * pStmt = NULL; /* Statement to execute. */ 03594 int rc = SQLITE_OK; /* Return Code */ 03595 const char *zLeftover; /* Tail of unprocessed SQL */ 03596 03597 SQLDBG((stderr, "--> %s(%p,%s,%p,%p)\n", __FUNCTION__, sql, zSql, xCallback, pzErrMsg)); 03598 if (pzErrMsg) 03599 *pzErrMsg = NULL; 03600 03601 while (zSql[0] && rc == SQLITE_OK) { 03602 rc = rpmsqlCmd(sql, "prepare_v2", db, 03603 sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover)); 03604 if (rc) 03605 goto bottom; 03606 03607 /* this happens for a comment or white-space */ 03608 if (pStmt == NULL) 03609 goto bottom; 03610 03611 /* echo the sql statement if echo on */ 03612 if (sql->ofd && F_ISSET(sql, ECHO)) { 03613 const char *zStmtSql = sqlite3_sql(pStmt); 03614 rpmsqlFprintf(sql, "%s\n", zStmtSql ? zStmtSql : zSql); 03615 (void) Fflush(sql->ofd); 03616 } 03617 03618 /* perform the first step. this will tell us if we 03619 ** have a result set or not and how wide it is. 03620 */ 03621 rc = rpmsqlCmd(sql, "step", db, 03622 sqlite3_step(pStmt)); 03623 /* if we have a result set... */ 03624 if (rc == SQLITE_ROW) { 03625 /* if we have a callback... */ 03626 if (xCallback) { 03627 /* allocate space for col name ptr, value ptr, and type */ 03628 int nCol = sqlite3_column_count(pStmt); 03629 size_t nb = 3 * nCol * sizeof(const char *) + 1; 03630 char ** azCols = xmalloc(nb); /* Result names */ 03631 char ** azVals = &azCols[nCol]; /* Result values */ 03632 int * aiTypes = (int *) &azVals[nCol]; /* Result types */ 03633 int i; 03634 03635 /* save off ptrs to column names */ 03636 for (i = 0; i < nCol; i++) 03637 azCols[i] = (char *) sqlite3_column_name(pStmt, i); 03638 03639 /* save off the prepared statment handle and reset row count */ 03640 sql->S = (void *) pStmt; 03641 sql->cnt = 0; 03642 do { 03643 /* extract the data and data types */ 03644 for (i = 0; i < nCol; i++) { 03645 azVals[i] = (char *) sqlite3_column_text(pStmt, i); 03646 aiTypes[i] = sqlite3_column_type(pStmt, i); 03647 if (!azVals[i] && (aiTypes[i] != SQLITE_NULL)) { 03648 rc = SQLITE_NOMEM; 03649 break; /* from for */ 03650 } 03651 } /* end for */ 03652 03653 /* if data and types extraction failed... */ 03654 if (rc != SQLITE_ROW) 03655 break; 03656 03657 /* call the supplied callback with the result row data */ 03658 if (xCallback (sql, nCol, azVals, azCols, aiTypes)) { 03659 rc = SQLITE_ABORT; 03660 break; 03661 } 03662 rc = rpmsqlCmd(sql, "step", db, 03663 sqlite3_step(pStmt)); 03664 } while (rc == SQLITE_ROW); 03665 azCols = _free(azCols); 03666 sql->S = NULL; 03667 } else { 03668 do { 03669 rc = rpmsqlCmd(sql, "step", db, 03670 sqlite3_step(pStmt)); 03671 } while (rc == SQLITE_ROW); 03672 } 03673 } 03674 03675 /* Finalize the statement just executed. If this fails, save a 03676 ** copy of the error message. Otherwise, set zSql to point to the 03677 ** next statement to execute. */ 03678 rc = rpmsqlCmd(sql, "finalize", db, 03679 sqlite3_finalize(pStmt)); 03680 03681 bottom: 03682 /* On error, retrieve message and exit. */ 03683 if (rc) { 03684 if (pzErrMsg) 03685 *pzErrMsg = save_err_msg(db); 03686 break; 03687 } 03688 03689 /* Move to next sql statement */ 03690 zSql = zLeftover; 03691 while (xisspace(zSql[0])) 03692 zSql++; 03693 } /* end while */ 03694 03695 return rc; 03696 } 03697 #endif /* defined(WITH_SQLITE) */ 03698 03699 /*==============================================================*/ 03700 03701 #if defined(WITH_SQLITE) 03702 03710 static int dump_callback(void *_sql, int nArg, char **azArg, char **azCol) 03711 { 03712 rpmsql sql = (rpmsql) _sql; 03713 sqlite3 * db = (sqlite3 *) sql->I; 03714 int rc; 03715 const char *zTable; 03716 const char *zType; 03717 const char *zSql; 03718 const char *zPrepStmt = 0; 03719 int ec = 1; /* assume failure */ 03720 03721 SQLDBG((stderr, "--> %s(%p,%d,%p,%p)\n", __FUNCTION__, _sql, nArg, azArg, azCol)); 03722 azCol = azCol; 03723 if (nArg != 3) 03724 goto exit; 03725 zTable = azArg[0]; 03726 zType = azArg[1]; 03727 zSql = azArg[2]; 03728 03729 if (!strcmp(zTable, "sqlite_sequence")) { 03730 zPrepStmt = "DELETE FROM sqlite_sequence;\n"; 03731 } else if (!strcmp(zTable, "sqlite_stat1")) { 03732 rpmsqlFprintf(sql, "ANALYZE sqlite_master;\n"); 03733 } else if (!strncmp(zTable, "sqlite_", 7)) { 03734 ec = 0; /* XXX success */ 03735 goto exit; 03736 } else if (!strncmp(zSql, "CREATE VIRTUAL TABLE", 20)) { 03737 char *zIns; 03738 if (!F_ISSET(sql, WRITABLE)) { 03739 rpmsqlFprintf(sql, "PRAGMA writable_schema=ON;\n"); 03740 sql->flags |= RPMSQL_FLAGS_WRITABLE; 03741 } 03742 zIns = 03743 sqlite3_mprintf 03744 ("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" 03745 "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql); 03746 rpmsqlFprintf(sql, "%s\n", zIns); 03747 sqlite3_free(zIns); 03748 ec = 0; /* XXX success */ 03749 goto exit; 03750 } else 03751 rpmsqlFprintf(sql, "%s;\n", zSql); 03752 03753 if (!strcmp(zType, "table")) { 03754 sqlite3_stmt * pTableInfo = NULL; 03755 char *zSelect = 0; 03756 char *zTableInfo = 0; 03757 char *zTmp = 0; 03758 int nRow = 0; 03759 03760 zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0); 03761 zTableInfo = appendText(zTableInfo, zTable, '"'); 03762 zTableInfo = appendText(zTableInfo, ");", 0); 03763 03764 rc = rpmsqlCmd(sql, "prepare", db, 03765 sqlite3_prepare(db, zTableInfo, -1, &pTableInfo, 0)); 03766 zTableInfo = _free(zTableInfo); 03767 if (rc != SQLITE_OK || !pTableInfo) 03768 goto exit; 03769 03770 zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0); 03771 zTmp = appendText(zTmp, zTable, '"'); 03772 if (zTmp) 03773 zSelect = appendText(zSelect, zTmp, '\''); 03774 zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); 03775 rc = rpmsqlCmd(sql, "step", db, 03776 sqlite3_step(pTableInfo)); 03777 while (rc == SQLITE_ROW) { 03778 const char *zText = 03779 (const char *) sqlite3_column_text(pTableInfo, 1); 03780 zSelect = appendText(zSelect, "quote(", 0); 03781 zSelect = appendText(zSelect, zText, '"'); 03782 rc = rpmsqlCmd(sql, "step", db, 03783 sqlite3_step(pTableInfo)); 03784 if (rc == SQLITE_ROW) 03785 zSelect = appendText(zSelect, ") || ',' || ", 0); 03786 else 03787 zSelect = appendText(zSelect, ") ", 0); 03788 nRow++; 03789 } 03790 rc = rpmsqlCmd(sql, "finalize", db, 03791 sqlite3_finalize(pTableInfo)); 03792 if (rc != SQLITE_OK || nRow == 0) { 03793 zSelect = _free(zSelect); 03794 goto exit; 03795 } 03796 03797 zSelect = appendText(zSelect, "|| ')' FROM ", 0); 03798 zSelect = appendText(zSelect, zTable, '"'); 03799 03800 rc = run_table_dump_query(sql, db, zSelect, zPrepStmt); 03801 if (rc == SQLITE_CORRUPT) { 03802 zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); 03803 rc = run_table_dump_query(sql, db, zSelect, NULL); 03804 } 03805 zSelect = _free(zSelect); 03806 } 03807 ec = 0; /* XXX success */ 03808 exit: 03809 return ec; 03810 } 03811 03820 static int run_schema_dump_query(rpmsql sql, 03821 const char *zQuery, char **pzErrMsg) 03822 { 03823 sqlite3 * db = (sqlite3 *) sql->I; 03824 int rc; 03825 03826 SQLDBG((stderr, "--> %s(%p,%s,%p)\n", __FUNCTION__, sql, zQuery, pzErrMsg)); 03827 rc = rpmsqlCmd(sql, "exec", db, 03828 sqlite3_exec(db, zQuery, dump_callback, sql, pzErrMsg)); 03829 if (rc == SQLITE_CORRUPT) { 03830 char *zQ2; 03831 if (pzErrMsg) 03832 sqlite3_free(*pzErrMsg); 03833 zQ2 = rpmExpand(zQuery, " ORDER BY rowid DESC", NULL); 03834 rc = rpmsqlCmd(sql, "exec", db, 03835 sqlite3_exec(db, zQ2, dump_callback, sql, pzErrMsg)); 03836 zQ2 = _free(zQ2); 03837 } 03838 return rc; 03839 } 03840 03841 /* 03842 * Text of a help message 03843 */ 03844 /*@unchecked@*/ 03845 static char zHelp[] = 03846 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" 03847 ".bail ON|OFF Stop after hitting an error. Default OFF\n" 03848 ".databases List names and files of attached databases\n" 03849 ".dump ?TABLE? ... Dump the database in an SQL text format\n" 03850 " If TABLE specified, only dump tables matching\n" 03851 " LIKE pattern TABLE.\n" 03852 ".echo ON|OFF Turn command echo on or off\n" 03853 ".exit Exit this program\n" 03854 ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" 03855 " With no args, it turns EXPLAIN on.\n" 03856 ".header(s) ON|OFF Turn display of headers on or off\n" 03857 ".help Show this message\n" 03858 ".import FILE TABLE Import data from FILE into TABLE\n" 03859 ".indices ?TABLE? Show names of all indices\n" 03860 " If TABLE specified, only show indices for tables\n" 03861 " matching LIKE pattern TABLE.\n" 03862 #ifdef SQLITE_ENABLE_IOTRACE 03863 ".iotrace FILE Enable I/O diagnostic logging to FILE\n" 03864 #endif 03865 ".load FILE ?ENTRY? Load an extension library\n" 03866 ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n" 03867 ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" 03868 " csv Comma-separated values\n" 03869 " column Left-aligned columns. (See .width)\n" 03870 " html HTML <table> code\n" 03871 " insert SQL insert statements for TABLE\n" 03872 " line One value per line\n" 03873 " list Values delimited by .separator string\n" 03874 " tabs Tab-separated values\n" 03875 " tcl TCL list elements\n" 03876 ".nullvalue STRING Print STRING in place of NULL values\n" 03877 ".output FILENAME Send output to FILENAME\n" 03878 ".output stdout Send output to the screen\n" 03879 ".prompt MAIN CONTINUE Replace the standard prompts\n" 03880 ".quit Exit this program\n" 03881 ".read FILENAME Execute SQL in FILENAME\n" 03882 ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" 03883 ".schema ?TABLE? Show the CREATE statements\n" 03884 " If TABLE specified, only show tables matching\n" 03885 " LIKE pattern TABLE.\n" 03886 ".separator STRING Change separator used by output mode and .import\n" 03887 ".show Show the current values for various settings\n" 03888 ".tables ?TABLE? List names of tables\n" 03889 " If TABLE specified, only list tables matching\n" 03890 " LIKE pattern TABLE.\n" 03891 ".timeout MS Try opening locked tables for MS milliseconds\n" 03892 ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"; 03893 03894 static char zTimerHelp[] = 03895 ".timer ON|OFF Turn the CPU timer measurement on or off\n"; 03896 03906 static void resolve_backslashes(char *z) 03907 { 03908 int i, j; 03909 char c; 03910 for (i = j = 0; (c = z[i]) != 0; i++, j++) { 03911 if (c == '\\') { 03912 c = z[++i]; 03913 if (c == 'n') { 03914 c = '\n'; 03915 } else if (c == 't') { 03916 c = '\t'; 03917 } else if (c == 'r') { 03918 c = '\r'; 03919 } else if (c >= '0' && c <= '7') { 03920 c -= '0'; 03921 if (z[i + 1] >= '0' && z[i + 1] <= '7') { 03922 i++; 03923 c = (c << 3) + z[i] - '0'; 03924 if (z[i + 1] >= '0' && z[i + 1] <= '7') { 03925 i++; 03926 c = (c << 3) + z[i] - '0'; 03927 } 03928 } 03929 } 03930 } 03931 z[j] = c; 03932 } 03933 z[j] = 0; 03934 } 03935 03939 static int booleanValue(const char * zArg) 03940 { 03941 int val = atoi(zArg); 03942 if (!strcasecmp(zArg, "on") || !strcasecmp(zArg, "yes")) 03943 val = 1; 03944 SQLDBG((stderr, "<-- %s(%s) val %d\n", __FUNCTION__, zArg, val)); 03945 return val; 03946 } 03947 03948 /*@unchecked@*/ /*@observer@*/ 03949 static const char *modeDescr[] = { 03950 "line", 03951 "column", 03952 "list", 03953 "semi", 03954 "html", 03955 "insert", 03956 "tcl", 03957 "csv", 03958 "explain", 03959 }; 03960 03961 /* forward ref @*/ 03962 static int rpmsqlInput(rpmsql sql); 03963 03964 static int rpmsqlFOpen(const char * fn, FD_t *fdp) 03965 /*@modifies *fdp @*/ 03966 { 03967 FD_t fd = *fdp; 03968 int rc = 0; 03969 03970 SQLDBG((stderr, "--> %s(%s,%p) fd %p\n", __FUNCTION__, fn, fdp, fd)); 03971 03972 if (fd) 03973 (void) Fclose(fd); /* XXX stdout/stderr were dup'd */ 03974 fd = NULL; 03975 /* XXX permit numeric fdno's? */ 03976 if (fn == NULL) 03977 fd = NULL; 03978 else if (!strcmp(fn, "stdout") || !strcmp(fn, "-")) 03979 fd = fdDup(STDOUT_FILENO); 03980 else if (!strcmp(fn, "stderr")) 03981 fd = fdDup(STDERR_FILENO); 03982 else if (!strcmp(fn, "off")) 03983 fd = NULL; 03984 else { 03985 fd = Fopen(fn, "wb"); 03986 if (fd == NULL || Ferror(fd)) { 03987 rpmsql_error(1, _("cannot open \"%s\""), fn); 03988 if (fd) (void) Fclose(fd); 03989 fd = NULL; 03990 rc = 1; 03991 } 03992 } 03993 *fdp = fd; 03994 03995 SQLDBG((stderr, "<-- %s(%s,%p) fd %p rc %d\n", __FUNCTION__, fn, fdp, fd, rc)); 03996 03997 return rc; 03998 } 03999 04006 static int rpmsqlMetaCommand(rpmsql sql, char *zLine) 04007 { 04008 sqlite3 * db = (sqlite3 *)sql->I; 04009 int i = 1; 04010 int nArg = 0; 04011 int n, c; 04012 int rc = 0; 04013 char *azArg[50]; 04014 04015 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, zLine)); 04016 04017 /* Parse the input line into tokens. */ 04018 while (zLine[i] && nArg < ArraySize(azArg)) { 04019 while (xisspace((unsigned char) zLine[i])) 04020 i++; 04021 if (zLine[i] == '\0') 04022 break; 04023 if (zLine[i] == '\'' || zLine[i] == '"') { 04024 int delim = zLine[i++]; 04025 azArg[nArg++] = &zLine[i]; 04026 while (zLine[i] && zLine[i] != delim) 04027 i++; 04028 if (zLine[i] == delim) 04029 zLine[i++] = '\0'; 04030 if (delim == '"') 04031 resolve_backslashes(azArg[nArg - 1]); 04032 } else { 04033 azArg[nArg++] = &zLine[i]; 04034 while (zLine[i] && !xisspace((unsigned char) zLine[i])) 04035 i++; 04036 if (zLine[i]) 04037 zLine[i++] = 0; 04038 resolve_backslashes(azArg[nArg - 1]); 04039 } 04040 } 04041 04042 /* Process the input line. */ 04043 if (nArg == 0) 04044 return 0; /* no tokens, no error */ 04045 n = strlen30(azArg[0]); 04046 c = azArg[0][0]; 04047 if (c == 'b' && n >= 3 && !strncmp(azArg[0], "backup", n) 04048 && nArg > 1 && nArg < 4) { 04049 const char *zDestFile; 04050 const char *zDb; 04051 sqlite3 * pDest; 04052 sqlite3_backup *pBackup; 04053 if (nArg == 2) { 04054 zDestFile = azArg[1]; 04055 zDb = "main"; 04056 } else { 04057 zDestFile = azArg[2]; 04058 zDb = azArg[1]; 04059 } 04060 rc = rpmsqlCmd(sql, "open", pDest, 04061 sqlite3_open(zDestFile, &pDest)); 04062 if (rc) { 04063 #ifdef DYING 04064 rpmsql_error(1, _("cannot open \"%s\""), zDestFile); 04065 #endif 04066 (void) rpmsqlCmd(sql, "close", pDest, 04067 sqlite3_close(pDest)); 04068 return 1; 04069 } 04070 _rpmsqlOpenDB(sql); 04071 db = (sqlite3 *)sql->I; 04072 pBackup = sqlite3_backup_init(pDest, "main", db, zDb); 04073 if (pBackup == NULL) { 04074 rpmsql_error(1, "%s", sqlite3_errmsg(pDest)); 04075 (void) rpmsqlCmd(sql, "close", pDest, 04076 sqlite3_close(pDest)); 04077 return 1; 04078 } 04079 while ((rc = rpmsqlCmd(sql, "backup_step", db, 04080 sqlite3_backup_step(pBackup, 100))) == SQLITE_OK) 04081 ; 04082 (void) rpmsqlCmd(sql, "backup_finish", pBackup, 04083 sqlite3_backup_finish(pBackup)); 04084 if (rc == SQLITE_DONE) { 04085 rc = 0; 04086 } else { 04087 rpmsql_error(1, "%s", sqlite3_errmsg(pDest)); 04088 rc = 1; 04089 } 04090 (void) rpmsqlCmd(sql, "close", pDest, 04091 sqlite3_close(pDest)); 04092 } else 04093 if (c == 'b' && n >= 3 && !strncmp(azArg[0], "bail", n) 04094 && nArg > 1 && nArg < 3) { 04095 if (booleanValue(azArg[1])) 04096 sql->flags |= RPMSQL_FLAGS_BAIL; 04097 else 04098 sql->flags &= ~RPMSQL_FLAGS_BAIL; 04099 } else 04100 if (c == 'd' && n > 1 && !strncmp(azArg[0], "databases", n) && nArg == 1) { 04101 /* XXX recursion b0rkage lies here. */ 04102 uint32_t _flags = sql->flags; 04103 uint32_t _mode = sql->mode; 04104 int _cnt = sql->cnt;; 04105 int _colWidth[3]; 04106 char *zErrMsg = NULL; 04107 memcpy(_colWidth, sql->colWidth, sizeof(_colWidth)); 04108 _rpmsqlOpenDB(sql); 04109 db = (sqlite3 *)sql->I; 04110 sql->flags |= RPMSQL_FLAGS_SHOWHDR; 04111 sql->mode = RPMSQL_MODE_COLUMN; 04112 sql->colWidth[0] = 3; 04113 sql->colWidth[1] = 15; 04114 sql->colWidth[2] = 58; 04115 sql->cnt = 0; 04116 (void) rpmsqlCmd(sql, "exec", db, 04117 sqlite3_exec(db, "PRAGMA database_list;", callback, sql, &zErrMsg)); 04118 if (zErrMsg) { 04119 rpmsql_error(1, "%s", zErrMsg); 04120 sqlite3_free(zErrMsg); 04121 rc = 1; 04122 } 04123 memcpy(sql->colWidth, _colWidth, sizeof(_colWidth)); 04124 sql->cnt = _cnt; 04125 sql->mode = _mode; 04126 sql->flags = _flags; 04127 } else 04128 if (c == 'd' && !strncmp(azArg[0], "dump", n) && nArg < 3) { 04129 char * t; 04130 _rpmsqlOpenDB(sql); 04131 db = (sqlite3 *)sql->I; 04132 /* When playing back a "dump", the content might appear in an order 04133 ** which causes immediate foreign key constraints to be violated. 04134 ** So disable foreign-key constraint enforcement to prevent problems. */ 04135 rpmsqlFprintf(sql, "PRAGMA foreign_keys=OFF;\n"); 04136 rpmsqlFprintf(sql, "BEGIN TRANSACTION;\n"); 04137 sql->flags &= ~RPMSQL_FLAGS_WRITABLE; 04138 (void) rpmsqlCmd(sql, "exec", db, 04139 sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0)); 04140 if (nArg == 1) { 04141 t = rpmExpand("SELECT name, type, sql FROM sqlite_master" 04142 " WHERE sql NOT NULL AND type=='table'" 04143 " AND name!='sqlite_sequence'", NULL); 04144 run_schema_dump_query(sql, t, NULL); 04145 t = _free(t); 04146 t = rpmExpand("SELECT name, type, sql FROM sqlite_master" 04147 " WHERE name=='sqlite_sequence'", NULL); 04148 run_schema_dump_query(sql, t, NULL); 04149 t = _free(t); 04150 t = rpmExpand("SELECT sql FROM sqlite_master" 04151 " WHERE sql NOT NULL AND type IN ('index','trigger','view')", NULL); 04152 run_table_dump_query(sql, db, t, NULL); 04153 t = _free(t); 04154 } else { 04155 int i; 04156 for (i = 1; i < nArg; i++) { 04157 t = rpmExpand( "SELECT name, type, sql FROM sqlite_master" 04158 " WHERE tbl_name LIKE '", azArg[i], "'" 04159 " AND type=='table' AND sql NOT NULL", NULL); 04160 run_schema_dump_query(sql, t, NULL); 04161 t = _free(t); 04162 t = rpmExpand( "SELECT sql FROM sqlite_master" 04163 " WHERE sql NOT NULL" 04164 " AND type IN ('index','trigger','view')" 04165 " AND tbl_name LIKE '", azArg[i], "'", NULL); 04166 run_table_dump_query(sql, db, t, NULL); 04167 t = _free(t); 04168 } 04169 } 04170 if (F_ISSET(sql, WRITABLE)) { 04171 rpmsqlFprintf(sql, "PRAGMA writable_schema=OFF;\n"); 04172 sql->flags &= ~RPMSQL_FLAGS_WRITABLE; 04173 } 04174 (void) rpmsqlCmd(sql, "exec", db, 04175 sqlite3_exec(db, "PRAGMA writable_schema=OFF", 0, 0, 0)); 04176 rpmsqlFprintf(sql, "COMMIT;\n"); 04177 } else 04178 if (c == 'e' && !strncmp(azArg[0], "echo", n) && nArg > 1 && nArg < 3) { 04179 if (booleanValue(azArg[1])) 04180 sql->flags |= RPMSQL_FLAGS_ECHO; 04181 else 04182 sql->flags &= ~RPMSQL_FLAGS_ECHO; 04183 } else 04184 if (c == 'e' && !strncmp(azArg[0], "exit", n) && nArg == 1) { 04185 rc = 2; 04186 } else 04187 if (c == 'e' && !strncmp(azArg[0], "explain", n) && nArg < 3) { 04188 int val = nArg >= 2 ? booleanValue(azArg[1]) : 1; 04189 if (val == 1) { 04190 if (!sql->explainPrev.valid) { 04191 sql->explainPrev.valid = 1; 04192 sql->explainPrev.mode = sql->mode; 04193 sql->explainPrev.flags = sql->flags; 04194 memcpy(sql->explainPrev.colWidth, sql->colWidth, 04195 sizeof(sql->colWidth)); 04196 } 04197 /* We could put this code under the !p->explainValid 04198 ** condition so that it does not execute if we are already in 04199 ** explain mode. However, always executing it allows us an easy 04200 ** way to reset to explain mode in case the user previously 04201 ** did an .explain followed by a .width, .mode or .header 04202 ** command. 04203 */ 04204 sql->mode = RPMSQL_MODE_EXPLAIN; 04205 sql->flags |= RPMSQL_FLAGS_SHOWHDR; 04206 memset(sql->colWidth, 0, ArraySize(sql->colWidth)); 04207 sql->colWidth[0] = 4; /* addr */ 04208 sql->colWidth[1] = 13; /* opcode */ 04209 sql->colWidth[2] = 4; /* P1 */ 04210 sql->colWidth[3] = 4; /* P2 */ 04211 sql->colWidth[4] = 4; /* P3 */ 04212 sql->colWidth[5] = 13; /* P4 */ 04213 sql->colWidth[6] = 2; /* P5 */ 04214 sql->colWidth[7] = 13; /* Comment */ 04215 } else if (sql->explainPrev.valid) { 04216 sql->explainPrev.valid = 0; 04217 sql->mode = sql->explainPrev.mode; 04218 sql->flags = sql->explainPrev.flags; 04219 memcpy(sql->colWidth, sql->explainPrev.colWidth, 04220 sizeof(sql->colWidth)); 04221 } 04222 } else 04223 if (c == 'h' 04224 && (!strncmp(azArg[0], "header", n) || !strncmp(azArg[0], "headers", n)) 04225 && nArg > 1 && nArg < 3) 04226 { 04227 if (booleanValue(azArg[1])) 04228 sql->flags |= RPMSQL_FLAGS_SHOWHDR; 04229 else 04230 sql->flags &= ~RPMSQL_FLAGS_SHOWHDR; 04231 } else 04232 if (c == 'h' && !strncmp(azArg[0], "help", n)) { 04233 rpmsql_error(0, "%s", zHelp); 04234 if (HAS_TIMER) 04235 rpmsql_error(0, "%s", zTimerHelp); 04236 } else 04237 if (c == 'i' && !strncmp(azArg[0], "import", n) && nArg == 3) { 04238 char *zTable = azArg[2]; /* Insert data into this table */ 04239 char *zFile = azArg[1]; /* The file from which to extract data */ 04240 sqlite3_stmt * pStmt = NULL;/* A statement */ 04241 int nCol; /* Number of columns in the table */ 04242 int nByte; /* Number of bytes in an SQL string */ 04243 int i, j; /* Loop counters */ 04244 int nSep; /* Number of bytes in sql->separator[] */ 04245 char *zSql; /* An SQL statement */ 04246 char *zLine; /* A single line of input from the file */ 04247 char **azCol; /* zLine[] broken up into columns */ 04248 char *zCommit; /* How to commit changes */ 04249 int lineno = 0; /* Line number of input file */ 04250 04251 _rpmsqlOpenDB(sql); 04252 db = (sqlite3 *)sql->I; 04253 nSep = strlen30(sql->separator); 04254 if (nSep == 0) { 04255 rpmsql_error(1, _("non-null separator required for import")); 04256 return 1; 04257 } 04258 zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 04259 assert(zSql != NULL); 04260 nByte = strlen30(zSql); 04261 rc = rpmsqlCmd(sql, "prepare", db, 04262 sqlite3_prepare(db, zSql, -1, &pStmt, 0)); 04263 sqlite3_free(zSql); 04264 if (rc) { 04265 #ifdef DYING 04266 sqlite3 * db = (sqlite3 *)sql->I; 04267 rpmsql_error(1, "%s", sqlite3_errmsg(db)); 04268 #endif 04269 if (pStmt) 04270 (void) rpmsqlCmd(sql, "finalize", db, 04271 sqlite3_finalize(pStmt)); 04272 return 1; 04273 } 04274 nCol = sqlite3_column_count(pStmt); 04275 (void) rpmsqlCmd(sql, "finalize", db, 04276 sqlite3_finalize(pStmt)); 04277 pStmt = 0; 04278 if (nCol == 0) 04279 return 0; /* no columns, no error */ 04280 zSql = xmalloc(nByte + 20 + nCol * 2); 04281 sqlite3_snprintf(nByte + 20, zSql, "INSERT INTO '%q' VALUES(?", 04282 zTable); 04283 j = strlen30(zSql); 04284 for (i = 1; i < nCol; i++) { 04285 zSql[j++] = ','; 04286 zSql[j++] = '?'; 04287 } 04288 zSql[j++] = ')'; 04289 zSql[j] = 0; 04290 rc = rpmsqlCmd(sql, "prepare", db, 04291 sqlite3_prepare(db, zSql, -1, &pStmt, 0)); 04292 zSql = _free(zSql); 04293 if (rc) { 04294 #ifdef DYING 04295 sqlite3 * db = (sqlite3 *)sql->I; 04296 rpmsql_error(1, "%s", sqlite3_errmsg(db)); 04297 #endif 04298 if (pStmt) 04299 (void) rpmsqlCmd(sql, "finalize", db, 04300 sqlite3_finalize(pStmt)); 04301 return 1; 04302 } 04303 assert(sql->ifd == NULL); 04304 sql->ifd = Fopen(zFile, "rb.fpio"); 04305 if (sql->ifd == NULL || Ferror(sql->ifd)) { 04306 rpmsql_error(1, _("cannot open \"%s\""), zFile); 04307 (void) rpmsqlCmd(sql, "finalize", db, 04308 sqlite3_finalize(pStmt)); 04309 if (sql->ifd) (void) Fclose(sql->ifd); 04310 sql->ifd = NULL; 04311 return 1; 04312 } 04313 assert(sql->buf == NULL); 04314 sql->nbuf = BUFSIZ; 04315 sql->buf = xmalloc(sql->nbuf); 04316 azCol = malloc(sizeof(azCol[0]) * (nCol + 1)); 04317 if (azCol == NULL) { 04318 if (sql->ifd) (void) Fclose(sql->ifd); 04319 sql->ifd = NULL; 04320 (void) rpmsqlCmd(sql, "finalize", db, 04321 sqlite3_finalize(pStmt)); 04322 assert(azCol); 04323 } 04324 (void) rpmsqlCmd(sql, "exec", db, 04325 sqlite3_exec(db, "BEGIN", 0, 0, 0)); 04326 zCommit = "COMMIT"; 04327 while ((zLine = local_getline(sql, NULL)) != NULL) { 04328 char *z; 04329 i = 0; 04330 lineno++; 04331 azCol[0] = zLine; 04332 for (i = 0, z = zLine; *z && *z != '\n' && *z != '\r'; z++) { 04333 if (*z == sql->separator[0] && !strncmp(z, sql->separator, nSep)) { 04334 *z = '\0'; 04335 i++; 04336 if (i < nCol) { 04337 azCol[i] = &z[nSep]; 04338 z += nSep - 1; 04339 } 04340 } 04341 } /* end for */ 04342 *z = '\0'; 04343 if (i + 1 != nCol) { 04344 rpmsql_error(1, 04345 _("%s line %d: expected %d columns of data but found %d"), 04346 zFile, lineno, nCol, i + 1); 04347 zCommit = "ROLLBACK"; 04348 rc = 1; 04349 break; /* from while */ 04350 } 04351 for (i = 0; i < nCol; i++) 04352 rc = rpmsqlCmd(sql, "bind_text", db, 04353 sqlite3_bind_text(pStmt, i + 1, azCol[i], -1, SQLITE_STATIC)); 04354 rc = rpmsqlCmd(sql, "step", db, 04355 sqlite3_step(pStmt)); 04356 rc = rpmsqlCmd(sql, "reset", db, 04357 sqlite3_reset(pStmt)); 04358 if (rc) { 04359 #ifdef DYING 04360 sqlite3 * db = (sqlite3 *)sql->I; 04361 rpmsql_error(1, "%s", sqlite3_errmsg(db)); 04362 #endif 04363 zCommit = "ROLLBACK"; 04364 rc = 1; 04365 break; /* from while */ 04366 } 04367 } /* end while */ 04368 azCol = _free(azCol); 04369 if (sql->ifd) (void) Fclose(sql->ifd); 04370 sql->ifd = NULL; 04371 sql->buf = _free(sql->buf); 04372 sql->nbuf = 0; 04373 (void) rpmsqlCmd(sql, "finalize", db, 04374 sqlite3_finalize(pStmt)); 04375 (void) rpmsqlCmd(sql, "exec", db, 04376 sqlite3_exec(db, zCommit, 0, 0, 0)); 04377 } else 04378 if (c == 'i' && !strncmp(azArg[0], "indices", n) && nArg < 3) { 04379 /* XXX recursion b0rkage lies here. */ 04380 uint32_t _flags = sql->flags; 04381 uint32_t _mode = sql->mode; 04382 char * t; 04383 char *zErrMsg = NULL; 04384 _rpmsqlOpenDB(sql); 04385 db = (sqlite3 *)sql->I; 04386 sql->flags &= ~RPMSQL_FLAGS_SHOWHDR; 04387 sql->mode = RPMSQL_MODE_LIST; 04388 if (nArg == 1) { 04389 t = rpmExpand("SELECT name FROM sqlite_master" 04390 " WHERE type='index' AND name NOT LIKE 'sqlite_%'" 04391 " UNION ALL " 04392 "SELECT name FROM sqlite_temp_master" 04393 " WHERE type='index'" 04394 " ORDER BY 1", NULL); 04395 rc = rpmsqlCmd(sql, "exec", db, 04396 sqlite3_exec(db, t, callback, sql, &zErrMsg)); 04397 t = _free(t); 04398 } else { 04399 t = rpmExpand("SELECT name FROM sqlite_master" 04400 " WHERE type='index' AND tbl_name LIKE '", azArg[1], "'", 04401 " UNION ALL " 04402 "SELECT name FROM sqlite_temp_master" 04403 " WHERE type='index' AND tbl_name LIKE '", azArg[1], "'", 04404 " ORDER BY 1", NULL); 04405 rc = rpmsqlCmd(sql, "exec", db, 04406 sqlite3_exec(db, t, callback, sql, &zErrMsg)); 04407 t = _free(t); 04408 } 04409 if (zErrMsg) { 04410 rpmsql_error(1, "%s", zErrMsg); 04411 sqlite3_free(zErrMsg); 04412 rc = 1; 04413 } else if (rc) { 04414 #ifdef DYING 04415 rpmsql_error(1, _("querying sqlite_master and sqlite_temp_master")); 04416 #endif 04417 rc = 1; 04418 } 04419 sql->mode = _mode; 04420 sql->flags = _flags; 04421 } else 04422 04423 #ifdef SQLITE_ENABLE_IOTRACE 04424 if (c == 'i' && !strncmp(azArg[0], "iotrace", n)) { 04425 extern void (*sqlite3IoTrace) (const char *, ...); 04426 rc = rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->tfd); 04427 sqlite3IoTrace = (sql->tfd ? iotracePrintf : NULL); 04428 } else 04429 #endif 04430 04431 if (c == 'l' && !strncmp(azArg[0], "load", n) && nArg >= 2) { 04432 const char *zFile, *zProc; 04433 char *zErrMsg = 0; 04434 zFile = azArg[1]; 04435 zProc = nArg >= 3 ? azArg[2] : 0; 04436 if (!F_ISSET(sql, NOLOAD)) { 04437 _rpmsqlOpenDB(sql); 04438 db = (sqlite3 *)sql->I; 04439 rc = rpmsqlCmd(sql, "load_extension", db, 04440 sqlite3_load_extension(db, zFile, zProc, &zErrMsg)); 04441 if (rc) { 04442 rpmsql_error(1, "%s", zErrMsg); 04443 sqlite3_free(zErrMsg); 04444 rc = 1; 04445 } 04446 } 04447 } else 04448 04449 if (c == 'l' && !strncmp(azArg[0], "log", n) && nArg >= 1) { 04450 /* XXX set rc? */ 04451 (void) rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->lfd); 04452 } else 04453 if (c == 'm' && !strncmp(azArg[0], "mode", n) && nArg == 2) { 04454 int n2 = strlen30(azArg[1]); 04455 if ((n2 == 4 && !strncmp(azArg[1], "line", n2)) 04456 || (n2 == 5 && !strncmp(azArg[1], "lines", n2))) { 04457 sql->mode = RPMSQL_MODE_LINE; 04458 } else if ((n2 == 6 && !strncmp(azArg[1], "column", n2)) 04459 || (n2 == 7 && !strncmp(azArg[1], "columns", n2))) { 04460 sql->mode = RPMSQL_MODE_COLUMN; 04461 } else if (n2 == 4 && !strncmp(azArg[1], "list", n2)) { 04462 sql->mode = RPMSQL_MODE_LIST; 04463 } else if (n2 == 4 && !strncmp(azArg[1], "html", n2)) { 04464 sql->mode = RPMSQL_MODE_HTML; 04465 } else if (n2 == 3 && !strncmp(azArg[1], "tcl", n2)) { 04466 sql->mode = RPMSQL_MODE_TCL; 04467 } else if (n2 == 3 && !strncmp(azArg[1], "csv", n2)) { 04468 sql->mode = RPMSQL_MODE_CSV; 04469 (void) stpcpy(sql->separator, ","); 04470 } else if (n2 == 4 && !strncmp(azArg[1], "tabs", n2)) { 04471 sql->mode = RPMSQL_MODE_LIST; 04472 (void) stpcpy(sql->separator, "\t"); 04473 } else if (n2 == 6 && !strncmp(azArg[1], "insert", n2)) { 04474 sql->mode = RPMSQL_MODE_INSERT; 04475 set_table_name(sql, "table"); 04476 } else { 04477 rpmsql_error(1, _("mode should be one of: %s"), 04478 "column csv html insert line list tabs tcl"); 04479 rc = 1; 04480 } 04481 } else 04482 if (c == 'm' && !strncmp(azArg[0], "mode", n) && nArg == 3) { 04483 int n2 = strlen30(azArg[1]); 04484 if (n2 == 6 && !strncmp(azArg[1], "insert", n2)) { 04485 sql->mode = RPMSQL_MODE_INSERT; 04486 set_table_name(sql, azArg[2]); 04487 } else { 04488 rpmsql_error(1, _("invalid arguments: " 04489 " \"%s\". Enter \".help\" for help"), azArg[2]); 04490 rc = 1; 04491 } 04492 } else 04493 if (c == 'n' && !strncmp(azArg[0], "nullvalue", n) && nArg == 2) { 04494 (void) stpncpy(sql->nullvalue, azArg[1], sizeof(sql->nullvalue)-1); 04495 } else 04496 if (c == 'o' && !strncmp(azArg[0], "output", n) && nArg == 2) { 04497 rc = rpmsqlFOpen((nArg >= 2 ? azArg[1] : NULL), &sql->ofd); 04498 04499 /* Make sure sql->ofd squirts _SOMEWHERE_. Save the name too. */ 04500 sql->outfile = _free(sql->outfile); 04501 if (sql->ofd) 04502 sql->outfile = xstrdup(azArg[1]); 04503 else { 04504 sql->ofd = fdDup(STDOUT_FILENO); 04505 sql->outfile = xstrdup("stdout"); 04506 } 04507 } else 04508 if (c == 'p' && !strncmp(azArg[0], "prompt", n) 04509 && (nArg == 2 || nArg == 3)) { 04510 if (nArg >= 2) { 04511 sql->zPrompt = _free(sql->zPrompt); 04512 sql->zPrompt = xstrdup(azArg[1]); 04513 } 04514 if (nArg >= 3) { 04515 sql->zContinue = _free(sql->zContinue); 04516 sql->zContinue = xstrdup(azArg[2]); 04517 } 04518 } else 04519 if (c == 'q' && !strncmp(azArg[0], "quit", n) && nArg == 1) { 04520 rc = 2; 04521 } else 04522 if (c == 'r' && n >= 3 && !strncmp(azArg[0], "read", n) 04523 && nArg == 2) { 04524 FD_t _ifd = sql->ifd; 04525 sql->ifd = Fopen(azArg[1], "rb.fpio"); 04526 if (sql->ifd == NULL || Ferror(sql->ifd)) { 04527 rpmsql_error(1, _("cannot open \"%s\""), azArg[1]); 04528 rc = 1; 04529 } else { 04530 /* XXX .read assumes .echo off? */ 04531 rc = rpmsqlInput(sql); 04532 } 04533 if (sql->ifd) (void) Fclose(sql->ifd); 04534 sql->ifd = _ifd; 04535 } else 04536 if (c == 'r' && n >= 3 && !strncmp(azArg[0], "restore", n) 04537 && nArg > 1 && nArg < 4) { 04538 const char *zSrcFile; 04539 const char *zDb; 04540 sqlite3 * pSrc; 04541 sqlite3_backup *pBackup; 04542 int nTimeout = 0; 04543 04544 if (nArg == 2) { 04545 zSrcFile = azArg[1]; 04546 zDb = "main"; 04547 } else { 04548 zSrcFile = azArg[2]; 04549 zDb = azArg[1]; 04550 } 04551 rc = rpmsqlCmd(sql, "open", pSrc, /* XXX watchout: arg order */ 04552 sqlite3_open(zSrcFile, &pSrc)); 04553 if (rc) { 04554 #ifdef DYING 04555 rpmsql_error(1, _("cannot open \"%s\""), zSrcFile); 04556 #endif 04557 (void) rpmsqlCmd(sql, "close", pSrc, 04558 sqlite3_close(pSrc)); 04559 return 1; 04560 } 04561 _rpmsqlOpenDB(sql); 04562 db = (sqlite3 *)sql->I; 04563 pBackup = sqlite3_backup_init(db, zDb, pSrc, "main"); 04564 if (pBackup == 0) { 04565 rpmsql_error(1, "%s", sqlite3_errmsg(db)); 04566 (void) rpmsqlCmd(sql, "close", db, 04567 sqlite3_close(pSrc)); 04568 return 1; 04569 } 04570 while ((rc = sqlite3_backup_step(pBackup, 100)) == SQLITE_OK 04571 || rc == SQLITE_BUSY) 04572 { 04573 if (rc == SQLITE_BUSY) { 04574 if (nTimeout++ >= 3) 04575 break; 04576 sqlite3_sleep(100); 04577 } 04578 } 04579 sqlite3_backup_finish(pBackup); 04580 switch (rc) { 04581 case SQLITE_DONE: 04582 rc = 0; 04583 break; 04584 case SQLITE_BUSY: 04585 case SQLITE_LOCKED: 04586 rpmsql_error(1, _("source database is busy")); 04587 rc = 1; 04588 break; 04589 default: 04590 rpmsql_error(1, "%s", sqlite3_errmsg(db)); 04591 rc = 1; 04592 break; 04593 } 04594 (void) rpmsqlCmd(sql, "close", pSrc, 04595 sqlite3_close(pSrc)); 04596 } else 04597 if (c == 's' && !strncmp(azArg[0], "schema", n) && nArg < 3) { 04598 /* XXX recursion b0rkage lies here. */ 04599 uint32_t _flags = sql->flags; 04600 uint32_t _mode = sql->mode; 04601 char *zErrMsg = 0; 04602 _rpmsqlOpenDB(sql); 04603 db = (sqlite3 *)sql->I; 04604 sql->flags &= ~RPMSQL_FLAGS_SHOWHDR; 04605 sql->mode = RPMSQL_MODE_SEMI; 04606 if (nArg > 1) { 04607 int i; 04608 for (i = 0; azArg[1][i]; i++) 04609 azArg[1][i] = (char) tolower(azArg[1][i]); 04610 if (!strcmp(azArg[1], "sqlite_master")) { 04611 char *new_argv[2], *new_colv[2]; 04612 new_argv[0] = "CREATE TABLE sqlite_master (\n" 04613 " type text,\n" 04614 " name text,\n" 04615 " tbl_name text,\n" 04616 " rootpage integer,\n" " sql text\n" ")"; 04617 new_argv[1] = 0; 04618 new_colv[0] = "sql"; 04619 new_colv[1] = 0; 04620 callback(sql, 1, new_argv, new_colv); 04621 rc = SQLITE_OK; 04622 } else if (!strcmp(azArg[1], "sqlite_temp_master")) { 04623 char *new_argv[2], *new_colv[2]; 04624 new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" 04625 " type text,\n" 04626 " name text,\n" 04627 " tbl_name text,\n" 04628 " rootpage integer,\n" " sql text\n" ")"; 04629 new_argv[1] = 0; 04630 new_colv[0] = "sql"; 04631 new_colv[1] = 0; 04632 callback(sql, 1, new_argv, new_colv); 04633 rc = SQLITE_OK; 04634 } else { 04635 char * t; 04636 t = rpmExpand( "SELECT sql FROM " 04637 " (SELECT sql sql, type type, tbl_name tbl_name, name name" 04638 " FROM sqlite_master UNION ALL" 04639 " SELECT sql, type, tbl_name, name FROM sqlite_temp_master)" 04640 " WHERE tbl_name LIKE '", azArg[1], "'" 04641 " AND type!='meta' AND sql NOTNULL " 04642 "ORDER BY substr(type,2,1), name", NULL); 04643 rc = rpmsqlCmd(sql, "exec", db, 04644 sqlite3_exec(db, t, callback, sql, &zErrMsg)); 04645 t = _free(t); 04646 } 04647 sql->mode = _mode; 04648 sql->flags = _flags; 04649 } else { 04650 rc = rpmsqlCmd(sql, "exec", db, 04651 sqlite3_exec(db, 04652 "SELECT sql FROM " 04653 " (SELECT sql sql, type type, tbl_name tbl_name, name name" 04654 " FROM sqlite_master UNION ALL" 04655 " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " 04656 "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" 04657 "ORDER BY substr(type,2,1), name", 04658 callback, sql, &zErrMsg)); 04659 } 04660 if (zErrMsg) { 04661 rpmsql_error(1, "%s", zErrMsg); 04662 sqlite3_free(zErrMsg); 04663 rc = 1; 04664 } else if (rc != SQLITE_OK) { 04665 rpmsql_error(1, _("querying schema information")); 04666 rc = 1; 04667 } else { 04668 rc = 0; 04669 } 04670 } else 04671 if (c == 's' && !strncmp(azArg[0], "separator", n) && nArg == 2) { 04672 (void) stpncpy(sql->separator, azArg[1], sizeof(sql->separator)-1); 04673 } else 04674 if (c == 's' && !strncmp(azArg[0], "show", n) && nArg == 1) { 04675 int i; 04676 rpmsqlFprintf(sql, "%9.9s: %s\n", "echo", F_ISSET(sql, ECHO) ? "on" : "off"); 04677 rpmsqlFprintf(sql, "%9.9s: %s\n", "explain", 04678 sql->explainPrev.valid ? "on" : "off"); 04679 rpmsqlFprintf(sql, "%9.9s: %s\n", "headers", 04680 F_ISSET(sql, SHOWHDR) ? "on" : "off"); 04681 rpmsqlFprintf(sql, "%9.9s: %s\n", "mode", modeDescr[sql->mode]); 04682 rpmsqlFprintf(sql, "%9.9s: ", "nullvalue"); 04683 output_c_string(sql, sql->nullvalue); 04684 rpmsqlFprintf(sql, "\n"); 04685 rpmsqlFprintf(sql, "%9.9s: %s\n", "output", 04686 (sql->outfile ? sql->outfile : "stdout")); 04687 rpmsqlFprintf(sql, "%9.9s: ", "separator"); 04688 output_c_string(sql, sql->separator); 04689 rpmsqlFprintf(sql, "\n"); 04690 rpmsqlFprintf(sql, "%9.9s: ", "width"); 04691 for (i = 0; 04692 i < (int) ArraySize(sql->colWidth) && sql->colWidth[i] != 0; 04693 i++) 04694 { 04695 rpmsqlFprintf(sql, "%d ", sql->colWidth[i]); 04696 } 04697 rpmsqlFprintf(sql, "\n"); 04698 } else 04699 if (c == 't' && n > 1 && !strncmp(azArg[0], "tables", n) && nArg < 3) { 04700 char **azResult; 04701 int nRow; 04702 char *zErrMsg; 04703 _rpmsqlOpenDB(sql); 04704 db = (sqlite3 *)sql->I; 04705 if (nArg == 1) { 04706 rc = rpmsqlCmd(sql, "get_table", db, 04707 sqlite3_get_table(db, 04708 "SELECT name FROM sqlite_master " 04709 "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' " 04710 "UNION ALL " 04711 "SELECT name FROM sqlite_temp_master " 04712 "WHERE type IN ('table','view') " 04713 "ORDER BY 1", 04714 &azResult, &nRow, 0, &zErrMsg)); 04715 } else { 04716 char * t; 04717 t = rpmExpand("SELECT name FROM sqlite_master " 04718 " WHERE type IN ('table','view') AND name LIKE '", azArg[1], "'" 04719 " UNION ALL " 04720 "SELECT name FROM sqlite_temp_master" 04721 " WHERE type IN ('table','view') AND name LIKE '", azArg[1], "'" 04722 "ORDER BY 1", NULL); 04723 rc = rpmsqlCmd(sql, "get_table", db, 04724 sqlite3_get_table(db, t, &azResult, &nRow, 0,&zErrMsg)); 04725 t = _free(t); 04726 } 04727 if (zErrMsg) { 04728 rpmsql_error(1, "%s", zErrMsg); 04729 sqlite3_free(zErrMsg); 04730 rc = 1; 04731 } else if (rc) { 04732 rpmsql_error(1, _("querying sqlite_master and sqlite_temp_master")); 04733 rc = 1; 04734 } else { 04735 int len, maxlen = 0; 04736 int i, j; 04737 int nPrintCol, nPrintRow; 04738 for (i = 1; i <= nRow; i++) { 04739 if (azResult[i] == 0) 04740 continue; 04741 len = strlen30(azResult[i]); 04742 if (len > maxlen) 04743 maxlen = len; 04744 } 04745 nPrintCol = 80 / (maxlen + 2); 04746 if (nPrintCol < 1) 04747 nPrintCol = 1; 04748 nPrintRow = (nRow + nPrintCol - 1) / nPrintCol; 04749 for (i = 0; i < nPrintRow; i++) { 04750 for (j = i + 1; j <= nRow; j += nPrintRow) { 04751 char *zSp = j <= nPrintRow ? "" : " "; 04752 rpmsqlFprintf(sql, "%s%-*s", zSp, maxlen, 04753 azResult[j] ? azResult[j] : ""); 04754 } 04755 rpmsqlFprintf(sql, "\n"); 04756 } 04757 } 04758 sqlite3_free_table(azResult); 04759 } else 04760 if (c == 't' && n > 4 && !strncmp(azArg[0], "timeout", n) && nArg == 2) { 04761 _rpmsqlOpenDB(sql); 04762 db = (sqlite3 *)sql->I; 04763 (void) rpmsqlCmd(sql, "busy_timeout", db, 04764 sqlite3_busy_timeout(db, atoi(azArg[1]))); 04765 } else 04766 if (HAS_TIMER && c == 't' && n >= 5 04767 && !strncmp(azArg[0], "timer", n) && nArg == 2) { 04768 sql->enableTimer = booleanValue(azArg[1]); 04769 } else 04770 if (c == 'w' && !strncmp(azArg[0], "width", n) && nArg > 1) { 04771 int j; 04772 assert(nArg <= ArraySize(azArg)); 04773 for (j = 1; j < nArg && j < ArraySize(sql->colWidth); j++) 04774 sql->colWidth[j - 1] = atoi(azArg[j]); 04775 } else 04776 { 04777 rpmsql_error(1, _("unknown command or invalid arguments: " 04778 " \"%s\". Enter \".help\" for help"), azArg[0]); 04779 rc = 1; 04780 } 04781 04782 return rc; 04783 } 04784 04785 #endif /* defined(WITH_SQLITE) */ 04786 04787 /*==============================================================*/ 04788 04789 #if defined(WITH_SQLITE) 04790 04795 static int _contains_semicolon(const char *z, int N) 04796 { 04797 int rc = 0; 04798 int i; 04799 for (i = 0; i < N; i++) { 04800 if (z[i] != ';') 04801 continue; 04802 rc = 1; 04803 break; 04804 } 04805 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, z, rc)); 04806 return rc; 04807 } 04808 04812 static int _all_whitespace(const char *z) 04813 { 04814 int rc = 1; 04815 04816 for (; *z; z++) { 04817 if (xisspace(*(unsigned char *) z)) 04818 continue; 04819 if (*z == '/' && z[1] == '*') { 04820 z += 2; 04821 while (*z && (*z != '*' || z[1] != '/')) 04822 z++; 04823 if (*z == '\0') { 04824 rc = 0; 04825 break; 04826 } 04827 z++; 04828 continue; 04829 } 04830 if (*z == '-' && z[1] == '-') { 04831 z += 2; 04832 while (*z && *z != '\n') 04833 z++; 04834 if (*z == '\0') 04835 break; 04836 continue; 04837 } 04838 rc = 0; 04839 break; 04840 } 04841 04842 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, z, rc)); 04843 return rc; 04844 } 04845 04851 static int _is_command_terminator(const char *zLine) 04852 { 04853 int rc = 1; 04854 04855 while (xisspace(*(unsigned char *) zLine)) 04856 zLine++; 04857 if (zLine[0] == '/' && _all_whitespace(&zLine[1])) 04858 goto exit; /* Oracle */ 04859 if (xtolower(zLine[0]) == 'g' && xtolower(zLine[1]) == 'o' 04860 && _all_whitespace(&zLine[2])) 04861 goto exit; /* SQL Server */ 04862 rc = 0; 04863 exit: 04864 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, zLine, rc)); 04865 return rc; 04866 } 04867 04872 static int _is_complete(char *zSql, int nSql) 04873 { 04874 int rc = 1; 04875 if (zSql == NULL) 04876 goto exit; 04877 zSql[nSql] = ';'; 04878 zSql[nSql + 1] = '\0'; 04879 rc = sqlite3_complete(zSql); 04880 zSql[nSql] = '\0'; 04881 exit: 04882 SQLDBG((stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, zSql, rc)); 04883 return rc; 04884 } 04885 04896 static int rpmsqlInput(rpmsql sql) 04897 { 04898 sqlite3 * db = (sqlite3 *) sql->I; 04899 char *zLine = 0; 04900 char *zSql = 0; 04901 int nSql = 0; 04902 int nSqlPrior = 0; 04903 char *zErrMsg; 04904 int rc; 04905 int errCnt = 0; 04906 int lineno = 0; 04907 int startline = 0; 04908 04909 char * _buf = sql->buf; 04910 size_t _nbuf = sql->nbuf; 04911 04912 SQLDBG((stderr, "--> %s(%p)\n", __FUNCTION__, sql)); 04913 if (_rpmsql_debug < 0) 04914 rpmsqlDebugDump(sql); 04915 04916 sql->nbuf = BUFSIZ; 04917 sql->buf = xmalloc(sql->nbuf); 04918 04919 while (errCnt == 0 || !F_ISSET(sql, BAIL) || F_ISSET(sql, PROMPT)) 04920 { 04921 if (sql->ofd) Fflush(sql->ofd); 04922 zLine = rpmsqlInputOneLine(sql, zSql); 04923 if (zLine == NULL) 04924 break; /* We have reached EOF */ 04925 if (_rpmsqlSeenInterrupt) { 04926 if (!F_ISSET(sql, PROMPT)) 04927 break; 04928 _rpmsqlSeenInterrupt = 0; 04929 } 04930 lineno++; 04931 if ((zSql == NULL || zSql[0] == '\0') && _all_whitespace(zLine)) 04932 continue; 04933 if (zLine && zLine[0] == '.' && nSql == 0) { 04934 if (F_ISSET(sql, ECHO)) 04935 rpmsqlFprintf(sql, "%s\n", zLine); 04936 rc = rpmsqlMetaCommand(sql, zLine); 04937 if (rc == 2) /* exit requested */ 04938 break; 04939 else if (rc) 04940 errCnt++; 04941 continue; 04942 } 04943 if (_is_command_terminator(zLine) && _is_complete(zSql, nSql)) 04944 memcpy(zLine, ";", 2); 04945 nSqlPrior = nSql; 04946 if (zSql == NULL) { 04947 int i; 04948 for (i = 0; zLine[i] && xisspace((unsigned char) zLine[i]); i++) 04949 ; 04950 if (zLine[i] != '\0') { 04951 nSql = strlen30(zLine); 04952 zSql = xmalloc(nSql + 3); 04953 memcpy(zSql, zLine, nSql + 1); 04954 startline = lineno; 04955 } 04956 } else { 04957 int len = strlen30(zLine); 04958 zSql = xrealloc(zSql, nSql + len + 4); 04959 zSql[nSql++] = '\n'; 04960 memcpy(&zSql[nSql], zLine, len + 1); 04961 nSql += len; 04962 } 04963 if (zSql && _contains_semicolon(&zSql[nSqlPrior], nSql - nSqlPrior) 04964 && sqlite3_complete(zSql)) { 04965 sql->cnt = 0; 04966 _rpmsqlOpenDB(sql); 04967 db = (sqlite3 *)sql->I; 04968 BEGIN_TIMER(sql); 04969 rc = _rpmsqlShellExec(sql, zSql, _rpmsqlShellCallback, &zErrMsg); 04970 END_TIMER(sql); 04971 if (rc || zErrMsg) { 04972 char zPrefix[100]; 04973 if (!F_ISSET(sql, PROMPT) || !F_ISSET(sql, INTERACTIVE)) 04974 snprintf(zPrefix, sizeof(zPrefix), 04975 "near line %d: ", startline); 04976 else 04977 zPrefix[0] = '\0'; 04978 rpmsql_error(1, "%s%s", zPrefix, 04979 zErrMsg ? zErrMsg : sqlite3_errmsg(db)); 04980 zErrMsg = _free(zErrMsg); 04981 errCnt++; 04982 } 04983 zSql = _free(zSql); 04984 nSql = 0; 04985 } 04986 } 04987 if (zSql) { 04988 if (!_all_whitespace(zSql)) 04989 rpmsql_error(1, _("incomplete SQL: %s"), zSql); 04990 zSql = _free(zSql); 04991 } 04992 04993 sql->buf = _free(sql->buf); 04994 sql->buf = _buf; 04995 sql->nbuf = _nbuf; 04996 04997 SQLDBG((stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, sql, errCnt)); 04998 04999 return errCnt; 05000 } 05001 05009 static int rpmsqlInitRC(rpmsql sql, const char *sqliterc) 05010 { 05011 int rc = 0; 05012 05013 SQLDBG((stderr, "--> %s(%p,%s)\n", __FUNCTION__, sql, sqliterc)); 05014 if (_rpmsql_debug < 0) 05015 rpmsqlDebugDump(sql); 05016 05017 if (sqliterc == NULL) 05018 sqliterc = sql->zInitrc; 05019 if (sqliterc) { 05020 FD_t _ifd = sql->ifd; 05021 sql->ifd = Fopen(sqliterc, "rb.fpio"); 05022 if (!(sql->ifd == NULL || Ferror(sql->ifd))) { 05023 if (F_ISSET(sql, INTERACTIVE)) 05024 rpmsql_error(0, "-- Loading resources from %s", sqliterc); 05025 rc = rpmsqlInput(sql); 05026 } 05027 if (sql->ifd) (void) Fclose(sql->ifd); 05028 sql->ifd = _ifd; 05029 } 05030 05031 SQLDBG((stderr, "<-- %s(%p,%s) rc %d\n", __FUNCTION__, sql, sqliterc, rc)); 05032 05033 return rc; 05034 } 05035 05036 #endif /* defined(WITH_SQLITE) */ 05037 05038 /*==============================================================*/ 05039 05040 #if defined(WITH_SQLITE) 05041 05044 static void rpmsqlArgCallback(poptContext con, 05045 /*@unused@ */ enum poptCallbackReason reason, 05046 const struct poptOption *opt, 05047 const char *arg, 05048 /*@unused@ */ void *_data) 05049 /*@ */ 05050 { 05051 rpmsql sql = &_sql; 05052 05053 /* XXX avoid accidental collisions with POPT_BIT_SET for flags */ 05054 if (opt->arg == NULL) 05055 switch (opt->val) { 05056 case 'S': /* -separator x */ 05057 assert(arg != NULL); 05058 (void) stpncpy(sql->separator, arg, sizeof(sql->separator)-1); 05059 break; 05060 case 'N': /* -nullvalue text */ 05061 assert(arg != NULL); 05062 (void) stpncpy(sql->nullvalue, arg, sizeof(sql->nullvalue)-1); 05063 break; 05064 case 'V': /* -version */ 05065 printf("%s\n", sqlite3_libversion()); 05066 /*@-exitarg@ */ exit(0); /*@=exitarg@ */ 05067 /*@notreached@ */ break; 05068 default: 05069 /* XXX fprintf(stderr, ...)? */ 05070 rpmsql_error(0, _("%s: Unknown callback(0x%x)\n"), 05071 __FUNCTION__, (unsigned) opt->val); 05072 poptPrintUsage(con, stderr, 0); 05073 /*@-exitarg@ */ exit(2); /*@=exitarg@ */ 05074 /*@notreached@ */ break; 05075 } 05076 } 05077 05078 /*@unchecked@*/ /*@observer@*/ 05079 static struct poptOption _rpmsqlOptions[] = { 05080 /*@-type@*//* FIX: cast? */ 05081 {NULL, '\0', 05082 POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE, 05083 rpmsqlArgCallback, 0, NULL, NULL}, 05084 /*@=type@*/ 05085 05086 { "debug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH|POPT_ARGFLAG_DOC_HIDDEN, &_rpmsql_debug, -1, 05087 N_("Debug embedded SQL interpreter"), NULL}, 05088 05089 { "init", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, &_sql.zInitFile, 0, 05090 N_("read/process named FILE"), N_("FILE") }, 05091 { "echo", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_ECHO, 05092 N_("print commands before execution"), NULL }, 05093 05094 { "load", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_NOLOAD, 05095 N_("disable extnsion loading (normally enabled)"), NULL }, 05096 { "header", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_SHOWHDR, 05097 N_("turn headers on or off"), NULL }, 05098 05099 { "bail", '\0', POPT_BIT_SET|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_BAIL, 05100 N_("stop after hitting an error"), NULL }, 05101 05102 { "interactive", '\0', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_INTERACTIVE, 05103 N_("force interactive I/O"), NULL }, 05104 { "batch", '\0', POPT_BIT_CLR|POPT_ARGFLAG_TOGGLE|POPT_ARGFLAG_ONEDASH, &_sql.flags, RPMSQL_FLAGS_INTERACTIVE, 05105 N_("force batch I/O"), NULL }, 05106 05107 { "column", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_COLUMN, 05108 N_("set output mode to 'column'"), NULL }, 05109 { "csv", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_CSV, 05110 N_("set output mode to 'csv'"), NULL }, 05111 { "html", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_HTML, 05112 N_("set output mode to HTML"), NULL }, 05113 { "line", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_LINE, 05114 N_("set output mode to 'line'"), NULL }, 05115 { "list", '\0', POPT_ARG_VAL|POPT_ARGFLAG_ONEDASH, &_sql.mode, RPMSQL_MODE_LIST, 05116 N_("set output mode to 'list'"), NULL }, 05117 { "separator", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, 0, 'S', 05118 N_("set output field separator (|)"), N_("CHAR") }, 05119 { "nullvalue", '\0', POPT_ARG_STRING|POPT_ARGFLAG_ONEDASH, 0, 'N', 05120 N_("set text string for NULL values"), N_("TEXT") }, 05121 05122 { "version", '\0', POPT_ARG_NONE|POPT_ARGFLAG_ONEDASH, 0, 'V', 05123 N_("show SQLite version"), NULL}, 05124 05125 #ifdef NOTYET 05126 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0, 05127 N_("Common options for all rpmio executables:"), NULL}, 05128 #endif 05129 05130 POPT_AUTOHELP {NULL, (char) -1, POPT_ARG_INCLUDE_TABLE, NULL, 0, 05131 N_("\ 05132 Usage: dbsql [OPTIONS] FILENAME [SQL]\n\ 05133 FILENAME is the name of an SQLite database. A new database is created\n\ 05134 if the file does not previously exist.\n\ 05135 \n\ 05136 OPTIONS include:\n\ 05137 -help show this message\n\ 05138 -init filename read/process named file\n\ 05139 -echo print commands before execution\n\ 05140 -[no]header turn headers on or off\n\ 05141 -bail stop after hitting an error\n\ 05142 -interactive force interactive I/O\n\ 05143 -batch force batch I/O\n\ 05144 -column set output mode to 'column'\n\ 05145 -csv set output mode to 'csv'\n\ 05146 -html set output mode to HTML\n\ 05147 -line set output mode to 'line'\n\ 05148 -list set output mode to 'list'\n\ 05149 -separator 'x' set output field separator (|)\n\ 05150 -nullvalue 'text' set text string for NULL values\n\ 05151 -version show SQLite version\n\ 05152 "), NULL}, 05153 05154 POPT_TABLEEND 05155 }; 05156 05157 #endif /* defined(WITH_SQLITE) */ 05158 05159 /*==============================================================*/ 05160 05164 static void rpmsqlFini(void * _sql) 05165 /*@globals fileSystem @*/ 05166 /*@modifies *_sql, fileSystem @*/ 05167 { 05168 rpmsql sql = _sql; 05169 05170 SQLDBG((stderr, "==> %s(%p)\n", __FUNCTION__, sql)); 05171 05172 sql->zDestTable = _free(sql->zDestTable); 05173 05174 if (sql->ifd) 05175 (void) Fclose(sql->ifd); /* XXX stdin dup'd */ 05176 sql->ifd = NULL; 05177 if (sql->ofd) 05178 (void) Fclose(sql->ofd); /* XXX stdout/stderr were dup'd */ 05179 sql->ofd = NULL; 05180 if (sql->lfd) 05181 (void) Fclose(sql->lfd); 05182 sql->lfd = NULL; 05183 if (sql->tfd) 05184 (void) Fclose(sql->tfd); 05185 sql->tfd = NULL; 05186 05187 sql->buf = _free(sql->buf); 05188 sql->buf = sql->b = NULL; 05189 sql->nbuf = sql->nb = 0; 05190 05191 /* XXX INTERACTIVE cruft. */ 05192 sql->zHome = _free(sql->zHome); 05193 sql->zInitrc = _free(sql->zInitrc); 05194 sql->zHistory = _free(sql->zHistory); 05195 sql->zPrompt = _free(sql->zPrompt); 05196 sql->zContinue = _free(sql->zContinue); 05197 05198 sql->outfile = _free(sql->outfile); 05199 05200 sql->zDbFilename = _free(sql->zDbFilename); 05201 sql->zInitFile = _free(sql->zInitFile); 05202 sql->av = argvFree(sql->av); 05203 #if defined(WITH_SQLITE) 05204 if (sql->I) { 05205 sqlite3 * db = (sqlite3 *)sql->I; 05206 (void) rpmsqlCmd(sql, "close", db, 05207 sqlite3_close(db)); 05208 } 05209 #endif 05210 sql->I = NULL; 05211 (void) rpmiobFree(sql->iob); 05212 sql->iob = NULL; 05213 } 05214 05215 /*@unchecked@*/ /*@only@*/ /*@null@*/ 05216 rpmioPool _rpmsqlPool; 05217 05218 static rpmsql rpmsqlGetPool(/*@null@*/ rpmioPool pool) 05219 /*@globals _rpmsqlPool, fileSystem @*/ 05220 /*@modifies pool, _rpmsqlPool, fileSystem @*/ 05221 { 05222 rpmsql sql; 05223 05224 if (_rpmsqlPool == NULL) { 05225 _rpmsqlPool = rpmioNewPool("sql", sizeof(*sql), -1, _rpmsql_debug, 05226 NULL, NULL, rpmsqlFini); 05227 pool = _rpmsqlPool; 05228 } 05229 sql = (rpmsql) rpmioGetPool(pool, sizeof(*sql)); 05230 memset(((char *)sql)+sizeof(sql->_item), 0, sizeof(*sql)-sizeof(sql->_item)); 05231 return sql; 05232 } 05233 05234 const char ** rpmsqlArgv(rpmsql sql, int * argcp) 05235 { 05236 const char ** av = sql->av; 05237 05238 if (argcp) 05239 *argcp = argvCount(av); 05240 return av; 05241 } 05242 05243 #if defined(WITH_SQLITE) 05244 05248 static void rpmsqlInitPopt(rpmsql sql, int ac, char ** av, poptOption tbl) 05249 /*@modifies sql @*/ 05250 { 05251 poptContext con; 05252 int rc; 05253 05254 if (av == NULL || av[0] == NULL || av[1] == NULL) 05255 goto exit; 05256 05257 con = poptGetContext(av[0], ac, (const char **)av, tbl, 0); 05258 05259 /* Process all options into _sql, whine if unknown options. */ 05260 while ((rc = poptGetNextOpt(con)) > 0) { 05261 const char * arg = poptGetOptArg(con); 05262 arg = _free(arg); 05263 switch (rc) { 05264 default: 05265 /* XXX fprintf(stderr, ...)? */ 05266 rpmsql_error(0, _("%s: option table misconfigured (%d)\n"), 05267 __FUNCTION__, rc); 05268 break; 05269 } 05270 } 05271 /* XXX FIXME: arrange error return iff rc < -1. */ 05272 if (rc) 05273 SQLDBG((stderr, "%s: poptGetNextOpt rc(%d): %s\n", __FUNCTION__, rc, poptStrerror(rc))); 05274 05275 /* Move the POPT parsed values into the current rpmsql object. */ 05276 sql->flags = _sql.flags; 05277 sql->mode = _sql.mode; 05278 if (_sql.zInitFile) { 05279 sql->zInitFile = _free(sql->zInitFile); 05280 sql->zInitFile = _sql.zInitFile; 05281 _sql.zInitFile = NULL; 05282 } 05283 memcpy(sql->separator, _sql.separator, sizeof(sql->separator)); 05284 memcpy(sql->nullvalue, _sql.nullvalue, sizeof(sql->nullvalue)); 05285 05286 sql->av = argvFree(sql->av); 05287 rc = argvAppend(&sql->av, poptGetArgs(con)); 05288 05289 con = poptFreeContext(con); 05290 05291 exit: 05292 /* If not overridden, set the separator according to mode. */ 05293 if (sql->separator[0] == '\0') 05294 switch (sql->mode) { 05295 default: 05296 case RPMSQL_MODE_LIST: (void)stpcpy(sql->separator, "|"); break; 05297 case RPMSQL_MODE_CSV: (void)stpcpy(sql->separator, ","); break; 05298 } 05299 05300 SQLDBG((stderr, "<== %s(%p, %p[%u], %p)\n", __FUNCTION__, sql, av, (unsigned)ac, tbl)); 05301 } 05302 #endif /* defined(WITH_SQLITE) */ 05303 05304 rpmsql rpmsqlNew(char ** av, uint32_t flags) 05305 { 05306 rpmsql sql = 05307 (flags & 0x80000000) ? rpmsqlI() : 05308 rpmsqlGetPool(_rpmsqlPool); 05309 int ac = argvCount((ARGV_t)av); 05310 05311 SQLDBG((stderr, "==> %s(%p[%u], 0x%x)\n", __FUNCTION__, av, (unsigned)ac, flags)); 05312 if (av && _rpmsql_debug < 0) 05313 argvPrint("argv", (ARGV_t)av, NULL); 05314 05315 sql->flags = flags; /* XXX useful? */ 05316 05317 #if defined(WITH_SQLITE) 05318 /* XXX Avoid initialization on global interpreter creation path. */ 05319 if (av) { 05320 static int _oneshot; 05321 sqlite3 * db = NULL; 05322 int xx; 05323 05324 if (!_oneshot) { 05325 #if defined(SQLITE_CONFIG_LOG) 05326 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, sql); 05327 #endif 05328 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); 05329 _oneshot++; 05330 } 05331 05332 /* Initialize defaults for popt parsing. */ 05333 memset(&_sql, 0, sizeof(_sql)); 05334 sql->flags = _sql.flags = flags; /* XXX INTERACTIVE defaulted here. */ 05335 sql->mode = _sql.mode = RPMSQL_MODE_LIST; 05336 05337 rpmsqlInitPopt(sql, ac, av, (poptOption) _rpmsqlOptions); 05338 05339 /* The 1st argument is the database to open (or :memory: default). */ 05340 if (sql->av && sql->av[0]) { 05341 sql->zDbFilename = xstrdup(sql->av[0]); /* XXX strdup? */ 05342 /* If database alread exists, open immediately. */ 05343 if (!Access(sql->zDbFilename, R_OK)) { 05344 xx = rpmsqlCmd(sql, "open", db, /* XXX watchout: arg order */ 05345 sqlite3_open(sql->zDbFilename, &db)); 05346 sql->I = (void *) db; 05347 } 05348 } else 05349 sql->zDbFilename = xstrdup(":memory:"); 05350 05351 /* Read ~/.sqliterc (if specified), then reparse options. */ 05352 if (sql->zInitFile || F_ISSET(sql, INTERACTIVE)) { 05353 sql->ofd = fdDup(STDOUT_FILENO); 05354 xx = rpmsqlInitRC(sql, sql->zInitFile); 05355 if (sql->ofd) (void) Fclose(sql->ofd); 05356 sql->ofd = NULL; 05357 rpmsqlInitPopt(sql, ac, av, (poptOption) _rpmsqlOptions); 05358 } 05359 05360 } 05361 05362 { /* XXX INTERACTIVE cruft. */ 05363 static const char _zInitrc[] = "/.sqliterc"; 05364 static const char _zHistory[] = "/.sqlite_history"; 05365 /* XXX getpwuid? */ 05366 sql->zHome = _free(sql->zHome); 05367 sql->zHome = xstrdup(getenv("HOME")); 05368 sql->zInitrc = _free(sql->zInitrc); 05369 sql->zInitrc = rpmGetPath(sql->zHome, _zInitrc, NULL); 05370 sql->zHistory = _free(sql->zHistory); 05371 sql->zHistory = rpmGetPath(sql->zHome, _zHistory, NULL); 05372 /* 05373 ** Prompt strings. Initialized in main. Settable with 05374 ** .prompt main continue 05375 */ 05376 /* Initialize the prompt from basename(argv[0]). */ 05377 if (sql->zPrompt == NULL) { /* XXX this test is useless */ 05378 char * t = xstrdup((av && av[0] ? av[0] : "sql")); 05379 char * bn = basename(t); 05380 sql->zPrompt = _free(sql->zPrompt); 05381 sql->zPrompt = rpmExpand(bn, "> ", NULL); 05382 t = _free(t); 05383 sql->zContinue = _free(sql->zContinue); 05384 sql->zContinue = t = xstrdup(sql->zPrompt); 05385 while (*t && *t != '>') 05386 *t++ = '-'; 05387 } 05388 } 05389 #else /* WITH_SQLITE */ 05390 if (av) 05391 (void) argvAppend(&sql->av, (ARGV_t) av); /* XXX useful? */ 05392 #endif /* WITH_SQLITE */ 05393 05394 /* Set sane defaults for output sink(s) dependent on INTERACTIVE. */ 05395 if (F_ISSET(sql, INTERACTIVE)) { 05396 if (sql->ofd == NULL) 05397 sql->ofd = fdDup(STDOUT_FILENO); 05398 } else { 05399 if (sql->iob == NULL) 05400 sql->iob = rpmiobNew(0); 05401 } 05402 05403 return rpmsqlLink(sql); 05404 } 05405 05406 rpmRC rpmsqlRun(rpmsql sql, const char * str, const char ** resultp) 05407 { 05408 rpmRC rc = RPMRC_FAIL; 05409 05410 SQLDBG((stderr, "==> %s(%p,%p[%u]) \"%s\"\n", __FUNCTION__, sql, str, (unsigned)(str ? strlen(str) : 0), str)); 05411 SQLDBG((stderr, "==========>\n%s\n<==========\n", str)); 05412 05413 if (sql == NULL) sql = rpmsqlI(); 05414 05415 #if defined(WITH_SQLITE) 05416 if (str != NULL) { 05417 const char * s = str; 05418 05419 /* Ignore leading whitespace. */ 05420 while (*s && xisspace((int)*s)) 05421 s++; 05422 05423 /* Perform the SQL operation(s). */ 05424 if (*s == '\0') { /* INTERACTIVE */ 05425 static int oneshot; 05426 uint32_t _flags = sql->flags; 05427 FD_t _ofd = sql->ofd; 05428 FD_t _ifd = sql->ifd; 05429 05430 SQLDBG((stderr, "*** %s: INTERACTIVE\n", __FUNCTION__)); 05431 sql->flags |= RPMSQL_FLAGS_INTERACTIVE; 05432 if (sql->ofd == NULL) 05433 sql->ofd = fdDup(STDOUT_FILENO); 05434 if (!oneshot) { 05435 #ifdef REFERENCE 05436 extern char *db_full_version(int *, int *, int *, int *, int *); 05437 fprintf(sql->out, "%s\n" 05438 "Enter \".help\" for instructions\n" 05439 "Enter SQL statements terminated with a \";\"\n", 05440 db_full_version(NULL, NULL, NULL, NULL, NULL)); 05441 #endif 05442 size_t nb; 05443 size_t nw; 05444 char * t = rpmExpand( 05445 "SQLite version ", sqlite3_libversion(), "\n", 05446 #if SQLITE_VERSION_NUMBER > 3006015 05447 "\t(", sqlite3_sourceid(), ")\n", 05448 #endif 05449 "Enter \".help\" for instructions\n", 05450 "Enter SQL statements terminated with a \";\"\n", NULL); 05451 nb = strlen(t); 05452 nw = Fwrite(t, 1, nb, sql->ofd); 05453 (void) Fflush(sql->ofd); 05454 assert(nb == nw); 05455 t = _free(t); 05456 #if defined(HAVE_READLINE) && HAVE_READLINE==1 05457 if (sql->zHistory) 05458 read_history(sql->zHistory); 05459 #endif 05460 oneshot++; 05461 } 05462 05463 sql->ifd = Fdopen(fdDup(fileno(stdin)), "rb.fpio"); 05464 assert(sql->ifd); 05465 05466 sql->flags |= RPMSQL_FLAGS_PROMPT; 05467 rc = rpmsqlInput(sql); 05468 sql->flags &= ~RPMSQL_FLAGS_PROMPT; 05469 05470 if (sql->ifd) (void) Fclose(sql->ifd); 05471 sql->ifd = _ifd; 05472 05473 if (sql->zHistory) { 05474 stifle_history(100); 05475 write_history(sql->zHistory); 05476 } 05477 if (_ofd == NULL) 05478 (void) Fclose(sql->ofd); 05479 sql->ofd = _ofd; 05480 sql->flags = _flags; 05481 if (rc != 0) rc = RPMRC_FAIL; 05482 } else 05483 if (!strcmp(s, "-") || !strcmp(s, "stdin")) { /* STDIN */ 05484 FD_t _ofd = sql->ofd; 05485 SQLDBG((stderr, "*** %s: STDIN\n", __FUNCTION__)); 05486 05487 if (sql->ofd == NULL) sql->ofd = fdDup(STDOUT_FILENO); 05488 assert(sql->ofd); 05489 05490 assert(sql->ifd == NULL); 05491 sql->ifd = Fdopen(fdDup(fileno(stdin)), "rb.fpio"); 05492 assert(sql->ifd); 05493 05494 rc = rpmsqlInput(sql); 05495 05496 if (sql->ifd) (void) Fclose(sql->ifd); 05497 sql->ifd = NULL; 05498 05499 if (_ofd == NULL) (void) Fclose(sql->ofd); 05500 sql->ofd = _ofd; 05501 05502 if (rc != 0) rc = RPMRC_FAIL; 05503 } else 05504 if (*s == '/') { /* FILE */ 05505 FD_t _ifd = sql->ifd; 05506 SQLDBG((stderr, "*** %s: FILE\n", __FUNCTION__)); 05507 sql->ifd = Fopen(s, "rb.fpio"); 05508 if (!(sql->ifd == NULL || Ferror(sql->ifd))) { 05509 rc = rpmsqlInput(sql); 05510 } 05511 if (sql->ifd) (void) Fclose(sql->ifd); 05512 sql->ifd = _ifd; 05513 if (rc != 0) rc = RPMRC_FAIL; 05514 } else { /* STRING */ 05515 SQLDBG((stderr, "*** %s: STRING\n", __FUNCTION__)); 05516 if (*s == '.') { 05517 char * t = xstrdup(s); 05518 rc = rpmsqlMetaCommand(sql, t); 05519 t = _free(t); 05520 } else { 05521 sqlite3 * db; 05522 char * zErrMsg = NULL; 05523 _rpmsqlOpenDB(sql); 05524 db = (sqlite3 *)sql->I; 05525 rc = _rpmsqlShellExec(sql, s, _rpmsqlShellCallback, &zErrMsg); 05526 if (zErrMsg) { 05527 rpmsql_error(1, "%s", zErrMsg); 05528 zErrMsg = _free(zErrMsg); 05529 if (rc == 0) rc = RPMRC_FAIL; 05530 } else if (rc != 0) { 05531 rpmsql_error(1, _("unable to process SQL \"%s\""), s); 05532 rc = RPMRC_FAIL; 05533 } 05534 } 05535 } 05536 05537 /* Return the SQL output. */ 05538 if (sql->iob) { 05539 (void) rpmiobRTrim(sql->iob); 05540 SQLDBG((stderr, "==========>\n%s\n<==========\n", rpmiobStr(sql->iob))); 05541 if (resultp) 05542 *resultp = rpmiobStr(sql->iob); /* XXX strdup? */ 05543 } 05544 05545 } 05546 #endif /* WITH_SQLITE */ 05547 05548 SQLDBG((stderr, "<== %s(%p,%p[%u]) rc %d\n", __FUNCTION__, sql, str, (unsigned)(str ? strlen(str) : 0), rc)); 05549 05550 return rc; 05551 }