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

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