rpm 5.3.7

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 #ifdef  DYING
00728     if (dbi->dbi_pagesize > 0) {
00729         int xx;
00730         sprintf(cmd, "PRAGMA cache_size = %d;", dbi->dbi_cachesize);
00731         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
00732     }
00733     if (dbi->dbi_cachesize > 0) {
00734         int xx;
00735         sprintf(cmd, "PRAGMA page_size = %d;", dbi->dbi_pagesize);
00736         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
00737     }
00738 #endif
00739 
00740     /* Check if the table exists... */
00741     sprintf(cmd,
00742         "SELECT name FROM 'sqlite_master' WHERE type='table' and name='%s';",
00743                 dbi->dbi_subfile);
00744 /*@-nullstate@*/
00745     rc = sqlite3_get_table(sqldb->db, cmd,
00746         &scp->av, &scp->nr, &scp->nc, (char **)&scp->pzErrmsg);
00747 /*@=nullstate@*/
00748     if (rc)
00749         goto exit;
00750 
00751     if (scp->nr < 1) {
00752         const char * valtype = "blob";
00753         const char * keytype;
00754 
00755         switch (dbi->dbi_rpmtag) {
00756         case RPMDBI_PACKAGES:
00757             keytype = "int UNIQUE PRIMARY KEY";
00758             valtype = "blob";
00759             break;
00760         default:
00761             switch (tagType(dbi->dbi_rpmtag) & RPM_MASK_TYPE) {
00762             case RPM_BIN_TYPE:
00763             default:
00764                 keytype = "blob UNIQUE";
00765                 /*@innerbreak@*/ break;
00766             case RPM_UINT8_TYPE:
00767             case RPM_UINT16_TYPE:
00768             case RPM_UINT32_TYPE:
00769             case RPM_UINT64_TYPE:
00770                 keytype = "int UNIQUE";
00771                 /*@innerbreak@*/ break;
00772             case RPM_STRING_TYPE:
00773             case RPM_STRING_ARRAY_TYPE:
00774             case RPM_I18NSTRING_TYPE:
00775                 keytype = "text UNIQUE";
00776                 /*@innerbreak@*/ break;
00777             }
00778         }
00779 if (_debug)
00780 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);
00781         sprintf(cmd, "CREATE %sTABLE '%s' (key %s, value %s)",
00782                         dbi->dbi_temporary ? "TEMPORARY " : "",
00783                         dbi->dbi_subfile, keytype, valtype);
00784         rc = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
00785         if (rc)
00786             goto exit;
00787 
00788         sprintf(cmd, "CREATE %sTABLE 'db_info' (endian TEXT)",
00789                         dbi->dbi_temporary ? "TEMPORARY " : "");
00790         rc = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
00791         if (rc)
00792             goto exit;
00793 
00794         sprintf(cmd, "INSERT INTO 'db_info' values('%u')", (unsigned)((union _dbswap *)&endian)->uc[0]);
00795         rc = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
00796         if (rc)
00797             goto exit;
00798     }
00799 
00800     if (dbi->dbi_no_fsync) {
00801         int xx;
00802         sprintf(cmd, "PRAGMA synchronous = OFF;");
00803         xx = sqlite3_exec(sqldb->db, cmd, NULL, NULL, (char **)&scp->pzErrmsg);
00804     }
00805 
00806 exit:
00807     if (rc)
00808         rpmlog(RPMLOG_WARNING, "Unable to initDB %s (%d)\n",
00809                 scp->pzErrmsg, rc);
00810 
00811     scp = scpFree(scp);
00812 
00813     return rc;
00814 }
00815 
00823 static int sql_cclose (dbiIndex dbi, /*@only@*/ DBC * dbcursor,
00824                 unsigned int flags)
00825         /*@globals fileSystem, internalState @*/
00826         /*@modifies dbi, *dbcursor, fileSystem, internalState @*/
00827 {
00828     SCP_t scp = (SCP_t)dbcursor;
00829     int rc;
00830 
00831 if (_debug)
00832 fprintf(stderr, "==> sql_cclose(%p)\n", scp);
00833 
00834     if (scp->lkey)
00835         scp->lkey = _free(scp->lkey);
00836 
00837     if (scp->ldata)
00838         scp->ldata = _free(scp->ldata);
00839 
00840 enterChroot(dbi);
00841 
00842     if (flags == DB_WRITECURSOR)
00843         rc = sql_commitTransaction(dbi, 1);
00844     else
00845         rc = sql_endTransaction(dbi);
00846 
00847 /*@-kepttrans -nullstate@*/
00848     scp = scpFree(scp);
00849 /*@=kepttrans =nullstate@*/
00850 
00851 leaveChroot(dbi);
00852 
00853     return rc;
00854 }
00855 
00862 static int sql_close(/*@only@*/ dbiIndex dbi, unsigned int flags)
00863         /*@globals fileSystem, internalState @*/
00864         /*@modifies dbi, fileSystem, internalState @*/
00865 {
00866     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
00867     int rc = 0;
00868 
00869     if (sqldb) {
00870 enterChroot(dbi);
00871 
00872         /* Commit, don't open a new one */
00873         rc = sql_commitTransaction(dbi, 1);
00874 
00875         (void) sqlite3_close(sqldb->db);
00876 
00877         rpmlog(RPMLOG_DEBUG, D_("closed   sql db         %s\n"),
00878                 dbi->dbi_subfile);
00879 
00880 #if defined(MAYBE) /* XXX should SQLite and BDB have different semantics? */
00881         if (dbi->dbi_temporary && !(dbi->dbi_eflags & DB_PRIVATE)) {
00882             const char * dbhome = NULL;
00883             urltype ut = urlPath(dbi->dbi_home, &dbhome);
00884             const char * dbfname = rpmGenPath(dbhome, dbi->dbi_file, NULL);
00885             int xx = (dbfname ? Unlink(dbfname) : 0);
00886             ut = ut; xx = xx;   /* XXX tell gcc to be quiet. */
00887             dbfname = _free(dbfname);
00888         }
00889 #endif
00890 
00891         dbi->dbi_stats = _free(dbi->dbi_stats);
00892         dbi->dbi_file = _free(dbi->dbi_file);
00893         dbi->dbi_db = _free(dbi->dbi_db);
00894 
00895 leaveChroot(dbi);
00896     }
00897 
00898     dbi = _free(dbi);
00899 
00900     return rc;
00901 }
00902 
00910 static int sql_open(rpmdb rpmdb, rpmTag rpmtag, /*@out@*/ dbiIndex * dbip)
00911         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00912         /*@modifies *dbip, rpmGlobalMacroContext, fileSystem, internalState @*/
00913 {
00914 /*@-nestedextern -shadow @*/
00915     extern struct _dbiVec sqlitevec;
00916 /*@=nestedextern -shadow @*/
00917 
00918     const char * urlfn = NULL;
00919     const char * root;
00920     const char * home;
00921     const char * dbhome;
00922     const char * dbfile;
00923     const char * dbfname;
00924     const char * sql_errcode;
00925     mode_t umask_safed = 0002;
00926     dbiIndex dbi;
00927     SQL_DB * sqldb;
00928     size_t len;
00929     int rc = 0;
00930     int xx;
00931 
00932     if (dbip)
00933         *dbip = NULL;
00934 
00935     /*
00936      * Parse db configuration parameters.
00937      */
00938     /*@-mods@*/
00939     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
00940         /*@-nullstate@*/
00941         return 1;
00942         /*@=nullstate@*/
00943     /*@=mods@*/
00944 
00945    /*
00946      * Get the prefix/root component and directory path
00947      */
00948     root = rpmdb->db_root;
00949     home = rpmdb->db_home;
00950 
00951     dbi->dbi_root = root;
00952     dbi->dbi_home = home;
00953 
00954     dbfile = tagName(dbi->dbi_rpmtag);
00955 
00956 enterChroot(dbi);
00957 
00958     /*
00959      * Make a copy of the tagName result..
00960      * use this for the filename and table name
00961      */
00962     {   
00963       char * t;
00964       len = strlen(dbfile);
00965       t = xcalloc(len + 1, sizeof(*t));
00966       (void) stpcpy( t, dbfile );
00967       dbi->dbi_file = t;
00968 /*@-kepttrans@*/ /* WRONG */
00969       dbi->dbi_subfile = t;
00970 /*@=kepttrans@*/
00971     }
00972 
00973     dbi->dbi_mode = O_RDWR;
00974 
00975     /*
00976      * Either the root or directory components may be a URL. Concatenate,
00977      * convert the URL to a path, and add the name of the file.
00978      */
00979     /*@-mods@*/
00980     urlfn = rpmGenPath(NULL, home, NULL);
00981     /*@=mods@*/
00982     (void) urlPath(urlfn, &dbhome);
00983 
00984     /*
00985      * Create the /var/lib/rpm directory if it doesn't exist (root only).
00986      */
00987     (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
00988 
00989     if (dbi->dbi_eflags & DB_PRIVATE)
00990         dbfname = xstrdup(":memory:");
00991     else
00992         dbfname = rpmGenPath(dbhome, dbi->dbi_file, NULL);
00993 
00994     rpmlog(RPMLOG_DEBUG, D_("opening  sql db         %s (%s) mode=0x%x\n"),
00995                 dbfname, dbi->dbi_subfile, dbi->dbi_mode);
00996 
00997     /* Open the Database */
00998     sqldb = xcalloc(1, sizeof(*sqldb));
00999 
01000     sql_errcode = NULL;
01001 /*@+longunsignedintegral@*/
01002     if (dbi->dbi_perms)
01003         /* mask-out permission bits which are not requested (security) */
01004         umask_safed = umask(~((mode_t)(dbi->dbi_perms)));
01005 /*@=longunsignedintegral@*/
01006     xx = sqlite3_open(dbfname, &sqldb->db);
01007     if (dbi->dbi_perms) {
01008         if ((0644 /* = SQLite hard-coded default */ & dbi->dbi_perms) != dbi->dbi_perms) {
01009             /* add requested permission bits which are still missing (semantic) */
01010             (void) Chmod(dbfname, dbi->dbi_perms);
01011         }
01012 /*@+longunsignedintegral@*/
01013         (void) umask(umask_safed);
01014 /*@=longunsignedintegral@*/
01015     }
01016     if (xx != SQLITE_OK)
01017         sql_errcode = sqlite3_errmsg(sqldb->db);
01018 
01019     if (sqldb->db)
01020         (void) sqlite3_busy_handler(sqldb->db, &sql_busy_handler, dbi);
01021 
01022     sqldb->transaction = 0;     /* Initialize no current transactions */
01023 
01024     dbi->dbi_db = (DB *)sqldb;
01025 
01026     if (sql_errcode != NULL) {
01027       rpmlog(RPMLOG_DEBUG, D_("Unable to open database: %s\n"), sql_errcode);
01028       rc = EINVAL;
01029     }
01030 
01031     /* initialize table */
01032     if (rc == 0)
01033         rc = sql_initDB(dbi);
01034 
01035     if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
01036         dbi->dbi_vec = &sqlitevec;
01037         *dbip = dbi;
01038     } else {
01039         (void) sql_close(dbi, 0);
01040     }
01041 
01042     urlfn = _free(urlfn);
01043     dbfname = _free(dbfname);
01044 
01045 /*@-usereleased@*/
01046 leaveChroot(dbi);
01047 /*@=usereleased@*/
01048 
01049     return rc;
01050 }
01051 
01058 static int sql_sync (dbiIndex dbi, /*@unused@*/ unsigned int flags)
01059         /*@globals fileSystem, internalState @*/
01060         /*@modifies fileSystem, internalState @*/
01061 {
01062     int rc = 0;
01063 
01064 enterChroot(dbi);
01065     rc = sql_commitTransaction(dbi, 0);
01066 leaveChroot(dbi);
01067 
01068     return rc;
01069 }
01070 
01078 static int sql_exists(dbiIndex dbi, DBT * key, unsigned int flags)
01079         /*@globals fileSystem @*/
01080         /*@modifies fileSystem @*/
01081 {
01082 if (_debug)
01083 fprintf(stderr, "*** sql_exists:\n");
01084     return EINVAL;
01085 }
01086 
01094 static int sql_seqno(dbiIndex dbi, int64_t * seqnop, unsigned int flags)
01095 {
01096 if (_debug)
01097 fprintf(stderr, "*** sql_seqno:\n");
01098     return EINVAL;
01099 }
01100 
01109 static int sql_copen (dbiIndex dbi,
01110                 /*@unused@*/ /*@null@*/ DB_TXN * txnid,
01111                 /*@out@*/ DBC ** dbcp, unsigned int flags)
01112         /*@globals fileSystem, internalState @*/
01113         /*@modifies dbi, *txnid, *dbcp, fileSystem, internalState @*/
01114 {
01115     SCP_t scp = scpNew(dbi->dbi_db);
01116     DBC * dbcursor = (DBC *)scp;
01117     int rc = 0;
01118 
01119 if (_debug)
01120 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);
01121 
01122 enterChroot(dbi);
01123 
01124     /* If we're going to write, start a transaction (lock the DB) */
01125     if (flags == DB_WRITECURSOR)
01126         rc = sql_startTransaction(dbi);
01127 
01128     if (dbcp)
01129         /*@-onlytrans@*/ *dbcp = dbcursor; /*@=onlytrans@*/
01130     else
01131         /*@-kepttrans -nullstate @*/ (void) sql_cclose(dbi, dbcursor, 0); /*@=kepttrans =nullstate @*/
01132 
01133 leaveChroot(dbi);
01134 
01135     return rc;
01136 }
01137 
01147 static int sql_cdel (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key,
01148                 DBT * data, unsigned int flags)
01149         /*@globals fileSystem, internalState @*/
01150         /*@modifies dbi, *dbcursor, fileSystem, internalState @*/
01151 {
01152 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
01153     SCP_t scp = scpNew(dbi->dbi_db);
01154     int rc = 0;
01155 
01156 dbg_keyval("sql_cdel", dbi, dbcursor, key, data, flags);
01157 enterChroot(dbi);
01158 
01159     scp->cmd = sqlite3_mprintf("DELETE FROM '%q' WHERE key=? AND value=?;",
01160         dbi->dbi_subfile);
01161 
01162     rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
01163     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) prepare %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01164     rc = sql_bind_key(dbi, scp, 1, key);
01165     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) bind key %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01166     rc = sql_bind_data(dbi, scp, 2, data);
01167     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) bind data %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01168 
01169     rc = sql_step(dbi, scp);
01170     if (rc) rpmlog(RPMLOG_WARNING, "cdel(%s) sql_step rc %d\n", dbi->dbi_subfile, rc);
01171 
01172     scp = scpFree(scp);
01173 
01174 leaveChroot(dbi);
01175 
01176     return rc;
01177 }
01178 
01188 static int sql_cget (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key,
01189                 DBT * data, unsigned int flags)
01190         /*@globals fileSystem, internalState @*/
01191         /*@modifies dbi, dbcursor, *key, *data, fileSystem, internalState @*/
01192 {
01193 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
01194     SCP_t scp = (SCP_t)dbcursor;
01195     int rc = 0;
01196     int ix;
01197 
01198 assert(dbcursor != NULL);
01199 dbg_keyval("sql_cget", dbi, dbcursor, key, data, flags);
01200 
01201 enterChroot(dbi);
01202 
01203     /*
01204      * First determine if this is a new scan or existing scan
01205      */
01206 
01207 if (_debug)
01208 fprintf(stderr, "\tcget(%s) scp %p rc %d flags %d av %p\n",
01209                 dbi->dbi_subfile, scp, rc, flags, scp->av);
01210     if ( flags == DB_SET || scp->used == 0 ) {
01211         scp->used = 1; /* Signal this scp as now in use... */
01212 /*@i@*/ scp = scpReset(scp);    /* Free av and avlen, reset counters.*/
01213 
01214 /* XXX: Should we also reset the key table here?  Can you re-use a cursor? */
01215 
01216         /*
01217          * If we're scanning everything, load the iterator key table
01218          */
01219         if ( key->size == 0) {
01220             scp->all = 1;
01221 
01222 /*
01223  * The only condition not dealt with is if there are multiple identical keys.  This can lead
01224  * to later iteration confusion.  (It may return the same value for the multiple keys.)
01225  */
01226 
01227 #ifdef  DYING
01228 /* Only RPMDBI_PACKAGES is supposed to be iterating, and this is guarenteed to be unique */
01229 assert(dbi->dbi_rpmtag == RPMDBI_PACKAGES);
01230 #endif
01231 
01232             switch (dbi->dbi_rpmtag) {
01233             case RPMDBI_PACKAGES:
01234                 scp->cmd = sqlite3_mprintf("SELECT key FROM '%q' ORDER BY key;",
01235                     dbi->dbi_subfile);
01236                 break;
01237             default:
01238                 scp->cmd = sqlite3_mprintf("SELECT key FROM '%q';",
01239                     dbi->dbi_subfile);
01240                 break;
01241             }
01242             rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
01243             if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) sequential prepare %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01244 
01245             rc = sql_step(dbi, scp);
01246             if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) sequential sql_step rc %d\n", dbi->dbi_subfile, rc);
01247 
01248             scp = scpResetKeys(scp);
01249             scp->nkeys = scp->nr;
01250             scp->keys = xcalloc(scp->nkeys, sizeof(*scp->keys));
01251             for (ix = 0; ix < scp->nkeys; ix++) {
01252                 scp->keys[ix] = xmalloc(sizeof(*scp->keys[0]));
01253                 scp->keys[ix]->size = (UINT32_T) scp->avlen[ix+1];
01254                 scp->keys[ix]->data = xmalloc(scp->keys[ix]->size);
01255                 memcpy(scp->keys[ix]->data, scp->av[ix+1], scp->avlen[ix+1]);
01256             }
01257         } else {
01258             /*
01259              * We're only scanning ONE element
01260              */
01261             scp = scpResetKeys(scp);
01262             scp->nkeys = 1;
01263             scp->keys = xcalloc(scp->nkeys, sizeof(*scp->keys));
01264             scp->keys[0] = xmalloc(sizeof(*scp->keys[0]));
01265             scp->keys[0]->size = key->size;
01266             scp->keys[0]->data = xmalloc(scp->keys[0]->size);
01267             memcpy(scp->keys[0]->data, key->data, key->size);
01268         }
01269 
01270 /*@i@*/ scp = scpReset(scp);    /* reset */
01271 
01272         /* Prepare SQL statement to retrieve the value for the current key */
01273         scp->cmd = sqlite3_mprintf("SELECT value FROM '%q' WHERE key=?;", dbi->dbi_subfile);
01274         rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
01275 
01276         if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) prepare %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01277     }
01278 
01279 /*@i@*/ scp = scpResetAv(scp);  /* Free av and avlen, reset counters.*/
01280 
01281     /* Now continue with a normal retrive based on key */
01282     if ((scp->rx + 1) > scp->nkeys )
01283         rc = DB_NOTFOUND; /* At the end of the list */
01284 
01285     if (rc != 0)
01286         goto exit;
01287 
01288     /* Bind key to prepared statement */
01289     rc = sql_bind_key(dbi, scp, 1, scp->keys[scp->rx]);
01290     if (rc) rpmlog(RPMLOG_WARNING, "cget(%s)  key bind %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01291 
01292     rc = sql_step(dbi, scp);
01293     if (rc) rpmlog(RPMLOG_WARNING, "cget(%s) sql_step rc %d\n", dbi->dbi_subfile, rc);
01294 
01295     rc = sqlite3_reset(scp->pStmt);
01296     if (rc) rpmlog(RPMLOG_WARNING, "reset %d\n", rc);
01297 
01298 /* 1 key should return 0 or 1 row/value */
01299 assert(scp->nr < 2);
01300 
01301     if (scp->nr == 0 && scp->all == 0)
01302         rc = DB_NOTFOUND; /* No data for that key found! */
01303 
01304     if (rc != 0)
01305         goto exit;
01306 
01307     /* If we're looking at the whole db, return the key */
01308     if (scp->all) {
01309 
01310 /* To get this far there has to be _1_ key returned! (protect against dup keys) */
01311 assert(scp->nr == 1);
01312 
01313         if ( scp->lkey ) {
01314             scp->lkey = _free(scp->lkey);
01315         }
01316 
01317         key->size = scp->keys[scp->rx]->size;
01318         key->data = xmalloc(key->size);
01319         if (! (key->flags & DB_DBT_MALLOC))
01320             scp->lkey = key->data;
01321 
01322         (void) memcpy(key->data, scp->keys[scp->rx]->data, key->size);
01323     }
01324 
01325     /* Construct and return the data element (element 0 is "value", 1 is _THE_ value)*/
01326     switch (dbi->dbi_rpmtag) {
01327     default:
01328         if ( scp->ldata ) {
01329             scp->ldata = _free(scp->ldata);
01330         }
01331 
01332         data->size = (UINT32_T) scp->avlen[1];
01333         data->data = xmalloc(data->size);
01334         if (! (data->flags & DB_DBT_MALLOC) )
01335             scp->ldata = data->data;
01336 
01337         (void) memcpy(data->data, scp->av[1], data->size);
01338     }
01339 
01340     scp->rx++;
01341 
01342     /* XXX FIXME: ptr alignment is fubar here. */
01343 if (_debug)
01344 fprintf(stderr, "\tcget(%s) found  key 0x%x (%d)\n", dbi->dbi_subfile,
01345                 key->data == NULL ? 0 : *(unsigned int *)key->data, key->size);
01346 if (_debug)
01347 fprintf(stderr, "\tcget(%s) found data 0x%x (%d)\n", dbi->dbi_subfile,
01348                 key->data == NULL ? 0 : *(unsigned int *)data->data, data->size);
01349 
01350 exit:
01351     if (rc == DB_NOTFOUND) {
01352 if (_debug)
01353 fprintf(stderr, "\tcget(%s) not found\n", dbi->dbi_subfile);
01354     }
01355 
01356 leaveChroot(dbi);
01357 
01358     return rc;
01359 }
01360 
01370 static int sql_cput (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key,
01371                         DBT * data, unsigned int flags)
01372         /*@globals fileSystem, internalState @*/
01373         /*@modifies dbi, *dbcursor, fileSystem, internalState @*/
01374 {
01375 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
01376     SCP_t scp = scpNew(dbi->dbi_db);
01377     int rc = 0;
01378 
01379 dbg_keyval("sql_cput", dbi, dbcursor, key, data, flags);
01380 
01381 enterChroot(dbi);
01382 
01383     switch (dbi->dbi_rpmtag) {
01384     default:
01385         scp->cmd = sqlite3_mprintf("INSERT OR REPLACE INTO '%q' VALUES(?, ?);",
01386                 dbi->dbi_subfile);
01387         rc = sqlite3_prepare(sqldb->db, scp->cmd, (int)strlen(scp->cmd), &scp->pStmt, &scp->pzErrmsg);
01388         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s) prepare %s (%d)\n",dbi->dbi_subfile,  sqlite3_errmsg(sqldb->db), rc);
01389         rc = sql_bind_key(dbi, scp, 1, key);
01390         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s)  key bind %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01391         rc = sql_bind_data(dbi, scp, 2, data);
01392         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s) data bind %s (%d)\n", dbi->dbi_subfile, sqlite3_errmsg(sqldb->db), rc);
01393 
01394         rc = sql_step(dbi, scp);
01395         if (rc) rpmlog(RPMLOG_WARNING, "cput(%s) sql_step rc %d\n", dbi->dbi_subfile, rc);
01396 
01397         break;
01398     }
01399 
01400     scp = scpFree(scp);
01401 
01402 leaveChroot(dbi);
01403 
01404     return rc;
01405 }
01406 
01412 static int sql_byteswapped (dbiIndex dbi)
01413         /*@globals fileSystem, internalState @*/
01414         /*@modifies fileSystem, internalState @*/
01415 {
01416     SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
01417     SCP_t scp = scpNew(dbi->dbi_db);
01418     int sql_rc, rc = 0;
01419     union _dbswap db_endian;
01420 
01421 enterChroot(dbi);
01422 
01423 /*@-nullstate@*/
01424     sql_rc = sqlite3_get_table(sqldb->db, "SELECT endian FROM 'db_info';",
01425         &scp->av, &scp->nr, &scp->nc, (char **)&scp->pzErrmsg);
01426 /*@=nullstate@*/
01427 
01428     if (sql_rc == 0 && scp->nr > 0) {
01429 assert(scp->av != NULL);
01430         db_endian.uc[0] = (unsigned char) strtol(scp->av[1], NULL, 10);
01431 
01432         if ( db_endian.uc[0] == ((union _dbswap *)&endian)->uc[0] )
01433             rc = 0; /* Native endian */
01434         else
01435             rc = 1; /* swapped */
01436 
01437     } else {
01438         if ( sql_rc ) {
01439             rpmlog(RPMLOG_DEBUG, D_("db_info failed %s (%d)\n"),
01440                 scp->pzErrmsg, sql_rc);
01441         }
01442         rpmlog(RPMLOG_WARNING, "Unable to determine DB endian.\n");
01443     }
01444 
01445     scp = scpFree(scp);
01446 
01447 leaveChroot(dbi);
01448 
01449     return rc;
01450 }
01451 
01452 /**************************************************
01453  *
01454  *  All of the following are not implemented!
01455  *  they are not used by the rest of the system
01456  *
01457  **************************************************/
01458 
01467 static int sql_associate (/*@unused@*/ dbiIndex dbi,
01468                 /*@unused@*/ dbiIndex dbisecondary,
01469     /*@unused@*/int (*callback) (DB *, const DBT *, const DBT *, DBT *),
01470                 /*@unused@*/ unsigned int flags)
01471         /*@*/
01472 {
01473 if (_debug)
01474 fprintf(stderr, "*** sql_associate:\n");
01475     return EINVAL;
01476 }
01477 
01486 static int sql_associate_foreign (/*@unused@*/ dbiIndex dbi,
01487                 /*@unused@*/ dbiIndex dbisecondary,
01488     /*@unused@*/int (*callback) (DB *, const DBT *, DBT *, const DBT *, int *),
01489                 /*@unused@*/ unsigned int flags)
01490         /*@*/
01491 {
01492 if (_debug)
01493 fprintf(stderr, "*** sql_associate_foreign:\n");
01494     return EINVAL;
01495 }
01496 
01505 static int sql_join (/*@unused@*/ dbiIndex dbi,
01506                 /*@unused@*/ DBC ** curslist,
01507                 /*@unused@*/ /*@out@*/ DBC ** dbcp,
01508                 /*@unused@*/ unsigned int flags)
01509         /*@globals fileSystem @*/
01510         /*@modifies dbi, *dbcp, fileSystem @*/
01511 {
01512 if (_debug)
01513 fprintf(stderr, "*** sql_join:\n");
01514     return EINVAL;
01515 }
01516 
01525 static int sql_cdup (/*@unused@*/ dbiIndex dbi,
01526                 /*@unused@*/ DBC * dbcursor,
01527                 /*@unused@*/ /*@out@*/ DBC ** dbcp,
01528                 /*@unused@*/ unsigned int flags)
01529         /*@globals fileSystem @*/
01530         /*@modifies dbi, *dbcp, fileSystem @*/
01531 {
01532 if (_debug)
01533 fprintf(stderr, "*** sql_cdup:\n");
01534     return EINVAL;
01535 }
01536 
01547 static int sql_cpget (/*@unused@*/ dbiIndex dbi,
01548                 /*@unused@*/ /*@null@*/ DBC * dbcursor,
01549                 /*@unused@*/ DBT * key,
01550                 /*@unused@*/ DBT * pkey,
01551                 /*@unused@*/ DBT * data,
01552                 /*@unused@*/ unsigned int flags)
01553         /*@globals fileSystem @*/
01554         /*@modifies *dbcursor, *key, *pkey, *data, fileSystem @*/
01555 {
01556 if (_debug)
01557 fprintf(stderr, "*** sql_cpget:\n");
01558     return EINVAL;
01559 }
01560 
01569 static int sql_ccount (/*@unused@*/ dbiIndex dbi,
01570                 /*@unused@*/ DBC * dbcursor,
01571                 /*@unused@*/ /*@out@*/ unsigned int * countp,
01572                 /*@unused@*/ unsigned int flags)
01573         /*@globals fileSystem @*/
01574         /*@modifies *dbcursor, fileSystem @*/
01575 {
01576 if (_debug)
01577 fprintf(stderr, "*** sql_ccount:\n");
01578     return EINVAL;
01579 }
01580 
01587 static int sql_stat (dbiIndex dbi, /*@unused@*/ unsigned int flags)
01588         /*@globals fileSystem, internalState @*/
01589         /*@modifies dbi, fileSystem, internalState @*/
01590 {
01591 /*@i@*/    SQL_DB * sqldb = (SQL_DB *) dbi->dbi_db;
01592     SCP_t scp = scpNew(dbi->dbi_db);
01593     int rc = 0;
01594     long nkeys = -1;
01595 
01596 enterChroot(dbi);
01597 
01598     dbi->dbi_stats = _free(dbi->dbi_stats);
01599 
01600 /*@-sizeoftype@*/
01601     dbi->dbi_stats = xcalloc(1, sizeof(DB_HASH_STAT));
01602 /*@=sizeoftype@*/
01603 
01604     scp->cmd = sqlite3_mprintf("SELECT COUNT('key') FROM '%q';", dbi->dbi_subfile);
01605 /*@-nullstate@*/
01606     rc = sqlite3_get_table(sqldb->db, scp->cmd,
01607                 &scp->av, &scp->nr, &scp->nc, (char **)&scp->pzErrmsg);
01608 /*@=nullstate@*/
01609 
01610     if ( rc == 0 && scp->nr > 0) {
01611 assert(scp->av != NULL);
01612         nkeys = strtol(scp->av[1], NULL, 10);
01613 
01614         rpmlog(RPMLOG_DEBUG, D_("  stat on %s nkeys %ld\n"),
01615                 dbi->dbi_subfile, nkeys);
01616     } else {
01617         if ( rc ) {
01618             rpmlog(RPMLOG_DEBUG, D_("stat failed %s (%d)\n"),
01619                 scp->pzErrmsg, rc);
01620         }
01621     }
01622 
01623     if (nkeys < 0)
01624         nkeys = 4096;  /* Good high value */
01625 
01626     ((DB_HASH_STAT *)(dbi->dbi_stats))->hash_nkeys = nkeys;
01627 
01628     scp = scpFree(scp);
01629 
01630 leaveChroot(dbi);
01631 
01632     return rc;
01633 }
01634 
01635 /* Major, minor, patch version of DB.. we're not using db.. so set to 0 */
01636 /* open, close, sync, associate, asociate_foreign, join */
01637 /* cursor_open, cursor_close, cursor_dup, cursor_delete, cursor_get, */
01638 /* cursor_pget?, cursor_put, cursor_count */
01639 /* db_bytewapped, stat */
01640 /*@observer@*/ /*@unchecked@*/
01641 struct _dbiVec sqlitevec = {
01642     "Sqlite " SQLITE_VERSION,
01643     ((SQLITE_VERSION_NUMBER / (1000 * 1000)) % 1000),
01644     ((SQLITE_VERSION_NUMBER / (       1000)) % 1000),
01645     ((SQLITE_VERSION_NUMBER                ) % 1000),
01646     sql_open,
01647     sql_close,
01648     sql_sync,
01649     sql_associate,
01650     sql_associate_foreign,
01651     sql_join,
01652     sql_exists,
01653     sql_seqno,
01654     sql_copen,
01655     sql_cclose,
01656     sql_cdup,
01657     sql_cdel,
01658     sql_cget,
01659     sql_cpget,
01660     sql_cput,
01661     sql_ccount,
01662     sql_byteswapped,
01663     sql_stat
01664 };
01665 
01666 /*@=evalorderuncon@*/
01667 /*@=modfilesystem@*/
01668 /*@=compmempass@*/
01669 /*@=compdef@*/
01670 /*@=moduncon@*/
01671 /*@=noeffectuncon@*/
01672 /*@=globuse@*/
01673 /*@=paramuse@*/
01674 /*@=mustmod@*/