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