• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

rpmdb/sqlite.c

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

Generated on Mon Nov 29 2010 05:18:47 for rpm by  doxygen 1.7.2