rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmdb/sqlite.c
Go to the documentation of this file.

    00001 /*@-mustmod@*/
    00002 /*@-paramuse@*/
    00003 /*@-globuse@*/
    00004 /*@-moduncon@*/
    00005 /*@-noeffectuncon@*/
    00006 /*@-compdef@*/
    00007 /*@-compmempass@*/
    00008 /*@-modfilesystem@*/
    00009 /*@-evalorderuncon@*/
    00010
    00011 /*
    00012  * sqlite.c
    00013  * sqlite interface for rpmdb
    00014  *
    00015  * Author: Mark Hatle <mhatle@mvista.com> or <fray@kernel.crashing.org>
    00016  * Copyright (c) 2004 MontaVista Software, Inc.
    00017  *
    00018  * This program is free software; you can redistribute it and/or
    00019  * modify it under the terms of the GNU General Public License
    00020  * or GNU Library General Public License, at your option,
    00021  * as published by the Free Software Foundation; either version 2
    00022  * of the License, or (at your option) any later version.
    00023  *
    00024  * This program is distributed in the hope that it will be useful,
    00025  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00026  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00027  * GNU General Public License for more details.
    00028  *
    00029  * You should have received a copy of the GNU General Public License
    00030  * and GNU Library Public License along with this program;
    00031  * if not, write to the Free Software Foundation, Inc.,
    00032  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    00033  *
    00034  */
    00035
    00036 #include "system.h"
    00037
    00038 #include <rpmio.h>
    00039 #include <rpmlog.h>
    00040 #include <rpmmacro.h>
    00041 #include <rpmurl.h>     /* XXX urlPath proto */
    00042
    00043 #include <rpmtag.h>
    00044 #define _RPMDB_INTERNAL
    00045 #include <rpmdb.h>
    00046
    00047 #include <sqlite3.h>
    00048
    00049 #include "debug.h"
    00050
    00051 #if defined(__LCLINT__)
    00052 #define UINT32_T        u_int32_t
    00053 #else
    00054 #define UINT32_T        rpmuint32_t
    00055 #endif
    00056
    00057 /*@access rpmdb @*/
    00058 /*@access dbiIndex @*/
    00059
    00060 /* XXX retrofit the *BSD typedef for the deprived. */
    00061 #if defined(__QNXNTO__)
    00062 typedef rpmuint32_t       u_int32_t;
    00063 #endif
    00064
    00065 /*@unchecked@*/
    00066 static int _debug = 0;
    00067
    00068 /* Define the things normally in a header... */
    00069 struct _sql_db_s;       typedef struct _sql_db_s        SQL_DB;
    00070 struct _sql_dbcursor_s; typedef struct _sql_dbcursor_s *SCP_t;
    00071
    00072 struct _sql_db_s {
    00073     sqlite3 * db;               /* Database pointer */
    00074     int transaction;            /* Do we have a transaction open? */
    00075 };
    00076
    00077 struct _sql_dbcursor_s {
    00078 /*@shared@*/
    00079     DB *dbp;
    00080
    00081 /*@only@*/ /*@relnull@*/
    00082     char * cmd;                 /* SQL command string */
    00083 /*@only@*/ /*@relnull@*/
    00084     sqlite3_stmt *pStmt;        /* SQL byte code */
    00085     const char * pzErrmsg;      /* SQL error msg */
    00086
    00087   /* Table -- result of query */
    00088 /*@only@*/ /*@relnull@*/
    00089     char ** av;                 /* item ptrs */
    00090 /*@only@*/ /*@relnull@*/
    00091     size_t * avlen;             /* item sizes */
    00092     int nalloc;
    00093     int ac;                     /* no. of items */
    00094     int rx;                     /* Which row are we on? 1, 2, 3 ... */
    00095     int nr;                     /* no. of rows */
    00096     int nc;                     /* no. of columns */
    00097
    00098     int all;                    /* sequential iteration cursor */
    00099 /*@relnull@*/
    00100     DBT ** keys;                /* array of package keys */
    00101     int nkeys;
    00102
    00103     int count;
    00104
    00105 /*@null@*/
    00106     void * lkey;                /* Last key returned */
    00107 /*@null@*/
    00108     void * ldata;               /* Last data returned */
    00109
    00110     int used;
    00111 };
    00112
    00113 /*@-redef@*/
    00114 union _dbswap {
    00115     rpmuint32_t ui;
    00116     unsigned char uc[4];
    00117 };
    00118 /*@=redef@*/
    00119
    00120 #define _DBSWAP(_a) \
    00121   { unsigned char _b, *_c = (_a).uc; \
    00122     _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
    00123     _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
    00124   }
    00125
    00126 /*@unchecked@*/
    00127 static unsigned int endian = 0x11223344;
    00128
    00129 /*@unchecked@*/ /*@only@*/ /*@null@*/
    00130 static const char * sqlCwd = NULL;
    00131 /*@unchecked@*/
    00132 static int sqlInRoot = 0;
    00133
    00134 static void enterChroot(dbiIndex dbi)
    00135         /*@globals sqlCwd, sqlInRoot, internalState @*/
    00136         /*@modifies sqlCwd, sqlInRoot, internalState @*/
    00137 {
    00138     char * currDir = NULL;
    00139     int xx;
    00140
    00141     if ((dbi->dbi_root[0] == '/' && dbi->dbi_root[1] == '\0') || dbi->dbi_rpmdb->db_chrootDone || sqlInRoot)
    00142        /* Nothing to do, was not already in chroot */
    00143        return;
    00144
    00145 if (_debug)
    00146 fprintf(stderr, "sql:chroot(%s)\n", dbi->dbi_root);
    00147
    00148     {
    00149       int currDirLen = 0;
    00150
    00151       do {
    00152         currDirLen += 128;
    00153         currDir = xrealloc(currDir, currDirLen);
    00154         memset(currDir, 0, currDirLen);
    00155       } while (getcwd(currDir, currDirLen) == NULL && errno == ERANGE);
    00156     }
    00157
    00158     sqlCwd = currDir;
    00159 /*@-globs@*/
    00160     xx = Chdir("/");
    00161 /*@=globs@*/
    00162 /*@-modobserver@*/
    00163     xx = Chroot(dbi->dbi_root);
    00164 /*@=modobserver@*/
    00165 assert(xx == 0);
    00166     sqlInRoot=1;
    00167 }
    00168
    00169 static void leaveChroot(dbiIndex dbi)
    00170         /*@globals sqlCwd, sqlInRoot, internalState @*/
    00171         /*@modifies sqlCwd, sqlInRoot, internalState @*/
    00172 {
    00173     int xx;
    00174
    00175     if ((dbi->dbi_root[0] == '/' && dbi->dbi_root[1] == '\0') || dbi->dbi_rpmdb->db_chrootDone || !sqlInRoot)
    00176        /* Nothing to do, not in chroot */
    00177        return;
    00178
    00179 if (_debug)
    00180 fprintf(stderr, "sql:chroot(.)\n");
    00181
    00182 /*@-modobserver@*/
    00183     xx = Chroot(".");
    00184 /*@=modobserver@*/
    00185 assert(xx == 0);
    00186     if (sqlCwd != NULL) {
    00187 /*@-globs@*/
    00188         xx = Chdir(sqlCwd);
    00189 /*@=globs@*/
    00190         sqlCwd = _free(sqlCwd);
    00191     }
    00192
    00193     sqlInRoot = 0;
    00194 }
    00195
    00196 static void dbg_scp(void *ptr)
    00197         /*@globals stderr, fileSystem @*/
    00198         /*@modifies stderr, fileSystem @*/
    00199 {
    00200     SCP_t scp = ptr;
    00201
    00202 if (_debug)
    00203 fprintf(stderr, "\tscp %p [%d:%d] av %p avlen %p nr [%d:%d] nc %d all %d\n", scp, scp->ac, scp->nalloc, scp->av, scp->avlen, scp->rx, scp->nr, scp->nc, scp->all);
    00204
    00205 }
    00206
    00207 static void dbg_keyval(const char * msg, dbiIndex dbi, /*@null@*/ DBC * dbcursor,
    00208                 DBT * key, DBT * data, unsigned int flags)
    00209         /*@globals stderr, fileSystem @*/
    00210         /*@modifies stderr, fileSystem @*/
    00211 {
    00212
    00213 if (!_debug) return;
    00214
    00215     fprintf(stderr, "%s on %s (%p,%p,%p,0x%x)", msg, dbi->dbi_subfile, dbcursor, key, data, flags);
    00216
    00217     /* XXX FIXME: ptr alignment is fubar here. */
    00218     if (key != NULL && key->data != NULL) {
    00219         fprintf(stderr, "  key 0x%x[%d]", *(unsigned int *)key->data, key->size);
    00220         if (dbi->dbi_rpmtag == RPMTAG_NAME)
    00221             fprintf(stderr, " \"%s\"", (const char *)key->data);
    00222     }
    00223     if (data != NULL && data->data != NULL)
    00224         fprintf(stderr, " data 0x%x[%d]", *(unsigned int *)data->data, data->size);
    00225
    00226     fprintf(stderr, "\n");
    00227     if (dbcursor != NULL)
    00228         dbg_scp(dbcursor);
    00229 }
    00230
    00231 /*@only@*/
    00232 static SCP_t scpResetKeys(/*@only@*/ SCP_t scp)
    00233         /*@modifies scp @*/
    00234 {
    00235     int ix;
    00236
    00237 if (_debug)
    00238 fprintf(stderr, "*** scpResetKeys(%p)\n", scp);
    00239 dbg_scp(scp);
    00240
    00241     for ( ix =0 ; ix < scp->nkeys ; ix++ ) {
    00242       scp->keys[ix]->data = _free(scp->keys[ix]->data);
    00243 /*@-unqualifiedtrans@*/
    00244       scp->keys[ix] = _free(scp->keys[ix]);
    00245 /*@=unqualifiedtrans@*/
    00246     }
    00247     scp->keys = _free(scp->keys);
    00248     scp->nkeys = 0;
    00249
    00250     return scp;
    00251 }
    00252
    00253 /*@only@*/
    00254 static SCP_t scpResetAv(/*@only@*/ SCP_t scp)
    00255         /*@modifies scp @*/
    00256 {
    00257     int xx;
    00258
    00259 if (_debug)
    00260 fprintf(stderr, "*** scpResetAv(%p)\n", scp);
    00261 dbg_scp(scp);
    00262
    00263     if (scp->av != NULL) {
    00264         if (scp->nalloc <= 0) {
    00265             /* Clean up SCP_t used by sqlite3_get_table(). */
    00266             sqlite3_free_table(scp->av);
    00267             scp->av = NULL;
    00268             scp->nalloc = 0;
    00269         } else {
    00270             /* Clean up SCP_t used by sql_step(). */
    00271 /*@-unqualifiedtrans@*/
    00272             for (xx = 0; xx < scp->ac; xx++)
    00273                 scp->av[xx] = _free(scp->av[xx]);
    00274 /*@=unqualifiedtrans@*/
    00275             if (scp->av != NULL)
    00276                 memset(scp->av, 0, scp->nalloc * sizeof(*scp->av));
    00277             if (scp->avlen != NULL)
    00278                 memset(scp->avlen, 0, scp->nalloc * sizeof(*scp->avlen));
    00279             scp->av = _free(scp->av);
    00280             scp->avlen = _free(scp->avlen);
    00281             scp->nalloc = 0;
    00282         }
    00283     } else
    00284         scp->nalloc = 0;
    00285     scp->ac = 0;
    00286     scp->nr = 0;
    00287     scp->nc = 0;
    00288
    00289     return scp;
    00290 }
    00291
    00292 /*@only@*/
    00293 static SCP_t scpReset(/*@only@*/ SCP_t scp)
    00294         /*@modifies scp @*/
    00295 {
    00296     int xx;
    00297
    00298 if (_debug)
    00299 fprintf(stderr, "*** scpReset(%p)\n", scp);
    00300 dbg_scp(scp);
    00301
    00302     if (scp->cmd) {
    00303         sqlite3_free(scp->cmd);
    00304         scp->cmd = NULL;
    00305     }
    00306     if (scp->pStmt) {
    00307         xx = sqlite3_reset(scp->pStmt);
    00308         if (xx) rpmlog(RPMLOG_WARNING, "reset %d\n", xx);
    00309         xx = sqlite3_finalize(scp->pStmt);
    00310         if (xx) rpmlog(RPMLOG_WARNING, "finalize %d\n", xx);
    00311         scp->pStmt = NULL;
    00312     }
    00313
    00314     scp = scpResetAv(scp);
    00315
    00316     scp->rx = 0;
    00317     return scp;
    00318 }
    00319
    00320 /*@null@*/
    00321 static SCP_t scpFree(/*@only@*/ SCP_t scp)
    00322         /*@modifies scp @*/
    00323 {
    00324     scp = scpReset(scp);
    00325     scp = scpResetKeys(scp);
    00326     scp->av = _free(scp->av);
    00327     scp->avlen = _free(scp->avlen);
    00328
    00329 if (_debug)
    00330 fprintf(stderr, "*** scpFree(%p)\n", scp);
    00331     scp = _free(scp);
    00332     return NULL;
    00333 }
    00334
    00335 static SCP_t scpNew(DB * dbp)
    00336         /*@*/
    00337 {
    00338     SCP_t scp = xcalloc(1, sizeof(*scp));
    00339 /*@-temptrans@*/
    00340     scp->dbp = dbp;
    00341 /*@=temptrans@*/
    00342
    00343     scp->used = 0;
    00344
    00345     scp->lkey = NULL;
    00346     scp->ldata = NULL;
    00347
    00348 if (_debug)
    00349 fprintf(stderr, "*** scpNew(%p)\n", scp);
    00350     return scp;
    00351 }
    00352
    00353 static int sql_step(dbiIndex dbi, SCP_t scp)
    00354         /*@modifies dbi, scp @*/
    00355 {
    00356     int swapped = dbiByteSwapped(dbi);
    00357     const char * cname;
    00358     const char * vtype;
    00359     size_t nb;
    00360     int loop;
    00361     int need;
    00362     int rc;
    00363     int i;
    00364
    00365     scp->nc = sqlite3_column_count(scp->pStmt);
    00366
    00367     if (scp->nr == 0 && scp->av != NULL)
    00368         need = 2 * scp->nc;
    00369     else
    00370         need = scp->nc;
    00371
    00372     /* XXX scp->nc = need = scp->nalloc = 0 case forces + 1 here */
    00373     if (!scp->ac && !need && !scp->nalloc)
    00374         need++;
    00375
    00376     if (scp->ac + need >= scp->nalloc) {
    00377         /* XXX +4 is bogus, was +1 */
    00378         scp->nalloc = 2 * scp->nalloc + need + 4;
    00379         scp->av = xrealloc(scp->av, scp->nalloc * sizeof(*scp->av));
    00380         scp->avlen = xrealloc(scp->avlen, scp->nalloc * sizeof(*scp->avlen));
    00381     }
    00382
    00383     if (scp->av != NULL && scp->nr == 0) {
    00384         for (i = 0; i < scp->nc; i++) {
    00385             scp->av[scp->ac] = xstrdup(sqlite3_column_name(scp->pStmt, i));
    00386             if (scp->avlen) scp->avlen[scp->ac] = strlen(scp->av[scp->ac]) + 1;
    00387             scp->ac++;
    00388 assert(scp->ac <= scp->nalloc);
    00389         }
    00390     }
    00391
    00392 /*@-infloopsuncon@*/
    00393     loop = 1;
    00394     while (loop) {
    00395         rc = sqlite3_step(scp->pStmt);
    00396         switch (rc) {
    00397         case SQLITE_DONE:
    00398 if (_debug)
    00399 fprintf(stderr, "sqlite3_step: DONE scp %p [%d:%d] av %p avlen %p\n", scp, scp->ac, scp->nalloc, scp->av, scp->avlen);
    00400             loop = 0;
    00401             /*@switchbreak@*/ break;
    00402         case SQLITE_ROW:
    00403             if (scp->av != NULL)
    00404             for (i = 0; i < scp->nc; i++) {
    00405                 /* Expand the row array for new elements */
    00406                 if (scp->ac + need >= scp->nalloc) {
    00407                     /* XXX +4 is bogus, was +1 */
    00408                     scp->nalloc = 2 * scp->nalloc + need + 4;
    00409                     scp->av = xrealloc(scp->av, scp->nalloc * sizeof(*scp->av));
    00410                     scp->avlen = xrealloc(scp->avlen, scp->nalloc * sizeof(*scp->avlen));
    00411                 }
    00412 assert(scp->av != NULL);
    00413 assert(scp->avlen != NULL);
    00414
    00415                 cname = sqlite3_column_name(scp->pStmt, i);
    00416                 vtype = sqlite3_column_decltype(scp->pStmt, i);
    00417                 nb = 0;
    00418
    00419                 if (!strcmp(vtype, "blob")) {
    00420                     const void * v = sqlite3_column_blob(scp->pStmt, i);
    00421                     nb = sqlite3_column_bytes(scp->pStmt, i);
    00422 if (_debug)
    00423 fprintf(stderr, "\t%d %s %s %p[%d]\n", i, cname, vtype, v, (int)nb);
    00424                     if (nb > 0) {
    00425                         void * t = xmalloc(nb);
    00426                         scp->av[scp->ac] = memcpy(t, v, nb);
    00427                         scp->avlen[scp->ac] = nb;
    00428                         scp->ac++;
    00429                     }
    00430                 } else
    00431                 if (!strcmp(vtype, "double")) {
    00432                     double v = sqlite3_column_double(scp->pStmt, i);
    00433                     nb = sizeof(v);
    00434 if (_debug)
    00435 fprintf(stderr, "\t%d %s %s %g\n", i, cname, vtype, v);
    00436                     if (nb > 0) {
    00437                         scp->av[scp->ac] = memcpy(xmalloc(nb), &v, nb);
    00438                         scp->avlen[scp->ac] = nb;
    00439 assert(swapped == 0); /* Byte swap?! */
    00440                         scp->ac++;
    00441                     }
    00442                 } else
    00443                 if (!strcmp(vtype, "int")) {
    00444                     rpmint32_t v = sqlite3_column_int(scp->pStmt, i);
    00445                     nb = sizeof(v);
    00446 if (_debug)
    00447 fprintf(stderr, "\t%d %s %s %d\n", i, cname, vtype, (int) v);
    00448                     if (nb > 0) {
    00449                         scp->av[scp->ac] = memcpy(xmalloc(nb), &v, nb);
    00450                         scp->avlen[scp->ac] = nb;
    00451 if (swapped == 1) {
    00452   union _dbswap dbswap;
    00453   memcpy(&dbswap.ui, scp->av[scp->ac], sizeof(dbswap.ui));
    00454   _DBSWAP(dbswap);
    00455   memcpy(scp->av[scp->ac], &dbswap.ui, sizeof(dbswap.ui));
    00456 }
    00457                         scp->ac++;
    00458                     }
    00459                 } else
    00460                 if (!strcmp(vtype, "int64")) {
    00461                     int64_t v = sqlite3_column_int64(scp->pStmt, i);
    00462                     nb = sizeof(v);
    00463 if (_debug)
    00464 fprintf(stderr, "\t%d %s %s %ld\n", i, cname, vtype, (long)v);
    00465                     if (nb > 0) {
    00466                         scp->av[scp->ac] = memcpy(xmalloc(nb), &v, nb);
    00467                         scp->avlen[scp->ac] = nb;
    00468 assert(swapped == 0); /* Byte swap?! */
    00469                         scp->ac++;
    00470                     }
    00471                 } else
    00472                 if (!strcmp(vtype, "text")) {
    00473                     const char * v = (const char *)sqlite3_column_text(scp->pStmt, i);
    00474                     nb = strlen(v) + 1;
    00475 if (_debug)
    00476 fprintf(stderr, "\t%d %s %s \"%s\"\n", i, cname, vtype, v);
    00477                     if (nb > 0) {
    00478                         scp->av[scp->ac] = memcpy(xmalloc(nb), v, nb);
    00479                         scp->avlen[scp->ac] = nb;
    00480                         scp->ac++;
    00481                     }
    00482                 }
    00483 assert(scp->ac <= scp->nalloc);
    00484             }
    00485             scp->nr++;
    00486             /*@switchbreak@*/ break;
    00487         case SQLITE_BUSY:
    00488             fprintf(stderr, "sqlite3_step: BUSY %d\n", rc);
    00489             /*@switchbreak@*/ break;
    00490         case SQLITE_ERROR:
    00491             fprintf(stderr, "sqlite3_step: ERROR %d -- %s\n", rc, scp->cmd);
    00492             fprintf(stderr, "              %s (%d)\n",
    00493                         sqlite3_errmsg(((SQL_DB*)dbi->dbi_db)->db), sqlite3_errcode(((SQL_DB*)dbi->dbi_db)->db));
    00494 /*@-nullpass@*/
    00495             fprintf(stderr, "              cwd '%s'\n", getcwd(NULL,0));
    00496 /*@=nullpass@*/
    00497             loop = 0;
    00498             /*@switchbreak@*/ break;
    00499         case SQLITE_MISUSE:
    00500             fprintf(stderr, "sqlite3_step: MISUSE %d\n", rc);
    00501             loop = 0;
    00502             /*@switchbreak@*/ break;
    00503         default:
    00504             fprintf(stderr, "sqlite3_step: rc %d\n", rc);
    00505             loop = 0;
    00506             /*@switchbreak@*/ break;
    00507         }
    00508     }
    00509 /*@=infloopsuncon@*/
    00510
    00511     if (rc == SQLITE_DONE)
    00512         rc = SQLITE_OK;
    00513
    00514     return rc;
    00515 }
    00516
    00517 static int sql_bind_key(dbiIndex dbi, SCP_t scp, int pos, DBT * key)
    00518         /*@modifies dbi, scp @*/
    00519 {
    00520     int swapped = dbiByteSwapped(dbi);
    00521     int rc = 0;
    00522     union _dbswap dbswap;
    00523
    00524 assert(key->data != NULL);
    00525     switch (dbi->dbi_rpmtag) {
    00526     case RPMDBI_PACKAGES:
    00527         {   unsigned int hnum;
    00528 /*@i@*/ assert(key->size == sizeof(rpmuint32_t));
    00529             memcpy(&hnum, key->data, sizeof(hnum));
    00530
    00531 if (swapped == 1) {
    00532   memcpy(&dbswap.ui, &hnum, sizeof(dbswap.ui));
    00533   _DBSWAP(dbswap);
    00534   memcpy(&hnum, &dbswap.ui, sizeof(dbswap.ui));
    00535 }
    00536             rc = sqlite3_bind_int(scp->pStmt, pos, hnum);
    00537         } break;
    00538     default:
    00539         switch (tagType(dbi->dbi_rpmtag) & RPM_MASK_TYPE) {
    00540         case RPM_BIN_TYPE:
    00541 /*@-castfcnptr -nullpass@*/ /* FIX: annotate sqlite. */
    00542             rc = sqlite3_bind_blob(scp->pStmt, pos, key->data, key->size, SQLITE_STATIC);
    00543 /*@=castfcnptr =nullpass@*/
    00544             /*@innerbreak@*/ break;
    00545         case RPM_UINT8_TYPE:
    00546         {   unsigned char i;
    00547 /*@i@*/ assert(key->size == sizeof(unsigned char));
    00548 assert(swapped == 0); /* Byte swap?! */
    00549             memcpy(&i, key->data, sizeof(i));
    00550             rc = sqlite3_bind_int(scp->pStmt, pos, (int) i);
    00551         } /*@innerbreak@*/ break;
    00552         case RPM_UINT16_TYPE:
    00553         {       unsigned short i;
    00554 /*@i@*/ assert(key->size == sizeof(rpmuint16_t));
    00555 assert(swapped == 0); /* Byte swap?! */
    00556             memcpy(&i, key->data, sizeof(i));
    00557             rc = sqlite3_bind_int(scp->pStmt, pos, (int) i);
    00558         } /*@innerbreak@*/ break;
    00559         case RPM_UINT64_TYPE:
    00560 assert(0);      /* borken */
    00561         /*@innerbreak@*/ break;
    00562         case RPM_UINT32_TYPE:
    00563         default:
    00564         {   unsigned int i;
    00565 /*@i@*/ assert(key->size == sizeof(rpmuint32_t));
    00566             memcpy(&i, key->data, sizeof(i));
    00567
    00568 if (swapped == 1)
    00569 {
    00570   memcpy(&dbswap.ui, &i, sizeof(dbswap.ui));
    00571   _DBSWAP(dbswap);
    00572   memcpy(&i, &dbswap.ui, sizeof(dbswap.ui));
    00573 }
    00574             rc = sqlite3_bind_int(scp->pStmt, pos, i);
    00575         }   /*@innerbreak@*/ break;
    00576         case RPM_STRING_TYPE:
    00577         case RPM_STRING_ARRAY_TYPE:
    00578         case RPM_I18NSTRING_TYPE:
    00579 /*@-castfcnptr -nullpass@*/ /* FIX: annotate sqlite. */
    00580             rc = sqlite3_bind_text(scp->pStmt, pos, key->data, key->size, SQLITE_STATIC);
    00581 /*@=castfcnptr =nullpass@*/
    00582             /*@innerbreak@*/ break;
    00583         }
    00584     }
    00585
    00586     return rc;
    00587 }
    00588
    00589 static int sql_bind_data(/*@unused@*/ dbiIndex dbi, SCP_t scp,
    00590                 int pos, DBT * data)
    00591         /*@modifies scp @*/
    00592 {
    00593     int rc;
    00594
    00595 assert(data->data != NULL);
    00596 /*@-castfcnptr -nullpass@*/ /* FIX: annotate sqlite */
    00597     rc = sqlite3_bind_blob(scp->pStmt, pos, data->data, data->size, SQLITE_STATIC);
    00598 /*@=castfcnptr =nullpass@*/
    00599
    00600     return rc;
    00601 }
    00602
    00603 /*===================================================================*/
    00604 /*
    00605  * Transaction support
    00606  */
    00607
    00608 static int sql_startTransaction(dbiIndex dbi)
    00609         /*@*/
    00610 {
    00611     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    00612     int rc = 0;
    00613
    00614     /* XXX:  Transaction Support */
    00615     if (!sqldb->transaction) {
    00616       char * pzErrmsg;
    00617       rc = sqlite3_exec(sqldb->db, "BEGIN TRANSACTION;", NULL, NULL, &pzErrmsg);
    00618
    00619 if (_debug)
    00620 fprintf(stderr, "Begin %s SQL transaction %s (%d)\n",
    00621                 dbi->dbi_subfile, pzErrmsg, rc);
    00622
    00623       if (rc == 0)
    00624         sqldb->transaction = 1;
    00625     }
    00626
    00627     return rc;
    00628 }
    00629
    00630 static int sql_endTransaction(dbiIndex dbi)
    00631         /*@*/
    00632 {
    00633     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    00634     int rc=0;
    00635
    00636     /* XXX:  Transaction Support */
    00637     if (sqldb->transaction) {
    00638       char * pzErrmsg;
    00639       rc = sqlite3_exec(sqldb->db, "END TRANSACTION;", NULL, NULL, &pzErrmsg);
    00640
    00641 if (_debug)
    00642 fprintf(stderr, "End %s SQL transaction %s (%d)\n",
    00643                 dbi->dbi_subfile, pzErrmsg, rc);
    00644
    00645       if (rc == 0)
    00646         sqldb->transaction = 0;
    00647     }
    00648
    00649     return rc;
    00650 }
    00651
    00652 static int sql_commitTransaction(dbiIndex dbi, int flag)
    00653         /*@*/
    00654 {
    00655     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    00656     int rc = 0;
    00657
    00658     /* XXX:  Transactions */
    00659     if ( sqldb->transaction ) {
    00660       char * pzErrmsg;
    00661       rc = sqlite3_exec(sqldb->db, "COMMIT;", NULL, NULL, &pzErrmsg);
    00662
    00663 if (_debug)
    00664 fprintf(stderr, "Commit %s SQL transaction(s) %s (%d)\n",
    00665                 dbi->dbi_subfile, pzErrmsg, rc);
    00666
    00667       sqldb->transaction=0;
    00668
    00669       /* Start a new transaction if we were in the middle of one */
    00670       if ( flag == 0 )
    00671         rc = sql_startTransaction(dbi);
    00672     }
    00673
    00674     return rc;
    00675 }
    00676
    00677 static int sql_busy_handler(void * dbi_void, int time)
    00678         /*@*/
    00679 {
    00680 /*@-castexpose@*/
    00681     dbiIndex dbi = (dbiIndex) dbi_void;
    00682 /*@=castexpose@*/
    00683
    00684     rpmlog(RPMLOG_WARNING, _("Unable to get lock on db %s, retrying... (%d)\n"),
    00685                 dbi->dbi_file, time);
    00686
    00687     (void) sleep(1);
    00688
    00689     return 1;
    00690 }
    00691
    00692 /*===================================================================*/
    00693
    00699 static int sql_initDB(dbiIndex dbi)
    00700         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00701         /*@modifies internalState @*/
    00702 {
    00703     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    00704     SCP_t scp = scpNew(dbi->dbi_db);
    00705     char cmd[BUFSIZ];
    00706     int rc = 0;
    00707
    00708     if (dbi->dbi_tmpdir) {
    00709         const char *root;
    00710         const char *tmpdir;
    00711         int xx;
    00712         root = (dbi->dbi_root ? dbi->dbi_root : dbi->dbi_rpmdb->db_root);
    00713         if ((root[0] == '/' && root[1] == '\0') || dbi->dbi_rpmdb->db_chrootDone)
    00714             root = NULL;
    00715         /*@-mods@*/
    00716         tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
    00717         /*@=mods@*/
    00718         sprintf(cmd, "PRAGMA temp_store_directory = '%s';", tmpdir);
    00719         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00720         tmpdir = _free(tmpdir);
    00721     }
    00722     if (dbi->dbi_eflags & DB_EXCL) {
    00723         int xx;
    00724         sprintf(cmd, "PRAGMA locking_mode = EXCLUSIVE;");
    00725         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00726     }
    00727     if (dbi->dbi_pagesize > 0) {
    00728         int xx;
    00729         sprintf(cmd, "PRAGMA cache_size = %d;", dbi->dbi_cachesize);
    00730         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00731     }
    00732     if (dbi->dbi_cachesize > 0) {
    00733         int xx;
    00734         sprintf(cmd, "PRAGMA page_size = %d;", dbi->dbi_pagesize);
    00735         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00736     }
    00737
    00738     /* Check if the table exists... */
    00739     sprintf(cmd,
    00740         "SELECT name FROM 'sqlite_master' WHERE type='table' and name='%s';",
    00741                 dbi->dbi_subfile);
    00742 /*@-nullstate@*/
    00743     rc = sqlite3_get_table(sqldb->db, cmd,
    00744         &scp->av, &scp->nr, &scp->nc, (char **)&scp->pzErrmsg);
    00745 /*@=nullstate@*/
    00746     if (rc)
    00747         goto exit;
    00748
    00749     if (scp->nr < 1) {
    00750         const char * valtype = "blob";
    00751         const char * keytype;
    00752
    00753         switch (dbi->dbi_rpmtag) {
    00754         case RPMDBI_PACKAGES:
    00755             keytype = "int UNIQUE PRIMARY KEY";
    00756             valtype = "blob";
    00757             break;
    00758         default:
    00759             switch (tagType(dbi->dbi_rpmtag) & RPM_MASK_TYPE) {
    00760             case RPM_BIN_TYPE:
    00761             default:
    00762                 keytype = "blob UNIQUE";
    00763                 /*@innerbreak@*/ break;
    00764             case RPM_UINT8_TYPE:
    00765             case RPM_UINT16_TYPE:
    00766             case RPM_UINT32_TYPE:
    00767             case RPM_UINT64_TYPE:
    00768                 keytype = "int UNIQUE";
    00769                 /*@innerbreak@*/ break;
    00770             case RPM_STRING_TYPE:
    00771             case RPM_STRING_ARRAY_TYPE:
    00772             case RPM_I18NSTRING_TYPE:
    00773                 keytype = "text UNIQUE";
    00774                 /*@innerbreak@*/ break;
    00775             }
    00776         }
    00777 if (_debug)
    00778 fprintf(stderr, "\t%s(%d) type(%d) keytype %s\n", tagName(dbi->dbi_rpmtag), dbi->dbi_rpmtag, (tagType(dbi->dbi_rpmtag) & RPM_MASK_TYPE), keytype);
    00779         sprintf(cmd, "CREATE %sTABLE '%s' (key %s, value %s)",
    00780                         dbi->dbi_temporary ? "TEMPORARY " : "",
    00781                         dbi->dbi_subfile, keytype, valtype);
    00782         rc = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00783         if (rc)
    00784             goto exit;
    00785
    00786         sprintf(cmd, "CREATE %sTABLE 'db_info' (endian TEXT)",
    00787                         dbi->dbi_temporary ? "TEMPORARY " : "");
    00788         rc = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00789         if (rc)
    00790             goto exit;
    00791
    00792         sprintf(cmd, "INSERT INTO 'db_info' values('%u')", (unsigned)((union _dbswap *)&endian)->uc[0]);
    00793         rc = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00794         if (rc)
    00795             goto exit;
    00796     }
    00797
    00798     if (dbi->dbi_no_fsync) {
    00799         int xx;
    00800         sprintf(cmd, "PRAGMA synchronous = OFF;");
    00801         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
    00802     }
    00803
    00804 exit:
    00805     if (rc)
    00806         rpmlog(RPMLOG_WARNING, "Unable to initDB %s (%d)\n",
    00807                 scp->pzErrmsg, rc);
    00808
    00809     scp = scpFree(scp);
    00810
    00811     return rc;
    00812 }
    00813
    00821 static int sql_cclose (dbiIndex dbi, /*@only@*/ DBC * dbcursor,
    00822                 unsigned int flags)
    00823         /*@globals fileSystem, internalState @*/
    00824         /*@modifies dbi, *dbcursor, fileSystem, internalState @*/
    00825 {
    00826     SCP_t scp = (SCP_t)dbcursor;
    00827     int rc;
    00828
    00829 if (_debug)
    00830 fprintf(stderr, "==> sql_cclose(%p)\n", scp);
    00831
    00832     if (scp->lkey)
    00833         scp->lkey = _free(scp->lkey);
    00834
    00835     if (scp->ldata)
    00836         scp->ldata = _free(scp->ldata);
    00837
    00838 enterChroot(dbi);
    00839
    00840     if (flags == DB_WRITECURSOR)
    00841         rc = sql_commitTransaction(dbi, 1);
    00842     else
    00843         rc = sql_endTransaction(dbi);
    00844
    00845 /*@-kepttrans -nullstate@*/
    00846     scp = scpFree(scp);
    00847 /*@=kepttrans =nullstate@*/
    00848
    00849 leaveChroot(dbi);
    00850
    00851     return rc;
    00852 }
    00853
    00860 static int sql_close(/*@only@*/ dbiIndex dbi, unsigned int flags)
    00861         /*@globals fileSystem, internalState @*/
    00862         /*@modifies dbi, fileSystem, internalState @*/
    00863 {
    00864     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    00865     int rc = 0;
    00866
    00867     if (sqldb) {
    00868 enterChroot(dbi);
    00869
    00870         /* Commit, don't open a new one */
    00871         rc = sql_commitTransaction(dbi, 1);
    00872
    00873         (void) sqlite3_close(sqldb->db);
    00874
    00875         rpmlog(RPMLOG_DEBUG, D_("closed   sql db         %s\n"),
    00876                 dbi->dbi_subfile);
    00877
    00878 #if defined(MAYBE) /* XXX should SQLite and BDB have different semantics? */
    00879         if (dbi->dbi_temporary && !(dbi->dbi_eflags & DB_PRIVATE)) {
    00880             const char * dbhome = NULL;
    00881             urltype ut = urlPath(dbi->dbi_home, &dbhome);
    00882             const char * dbfname = rpmGenPath(dbhome, dbi->dbi_file, NULL);
    00883             int xx = (dbfname ? Unlink(dbfname) : 0);
    00884             ut = ut; xx = xx;   /* XXX tell gcc to be quiet. */
    00885             dbfname = _free(dbfname);
    00886         }
    00887 #endif
    00888
    00889         dbi->dbi_stats = _free(dbi->dbi_stats);
    00890         dbi->dbi_file = _free(dbi->dbi_file);
    00891         dbi->dbi_db = _free(dbi->dbi_db);
    00892
    00893 leaveChroot(dbi);
    00894     }
    00895
    00896     dbi = _free(dbi);
    00897
    00898     return rc;
    00899 }
    00900
    00908 static int sql_open(rpmdb rpmdb, rpmTag rpmtag, /*@out@*/ dbiIndex * dbip)
    00909         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00910         /*@modifies *dbip, rpmGlobalMacroContext, fileSystem, internalState @*/
    00911 {
    00912 /*@-nestedextern -shadow @*/
    00913     extern struct _dbiVec sqlitevec;
    00914 /*@=nestedextern -shadow @*/
    00915
    00916     const char * urlfn = NULL;
    00917     const char * root;
    00918     const char * home;
    00919     const char * dbhome;
    00920     const char * dbfile;
    00921     const char * dbfname;
    00922     const char * sql_errcode;
    00923     mode_t umask_safed = 0002;
    00924     dbiIndex dbi;
    00925     SQL_DB * sqldb;
    00926     size_t len;
    00927     int rc = 0;
    00928     int xx;
    00929
    00930     if (dbip)
    00931         *dbip = NULL;
    00932
    00933     /*
    00934      * Parse db configuration parameters.
    00935      */
    00936     /*@-mods@*/
    00937     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
    00938         /*@-nullstate@*/
    00939         return 1;
    00940         /*@=nullstate@*/
    00941     /*@=mods@*/
    00942
    00943    /*
    00944      * Get the prefix/root component and directory path
    00945      */
    00946     root = rpmdb->db_root;
    00947     home = rpmdb->db_home;
    00948
    00949     dbi->dbi_root = root;
    00950     dbi->dbi_home = home;
    00951
    00952     dbfile = tagName(dbi->dbi_rpmtag);
    00953
    00954 enterChroot(dbi);
    00955
    00956     /*
    00957      * Make a copy of the tagName result..
    00958      * use this for the filename and table name
    00959      */
    00960     {
    00961       char * t;
    00962       len = strlen(dbfile);
    00963       t = xcalloc(len + 1, sizeof(*t));
    00964       (void) stpcpy( t, dbfile );
    00965       dbi->dbi_file = t;
    00966 /*@-kepttrans@*/ /* WRONG */
    00967       dbi->dbi_subfile = t;
    00968 /*@=kepttrans@*/
    00969     }
    00970
    00971     dbi->dbi_mode = O_RDWR;
    00972
    00973     /*
    00974      * Either the root or directory components may be a URL. Concatenate,
    00975      * convert the URL to a path, and add the name of the file.
    00976      */
    00977     /*@-mods@*/
    00978     urlfn = rpmGenPath(NULL, home, NULL);
    00979     /*@=mods@*/
    00980     (void) urlPath(urlfn, &dbhome);
    00981
    00982     /*
    00983      * Create the /var/lib/rpm directory if it doesn't exist (root only).
    00984      */
    00985     (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
    00986
    00987     if (dbi->dbi_eflags & DB_PRIVATE)
    00988         dbfname = xstrdup(":memory:");
    00989     else
    00990         dbfname = rpmGenPath(dbhome, dbi->dbi_file, NULL);
    00991
    00992     rpmlog(RPMLOG_DEBUG, D_("opening  sql db         %s (%s) mode=0x%x\n"),
    00993                 dbfname, dbi->dbi_subfile, dbi->dbi_mode);
    00994
    00995     /* Open the Database */
    00996     sqldb = xcalloc(1, sizeof(*sqldb));
    00997
    00998     sql_errcode = NULL;
    00999 /*@+longunsignedintegral@*/
    01000     if (dbi->dbi_perms)
    01001         /* mask-out permission bits which are not requested (security) */
    01002         umask_safed = umask(~((mode_t)(dbi->dbi_perms)));
    01003 /*@=longunsignedintegral@*/
    01004     xx = sqlite3_open(dbfname, &sqldb->db);
    01005     if (dbi->dbi_perms) {
    01006         if ((0644 /* = SQLite hard-coded default */ & dbi->dbi_perms) != dbi->dbi_perms) {
    01007             /* add requested permission bits which are still missing (semantic) */
    01008             (void) Chmod(dbfname, dbi->dbi_perms);
    01009         }
    01010 /*@+longunsignedintegral@*/
    01011         (void) umask(umask_safed);
    01012 /*@=longunsignedintegral@*/
    01013     }
    01014     if (xx != SQLITE_OK)
    01015         sql_errcode = sqlite3_errmsg(sqldb->db);
    01016
    01017     if (sqldb->db)
    01018         (void) sqlite3_busy_handler(sqldb->db, &sql_busy_handler, dbi);
    01019
    01020     sqldb->transaction = 0;     /* Initialize no current transactions */
    01021
    01022     dbi->dbi_db = (DB *)sqldb;
    01023
    01024     if (sql_errcode != NULL) {
    01025       rpmlog(RPMLOG_DEBUG, D_("Unable to open database: %s\n"), sql_errcode);
    01026       rc = EINVAL;
    01027     }
    01028
    01029     /* initialize table */
    01030     if (rc == 0)
    01031         rc = sql_initDB(dbi);
    01032
    01033     if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
    01034         dbi->dbi_vec = &sqlitevec;
    01035         *dbip = dbi;
    01036     } else {
    01037         (void) sql_close(dbi, 0);
    01038     }
    01039
    01040     urlfn = _free(urlfn);
    01041     dbfname = _free(dbfname);
    01042
    01043 /*@-usereleased@*/
    01044 leaveChroot(dbi);
    01045 /*@=usereleased@*/
    01046
    01047     return rc;
    01048 }
    01049
    01056 static int sql_sync (dbiIndex dbi, /*@unused@*/ unsigned int flags)
    01057         /*@globals fileSystem, internalState @*/
    01058         /*@modifies fileSystem, internalState @*/
    01059 {
    01060     int rc = 0;
    01061
    01062 enterChroot(dbi);
    01063     rc = sql_commitTransaction(dbi, 0);
    01064 leaveChroot(dbi);
    01065
    01066     return rc;
    01067 }
    01068
    01077 static int sql_copen (dbiIndex dbi,
    01078                 /*@unused@*/ /*@null@*/ DB_TXN * txnid,
    01079                 /*@out@*/ DBC ** dbcp, unsigned int flags)
    01080         /*@globals fileSystem, internalState @*/
    01081         /*@modifies dbi, *txnid, *dbcp, fileSystem, internalState @*/
    01082 {
    01083     SCP_t scp = scpNew(dbi->dbi_db);
    01084     DBC * dbcursor = (DBC *)scp;
    01085     int rc = 0;
    01086
    01087 if (_debug)
    01088 fprintf(stderr, "==> sql_copen(%s) tag %d type %d scp %p\n", tagName(dbi->dbi_rpmtag), dbi->dbi_rpmtag, (tagType(dbi->dbi_rpmtag) & RPM_MASK_TYPE), scp);
    01089
    01090 enterChroot(dbi);
    01091
    01092     /* If we're going to write, start a transaction (lock the DB) */
    01093     if (flags == DB_WRITECURSOR)
    01094         rc = sql_startTransaction(dbi);
    01095
    01096     if (dbcp)
    01097         /*@-onlytrans@*/ *dbcp = dbcursor; /*@=onlytrans@*/
    01098     else
    01099         /*@-kepttrans -nullstate @*/ (void) sql_cclose(dbi, dbcursor, 0); /*@=kepttrans =nullstate @*/
    01100
    01101 leaveChroot(dbi);
    01102
    01103     return rc;
    01104 }
    01105
    01115 static int sql_cdel (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key,
    01116                 DBT * data, unsigned int flags)
    01117         /*@globals fileSystem, internalState @*/
    01118         /*@modifies dbi, *dbcursor, fileSystem, internalState @*/
    01119 {
    01120 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    01121     SCP_t scp = scpNew(dbi->dbi_db);
    01122     int rc = 0;
    01123
    01124 dbg_keyval("sql_cdel", dbi, dbcursor, key, data, flags);
    01125 enterChroot(dbi);
    01126
    01127     scp->cmd = sqlite3_mprintf("DELETE FROM '%q' WHERE key=? AND value=?;",
    01128         dbi->dbi_subfile);
    01129
    01130     rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
    01131     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) prepare %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01132     rc = sql_bind_key(dbi, scp, 1, key);
    01133     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) bind key %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01134     rc = sql_bind_data(dbi, scp, 2, data);
    01135     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) bind data %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01136
    01137     rc = sql_step(dbi, scp);
    01138     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) sql_step rc %d\n", dbi->dbi_subfile, rc);
    01139
    01140     scp = scpFree(scp);
    01141
    01142 leaveChroot(dbi);
    01143
    01144     return rc;
    01145 }
    01146
    01156 static int sql_cget (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key,
    01157                 DBT * data, unsigned int flags)
    01158         /*@globals fileSystem, internalState @*/
    01159         /*@modifies dbi, dbcursor, *key, *data, fileSystem, internalState @*/
    01160 {
    01161 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    01162     SCP_t scp = (SCP_t)dbcursor;
    01163     int rc = 0;
    01164     int ix;
    01165
    01166 assert(dbcursor != NULL);
    01167 dbg_keyval("sql_cget", dbi, dbcursor, key, data, flags);
    01168
    01169 enterChroot(dbi);
    01170
    01171     /*
    01172      * First determine if this is a new scan or existing scan
    01173      */
    01174
    01175 if (_debug)
    01176 fprintf(stderr, "\tcget(%s) scp %p rc %d flags %d av %p\n",
    01177                 dbi->dbi_subfile, scp, rc, flags, scp->av);
    01178     if ( flags == DB_SET || scp->used == 0 ) {
    01179         scp->used = 1; /* Signal this scp as now in use... */
    01180 /*@i@*/ scp = scpReset(scp);    /* Free av and avlen, reset counters.*/
    01181
    01182 /* XXX: Should we also reset the key table here?  Can you re-use a cursor? */
    01183
    01184         /*
    01185          * If we're scanning everything, load the iterator key table
    01186          */
    01187         if ( key->size == 0) {
    01188             scp->all = 1;
    01189
    01190 /*
    01191  * The only condition not dealt with is if there are multiple identical keys.  This can lead
    01192  * to later iteration confusion.  (It may return the same value for the multiple keys.)
    01193  */
    01194
    01195 #ifdef  DYING
    01196 /* Only RPMDBI_PACKAGES is supposed to be iterating, and this is guarenteed to be unique */
    01197 assert(dbi->dbi_rpmtag == RPMDBI_PACKAGES);
    01198 #endif
    01199
    01200             switch (dbi->dbi_rpmtag) {
    01201             case RPMDBI_PACKAGES:
    01202                 scp->cmd = sqlite3_mprintf("SELECT key FROM '%q' ORDER BY key;",
    01203                     dbi->dbi_subfile);
    01204                 break;
    01205             default:
    01206                 scp->cmd = sqlite3_mprintf("SELECT key FROM '%q';",
    01207                     dbi->dbi_subfile);
    01208                 break;
    01209             }
    01210             rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
    01211             if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) sequential prepare %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01212
    01213             rc = sql_step(dbi, scp);
    01214             if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) sequential sql_step rc %d\n", dbi->dbi_subfile, rc);
    01215
    01216             scp = scpResetKeys(scp);
    01217             scp->nkeys = scp->nr;
    01218             scp->keys = xcalloc(scp->nkeys, sizeof(*scp->keys));
    01219             for (ix = 0; ix < scp->nkeys; ix++) {
    01220                 scp->keys[ix] = xmalloc(sizeof(*scp->keys[0]));
    01221                 scp->keys[ix]->size = (UINT32_T) scp->avlen[ix+1];
    01222                 scp->keys[ix]->data = xmalloc(scp->keys[ix]->size);
    01223                 memcpy(scp->keys[ix]->data, scp->av[ix+1], scp->avlen[ix+1]);
    01224             }
    01225         } else {
    01226             /*
    01227              * We're only scanning ONE element
    01228              */
    01229             scp = scpResetKeys(scp);
    01230             scp->nkeys = 1;
    01231             scp->keys = xcalloc(scp->nkeys, sizeof(*scp->keys));
    01232             scp->keys[0] = xmalloc(sizeof(*scp->keys[0]));
    01233             scp->keys[0]->size = key->size;
    01234             scp->keys[0]->data = xmalloc(scp->keys[0]->size);
    01235             memcpy(scp->keys[0]->data, key->data, key->size);
    01236         }
    01237
    01238 /*@i@*/ scp = scpReset(scp);    /* reset */
    01239
    01240         /* Prepare SQL statement to retrieve the value for the current key */
    01241         scp->cmd = sqlite3_mprintf("SELECT value FROM '%q' WHERE key=?;", dbi->dbi_subfile);
    01242         rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
    01243
    01244         if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) prepare %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01245     }
    01246
    01247 /*@i@*/ scp = scpResetAv(scp);  /* Free av and avlen, reset counters.*/
    01248
    01249     /* Now continue with a normal retrive based on key */
    01250     if ((scp->rx + 1) > scp->nkeys )
    01251         rc = DB_NOTFOUND; /* At the end of the list */
    01252
    01253     if (rc != 0)
    01254         goto exit;
    01255
    01256     /* Bind key to prepared statement */
    01257     rc = sql_bind_key(dbi, scp, 1, scp->keys[scp->rx]);
    01258     if (rc) rpmlog(RPMLOG_WARNING, "cget(%s)  key bind %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01259
    01260     rc = sql_step(dbi, scp);
    01261     if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) sql_step rc %d\n", dbi->dbi_subfile, rc);
    01262
    01263     rc = sqlite3_reset(scp->pStmt);
    01264     if (rc) rpmlog(RPMLOG_WARNING, "reset %d\n", rc);
    01265
    01266 /* 1 key should return 0 or 1 row/value */
    01267 assert(scp->nr < 2);
    01268
    01269     if (scp->nr == 0 && scp->all == 0)
    01270         rc = DB_NOTFOUND; /* No data for that key found! */
    01271
    01272     if (rc != 0)
    01273         goto exit;
    01274
    01275     /* If we're looking at the whole db, return the key */
    01276     if (scp->all) {
    01277
    01278 /* To get this far there has to be _1_ key returned! (protect against dup keys) */
    01279 assert(scp->nr == 1);
    01280
    01281         if ( scp->lkey ) {
    01282             scp->lkey = _free(scp->lkey);
    01283         }
    01284
    01285         key->size = scp->keys[scp->rx]->size;
    01286         key->data = xmalloc(key->size);
    01287         if (! (key->flags & DB_DBT_MALLOC))
    01288             scp->lkey = key->data;
    01289
    01290         (void) memcpy(key->data, scp->keys[scp->rx]->data, key->size);
    01291     }
    01292
    01293     /* Construct and return the data element (element 0 is "value", 1 is _THE_ value)*/
    01294     switch (dbi->dbi_rpmtag) {
    01295     default:
    01296         if ( scp->ldata ) {
    01297             scp->ldata = _free(scp->ldata);
    01298         }
    01299
    01300         data->size = (UINT32_T) scp->avlen[1];
    01301         data->data = xmalloc(data->size);
    01302         if (! (data->flags & DB_DBT_MALLOC) )
    01303             scp->ldata = data->data;
    01304
    01305         (void) memcpy(data->data, scp->av[1], data->size);
    01306     }
    01307
    01308     scp->rx++;
    01309
    01310     /* XXX FIXME: ptr alignment is fubar here. */
    01311 if (_debug)
    01312 fprintf(stderr, "\tcget(%s) found  key 0x%x (%d)\n", dbi->dbi_subfile,
    01313                 key->data == NULL ? 0 : *(unsigned int *)key->data, key->size);
    01314 if (_debug)
    01315 fprintf(stderr, "\tcget(%s) found data 0x%x (%d)\n", dbi->dbi_subfile,
    01316                 key->data == NULL ? 0 : *(unsigned int *)data->data, data->size);
    01317
    01318 exit:
    01319     if (rc == DB_NOTFOUND) {
    01320 if (_debug)
    01321 fprintf(stderr, "\tcget(%s) not found\n", dbi->dbi_subfile);
    01322     }
    01323
    01324 leaveChroot(dbi);
    01325
    01326     return rc;
    01327 }
    01328
    01338 static int sql_cput (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key,
    01339                         DBT * data, unsigned int flags)
    01340         /*@globals fileSystem, internalState @*/
    01341         /*@modifies dbi, *dbcursor, fileSystem, internalState @*/
    01342 {
    01343 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    01344     SCP_t scp = scpNew(dbi->dbi_db);
    01345     int rc = 0;
    01346
    01347 dbg_keyval("sql_cput", dbi, dbcursor, key, data, flags);
    01348
    01349 enterChroot(dbi);
    01350
    01351     switch (dbi->dbi_rpmtag) {
    01352     default:
    01353         scp->cmd = sqlite3_mprintf("INSERT OR REPLACE INTO '%q' VALUES(?, ?);",
    01354                 dbi->dbi_subfile);
    01355         rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
    01356         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s) prepare %s (%d)\n",dbi->dbi_subfile,  sqlite3_errmsg(sqldb->db), rc);
    01357         rc = sql_bind_key(dbi, scp, 1, key);
    01358         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s)  key bind %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01359         rc = sql_bind_data(dbi, scp, 2, data);
    01360         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s) data bind %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
    01361
    01362         rc = sql_step(dbi, scp);
    01363         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s) sql_step rc %d\n", dbi->dbi_subfile, rc);
    01364
    01365         break;
    01366     }
    01367
    01368     scp = scpFree(scp);
    01369
    01370 leaveChroot(dbi);
    01371
    01372     return rc;
    01373 }
    01374
    01380 static int sql_byteswapped (dbiIndex dbi)
    01381         /*@globals fileSystem, internalState @*/
    01382         /*@modifies fileSystem, internalState @*/
    01383 {
    01384     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    01385     SCP_t scp = scpNew(dbi->dbi_db);
    01386     int sql_rc, rc = 0;
    01387     union _dbswap db_endian;
    01388
    01389 enterChroot(dbi);
    01390
    01391 /*@-nullstate@*/
    01392     sql_rc = sqlite3_get_table(sqldb->db, "SELECT endian FROM 'db_info';",
    01393         &scp->av, &scp->nr, &scp->nc, (char **)&scp->pzErrmsg);
    01394 /*@=nullstate@*/
    01395
    01396     if (sql_rc == 0 && scp->nr > 0) {
    01397 assert(scp->av != NULL);
    01398         db_endian.uc[0] = (unsigned char) strtol(scp->av[1], NULL, 10);
    01399
    01400         if ( db_endian.uc[0] == ((union _dbswap *)&endian)->uc[0] )
    01401             rc = 0; /* Native endian */
    01402         else
    01403             rc = 1; /* swapped */
    01404
    01405     } else {
    01406         if ( sql_rc ) {
    01407             rpmlog(RPMLOG_DEBUG, D_("db_info failed %s (%d)\n"),
    01408                 scp->pzErrmsg, sql_rc);
    01409         }
    01410         rpmlog(RPMLOG_WARNING, "Unable to determine DB endian.\n");
    01411     }
    01412
    01413     scp = scpFree(scp);
    01414
    01415 leaveChroot(dbi);
    01416
    01417     return rc;
    01418 }
    01419
    01420 /**************************************************
    01421  *
    01422  *  All of the following are not implemented!
    01423  *  they are not used by the rest of the system
    01424  *
    01425  **************************************************/
    01426
    01435 static int sql_associate (/*@unused@*/ dbiIndex dbi,
    01436                 /*@unused@*/ dbiIndex dbisecondary,
    01437     /*@unused@*/int (*callback) (DB *, const DBT *, const DBT *, DBT *),
    01438                 /*@unused@*/ unsigned int flags)
    01439         /*@*/
    01440 {
    01441 if (_debug)
    01442 fprintf(stderr, "*** sql_associate:\n");
    01443     return EINVAL;
    01444 }
    01445
    01454 static int sql_join (/*@unused@*/ dbiIndex dbi,
    01455                 /*@unused@*/ DBC ** curslist,
    01456                 /*@unused@*/ /*@out@*/ DBC ** dbcp,
    01457                 /*@unused@*/ unsigned int flags)
    01458         /*@globals fileSystem @*/
    01459         /*@modifies dbi, *dbcp, fileSystem @*/
    01460 {
    01461 if (_debug)
    01462 fprintf(stderr, "*** sql_join:\n");
    01463     return EINVAL;
    01464 }
    01465
    01474 static int sql_cdup (/*@unused@*/ dbiIndex dbi,
    01475                 /*@unused@*/ DBC * dbcursor,
    01476                 /*@unused@*/ /*@out@*/ DBC ** dbcp,
    01477                 /*@unused@*/ unsigned int flags)
    01478         /*@globals fileSystem @*/
    01479         /*@modifies dbi, *dbcp, fileSystem @*/
    01480 {
    01481 if (_debug)
    01482 fprintf(stderr, "*** sql_cdup:\n");
    01483     return EINVAL;
    01484 }
    01485
    01496 static int sql_cpget (/*@unused@*/ dbiIndex dbi,
    01497                 /*@unused@*/ /*@null@*/ DBC * dbcursor,
    01498                 /*@unused@*/ DBT * key,
    01499                 /*@unused@*/ DBT * pkey,
    01500                 /*@unused@*/ DBT * data,
    01501                 /*@unused@*/ unsigned int flags)
    01502         /*@globals fileSystem @*/
    01503         /*@modifies *dbcursor, *key, *pkey, *data, fileSystem @*/
    01504 {
    01505 if (_debug)
    01506 fprintf(stderr, "*** sql_cpget:\n");
    01507     return EINVAL;
    01508 }
    01509
    01518 static int sql_ccount (/*@unused@*/ dbiIndex dbi,
    01519                 /*@unused@*/ DBC * dbcursor,
    01520                 /*@unused@*/ /*@out@*/ unsigned int * countp,
    01521                 /*@unused@*/ unsigned int flags)
    01522         /*@globals fileSystem @*/
    01523         /*@modifies *dbcursor, fileSystem @*/
    01524 {
    01525 if (_debug)
    01526 fprintf(stderr, "*** sql_ccount:\n");
    01527     return EINVAL;
    01528 }
    01529
    01536 static int sql_stat (dbiIndex dbi, /*@unused@*/ unsigned int flags)
    01537         /*@globals fileSystem, internalState @*/
    01538         /*@modifies dbi, fileSystem, internalState @*/
    01539 {
    01540 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
    01541     SCP_t scp = scpNew(dbi->dbi_db);
    01542     int rc = 0;
    01543     long nkeys = -1;
    01544
    01545 enterChroot(dbi);
    01546
    01547     dbi->dbi_stats = _free(dbi->dbi_stats);
    01548
    01549 /*@-sizeoftype@*/
    01550     dbi->dbi_stats = xcalloc(1, sizeof(DB_HASH_STAT));
    01551 /*@=sizeoftype@*/
    01552
    01553     scp->cmd = sqlite3_mprintf("SELECT COUNT('key') FROM '%q';", dbi->dbi_subfile);
    01554 /*@-nullstate@*/
    01555     rc = sqlite3_get_table(sqldb->db, scp->cmd,
    01556                 &scp->av, &scp->nr, &scp->nc, (char **)&scp->pzErrmsg);
    01557 /*@=nullstate@*/
    01558
    01559     if ( rc == 0 && scp->nr > 0) {
    01560 assert(scp->av != NULL);
    01561         nkeys = strtol(scp->av[1], NULL, 10);
    01562
    01563         rpmlog(RPMLOG_DEBUG, D_("  stat on %s nkeys %ld\n"),
    01564                 dbi->dbi_subfile, nkeys);
    01565     } else {
    01566         if ( rc ) {
    01567             rpmlog(RPMLOG_DEBUG, D_("stat failed %s (%d)\n"),
    01568                 scp->pzErrmsg, rc);
    01569         }
    01570     }
    01571
    01572     if (nkeys < 0)
    01573         nkeys = 4096;  /* Good high value */
    01574
    01575     ((DB_HASH_STAT *)(dbi->dbi_stats))->hash_nkeys = nkeys;
    01576
    01577     scp = scpFree(scp);
    01578
    01579 leaveChroot(dbi);
    01580
    01581     return rc;
    01582 }
    01583
    01584 /* Major, minor, patch version of DB.. we're not using db.. so set to 0 */
    01585 /* open, close, sync, associate, join */
    01586 /* cursor_open, cursor_close, cursor_dup, cursor_delete, cursor_get, */
    01587 /* cursor_pget?, cursor_put, cursor_count */
    01588 /* db_bytewapped, stat */
    01589 /*@observer@*/ /*@unchecked@*/
    01590 struct _dbiVec sqlitevec = {
    01591     0, 0, 0,
    01592     sql_open,
    01593     sql_close,
    01594     sql_sync,
    01595     sql_associate,
    01596     sql_join,
    01597     sql_copen,
    01598     sql_cclose,
    01599     sql_cdup,
    01600     sql_cdel,
    01601     sql_cget,
    01602     sql_cpget,
    01603     sql_cput,
    01604     sql_ccount,
    01605     sql_byteswapped,
    01606     sql_stat
    01607 };
    01608
    01609 /*@=evalorderuncon@*/
    01610 /*@=modfilesystem@*/
    01611 /*@=compmempass@*/
    01612 /*@=compdef@*/
    01613 /*@=moduncon@*/
    01614 /*@=noeffectuncon@*/
    01615 /*@=globuse@*/
    01616 /*@=paramuse@*/
    01617 /*@=mustmod@*/