rpm 5.2.1

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@*/