1 #include "system.h"
2
3 #include <sqlite3.h>
4 #include <fcntl.h>
5
6 #include <rpm/rpmlog.h>
7 #include <rpm/rpmfileutil.h>
8 #include <rpm/rpmmacro.h>
9 #include "lib/rpmdb_internal.h"
10
11 #include "debug.h"
12
13 static const int sleep_ms = 50;
14
15 struct dbiCursor_s {
16 sqlite3 *sdb;
17 sqlite3_stmt *stmt;
18 const char *fmt;
19 int flags;
20 rpmTagVal tag;
21 int ctype;
22 struct dbiCursor_s *subc;
23
24 const void *key;
25 unsigned int keylen;
26 };
27
28 static int sqlexec(sqlite3 *sdb, const char *fmt, ...);
29
rpm_match3(sqlite3_context * sctx,int argc,sqlite3_value ** argv)30 static void rpm_match3(sqlite3_context *sctx, int argc, sqlite3_value **argv)
31 {
32 int match = 0;
33 if (argc == 3) {
34 int b1len = sqlite3_value_bytes(argv[0]);
35 int b2len = sqlite3_value_bytes(argv[1]);
36 int n = sqlite3_value_int(argv[2]);
37 if (b1len >= n && b2len >= n) {
38 const char *b1 = sqlite3_value_blob(argv[0]);
39 const char *b2 = sqlite3_value_blob(argv[1]);
40 match = (memcmp(b1, b2, n) == 0);
41 }
42 }
43 sqlite3_result_int(sctx, match);
44 }
45
errCb(void * data,int err,const char * msg)46 static void errCb(void *data, int err, const char *msg)
47 {
48 rpmdb rdb = data;
49 rpmlog(RPMLOG_WARNING, "%s: %s: %s\n",
50 rdb->db_descr, sqlite3_errstr(err), msg);
51 }
52
dbiCursorReset(dbiCursor dbc)53 static int dbiCursorReset(dbiCursor dbc)
54 {
55 if (dbc->stmt) {
56 sqlite3_reset(dbc->stmt);
57 sqlite3_clear_bindings(dbc->stmt);
58 }
59 return 0;
60 }
61
dbiCursorResult(dbiCursor dbc)62 static int dbiCursorResult(dbiCursor dbc)
63 {
64 int rc = sqlite3_errcode(dbc->sdb);
65 int err = (rc != SQLITE_OK && rc != SQLITE_DONE && rc != SQLITE_ROW);
66 if (err) {
67 rpmlog(RPMLOG_ERR, "%s: %d: %s\n", sqlite3_sql(dbc->stmt),
68 sqlite3_errcode(dbc->sdb), sqlite3_errmsg(dbc->sdb));
69 }
70 return err ? RPMRC_FAIL : RPMRC_OK;
71 }
72
dbiCursorPrep(dbiCursor dbc,const char * fmt,...)73 static int dbiCursorPrep(dbiCursor dbc, const char *fmt, ...)
74 {
75 if (dbc->stmt == NULL) {
76 char *cmd = NULL;
77 va_list ap;
78
79 va_start(ap, fmt);
80 cmd = sqlite3_vmprintf(fmt, ap);
81 va_end(ap);
82
83 sqlite3_prepare_v2(dbc->sdb, cmd, -1, &dbc->stmt, NULL);
84 sqlite3_free(cmd);
85 } else {
86 dbiCursorReset(dbc);
87 }
88
89 return dbiCursorResult(dbc);
90 }
91
dbiCursorBindPkg(dbiCursor dbc,unsigned int hnum,void * blob,unsigned int bloblen)92 static int dbiCursorBindPkg(dbiCursor dbc, unsigned int hnum,
93 void *blob, unsigned int bloblen)
94 {
95 int rc = 0;
96
97 if (hnum)
98 rc = sqlite3_bind_int(dbc->stmt, 1, hnum);
99 else
100 rc = sqlite3_bind_null(dbc->stmt, 1);
101
102 if (blob) {
103 if (!rc)
104 rc = sqlite3_bind_blob(dbc->stmt, 2, blob, bloblen, NULL);
105 }
106 return dbiCursorResult(dbc);
107 }
108
dbiCursorBindIdx(dbiCursor dbc,const void * key,int keylen,dbiIndexItem rec)109 static int dbiCursorBindIdx(dbiCursor dbc, const void *key, int keylen,
110 dbiIndexItem rec)
111 {
112 int rc;
113 if (dbc->ctype == SQLITE_TEXT) {
114 rc = sqlite3_bind_text(dbc->stmt, 1, key, keylen, NULL);
115 } else {
116 rc = sqlite3_bind_blob(dbc->stmt, 1, key, keylen, NULL);
117 }
118
119 if (rec) {
120 if (!rc)
121 rc = sqlite3_bind_int(dbc->stmt, 2, rec->hdrNum);
122 if (!rc)
123 rc = sqlite3_bind_int(dbc->stmt, 3, rec->tagNum);
124 }
125
126 return dbiCursorResult(dbc);
127 }
128
sqlite_init(rpmdb rdb,const char * dbhome)129 static int sqlite_init(rpmdb rdb, const char * dbhome)
130 {
131 int rc = 0;
132 char *dbfile = NULL;
133
134 if (rdb->db_dbenv == NULL) {
135 dbfile = rpmGenPath(dbhome, rdb->db_ops->path, NULL);
136 sqlite3 *sdb = NULL;
137 int xx, flags = 0;
138 int retry_open = 1;
139 if ((rdb->db_mode & O_ACCMODE) == O_RDONLY)
140 flags |= SQLITE_OPEN_READONLY;
141 else
142 flags |= (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
143
144 while (retry_open--) {
145 xx = sqlite3_open_v2(dbfile, &sdb, flags, NULL);
146 /* Attempt to create if missing, discarding OPEN_READONLY (!) */
147 if (xx == SQLITE_CANTOPEN && (flags & SQLITE_OPEN_READONLY)) {
148 /* Sqlite allocates resources even on failure to open (!) */
149 sqlite3_close(sdb);
150 flags &= ~SQLITE_OPEN_READONLY;
151 flags |= (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
152 retry_open++;
153 }
154 }
155
156 if (xx != SQLITE_OK) {
157 rpmlog(RPMLOG_ERR, _("Unable to open sqlite database %s: %s\n"),
158 dbfile, sqlite3_errstr(xx));
159 rc = 1;
160 goto exit;
161 }
162
163 sqlite3_create_function(sdb, "match", 3,
164 (SQLITE_UTF8|SQLITE_DETERMINISTIC),
165 NULL, rpm_match3, NULL, NULL);
166
167 sqlite3_busy_timeout(sdb, sleep_ms);
168 sqlite3_config(SQLITE_CONFIG_LOG, errCb, rdb);
169
170 sqlexec(sdb, "PRAGMA secure_delete = OFF");
171 sqlexec(sdb, "PRAGMA case_sensitive_like = ON");
172
173 if (sqlite3_db_readonly(sdb, NULL) == 0) {
174 if (sqlexec(sdb, "PRAGMA journal_mode = WAL") == 0) {
175 int one = 1;
176 /* Annoying but necessary to support non-privileged readers */
177 sqlite3_file_control(sdb, NULL, SQLITE_FCNTL_PERSIST_WAL, &one);
178
179 if (!rpmExpandNumeric("%{?_flush_io}"))
180 sqlexec(sdb, "PRAGMA wal_autocheckpoint = 0");
181 }
182 }
183
184 rdb->db_dbenv = sdb;
185 }
186 rdb->db_opens++;
187
188 exit:
189 free(dbfile);
190 return rc;
191 }
192
sqlite_fini(rpmdb rdb)193 static int sqlite_fini(rpmdb rdb)
194 {
195 int rc = 0;
196 if (rdb) {
197 sqlite3 *sdb = rdb->db_dbenv;
198 if (rdb->db_opens > 1) {
199 rdb->db_opens--;
200 } else {
201 if (sqlite3_db_readonly(sdb, NULL) == 0) {
202 sqlexec(sdb, "PRAGMA optimize");
203 sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE");
204 }
205 rdb->db_dbenv = NULL;
206 int xx = sqlite3_close(sdb);
207 rc = (xx != SQLITE_OK);
208 }
209 }
210
211 return rc;
212 }
213
sqlexec(sqlite3 * sdb,const char * fmt,...)214 static int sqlexec(sqlite3 *sdb, const char *fmt, ...)
215 {
216 int rc = 0;
217 char *cmd = NULL;
218 char *err = NULL;
219 va_list ap;
220
221 va_start(ap, fmt);
222 cmd = sqlite3_vmprintf(fmt, ap);
223 va_end(ap);
224
225 /* sqlite3_exec() doesn't seeem to honor sqlite3_busy_timeout() */
226 while ((rc = sqlite3_exec(sdb, cmd, NULL, NULL, &err)) == SQLITE_BUSY) {
227 usleep(sleep_ms);
228 }
229
230 if (rc)
231 rpmlog(RPMLOG_ERR, "sqlite failure: %s: %s\n", cmd, err);
232 else
233 rpmlog(RPMLOG_DEBUG, "%s: %d\n", cmd, rc);
234
235 sqlite3_free(cmd);
236
237 return rc ? RPMRC_FAIL : RPMRC_OK;
238 }
239
dbiExists(dbiIndex dbi)240 static int dbiExists(dbiIndex dbi)
241 {
242 const char *col = (dbi->dbi_type == DBI_PRIMARY) ? "hnum" : "key";
243 const char *tbl = dbi->dbi_file;
244 int rc = sqlite3_table_column_metadata(dbi->dbi_db, NULL, tbl, col,
245 NULL, NULL, NULL, NULL, NULL);
246 return (rc == 0);
247 }
248
init_table(dbiIndex dbi,rpmTagVal tag)249 static int init_table(dbiIndex dbi, rpmTagVal tag)
250 {
251 int rc = 0;
252
253 if (dbiExists(dbi))
254 return 0;
255
256 if (dbi->dbi_type == DBI_PRIMARY) {
257 rc = sqlexec(dbi->dbi_db,
258 "CREATE TABLE IF NOT EXISTS '%q' ("
259 "hnum INTEGER PRIMARY KEY AUTOINCREMENT,"
260 "blob BLOB NOT NULL"
261 ")",
262 dbi->dbi_file);
263 } else {
264 const char *keytype = (rpmTagGetClass(tag) == RPM_STRING_CLASS) ?
265 "TEXT" : "BLOB";
266 rc = sqlexec(dbi->dbi_db,
267 "CREATE TABLE IF NOT EXISTS '%q' ("
268 "key '%q' NOT NULL, "
269 "hnum INTEGER NOT NULL, "
270 "idx INTEGER NOT NULL, "
271 "FOREIGN KEY (hnum) REFERENCES 'Packages'(hnum)"
272 ")",
273 dbi->dbi_file, keytype);
274 }
275 if (!rc)
276 dbi->dbi_flags |= DBI_CREATED;
277
278 return rc;
279 }
280
create_index(sqlite3 * sdb,const char * table,const char * col)281 static int create_index(sqlite3 *sdb, const char *table, const char *col)
282 {
283 return sqlexec(sdb,
284 "CREATE INDEX IF NOT EXISTS '%s_%s_idx' ON '%q'(%s ASC)",
285 table, col, table, col);
286 }
287
init_index(dbiIndex dbi,rpmTagVal tag)288 static int init_index(dbiIndex dbi, rpmTagVal tag)
289 {
290 int rc = 0;
291
292 /* Can't create on readonly database, but things will still work */
293 if (sqlite3_db_readonly(dbi->dbi_db, NULL) == 1)
294 return 0;
295
296 if (dbi->dbi_type == DBI_SECONDARY) {
297 int string = (rpmTagGetClass(tag) == RPM_STRING_CLASS);
298 int array = (rpmTagGetReturnType(tag) == RPM_ARRAY_RETURN_TYPE);
299 if (!rc && string)
300 rc = create_index(dbi->dbi_db, dbi->dbi_file, "key");
301 if (!rc && array)
302 rc = create_index(dbi->dbi_db, dbi->dbi_file, "hnum");
303 }
304 return rc;
305 }
306
sqlite_Open(rpmdb rdb,rpmDbiTagVal rpmtag,dbiIndex * dbip,int flags)307 static int sqlite_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
308 {
309 int rc = sqlite_init(rdb, rpmdbHome(rdb));
310
311 if (!rc) {
312 dbiIndex dbi = dbiNew(rdb, rpmtag);
313 dbi->dbi_db = rdb->db_dbenv;
314
315 rc = init_table(dbi, rpmtag);
316
317 if (!rc && !(rdb->db_flags & RPMDB_FLAG_REBUILD))
318 rc = init_index(dbi, rpmtag);
319
320 if (!rc && dbip)
321 *dbip = dbi;
322 else
323 dbiFree(dbi);
324 }
325
326 return rc;
327 }
328
sqlite_Close(dbiIndex dbi,unsigned int flags)329 static int sqlite_Close(dbiIndex dbi, unsigned int flags)
330 {
331 rpmdb rdb = dbi->dbi_rpmdb;
332 int rc = 0;
333 if (rdb->db_flags & RPMDB_FLAG_REBUILD)
334 rc = init_index(dbi, rpmTagGetValue(dbi->dbi_file));
335 sqlite_fini(dbi->dbi_rpmdb);
336 dbiFree(dbi);
337 return rc;
338 }
339
sqlite_Verify(dbiIndex dbi,unsigned int flags)340 static int sqlite_Verify(dbiIndex dbi, unsigned int flags)
341 {
342 int errors = -1;
343 int key_errors = -1;
344 sqlite3_stmt *s = NULL;
345 const char *cmd = "PRAGMA integrity_check";
346
347 if (dbi->dbi_type == DBI_SECONDARY)
348 return RPMRC_OK;
349
350 if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) {
351 errors = 0;
352 while (sqlite3_step(s) == SQLITE_ROW) {
353 const char *txt = (const char *)sqlite3_column_text(s, 0);
354 if (!rstreq(txt, "ok")) {
355 errors++;
356 rpmlog(RPMLOG_ERR, "verify: %s\n", txt);
357 }
358 }
359 sqlite3_finalize(s);
360 } else {
361 rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db));
362 }
363
364 /* No point checking higher-level errors if low-level errors exist */
365 if (errors)
366 goto exit;
367
368 cmd = "PRAGMA foreign_key_check";
369 if (sqlite3_prepare_v2(dbi->dbi_db, cmd, -1, &s, NULL) == SQLITE_OK) {
370 key_errors = 0;
371 while (sqlite3_step(s) == SQLITE_ROW) {
372 key_errors++;
373 rpmlog(RPMLOG_ERR, "verify key: %s[%lld]\n",
374 sqlite3_column_text(s, 0),
375 sqlite3_column_int64(s, 1));
376 }
377 sqlite3_finalize(s);
378 } else {
379 rpmlog(RPMLOG_ERR, "%s: %s\n", cmd, sqlite3_errmsg(dbi->dbi_db));
380 }
381
382 exit:
383
384 return (errors == 0 && key_errors == 0) ? RPMRC_OK : RPMRC_FAIL;
385 }
386
sqlite_SetFSync(rpmdb rdb,int enable)387 static void sqlite_SetFSync(rpmdb rdb, int enable)
388 {
389 sqlexec(rdb->db_dbenv,
390 "PRAGMA synchronous = %s", enable ? "FULL" : "OFF");
391 }
392
sqlite_Ctrl(rpmdb rdb,dbCtrlOp ctrl)393 static int sqlite_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
394 {
395 int rc = 0;
396
397 switch (ctrl) {
398 case DB_CTRL_LOCK_RW:
399 rc = sqlexec(rdb->db_dbenv, "SAVEPOINT 'rwlock'");
400 break;
401 case DB_CTRL_UNLOCK_RW:
402 rc = sqlexec(rdb->db_dbenv, "RELEASE 'rwlock'");
403 break;
404 default:
405 break;
406 }
407
408 return rc;
409 }
410
sqlite_CursorInit(dbiIndex dbi,unsigned int flags)411 static dbiCursor sqlite_CursorInit(dbiIndex dbi, unsigned int flags)
412 {
413 dbiCursor dbc = xcalloc(1, sizeof(*dbc));
414 dbc->sdb = dbi->dbi_db;
415 dbc->flags = flags;
416 dbc->tag = rpmTagGetValue(dbi->dbi_file);
417 if (rpmTagGetClass(dbc->tag) == RPM_STRING_CLASS) {
418 dbc->ctype = SQLITE_TEXT;
419 } else {
420 dbc->ctype = SQLITE_BLOB;
421 }
422 if (dbc->flags & DBC_WRITE)
423 sqlexec(dbc->sdb, "SAVEPOINT '%s'", dbi->dbi_file);
424 return dbc;
425 }
426
sqlite_CursorFree(dbiIndex dbi,dbiCursor dbc)427 static dbiCursor sqlite_CursorFree(dbiIndex dbi, dbiCursor dbc)
428 {
429 if (dbc) {
430 sqlite3_finalize(dbc->stmt);
431 if (dbc->subc)
432 dbiCursorFree(dbi, dbc->subc);
433 if (dbc->flags & DBC_WRITE)
434 sqlexec(dbc->sdb, "RELEASE '%s'", dbi->dbi_file);
435 free(dbc);
436 }
437 return NULL;
438 }
439
sqlite_pkgdbPut(dbiIndex dbi,dbiCursor dbc,unsigned int * hdrNum,unsigned char * hdrBlob,unsigned int hdrLen)440 static rpmRC sqlite_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum, unsigned char *hdrBlob, unsigned int hdrLen)
441 {
442 int rc = 0;
443 dbiCursor dbwc = NULL;
444
445 /* Avoid trashing existing query cursor on header rewrite */
446 if (hdrNum && *hdrNum) {
447 dbwc = dbiCursorInit(dbi, DBC_WRITE);
448 dbc = dbwc;
449 }
450
451 if (!rc) {
452 rc = dbiCursorPrep(dbc, "INSERT OR REPLACE INTO '%q' VALUES(?, ?)",
453 dbi->dbi_file);
454 }
455
456 if (!rc)
457 rc = dbiCursorBindPkg(dbc, *hdrNum, hdrBlob, hdrLen);
458
459 if (!rc)
460 while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {};
461
462 /* XXX rowid is a 64bit integer and could overflow hdrnum */
463 if (rc == SQLITE_DONE && *hdrNum == 0)
464 *hdrNum = sqlite3_last_insert_rowid(dbc->sdb);
465
466 rc = dbiCursorResult(dbc);
467
468 if (dbwc)
469 dbiCursorFree(dbi, dbwc);
470
471 return rc;
472 }
473
sqlite_pkgdbDel(dbiIndex dbi,dbiCursor dbc,unsigned int hdrNum)474 static rpmRC sqlite_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
475 {
476 int rc = dbiCursorPrep(dbc, "DELETE FROM '%q' WHERE hnum=?;",
477 dbi->dbi_file);
478
479 if (!rc)
480 rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0);
481
482 if (!rc)
483 while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {};
484
485 return dbiCursorResult(dbc);
486 }
487
sqlite_stepPkg(dbiCursor dbc,unsigned char ** hdrBlob,unsigned int * hdrLen)488 static rpmRC sqlite_stepPkg(dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen)
489 {
490 int rc = sqlite3_step(dbc->stmt);
491
492 if (rc == SQLITE_ROW) {
493 if (hdrLen)
494 *hdrLen = sqlite3_column_bytes(dbc->stmt, 1);
495 if (hdrBlob)
496 *hdrBlob = (void *) sqlite3_column_blob(dbc->stmt, 1);
497 }
498 return rc;
499 }
500
sqlite_pkgdbByKey(dbiIndex dbi,dbiCursor dbc,unsigned int hdrNum,unsigned char ** hdrBlob,unsigned int * hdrLen)501 static rpmRC sqlite_pkgdbByKey(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
502 {
503 int rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q' WHERE hnum=?",
504 dbi->dbi_file);
505
506 if (!rc)
507 rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0);
508
509 if (!rc)
510 rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen);
511
512 return dbiCursorResult(dbc);
513 }
514
sqlite_pkgdbIter(dbiIndex dbi,dbiCursor dbc,unsigned char ** hdrBlob,unsigned int * hdrLen)515 static rpmRC sqlite_pkgdbIter(dbiIndex dbi, dbiCursor dbc,
516 unsigned char **hdrBlob, unsigned int *hdrLen)
517 {
518 int rc = RPMRC_OK;
519 if (dbc->stmt == NULL) {
520 rc = dbiCursorPrep(dbc, "SELECT hnum, blob FROM '%q'", dbi->dbi_file);
521 }
522
523 if (!rc)
524 rc = sqlite_stepPkg(dbc, hdrBlob, hdrLen);
525
526 if (rc == SQLITE_DONE) {
527 rc = RPMRC_NOTFOUND;
528 } else {
529 rc = dbiCursorResult(dbc);
530 }
531
532 return rc;
533 }
534
sqlite_pkgdbGet(dbiIndex dbi,dbiCursor dbc,unsigned int hdrNum,unsigned char ** hdrBlob,unsigned int * hdrLen)535 static rpmRC sqlite_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen)
536 {
537 int rc;
538
539 if (hdrNum) {
540 rc = sqlite_pkgdbByKey(dbi, dbc, hdrNum, hdrBlob, hdrLen);
541 } else {
542 rc = sqlite_pkgdbIter(dbi, dbc, hdrBlob, hdrLen);
543 }
544
545 return rc;
546 }
547
sqlite_pkgdbKey(dbiIndex dbi,dbiCursor dbc)548 static unsigned int sqlite_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
549 {
550 return sqlite3_column_int(dbc->stmt, 0);
551 }
552
sqlite_idxdbByKey(dbiIndex dbi,dbiCursor dbc,const char * keyp,size_t keylen,int searchType,dbiIndexSet * set)553 static rpmRC sqlite_idxdbByKey(dbiIndex dbi, dbiCursor dbc,
554 const char *keyp, size_t keylen, int searchType,
555 dbiIndexSet *set)
556 {
557 int rc = RPMRC_NOTFOUND;
558
559 if (searchType == DBC_PREFIX_SEARCH) {
560 rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' "
561 "WHERE MATCH(key,'%q',%d) "
562 "ORDER BY key",
563 dbi->dbi_file, keyp, keylen);
564 } else {
565 rc = dbiCursorPrep(dbc, "SELECT hnum, idx FROM '%q' WHERE key=?",
566 dbi->dbi_file);
567 if (!rc)
568 rc = dbiCursorBindIdx(dbc, keyp, keylen, NULL);
569 }
570
571
572 if (!rc) {
573 while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {
574 unsigned int hnum = sqlite3_column_int(dbc->stmt, 0);
575 unsigned int tnum = sqlite3_column_int(dbc->stmt, 1);
576
577 if (*set == NULL)
578 *set = dbiIndexSetNew(5);
579 dbiIndexSetAppendOne(*set, hnum, tnum, 0);
580 }
581 }
582
583 if (rc == SQLITE_DONE) {
584 rc = (*set) ? RPMRC_OK : RPMRC_NOTFOUND;
585 } else {
586 rc = dbiCursorResult(dbc);
587 }
588
589 return rc;
590 }
591
sqlite_idxdbIter(dbiIndex dbi,dbiCursor dbc,dbiIndexSet * set)592 static rpmRC sqlite_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set)
593 {
594 int rc = RPMRC_OK;
595
596 if (dbc->stmt == NULL) {
597 rc = dbiCursorPrep(dbc, "SELECT DISTINCT key FROM '%q' ORDER BY key",
598 dbi->dbi_file);
599 if (set)
600 dbc->subc = dbiCursorInit(dbi, 0);
601 }
602
603 if (!rc)
604 rc = sqlite3_step(dbc->stmt);
605
606 if (rc == SQLITE_ROW) {
607 if (dbc->ctype == SQLITE_TEXT) {
608 dbc->key = sqlite3_column_text(dbc->stmt, 0);
609 } else {
610 dbc->key = sqlite3_column_blob(dbc->stmt, 0);
611 }
612 dbc->keylen = sqlite3_column_bytes(dbc->stmt, 0);
613 if (dbc->subc) {
614 rc = sqlite_idxdbByKey(dbi, dbc->subc, dbc->key, dbc->keylen,
615 DBC_NORMAL_SEARCH, set);
616 } else {
617 rc = RPMRC_OK;
618 }
619 } else if (rc == SQLITE_DONE) {
620 rc = RPMRC_NOTFOUND;
621 } else {
622 rc = dbiCursorResult(dbc);
623 }
624
625 return rc;
626 }
627
sqlite_idxdbGet(dbiIndex dbi,dbiCursor dbc,const char * keyp,size_t keylen,dbiIndexSet * set,int searchType)628 static rpmRC sqlite_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType)
629 {
630 int rc;
631 if (keyp) {
632 rc = sqlite_idxdbByKey(dbi, dbc, keyp, keylen, searchType, set);
633 } else {
634 rc = sqlite_idxdbIter(dbi, dbc, set);
635 }
636
637 return rc;
638 }
639
sqlite_idxdbPutOne(dbiIndex dbi,dbiCursor dbc,const char * keyp,size_t keylen,dbiIndexItem rec)640 static rpmRC sqlite_idxdbPutOne(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
641 {
642 int rc = dbiCursorPrep(dbc, "INSERT INTO '%q' VALUES(?, ?, ?)",
643 dbi->dbi_file);
644
645 if (!rc)
646 rc = dbiCursorBindIdx(dbc, keyp, keylen, rec);
647
648 if (!rc)
649 while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {};
650
651 return dbiCursorResult(dbc);
652 }
653
sqlite_idxdbPut(dbiIndex dbi,rpmTagVal rpmtag,unsigned int hdrNum,Header h)654 static rpmRC sqlite_idxdbPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
655 {
656 return tag2index(dbi, rpmtag, hdrNum, h, sqlite_idxdbPutOne);
657 }
658
sqlite_idxdbDel(dbiIndex dbi,rpmTagVal rpmtag,unsigned int hdrNum,Header h)659 static rpmRC sqlite_idxdbDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
660 {
661 dbiCursor dbc = dbiCursorInit(dbi, DBC_WRITE);
662 int rc = dbiCursorPrep(dbc, "DELETE FROM '%q' WHERE hnum=?", dbi->dbi_file);
663
664 if (!rc)
665 rc = dbiCursorBindPkg(dbc, hdrNum, NULL, 0);
666
667 if (!rc)
668 while ((rc = sqlite3_step(dbc->stmt)) == SQLITE_ROW) {};
669
670 rc = dbiCursorResult(dbc);
671 dbiCursorFree(dbi, dbc);
672 return rc;
673 }
674
sqlite_idxdbKey(dbiIndex dbi,dbiCursor dbc,unsigned int * keylen)675 static const void * sqlite_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
676 {
677 const void *key = NULL;
678 if (dbc) {
679 key = dbc->key;
680 if (key && keylen)
681 *keylen = dbc->keylen;
682 }
683 return key;
684 }
685
686
687
688 struct rpmdbOps_s sqlite_dbops = {
689 .name = "sqlite",
690 .path = "rpmdb.sqlite",
691
692 .open = sqlite_Open,
693 .close = sqlite_Close,
694 .verify = sqlite_Verify,
695 .setFSync = sqlite_SetFSync,
696 .ctrl = sqlite_Ctrl,
697
698 .cursorInit = sqlite_CursorInit,
699 .cursorFree = sqlite_CursorFree,
700
701 .pkgdbPut = sqlite_pkgdbPut,
702 .pkgdbDel = sqlite_pkgdbDel,
703 .pkgdbGet = sqlite_pkgdbGet,
704 .pkgdbKey = sqlite_pkgdbKey,
705
706 .idxdbGet = sqlite_idxdbGet,
707 .idxdbPut = sqlite_idxdbPut,
708 .idxdbDel = sqlite_idxdbDel,
709 .idxdbKey = sqlite_idxdbKey
710 };
711
712