Add toy db->associate, db->join, dbcursor->c_pget wrappers.
authorjbj <devnull@localhost>
Sat, 4 May 2002 20:13:14 +0000 (20:13 +0000)
committerjbj <devnull@localhost>
Sat, 4 May 2002 20:13:14 +0000 (20:13 +0000)
CVS patchset: 5421
CVS date: 2002/05/04 20:13:14

build/pack.c
lib/package.c
lib/query.c
lib/rpminstall.c
lib/rpmlib.h
python/header-py.c
rpm2cpio.c
rpmdb/db3.c
rpmdb/rpmdb.c
rpmdb/rpmdb.h

index 768e0c9..5fbaf9b 100644 (file)
@@ -333,7 +333,7 @@ int readRPM(const char *fileName, Spec *specp, struct rpmlead *lead,
     }
 
     switch (rc) {
-    case RPMRC_BADMAGIC:
+    case RPMRC_NOTFOUND:
        rpmError(RPMERR_BADMAGIC, _("readRPM: %s is not an RPM package\n"),
                (fileName ? fileName : "<stdin>"));
        return RPMERR_BADMAGIC;
index 78baa22..ada52b7 100644 (file)
@@ -172,7 +172,7 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd,
     if (l->magic[0] != RPMLEAD_MAGIC0 || l->magic[1] != RPMLEAD_MAGIC1
      || l->magic[2] != RPMLEAD_MAGIC2 || l->magic[3] != RPMLEAD_MAGIC3) {
        rpmError(RPMERR_READLEAD, _("%s: bad magic\n"), fn);
-       rc = RPMRC_BADMAGIC;
+       rc = RPMRC_NOTFOUND;
        goto exit;
     }
 
index 37bb3af..4b24db6 100644 (file)
@@ -632,7 +632,7 @@ restart:
 
            (void) Fclose(fd);
 
-           if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADMAGIC)) {
+           if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_NOTFOUND)) {
                rpmError(RPMERR_QUERY, _("query of %s failed\n"), fileURL);
                res = 1;
                /*@loopbreak@*/ break;
index 2878e61..11e13f2 100644 (file)
@@ -482,7 +482,7 @@ restart:
            continue;
        }
 
-       if (eiu->rpmrc != RPMRC_BADMAGIC) {
+       if (eiu->rpmrc != RPMRC_NOTFOUND) {
            rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *eiu->fnp);
            eiu->numFailed++; *eiu->fnp = NULL;
            break;
index 904eca3..d1f9d43 100644 (file)
@@ -16,7 +16,7 @@
  */
 typedef        enum rpmRC_e {
     RPMRC_OK           = 0,
-    RPMRC_BADMAGIC     = 1,
+    RPMRC_NOTFOUND     = 1,
     RPMRC_FAIL         = 2,
     RPMRC_BADSIZE      = 3,
     RPMRC_SHORTREAD    = 4
index 7e3d123..93a6af8 100644 (file)
@@ -799,7 +799,7 @@ PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
        isSource = headerIsEntry(header, RPMTAG_SOURCEPACKAGE);
        break;
 
-    case RPMRC_BADMAGIC:
+    case RPMRC_NOTFOUND:
        Py_INCREF(Py_None);
        h = (hdrObject *) Py_None;
        break;
index 73bbf80..397303c 100644 (file)
@@ -43,7 +43,7 @@ int main(int argc, char **argv)
     case RPMRC_BADSIZE:
     case RPMRC_OK:
        break;
-    case RPMRC_BADMAGIC:
+    case RPMRC_NOTFOUND:
        fprintf(stderr, _("argument is not an RPM package\n"));
        exit(EXIT_FAILURE);
        break;
index 9c0f3c3..0d835cb 100644 (file)
@@ -300,9 +300,7 @@ static int db3sync(dbiIndex dbi, unsigned int flags)
     return rc;
 }
 
-#ifdef DYING
-/*@unused@*/
-static int db3c_dup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
+static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
                unsigned int flags)
        /*@globals fileSystem @*/
        /*@modifies *dbcp, fileSystem @*/
@@ -316,7 +314,6 @@ static int db3c_dup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
     return rc;
     /*@=nullstate @*/
 }
-#endif
 
 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
                unsigned int flags)
@@ -416,31 +413,46 @@ static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
        /*@modifies *dbcursor, *key, *data, fileSystem @*/
 {
     DB * db = dbi->dbi_db;
+    int _printit;
     int rc;
 
     assert(db != NULL);
     if (dbcursor == NULL) {
-       int _printit;
-
        /* XXX duplicates require cursors. */
        rc = db->get(db, dbi->dbi_txnid, key, data, 0);
        /* XXX DB_NOTFOUND can be returned */
        _printit = (rc == DB_NOTFOUND ? 0 : _debug);
        rc = cvtdberr(dbi, "db->get", rc, _printit);
     } else {
-       int _printit;
-
        /* XXX db3 does DB_FIRST on uninitialized cursor */
        rc = dbcursor->c_get(dbcursor, key, data, flags);
        /* XXX DB_NOTFOUND can be returned */
        _printit = (rc == DB_NOTFOUND ? 0 : _debug);
        rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
-
     }
 
-    /*@-compmempass -nullstate@*/
     return rc;
-    /*@=compmempass =nullstate@*/
+}
+
+static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey,
+               DBT * data, unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies *dbcursor, *key, *data, fileSystem @*/
+{
+    DB * db = dbi->dbi_db;
+    int _printit;
+    int rc;
+
+    assert(db != NULL);
+    assert(dbcursor != NULL);
+
+    /* XXX db3 does DB_FIRST on uninitialized cursor */
+    rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags);
+    /* XXX DB_NOTFOUND can be returned */
+    _printit = (rc == DB_NOTFOUND ? 0 : _debug);
+    rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit);
+
+    return rc;
 }
 
 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
@@ -506,6 +518,38 @@ static int db3stat(dbiIndex dbi, unsigned int flags)
     return rc;
 }
 
+static int db3associate(dbiIndex dbi, dbiIndex dbisecondary,
+               int (*callback)(DB *, const DBT *, const DBT *, DBT *),
+               unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, fileSystem @*/
+{
+    DB * db = dbi->dbi_db;
+    DB * secondary = dbisecondary->dbi_db;
+    int rc;
+
+/*@-moduncon@*/ /* FIX: annotate db3 methods */
+    rc = db->associate(db, secondary, callback, flags);
+/*@=moduncon@*/
+    rc = cvtdberr(dbi, "db->associate", rc, _debug);
+    return rc;
+}
+
+static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp,
+               unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, fileSystem @*/
+{
+    DB * db = dbi->dbi_db;
+    int rc;
+
+/*@-moduncon@*/ /* FIX: annotate db3 methods */
+    rc = db->join(db, curslist, dbcp, flags);
+/*@=moduncon@*/
+    rc = cvtdberr(dbi, "db->join", rc, _debug);
+    return rc;
+}
+
 /*@-moduncon@*/ /* FIX: annotate db3 methods */
 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
        /*@globals rpmGlobalMacroContext,
@@ -652,7 +696,7 @@ exit:
 }
 /*@=moduncon@*/
 
-static int db3open(rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
+static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip)
        /*@globals rpmGlobalMacroContext,
                fileSystem @*/
        /*@modifies *dbip, fileSystem @*/
@@ -1100,8 +1144,9 @@ static int db3open(rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
 /*@observer@*/ /*@unchecked@*/
 struct _dbiVec db3vec = {
     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
-    db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput,
-    db3ccount, db3byteswapped, db3stat
+    db3open, db3close, db3sync, db3associate, db3join,
+    db3copen, db3cclose, db3cdup, db3cdel, db3cget, db3cpget, db3cput, db3ccount,
+    db3byteswapped, db3stat
 };
 /*@=exportheadervar@*/
 /*@=type@*/
index f23cbf4..fbf80fe 100644 (file)
@@ -1,4 +1,4 @@
-/*@-sizeoftype @*/
+/*@-compmempass -sizeoftype @*/
 /** \ingroup rpmdb dbi
  * \file rpmdb/rpmdb.c
  */
@@ -503,7 +503,7 @@ assert(key->size != 0);
  * @param flags                update flags
  * @return             0 success, 1 not found
  */
-/*@-compmempass -mustmod@*/
+/*@-mustmod@*/
 static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
                int flags)
        /*@globals fileSystem @*/
@@ -535,7 +535,7 @@ static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
 
     return rc;
 }
-/*@=compmempass =mustmod@*/
+/*@=mustmod@*/
 
 /* XXX assumes hdrNum is first int in dbiIndexItem */
 static int hdrNumCmp(const void * one, const void * two)
@@ -581,9 +581,7 @@ static int dbiAppendSet(dbiIndexSet set, const void * recs,
     if (set->count > 1 && sortset)
        qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
 
-    /*@-compmempass@*/ /* FIX: set->recs.{hdrNum,tagNum,fpNum,dbNum} undef */
     return 0;
-    /*@=compmempass@*/
 }
 
 /**
@@ -1018,12 +1016,10 @@ int rpmdbVerify(const char * prefix)
 /*@=globs@*/
 
 static int rpmdbFindByFile(rpmdb db, /*@null@*/ const char * filespec,
-                       /*@out@*/ dbiIndexSet * matches)
+               DBT * key, DBT * data, /*@out@*/ dbiIndexSet * matches)
        /*@globals fileSystem @*/
        /*@modifies db, *matches, fileSystem @*/
 {
-DBT * key = alloca(sizeof(*key));
-DBT * data = alloca(sizeof(*data));
     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
     HFD_t hfd = headerFreeData;
     const char * dirName;
@@ -1217,25 +1213,25 @@ xx = dbt2set(dbi, data, &matches);
  * Attempt partial matches on name[-version[-release]] strings.
  * @param dbi          index database handle (always RPMTAG_NAME)
  * @param dbcursor     index database cursor
+ * @param key          search key/length
+ * @param data         search data/length
  * @param name         package name
  * @param version      package version (can be a pattern)
  * @param release      package release (can be a pattern)
  * @retval matches     set of header instances that match
- * @return             0 on match, 1 on no match, 2 on error
+ * @return             RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
  */
-static int dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
+static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
+               DBT * key, DBT * data,
                const char * name,
                /*@null@*/ const char * version,
                /*@null@*/ const char * release,
                /*@out@*/ dbiIndexSet * matches)
        /*@globals fileSystem @*/
-       /*@modifies dbi, *dbcursor, *matches, fileSystem @*/
+       /*@modifies dbi, *dbcursor, *key, *data, *matches, fileSystem @*/
 {
-DBT * key = alloca(sizeof(*key));
-DBT * data = alloca(sizeof(*data));
-    int gotMatches;
+    int gotMatches = 0;
     int rc;
-int xx;
     int i;
 
 memset(key, 0, sizeof(*key));
@@ -1244,74 +1240,63 @@ key->size = strlen(name);
 memset(data, 0, sizeof(*data));
     rc = dbiSearch(dbi, dbcursor, key, data, DB_SET);
 if (rc == 0)
-xx = dbt2set(dbi, data, matches);
+rc = dbt2set(dbi, data, matches);
 
     if (rc != 0) {
-       rc = ((rc == -1) ? 2 : 1);
+       rc = ((rc == -1) ? RPMRC_FAIL : RPMRC_NOTFOUND);
        goto exit;
     }
 
     if (version == NULL && release == NULL) {
-       rc = 0;
+       rc = RPMRC_OK;
        goto exit;
     }
 
-    gotMatches = 0;
-
     /* Make sure the version and release match. */
     /*@-branchstate@*/
     for (i = 0; i < dbiIndexSetCount(*matches); i++) {
        unsigned int recoff = dbiIndexRecordOffset(*matches, i);
+       rpmdbMatchIterator mi;
        Header h;
 
        if (recoff == 0)
            continue;
 
-       {   rpmdbMatchIterator mi;
-           mi = rpmdbInitIterator(dbi->dbi_rpmdb,
+       mi = rpmdbInitIterator(dbi->dbi_rpmdb,
                        RPMDBI_PACKAGES, &recoff, sizeof(recoff));
 
-           /* Set iterator selectors for version/release if available. */
-           if (version &&
-               rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
-           {
-               rc = 2;
-               goto exit;
-           }
-           if (release &&
-               rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
-           {
-               rc = 2;
-               goto exit;
-           }
-
-           h = rpmdbNextIterator(mi);
-           if (h)
-               h = headerLink(h, "dbiFindMatches");
-           mi = rpmdbFreeIterator(mi);
+       /* Set iterator selectors for version/release if available. */
+       if (version &&
+           rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
+       {
+           rc = RPMRC_FAIL;
+           goto exit;
+       }
+       if (release &&
+           rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
+       {
+           rc = RPMRC_FAIL;
+           goto exit;
        }
 
-       if (h)  /* structure assignment */
+       h = rpmdbNextIterator(mi);
+       if (h)
            (*matches)->recs[gotMatches++] = (*matches)->recs[i];
        else
            (*matches)->recs[i].hdrNum = 0;
-
-       h = headerFree(h, "dbiFindMatches");
+       mi = rpmdbFreeIterator(mi);
     }
     /*@=branchstate@*/
 
     if (gotMatches) {
        (*matches)->count = gotMatches;
-       rc = 0;
+       rc = RPMRC_OK;
     } else
-       rc = 1;
+       rc = RPMRC_NOTFOUND;
 
 exit:
-    if (rc && matches && *matches) {
-       /*@-unqualifiedtrans@*/         /* FIX: double indirection */
+    if (rc && matches && *matches)
        *matches = dbiFreeIndexSet(*matches);
-       /*@=unqualifiedtrans@*/
-    }
     return rc;
 }
 
@@ -1323,9 +1308,9 @@ exit:
  * @param dbcursor     index database cursor
  * @param arg          name[-version[-release]] string
  * @retval matches     set of header instances that match
- * @return             0 on match, 1 on no match, 2 on error
+ * @return             RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
  */
-static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor,
+static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
                /*@null@*/ const char * arg, /*@out@*/ dbiIndexSet * matches)
        /*@globals fileSystem @*/
        /*@modifies dbi, *dbcursor, *matches, fileSystem @*/
@@ -1335,13 +1320,13 @@ static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor,
     char * s;
     char c;
     int brackets;
-    int rc;
+    rpmRC rc;
  
-    if (arg == NULL || strlen(arg) == 0) return 1;
+    if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
 
     /* did they give us just a name? */
-    rc = dbiFindMatches(dbi, dbcursor, arg, NULL, NULL, matches);
-    if (rc != 1) return rc;
+    rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
+    if (rc != RPMRC_NOTFOUND) return rc;
 
     /*@-unqualifiedtrans@*/
     *matches = dbiFreeIndexSet(*matches);
@@ -1368,11 +1353,11 @@ static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor,
     }
 
     /*@-nullstate@*/   /* FIX: *matches may be NULL. */
-    if (s == localarg) return 1;
+    if (s == localarg) return RPMRC_NOTFOUND;
 
     *s = '\0';
-    rc = dbiFindMatches(dbi, dbcursor, localarg, s + 1, NULL, matches);
-    if (rc != 1) return rc;
+    rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
+    if (rc != RPMRC_NOTFOUND) return rc;
 
     /*@-unqualifiedtrans@*/
     *matches = dbiFreeIndexSet(*matches);
@@ -1398,10 +1383,10 @@ static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor,
            break;
     }
 
-    if (s == localarg) return 1;
+    if (s == localarg) return RPMRC_NOTFOUND;
 
     *s = '\0';
-    return dbiFindMatches(dbi, dbcursor, localarg, s + 1, release, matches);
+    return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
     /*@=nullstate@*/
 }
 
@@ -1951,7 +1936,6 @@ Header XrpmdbNextIterator(rpmdbMatchIterator mi,
     return rpmdbNextIterator(mi);
 }
 
-/*@-compmempass@*/
 Header rpmdbNextIterator(rpmdbMatchIterator mi)
 {
     dbiIndex dbi;
@@ -2111,7 +2095,6 @@ exit:
     /*@-compdef -usereleased@*/ return mi->mi_h; /*@=compdef =usereleased@*/
     /*@=retexpose =retalias@*/
 }
-/*@=compmempass@*/
 
 static void rpmdbSortIterator(/*@null@*/ rpmdbMatchIterator mi)
        /*@modifies mi @*/
@@ -2236,11 +2219,11 @@ DBT * data = alloca(sizeof(*data));
        if (isLabel) {
            /* XXX HACK to get rpmdbFindByLabel out of the API */
            xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
-           rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
+           rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set);
            xx = dbiCclose(dbi, dbcursor, 0);
            dbcursor = NULL;
        } else if (rpmtag == RPMTAG_BASENAMES) {
-           rc = rpmdbFindByFile(db, keyp, &set);
+           rc = rpmdbFindByFile(db, keyp, key, data, &set);
        } else {
            xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
 
@@ -2643,9 +2626,7 @@ DBT * data = alloca(sizeof(*data));
        memset(data, 0, sizeof(*data));
 /*@i@*/        data->data = datap;
        data->size = datalen;
-/*@-compmempass@*/
        rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
-/*@=compmempass@*/
        keyp = key->data;
        keylen = key->size;
        datap = data->data;
@@ -2673,9 +2654,7 @@ DBT * data = alloca(sizeof(*data));
 /*@=kepttrans@*/
        data->size = datalen;
 
-/*@-compmempass@*/
        rc = dbiPut(dbi, dbcursor, key, data, 0);
-/*@=compmempass@*/
        xx = dbiSync(dbi, 0);
 
        xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
@@ -2982,9 +2961,7 @@ key->data = (void *) fpList[i].baseName;
 key->size = strlen((char *)key->data);
 if (key->size == 0) key->size++;       /* XXX "/" fixup. */
 
-       /*@-compmempass@*/
        xx = rpmdbGrowIterator(mi, key, i);
-       /*@=compmempass@*/
        matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
     }
 
@@ -3461,4 +3438,4 @@ exit:
 }
 /*@=globs@*/
 /*@=mods@*/
-/*@=sizeoftype @*/
+/*@=compmempass =sizeoftype @*/
index e07cc5a..4bbd57f 100644 (file)
@@ -54,7 +54,7 @@ struct _dbiVec {
  * @return             0 on success
  */
     int (*open) (rpmdb rpmdb, rpmTag rpmtag, /*@out@*/ dbiIndex * dbip)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbip, fileSystem @*/;
 
 /** \ingroup dbi
@@ -64,7 +64,7 @@ struct _dbiVec {
  * @return             0 on success
  */
     int (*close) (/*@only@*/ dbiIndex dbi, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, fileSystem @*/;
 
 /** \ingroup dbi
@@ -74,20 +74,47 @@ struct _dbiVec {
  * @return             0 on success
  */
     int (*sync) (dbiIndex dbi, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies fileSystem @*/;
 
 /** \ingroup dbi
+ * Associate secondary database with primary.
+ * @param dbi          index database handle
+ * @param dbisecondary secondary index database handle
+ * @param callback     create secondary key from primary (NULL if DB_RDONLY)
+ * @param flags                DB_CREATE or 0
+ * @return             0 on success
+ */
+    int (*associate) (dbiIndex dbi, dbiIndex dbisecondary,
+                int (*callback) (DB *, const DBT *, const DBT *, DBT *),
+                unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, fileSystem @*/;
+
+/** \ingroup dbi
+ * Return join cursor for list of cursors.
+ * @param dbi          index database handle
+ * @param curslist     NULL terminated list of database cursors
+ * @retval dbcp                address of join database cursor
+ * @param flags                DB_JOIN_NOSORT or 0
+ * @return             0 on success
+ */
+    int (*join) (dbiIndex dbi, DBC ** curslist, /*@out@*/ DBC ** dbcp,
+                unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, *dbcp, fileSystem @*/;
+
+/** \ingroup dbi
  * Open database cursor.
  * @param dbi          index database handle
  * @param txnid                database transaction handle
- * @retval dbcp                address of database cursor
- * @param flags                (unused)
+ * @retval dbcp                address of new database cursor
+ * @param dbiflags     DB_WRITECURSOR or 0
  * @return             0 on success
  */
     int (*copen) (dbiIndex dbi, /*@null@*/ DB_TXN * txnid,
-                       /*@out@*/ DBC ** dbcp, unsigned int flags)
-       /*@globals fileSystem@*/
+                       /*@out@*/ DBC ** dbcp, unsigned int dbiflags)
+       /*@globals fileSystem @*/
        /*@modifies dbi, *txnid, *dbcp, fileSystem @*/;
 
 /** \ingroup dbi
@@ -98,10 +125,23 @@ struct _dbiVec {
  * @return             0 on success
  */
     int (*cclose) (dbiIndex dbi, /*@only@*/ DBC * dbcursor, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, *dbcursor, fileSystem @*/;
 
 /** \ingroup dbi
+ * Duplicate a database cursor.
+ * @param dbi          index database handle
+ * @param dbcursor     database cursor
+ * @retval dbcp                address of new database cursor
+ * @param flags                DB_POSITION for same position, 0 for uninitialized
+ * @return             0 on success
+ */
+    int (*cdup) (dbiIndex dbi, DBC * dbcursor, /*@out@*/ DBC ** dbcp,
+               unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, *dbcp, fileSystem @*/;
+
+/** \ingroup dbi
  * Delete (key,data) pair(s) using db->del or dbcursor->c_del.
  * @param dbi          index database handle
  * @param dbcursor     database cursor (NULL will use db->del)
@@ -112,7 +152,7 @@ struct _dbiVec {
  */
     int (*cdel) (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
                        unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, fileSystem @*/;
 
 /** \ingroup dbi
@@ -126,10 +166,25 @@ struct _dbiVec {
  */
     int (*cget) (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
                        unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, *key, *data, fileSystem @*/;
 
 /** \ingroup dbi
+ * Retrieve (key,data) pair using dbcursor->c_pget.
+ * @param dbi          index database handle
+ * @param dbcursor     database cursor
+ * @param key          secondary retrieve key value/length/flags
+ * @param pkey         primary retrieve key value/length/flags
+ * @param data         primary retrieve data value/length/flags
+ * @param flags                DB_NEXT, DB_SET, or 0
+ * @return             0 on success
+ */
+    int (*cpget) (dbiIndex dbi, /*@null@*/ DBC * dbcursor,
+               DBT * key, DBT * pkey, DBT * data, unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies *dbcursor, *key, *pkey, *data, fileSystem @*/;
+
+/** \ingroup dbi
  * Store (key,data) pair using db->put or dbcursor->c_put.
  * @param dbi          index database handle
  * @param dbcursor     database cursor (NULL will use db->put)
@@ -140,7 +195,7 @@ struct _dbiVec {
  */
     int (*cput) (dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
                        unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, fileSystem @*/;
 
 /** \ingroup dbi
@@ -154,7 +209,7 @@ struct _dbiVec {
     int (*ccount) (dbiIndex dbi, DBC * dbcursor,
                        /*@out@*/ unsigned int * countp,
                        unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, fileSystem @*/;
 
 /** \ingroup dbi
@@ -163,8 +218,8 @@ struct _dbiVec {
  * @return             0 no
  */
     int (*byteswapped) (dbiIndex dbi)
-       /*@globals fileSystem@*/
-       /*@modifies fileSystem@*/;
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/;
 
 /** \ingroup dbi
  * Save statistics in database handle.
@@ -173,7 +228,7 @@ struct _dbiVec {
  * @return             0 on success
  */
     int (*stat) (dbiIndex dbi, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, fileSystem @*/;
 
 };
@@ -226,7 +281,7 @@ struct _dbiIndex {
     int        dbi_lorder;
 /*@unused@*/
     void (*db_errcall) (const char *db_errpfx, char *buffer)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies fileSystem @*/;
 /*@unused@*/ /*@shared@*/
     FILE *     dbi_errfile;
@@ -250,7 +305,7 @@ struct _dbiIndex {
 #if 0
     int        (*dbi_tx_recover) (DB_ENV *dbenv, DBT *log_rec,
                                DB_LSN *lsnp, int redo, void *info)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies fileSystem @*/;
 #endif
        /* dbinfo parameters */
@@ -409,7 +464,7 @@ extern const char *const prDbiOpenFlags(int dbflags, int print_dbenv_flags)
 /*@unused@*/ static inline
 int dbiCopen(dbiIndex dbi, /*@null@*/ DB_TXN * txnid,
                /*@out@*/ DBC ** dbcp, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, *dbcp, fileSystem @*/
 {
     return (*dbi->dbi_vec->copen) (dbi, txnid, dbcp, flags);
@@ -424,13 +479,29 @@ int dbiCopen(dbiIndex dbi, /*@null@*/ DB_TXN * txnid,
  */
 /*@unused@*/ static inline
 int dbiCclose(dbiIndex dbi, /*@only@*/ DBC * dbcursor, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, *dbcursor, fileSystem @*/
 {
     return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
 }
 
 /** \ingroup dbi
+ * Duplicate a database cursor.
+ * @param dbi          index database handle
+ * @param dbcursor     database cursor
+ * @retval dbcp                address of new database cursor
+ * @param flags                DB_POSITION for same position, 0 for uninitialized
+ * @return             0 on success
+ */
+/*@unused@*/ static inline
+int dbiCdup(dbiIndex dbi, DBC * dbcursor, /*@out@*/ DBC ** dbcp,
+               unsigned int flags)
+       /*@modifies dbi, *dbcp @*/
+{
+    return (*dbi->dbi_vec->cdup) (dbi, dbcursor, dbcp, flags);
+}
+
+/** \ingroup dbi
  * Delete (key,data) pair(s) from index database.
  * @param dbi          index database handle
  * @param dbcursor     database cursor (NULL will use db->del)
@@ -442,7 +513,7 @@ int dbiCclose(dbiIndex dbi, /*@only@*/ DBC * dbcursor, unsigned int flags)
 /*@unused@*/ static inline
 int dbiDel(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
                unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, fileSystem @*/
 {
     assert(key->size > 0);
@@ -461,7 +532,7 @@ int dbiDel(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
 /*@unused@*/ static inline
 int dbiGet(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
                unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, *key, *data, fileSystem @*/
 {
     assert((flags == DB_NEXT) || key->size > 0);
@@ -469,6 +540,26 @@ int dbiGet(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
 }
 
 /** \ingroup dbi
+ * Retrieve (key,data) pair using dbcursor->c_pget.
+ * @param dbi          index database handle
+ * @param dbcursor     database cursor (NULL will use db->get)
+ * @param key          secondary retrieve key value/length/flags
+ * @param pkey         primary retrieve key value/length/flags
+ * @param data         primary retrieve data value/length/flags
+ * @param flags                DB_NEXT, DB_SET, or 0
+ * @return             0 on success
+ */
+/*@unused@*/ static inline
+int dbiPget(dbiIndex dbi, /*@null@*/ DBC * dbcursor,
+               DBT * key, DBT * pkey, DBT * data, unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies *dbcursor, *key, *pkey, *data, fileSystem @*/
+{
+    assert((flags == DB_NEXT) || key->size > 0);
+    return (dbi->dbi_vec->cpget) (dbi, dbcursor, key, pkey, data, flags);
+}
+
+/** \ingroup dbi
  * Store (key,data) pair in index database.
  * @param dbi          index database handle
  * @param dbcursor     database cursor (NULL will use db->put)
@@ -480,7 +571,7 @@ int dbiGet(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
 /*@unused@*/ static inline
 int dbiPut(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
                unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, *key, fileSystem @*/
 {
     assert(key->size > 0);
@@ -498,7 +589,7 @@ int dbiPut(dbiIndex dbi, /*@null@*/ DBC * dbcursor, DBT * key, DBT * data,
 /*@unused@*/ static inline
 int dbiCount(dbiIndex dbi, DBC * dbcursor, /*@out@*/ unsigned int * countp,
                unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies *dbcursor, fileSystem @*/
 {
     return (*dbi->dbi_vec->ccount) (dbi, dbcursor, countp, flags);
@@ -512,7 +603,7 @@ int dbiCount(dbiIndex dbi, DBC * dbcursor, /*@out@*/ unsigned int * countp,
  */
 /*@unused@*/ static inline
 int dbiVerify(/*@only@*/ dbiIndex dbi, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, fileSystem @*/
 {
     dbi->dbi_verify_on_close = 1;
@@ -527,7 +618,7 @@ int dbiVerify(/*@only@*/ dbiIndex dbi, unsigned int flags)
  */
 /*@unused@*/ static inline
 int dbiClose(/*@only@*/ dbiIndex dbi, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies dbi, fileSystem @*/
 {
     return (*dbi->dbi_vec->close) (dbi, flags);
@@ -541,13 +632,48 @@ int dbiClose(/*@only@*/ dbiIndex dbi, unsigned int flags)
  */
 /*@unused@*/ static inline
 int dbiSync (dbiIndex dbi, unsigned int flags)
-       /*@globals fileSystem@*/
+       /*@globals fileSystem @*/
        /*@modifies fileSystem @*/
 {
     return (*dbi->dbi_vec->sync) (dbi, flags);
 }
 
 /** \ingroup dbi
+ * Associate secondary database with primary.
+ * @param dbi          index database handle
+ * @param dbisecondary secondary index database handle
+ * @param callback     create secondary key from primary (NULL if DB_RDONLY)
+ * @param flags                DB_CREATE or 0
+ * @return             0 on success
+ */
+/*@unused@*/ static inline
+int dbiAssociate(dbiIndex dbi, dbiIndex dbisecondary,
+                int (*callback) (DB *, const DBT *, const DBT *, DBT *),
+                unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, fileSystem @*/
+{
+    return (*dbi->dbi_vec->associate) (dbi, dbisecondary, callback, flags);
+}
+
+/** \ingroup dbi
+ * Return join cursor for list of cursors.
+ * @param dbi          index database handle
+ * @param curslist     NULL terminated list of database cursors
+ * @retval dbcp                address of join database cursor
+ * @param flags                DB_JOIN_NOSORT or 0
+ * @return             0 on success
+ */
+/*@unused@*/ static inline
+int dbiJoin(dbiIndex dbi, DBC ** curslist, /*@out@*/ DBC ** dbcp,
+                unsigned int flags)
+       /*@globals fileSystem @*/
+       /*@modifies dbi, *dbcp, fileSystem @*/
+{
+    return (*dbi->dbi_vec->join) (dbi, curslist, dbcp, flags);
+}
+
+/** \ingroup dbi
  * Is database byte swapped?
  * @param dbi          index database handle
  * @return             0 no