Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Start moving init functions.
Vsevolod Stakhov committed 11 years ago
commit cae07a8ae4e1d20d4b9942d38f02aa34cae038a6
parent bdd4397
11 files changed +956 -864
modified libpkg/pkgdb_repo.c
@@ -53,368 +53,6 @@
#include "private/pkgdb.h"
#include "private/repodb.h"

-
/* The package repo schema major revision */
-
#define REPO_SCHEMA_MAJOR 2
-

-
/* The package repo schema minor revision.
-
   Minor schema changes don't prevent older pkgng
-
   versions accessing the repo. */
-
#define REPO_SCHEMA_MINOR 10
-

-
/* REPO_SCHEMA_VERSION=2007 */
-
#define REPO_SCHEMA_VERSION (REPO_SCHEMA_MAJOR * 1000 + REPO_SCHEMA_MINOR)
-

-
typedef enum _sql_prstmt_index {
-
	PKG = 0,
-
	DEPS,
-
	CAT1,
-
	CAT2,
-
	LIC1,
-
	LIC2,
-
	OPT1,
-
	OPT2,
-
	SHLIB1,
-
	SHLIB_REQD,
-
	SHLIB_PROV,
-
	ANNOTATE1,
-
	ANNOTATE2,
-
	EXISTS,
-
	VERSION,
-
	DELETE,
-
	FTS_APPEND,
-
	PRSTMT_LAST,
-
} sql_prstmt_index;
-

-
static sql_prstmt sql_prepared_statements[PRSTMT_LAST] = {
-
	[PKG] = {
-
		NULL,
-
		"INSERT INTO packages ("
-
		"origin, name, version, comment, desc, arch, maintainer, www, "
-
		"prefix, pkgsize, flatsize, licenselogic, cksum, path, manifestdigest, olddigest"
-
		")"
-
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16)",
-
		"TTTTTTTTTIIITTTT",
-
	},
-
	[DEPS] = {
-
		NULL,
-
		"INSERT INTO deps (origin, name, version, package_id) "
-
		"VALUES (?1, ?2, ?3, ?4)",
-
		"TTTI",
-
	},
-
	[CAT1] = {
-
		NULL,
-
		"INSERT OR IGNORE INTO categories(name) VALUES(?1)",
-
		"T",
-
	},
-
	[CAT2] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_categories(package_id, category_id) "
-
		"VALUES (?1, (SELECT id FROM categories WHERE name = ?2))",
-
		"IT",
-
	},
-
	[LIC1] = {
-
		NULL,
-
		"INSERT OR IGNORE INTO licenses(name) VALUES(?1)",
-
		"T",
-
	},
-
	[LIC2] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_licenses(package_id, license_id) "
-
		"VALUES (?1, (SELECT id FROM licenses WHERE name = ?2))",
-
		"IT",
-
	},
-
	[OPT1] = {
-
		NULL,
-
		"INSERT OR IGNORE INTO option(option) "
-
		"VALUES (?1)",
-
		"T",
-
	},
-
	[OPT2] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_option (option_id, value, package_id) "
-
		"VALUES (( SELECT option_id FROM option WHERE option = ?1), ?2, ?3)",
-
		"TTI",
-
	},
-
	[SHLIB1] = {
-
		NULL,
-
		"INSERT OR IGNORE INTO shlibs(name) VALUES(?1)",
-
		"T",
-
	},
-
	[SHLIB_REQD] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_shlibs_required(package_id, shlib_id) "
-
		"VALUES (?1, (SELECT id FROM shlibs WHERE name = ?2))",
-
		"IT",
-
	},
-
	[SHLIB_PROV] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_shlibs_provided(package_id, shlib_id) "
-
		"VALUES (?1, (SELECT id FROM shlibs WHERE name = ?2))",
-
		"IT",
-
	},
-
	[EXISTS] = {
-
		NULL,
-
		"SELECT count(*) FROM packages WHERE cksum=?1",
-
		"T",
-
	},
-
	[ANNOTATE1] = {
-
		NULL,
-
		"INSERT OR IGNORE INTO annotation(annotation) "
-
		"VALUES (?1)",
-
		"T",
-
	},
-
	[ANNOTATE2] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_annotation(package_id, tag_id, value_id) "
-
		"VALUES (?1,"
-
		" (SELECT annotation_id FROM annotation WHERE annotation=?2),"
-
		" (SELECT annotation_id FROM annotation WHERE annotation=?3))",
-
		"ITT",
-
	},
-
	[VERSION] = {
-
		NULL,
-
		"SELECT version FROM packages WHERE origin=?1",
-
		"T",
-
	},
-
	[DELETE] = {
-
		NULL,
-
		"DELETE FROM packages WHERE origin=?1;"
-
		"DELETE FROM pkg_search WHERE origin=?1;",
-
		"TT",
-
	},
-
	[FTS_APPEND] = {
-
		NULL,
-
		"INSERT OR ROLLBACK INTO pkg_search(id, name, origin) "
-
		"VALUES (?1, ?2 || '-' || ?3, ?4);",
-
		"ITTT"
-
	}
-
	/* PRSTMT_LAST */
-
};
-

-

-
static void
-
file_exists(sqlite3_context *ctx, int argc, sqlite3_value **argv)
-
{
-
	char	 fpath[MAXPATHLEN];
-
	sqlite3	*db = sqlite3_context_db_handle(ctx);
-
	char	*path = dirname(sqlite3_db_filename(db, "main"));
-
	char	 cksum[SHA256_DIGEST_LENGTH * 2 +1];
-

-
	if (argc != 2) {
-
		sqlite3_result_error(ctx, "file_exists needs two argument", -1);
-
		return;
-
	}
-

-
	snprintf(fpath, sizeof(fpath), "%s/%s", path, sqlite3_value_text(argv[0]));
-

-
	if (access(fpath, R_OK) == 0) {
-
		sha256_file(fpath, cksum);
-
		if (strcmp(cksum, sqlite3_value_text(argv[1])) == 0)
-
			sqlite3_result_int(ctx, 1);
-
		else
-
			sqlite3_result_int(ctx, 0);
-
	} else {
-
		sqlite3_result_int(ctx, 0);
-
	}
-
}
-

-
static int
-
get_repo_user_version(sqlite3 *sqlite, const char *database, int *reposcver)
-
{
-
	sqlite3_stmt *stmt;
-
	int retcode;
-
	char sql[BUFSIZ];
-
	const char *fmt = "PRAGMA %Q.user_version";
-

-
	assert(database != NULL);
-

-
	sqlite3_snprintf(sizeof(sql), sql, fmt, database);
-

-
	if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite, sql);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (sqlite3_step(stmt) == SQLITE_ROW) {
-
		*reposcver = sqlite3_column_int(stmt, 0);
-
		retcode = EPKG_OK;
-
	} else {
-
		*reposcver = -1;
-
		retcode = EPKG_FATAL;
-
	}
-
	sqlite3_finalize(stmt);
-
	return (retcode);
-
}
-

-
static int
-
initialize_prepared_statements(sqlite3 *sqlite)
-
{
-
	sql_prstmt_index i, last;
-
	int ret;
-

-
	last = PRSTMT_LAST;
-

-
	for (i = 0; i < last; i++) {
-
		ret = sqlite3_prepare_v2(sqlite, SQL(i), -1, &STMT(i), NULL);
-
		if (ret != SQLITE_OK) {
-
			ERROR_SQLITE(sqlite, SQL(i));
-
			return (EPKG_FATAL);
-
		}
-
	}
-

-
	return (EPKG_OK);
-
}
-

-
static int
-
run_prepared_statement(sql_prstmt_index s, ...)
-
{
-
	int retcode;	/* Returns SQLITE error code */
-
	va_list ap;
-
	sqlite3_stmt *stmt;
-
	int i;
-
	const char *argtypes;
-

-
	stmt = STMT(s);
-
	argtypes = sql_prepared_statements[s].argtypes;
-

-
	sqlite3_reset(stmt);
-

-
	va_start(ap, s);
-

-
	for (i = 0; argtypes[i] != '\0'; i++)
-
	{
-
		switch (argtypes[i]) {
-
		case 'T':
-
			sqlite3_bind_text(stmt, i + 1, va_arg(ap, const char*),
-
			    -1, SQLITE_STATIC);
-
			break;
-
		case 'I':
-
			sqlite3_bind_int64(stmt, i + 1, va_arg(ap, int64_t));
-
			break;
-
		}
-
	}
-

-
	va_end(ap);
-

-
	retcode = sqlite3_step(stmt);
-

-
	return (retcode);
-
}
-

-
void
-
pkgdb_repo_finalize_statements(void)
-
{
-
	sql_prstmt_index i, last;
-

-
	last = PRSTMT_LAST;
-

-
	for (i = 0; i < last; i++)
-
	{
-
		if (STMT(i) != NULL) {
-
			sqlite3_finalize(STMT(i));
-
			STMT(i) = NULL;
-
		}
-
	}
-
	return;
-
}
-

-
int
-
pkgdb_repo_open(const char *repodb, bool force, sqlite3 **sqlite,
-
	bool *incremental)
-
{
-
	bool db_not_open;
-
	int reposcver;
-
	int retcode = EPKG_OK;
-

-
	if (access(repodb, R_OK) == 0)
-
		*incremental = true;
-
	else
-
		*incremental = false;
-

-
	sqlite3_initialize();
-
	db_not_open = true;
-
	while (db_not_open) {
-
		if (sqlite3_open(repodb, sqlite) != SQLITE_OK) {
-
			sqlite3_shutdown();
-
			return (EPKG_FATAL);
-
		}
-

-
		db_not_open = false;
-

-
		/* If the schema is too old, or we're forcing a full
-
			   update, then we cannot do an incremental update.
-
			   Delete the existing repo, and promote this to a
-
			   full update */
-
		if (!*incremental)
-
			continue;
-
		retcode = get_repo_user_version(*sqlite, "main", &reposcver);
-
		if (retcode != EPKG_OK)
-
			return (EPKG_FATAL);
-
		if (force || reposcver != REPO_SCHEMA_VERSION) {
-
			if (reposcver != REPO_SCHEMA_VERSION)
-
				pkg_emit_error("re-creating repo to upgrade schema version "
-
						"from %d to %d", reposcver,
-
						REPO_SCHEMA_VERSION);
-
			sqlite3_close(*sqlite);
-
			unlink(repodb);
-
			*incremental = false;
-
			db_not_open = true;
-
		}
-
	}
-

-
	sqlite3_create_function(*sqlite, "file_exists", 2, SQLITE_ANY, NULL,
-
	    file_exists, NULL, NULL);
-

-
	if (!*incremental) {
-
		retcode = sql_exec(*sqlite, initsql, REPO_SCHEMA_VERSION);
-
		if (retcode != EPKG_OK)
-
			return (retcode);
-
	}
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkgdb_repo_init(sqlite3 *sqlite)
-
{
-
	int retcode = EPKG_OK;
-

-
	retcode = sql_exec(sqlite, "PRAGMA synchronous=default");
-
	if (retcode != EPKG_OK)
-
		return (retcode);
-

-
	retcode = sql_exec(sqlite, "PRAGMA foreign_keys=on");
-
	if (retcode != EPKG_OK)
-
		return (retcode);
-

-
	retcode = initialize_prepared_statements(sqlite);
-
	if (retcode != EPKG_OK)
-
		return (retcode);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
pkgdb_repo_close(sqlite3 *sqlite, bool commit)
-
{
-
	int retcode = EPKG_OK;
-

-
	if (sqlite == NULL)
-
		return (retcode);
-

-
	if (commit) {
-
		if (pkgdb_transaction_commit(sqlite, NULL) != SQLITE_OK)
-
			retcode = EPKG_FATAL;
-
	}
-
	else {
-
		if (pkgdb_transaction_rollback(sqlite, NULL) != SQLITE_OK)
-
				retcode = EPKG_FATAL;
-
	}
-
	pkgdb_repo_finalize_statements();
-

-
	return (retcode);
-
}
-

static int
maybe_delete_conflicting(const char *origin, const char *version,
			 const char *pkg_path, bool forced)
modified libpkg/private/pkg.h
@@ -369,7 +369,7 @@ struct pkg_repo {
	UT_hash_handle hh;

	/* Opaque repository data */
-
	void *repo_data;
+
	void *priv;
};

/* sql helpers */
@@ -578,7 +578,7 @@ int pkg_emit_filelist(struct pkg *, FILE *);

int do_extract_mtree(char *mtree, const char *prefix);

-
int pkg_repo_update_binary_pkgs(struct pkg_repo *repo, bool force);
+
int pkg_repo_binary_update(struct pkg_repo *repo, bool force);

bool ucl_object_emit_sbuf(const ucl_object_t *obj, enum ucl_emitter emit_type,
    struct sbuf **buf);
modified libpkg/private/pkgdb.h
@@ -68,38 +68,6 @@ struct pkgdb_it *pkgdb_it_new(struct pkgdb *db, sqlite3_stmt *s, int type, short
void pkgshell_open(const char **r);

/**
-
 * Open repodb for specified path
-
 * @param repodb path of repodb
-
 * @param force create repository if not exists
-
 * @param sqlite destination db pointer
-
 * @param incremental if this param is set to false, then database was re-created
-
 *  and thus needs to be updated
-
 * @return EPKG_OK if succeed
-
 */
-
int pkgdb_repo_open(const char *repodb, bool force, sqlite3 **sqlite,
-
	bool *incremental);
-

-
/**
-
 * Init repository for pkgdb_repo* functions
-
 * @param sqlite sqlite object
-
 * @return EPKG_OK if succeed
-
 */
-
int pkgdb_repo_init(sqlite3 *sqlite);
-

-
/**
-
 * Finalize prepared statements for a repo
-
 */
-
void pkgdb_repo_finalize_statements(void);
-

-
/**
-
 * Close repodb and commit/rollback transaction started
-
 * @param sqlite sqlite pointer
-
 * @param commit commit transaction if true, rollback otherwise
-
 * @return EPKG_OK if succeed
-
 */
-
int pkgdb_repo_close(sqlite3 *sqlite, bool commit);
-

-
/**
 * Check whether a package with the cehcksum specified exists in pkg_repo
 * @param sqlite sqlite pointer
 * @param cksum sha256 printed checksum
modified libpkg/private/repodb.h
@@ -40,452 +40,5 @@ static const char repo_digests_archive[] = "digests";
static const char repo_conflicts_file[] = "conflicts";
static const char repo_conflicts_archive[] = "conflicts";

-
static const char initsql[] = ""
-
	"CREATE TABLE packages ("
-
	    "id INTEGER PRIMARY KEY,"
-
	    "origin TEXT UNIQUE,"
-
	    "name TEXT NOT NULL,"
-
	    "version TEXT NOT NULL,"
-
	    "comment TEXT NOT NULL,"
-
	    "desc TEXT NOT NULL,"
-
	    "osversion TEXT,"
-
	    "arch TEXT NOT NULL,"
-
	    "maintainer TEXT NOT NULL,"
-
	    "www TEXT,"
-
	    "prefix TEXT NOT NULL,"
-
	    "pkgsize INTEGER NOT NULL,"
-
	    "flatsize INTEGER NOT NULL,"
-
	    "licenselogic INTEGER NOT NULL,"
-
	    "cksum TEXT NOT NULL,"
-
	    /* relative path to the package in the repository */
-
	    "path TEXT NOT NULL,"
-
	    "pkg_format_version INTEGER,"
-
	    "manifestdigest TEXT NULL,"
-
	    "olddigest TEXT NULL"
-
	");"
-
	"CREATE TABLE deps ("
-
	    "origin TEXT,"
-
	    "name TEXT,"
-
	    "version TEXT,"
-
	    "package_id INTEGER REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "UNIQUE(package_id, origin)"
-
	");"
-
	"CREATE TABLE categories ("
-
	    "id INTEGER PRIMARY KEY, "
-
	    "name TEXT NOT NULL UNIQUE "
-
	");"
-
	"CREATE TABLE pkg_categories ("
-
	    "package_id INTEGER REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "category_id INTEGER REFERENCES categories(id)"
-
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
	    "UNIQUE(package_id, category_id)"
-
	");"
-
	"CREATE TABLE licenses ("
-
	    "id INTEGER PRIMARY KEY,"
-
	    "name TEXT NOT NULL UNIQUE"
-
	");"
-
	"CREATE TABLE pkg_licenses ("
-
	    "package_id INTEGER REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "license_id INTEGER REFERENCES licenses(id)"
-
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
	    "UNIQUE(package_id, license_id)"
-
	");"
-
	"CREATE TABLE option ("
-
		"option_id INTEGER PRIMARY KEY,"
-
		"option TEXT NOT NULL UNIQUE"
-
	");"
-
	"CREATE TABLE option_desc ("
-
		"option_desc_id INTEGER PRIMARY KEY,"
-
		"option_desc TEXT NOT NULL UNIQUE"
-
	");"
-
	"CREATE TABLE pkg_option ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"value TEXT NOT NULL,"
-
		"PRIMARY KEY(package_id, option_id)"
-
	");"
-
	"CREATE TABLE pkg_option_desc ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"option_desc_id INTEGER NOT NULL "
-
			"REFERENCES option_desc(option_desc_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"PRIMARY KEY(package_id, option_id)"
-
	");"
-
	"CREATE TABLE pkg_option_default ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"default_value TEXT NOT NULL,"
-
		"PRIMARY KEY(package_id, option_id)"
-
	");"
-
	"CREATE TABLE shlibs ("
-
	    "id INTEGER PRIMARY KEY,"
-
	    "name TEXT NOT NULL UNIQUE "
-
	");"
-
	"CREATE TABLE pkg_shlibs_required ("
-
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
-
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
	    "UNIQUE(package_id, shlib_id)"
-
	");"
-
	"CREATE TABLE pkg_shlibs_provided ("
-
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
-
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
	    "UNIQUE(package_id, shlib_id)"
-
	");"
-
	"CREATE TABLE annotation ("
-
	    "annotation_id INTEGER PRIMARY KEY,"
-
	    "annotation TEXT NOT NULL UNIQUE"
-
	");"
-
	"CREATE TABLE pkg_annotation ("
-
	    "package_id INTERGER REFERENCES packages(id)"
-
	    " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	    "tag_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
-
	    " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	    "value_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
-
	    " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	    "UNIQUE (package_id, tag_id)"
-
	");"
-
	"CREATE TABLE pkg_conflicts ("
-
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "conflict_id INTEGER NOT NULL,"
-
	    "UNIQUE(package_id, conflict_id)"
-
	");"
-
	"CREATE TABLE provides("
-
	"    id INTEGER PRIMARY KEY,"
-
	"    provide TEXT NOT NULL"
-
	");"
-
	"CREATE TABLE pkg_provides ("
-
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "provide_id INTEGER NOT NULL REFERENCES provides(id)"
-
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
	    "UNIQUE(package_id, provide_id)"
-
	");"
-
	"CREATE INDEX packages_origin ON packages(origin COLLATE NOCASE);"
-
	"CREATE INDEX packages_name ON packages(name COLLATE NOCASE);"
-
	"CREATE INDEX packages_uid_nocase ON packages(name COLLATE NOCASE, origin COLLATE NOCASE);"
-
	"CREATE INDEX packages_version_nocase ON packages(name COLLATE NOCASE, version);"
-
	"CREATE INDEX packages_uid ON packages(name, origin);"
-
	"CREATE INDEX packages_version ON packages(name, version);"
-
	"CREATE UNIQUE INDEX packages_digest ON packages(manifestdigest);"
-
	/* FTS search table */
-
	"CREATE VIRTUAL TABLE pkg_search USING fts4(id, name, origin);"
-

-
	"PRAGMA user_version=%d;"
-
	;
-

-
struct repo_changes {
-
	int version;		/* The repo schema this change applies to */
-
	int next_version;	/* The repo schema this change creates */
-
	const char *message;
-
	const char *sql;
-
};
-

-
/* How to upgrade an older repo to match what the current system
-
   expects */
-
static const struct repo_changes repo_upgrades[] = {
-
	{2001,
-
	 2002,
-
	 "Modify shlib tracking to add \'provided\' capability",
-

-
	 "CREATE TABLE %Q.pkg_shlibs_required ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id)"
-
		" ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
-
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
		"UNIQUE (package_id, shlib_id)"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_shlibs_provided ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id)"
-
		" ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
-
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
		"UNIQUE (package_id, shlib_id)"
-
	 ");"
-
	 "INSERT INTO %Q.pkg_shlibs_required (package_id, shlib_id)"
-
		" SELECT package_id, shlib_id FROM %Q.pkg_shlibs;"
-
	 "DROP TABLE %Q.pkg_shlibs;"
-
	},
-
	{2002,
-
	 2003,
-
	 "Add abstract metadata capability",
-

-
	 "CREATE TABLE %Q.abstract ("
-
		"abstract_id INTEGER PRIMARY KEY,"
-
		"abstract TEXT NOT NULL UNIQUE"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_abstract ("
-
		"package_id INTERGER REFERENCES packages(id)"
-
		" ON DELETE CASCADE ON UPDATE RESTRICT,"
-
		"key_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
-
		" ON DELETE CASCADE ON UPDATE RESTRICT,"
-
		"value_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
-
		" ON DELETE CASCADE ON UPDATE RESTRICT"
-
	 ");"
-
	},
-
	{2003,
-
	 2004,
-
	"Add manifest digest field",
-

-
	"ALTER TABLE %Q.packages ADD COLUMN manifestdigest TEXT NULL;"
-
	"CREATE INDEX IF NOT EXISTS %Q.pkg_digest_id ON packages(origin, manifestdigest);"
-
	},
-
	{2004,
-
	 2005,
-
	 "Rename 'abstract metadata' to 'annotations'",
-

-
	 "CREATE TABLE %Q.annotation ("
-
	        "annotation_id INTEGER PRIMARY KEY,"
-
	        "annotation TEXT NOT NULL UNIQUE"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_annotation ("
-
	        "package_id INTEGER REFERENCES packages(id)"
-
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	        "tag_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
-
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	        "value_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
-
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	        "UNIQUE (package_id, tag_id)"
-
	 ");"
-
	 "INSERT INTO %Q.annotation (annotation_id, annotation)"
-
	        " SELECT abstract_id, abstract FROM %Q.abstract;"
-
	 "INSERT INTO %Q.pkg_annotation (package_id,tag_id,value_id)"
-
	        " SELECT package_id,key_id,value_id FROM %Q.pkg_abstract;"
-
	 "DROP TABLE pkg_abstract;"
-
	 "DROP TABLE abstract;"
-
	},
-
	{2005,
-
	 2006,
-
	 "Add capability to track option descriptions and defaults",
-

-
	 "CREATE TABLE %Q.option ("
-
		"option_id INTEGER PRIMARY KEY,"
-
		"option TEXT NOT NULL UNIQUE"
-
	 ");"
-
	 "CREATE TABLE %Q.option_desc ("
-
		"option_desc_id INTEGER PRIMARY KEY,"
-
		"option_desc TEXT NOT NULL UNIQUE"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_option ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"value TEXT NOT NULL,"
-
		"PRIMARY KEY(package_id, option_id)"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_option_desc ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"option_desc_id INTEGER NOT NULL "
-
			"REFERENCES option_desc(option_desc_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"PRIMARY KEY(package_id, option_id)"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_option_default ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
-
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
-
		"default_value TEXT NOT NULL,"
-
		"PRIMARY KEY(package_id, option_id)"
-
	 ");"
-
	 "INSERT INTO %Q.option (option) "
-
		"SELECT DISTINCT option FROM %Q.options;"
-
	 "INSERT INTO %Q.pkg_option(package_id, option_id, value) "
-
		"SELECT package_id, option_id, value "
-
		"FROM %Q.options oo JOIN %Q.option o "
-
			"ON (oo.option = o.option);"
-
	 "DROP TABLE %Q.options;",
-
	},
-
	{2006,
-
	 2007,
-
	 "Add conflicts and provides",
-

-
	"CREATE TABLE %Q.pkg_conflicts ("
-
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "conflict_id INTEGER NOT NULL,"
-
	    "UNIQUE(package_id, conflict_id)"
-
	");"
-
	"CREATE TABLE %Q.provides("
-
	"    id INTEGER PRIMARY KEY,"
-
	"    provide TEXT NOT NULL"
-
	");"
-
	"CREATE TABLE %Q.pkg_provides ("
-
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
-
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
-
	    "provide_id INTEGER NOT NULL REFERENCES provides(id)"
-
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
	    "UNIQUE(package_id, provide_id)"
-
	");"
-
	},
-
	{2007,
-
	 2008,
-
	 "Add FTS index",
-

-
	 "CREATE VIRTUAL TABLE %Q.pkg_search USING fts4(id, name, origin);"
-
	 "INSERT INTO %Q.pkg_search SELECT id, name || '-' || version, origin FROM %Q.packages;"
-
	 "CREATE INDEX %Q.packages_origin ON packages(origin COLLATE NOCASE);"
-
	 "CREATE INDEX %Q.packages_name ON packages(name COLLATE NOCASE);"
-
	},
-
	{2008,
-
	 2009,
-
	 "Optimize indicies",
-

-
	 "CREATE INDEX IF NOT EXISTS %Q.packages_uid_nocase ON packages(name COLLATE NOCASE, origin COLLATE NOCASE);"
-
	 "CREATE INDEX IF NOT EXISTS %Q.packages_version_nocase ON packages(name COLLATE NOCASE, version);"
-
	 "CREATE INDEX IF NOT EXISTS %Q.packages_uid ON packages(name, origin);"
-
	 "CREATE INDEX IF NOT EXISTS %Q.packages_version ON packages(name, version);"
-
	 "CREATE UNIQUE INDEX IF NOT EXISTS %Q.packages_digest ON packages(manifestdigest);"
-
	},
-
	{2009,
-
	 2010,
-
	 "Add legacy digest field",
-

-
	 "ALTER TABLE %Q.packages ADD COLUMN olddigest TEXT NULL;"
-
	 "UPDATE %Q.packages SET olddigest=manifestdigest WHERE olddigest=NULL;"
-
	},
-
	/* Mark the end of the array */
-
	{ -1, -1, NULL, NULL, }
-

-
};
-

-
/* How to downgrade a newer repo to match what the current system
-
   expects */
-
static const struct repo_changes repo_downgrades[] = {
-
	{2010,
-
	 2009,
-
	 "Drop olddigest field",
-

-
	 "ALTER TABLE %Q.packages REMOVE COLUMN olddigest;"
-
	},
-
	{2009,
-
	 2008,
-
	 "Drop indicies",
-

-
	 "DROP INDEX %Q.packages_uid_nocase;"
-
	 "DROP INDEX %Q.packages_version_nocase;"
-
	 "DROP INDEX %Q.packages_uid;"
-
	 "DROP INDEX %Q.packages_version;"
-
	 "DROP INDEX %Q.packages_digest;"
-
	},
-
	{2008,
-
	 2007,
-
	 "Drop FTS index",
-

-
	 "DROP TABLE %Q.pkg_search;"
-
	},
-
	{2007,
-
	 2006,
-
	 "Revert conflicts and provides creation",
-

-
	 "DROP TABLE %Q.pkg_provides;"
-
	 "DROP TABLE %Q.provides;"
-
	 "DROP TABLE %Q.conflicts;"
-
	},
-
	{2006,
-
	 2005,
-
	 "Revert addition of extra options related data",
-

-
	 "CREATE TABLE %Q.options ("
-
		"package_id INTEGER REFERENCES packages(id) "
-
			"ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"option TEXT,"
-
		"value TEXT,"
-
		"PRIMARY KEY(package_id,option)"
-
	 ");"
-
	 "INSERT INTO %Q.options (package_id, option, value) "
-
		 "SELECT package_id, option, value "
-
		"FROM %Q.pkg_option JOIN %Q.option USING(option_id);"
-
	 "DROP TABLE pkg_option;"
-
	 "DROP TABLE pkg_option_default;"
-
	 "DROP TABLE option;"
-
	 "DROP TABLE pkg_option_desc;"
-
	 "DROP TABLE option_desc;",
-
	},
-
	{2005,
-
	 2004,
-
	 "Revert rename of 'abstract metadata' to 'annotations'",
-

-
	 "CREATE TABLE %Q.abstract ("
-
	        "abstract_id INTEGER PRIMARY KEY,"
-
	        "abstract TEXT NOT NULL UNIQUE"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_abstract ("
-
	        "package_id INTEGER REFERENCES packages(id)"
-
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	        "key_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
-
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
-
	        "value_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
-
	        " ON DELETE CASCADE ON UPDATE RESTRICT"
-
	 ");"
-
	 "INSERT INTO %Q.abstract (abstract_id, abstract)"
-
	        " SELECT annotation_id, annotation FROM %Q.annotation;"
-
	 "INSERT INTO %Q.pkg_abstract (package_id,key_id,value_id)"
-
	        " SELECT package_id,tag_id,value_id FROM %Q.pkg_annotation;"
-
	 "DROP TABLE %Q.pkg_annotation;"
-
	 "DROP TABLE %Q.annotation;"
-
	},
-
	{2004,
-
	 2003,
-
	 "Drop manifest digest index",
-

-
	 "DROP INDEX %Q.pkg_digest_id;"
-
	},
-
	{2003,
-
	 2002,
-
	 "Drop abstract metadata",
-

-
	 "DROP TABLE %Q.pkg_abstract;"
-
	 "DROP TABLE %Q.abstract;"
-
	},
-
	{2002,
-
	 2001,
-
	 "Drop \'shlibs provided\' but retain \'shlibs required\'",
-

-
	 "CREATE TABLE %Q.pkg_shlibs_required ("
-
		"package_id INTEGER NOT NULL REFERENCES packages(id)"
-
		" ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
-
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
		"UNIQUE (package_id, shlib_id)"
-
	 ");"
-
	 "CREATE TABLE %Q.pkg_shlibs ("
-
		"package_id INTEGER REFERENCES packages(id)"
-
		" ON DELETE CASCADE ON UPDATE CASCADE,"
-
		"shlib_id INTEGER REFERENCES shlibs(id)"
-
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
-
		"PRIMARY KEY (package_id, shlib_id)"
-
	 ");"
-
	 "INSERT INTO %Q.pkg_shlibs (package_id, shlib_id)"
-
		" SELECT package_id, shlib_id FROM %Q.pkg_shlibs_required;"
-
	 "DELETE FROM %Q.shlibs WHERE id NOT IN"
-
		" (SELECT shlib_id FROM %Q.pkg_shlibs);"
-
	 "DROP TABLE %Q.pkg_shlibs_provided;"
-
	 "DROP TABLE %Q.pkg_shlibs_required;"
-
	},
-

-

-
	/* Mark the end of the array */
-
	{ -1, -1, NULL, NULL, }
-

-
};

#endif	/* _REPODB */
modified libpkg/repo/binary/Makefile.am
@@ -7,7 +7,8 @@ pkg_common_cflags= -I$(top_srcdir)/libpkg \
			-I$(top_srcdir)/external/sqlite \
			-Wno-pointer-sign

-
librepo_binary_la_SOURCES= binary.c \
+
librepo_binary_la_SOURCES=	binary.c \
+
							init.c \
							update.c
librepo_binary_la_CFLAGS=	$(pkg_common_cflags) -shared

modified libpkg/repo/binary/binary.c
@@ -25,11 +25,11 @@

struct pkg_repo_ops pkg_repo_binary_ops = {
	.type = "binary",
-
	.init = NULL,
+
	.init = pkg_repo_binary_init,
	.access = NULL,
	.open = NULL,
-
	.close = NULL,
-
	.update = pkg_repo_update_binary_pkgs,
+
	.close = pkg_repo_binary_close,
+
	.update = pkg_repo_binary_update,
	.query = NULL,
	.fetch_pkg = NULL
};
modified libpkg/repo/binary/binary.h
@@ -30,6 +30,8 @@

extern struct pkg_repo_ops pkg_repo_binary_ops;

-
int pkg_repo_update_binary_pkgs(struct pkg_repo *repo, bool force);
+
int pkg_repo_binary_update(struct pkg_repo *repo, bool force);
+
int pkg_repo_binary_init(struct pkg_repo *repo);
+
int pkg_repo_binary_close(struct pkg_repo *repo, bool commit);

#endif /* BINARY_H_ */
added libpkg/repo/binary/binary_private.h
@@ -0,0 +1,617 @@
+
/* Copyright (c) 2014, Vsevolod Stakhov
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 *       * Redistributions of source code must retain the above copyright
+
 *         notice, this list of conditions and the following disclaimer.
+
 *       * Redistributions in binary form must reproduce the above copyright
+
 *         notice, this list of conditions and the following disclaimer in the
+
 *         documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+
#ifndef INIT_PRIVATE_H_
+
#define INIT_PRIVATE_H_
+

+
#include <sqlite3.h>
+

+
#include "pkg.h"
+
#include "private/pkg.h"
+

+
static const char initsql[] = ""
+
	"CREATE TABLE packages ("
+
	    "id INTEGER PRIMARY KEY,"
+
	    "origin TEXT UNIQUE,"
+
	    "name TEXT NOT NULL,"
+
	    "version TEXT NOT NULL,"
+
	    "comment TEXT NOT NULL,"
+
	    "desc TEXT NOT NULL,"
+
	    "osversion TEXT,"
+
	    "arch TEXT NOT NULL,"
+
	    "maintainer TEXT NOT NULL,"
+
	    "www TEXT,"
+
	    "prefix TEXT NOT NULL,"
+
	    "pkgsize INTEGER NOT NULL,"
+
	    "flatsize INTEGER NOT NULL,"
+
	    "licenselogic INTEGER NOT NULL,"
+
	    "cksum TEXT NOT NULL,"
+
	    /* relative path to the package in the repository */
+
	    "path TEXT NOT NULL,"
+
	    "pkg_format_version INTEGER,"
+
	    "manifestdigest TEXT NULL,"
+
	    "olddigest TEXT NULL"
+
	");"
+
	"CREATE TABLE deps ("
+
	    "origin TEXT,"
+
	    "name TEXT,"
+
	    "version TEXT,"
+
	    "package_id INTEGER REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "UNIQUE(package_id, origin)"
+
	");"
+
	"CREATE TABLE categories ("
+
	    "id INTEGER PRIMARY KEY, "
+
	    "name TEXT NOT NULL UNIQUE "
+
	");"
+
	"CREATE TABLE pkg_categories ("
+
	    "package_id INTEGER REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "category_id INTEGER REFERENCES categories(id)"
+
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
	    "UNIQUE(package_id, category_id)"
+
	");"
+
	"CREATE TABLE licenses ("
+
	    "id INTEGER PRIMARY KEY,"
+
	    "name TEXT NOT NULL UNIQUE"
+
	");"
+
	"CREATE TABLE pkg_licenses ("
+
	    "package_id INTEGER REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "license_id INTEGER REFERENCES licenses(id)"
+
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
	    "UNIQUE(package_id, license_id)"
+
	");"
+
	"CREATE TABLE option ("
+
		"option_id INTEGER PRIMARY KEY,"
+
		"option TEXT NOT NULL UNIQUE"
+
	");"
+
	"CREATE TABLE option_desc ("
+
		"option_desc_id INTEGER PRIMARY KEY,"
+
		"option_desc TEXT NOT NULL UNIQUE"
+
	");"
+
	"CREATE TABLE pkg_option ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"value TEXT NOT NULL,"
+
		"PRIMARY KEY(package_id, option_id)"
+
	");"
+
	"CREATE TABLE pkg_option_desc ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"option_desc_id INTEGER NOT NULL "
+
			"REFERENCES option_desc(option_desc_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"PRIMARY KEY(package_id, option_id)"
+
	");"
+
	"CREATE TABLE pkg_option_default ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"default_value TEXT NOT NULL,"
+
		"PRIMARY KEY(package_id, option_id)"
+
	");"
+
	"CREATE TABLE shlibs ("
+
	    "id INTEGER PRIMARY KEY,"
+
	    "name TEXT NOT NULL UNIQUE "
+
	");"
+
	"CREATE TABLE pkg_shlibs_required ("
+
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
+
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
	    "UNIQUE(package_id, shlib_id)"
+
	");"
+
	"CREATE TABLE pkg_shlibs_provided ("
+
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
+
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
	    "UNIQUE(package_id, shlib_id)"
+
	");"
+
	"CREATE TABLE annotation ("
+
	    "annotation_id INTEGER PRIMARY KEY,"
+
	    "annotation TEXT NOT NULL UNIQUE"
+
	");"
+
	"CREATE TABLE pkg_annotation ("
+
	    "package_id INTERGER REFERENCES packages(id)"
+
	    " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	    "tag_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
+
	    " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	    "value_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
+
	    " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	    "UNIQUE (package_id, tag_id)"
+
	");"
+
	"CREATE TABLE pkg_conflicts ("
+
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "conflict_id INTEGER NOT NULL,"
+
	    "UNIQUE(package_id, conflict_id)"
+
	");"
+
	"CREATE TABLE provides("
+
	"    id INTEGER PRIMARY KEY,"
+
	"    provide TEXT NOT NULL"
+
	");"
+
	"CREATE TABLE pkg_provides ("
+
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "provide_id INTEGER NOT NULL REFERENCES provides(id)"
+
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
	    "UNIQUE(package_id, provide_id)"
+
	");"
+
	"CREATE INDEX packages_origin ON packages(origin COLLATE NOCASE);"
+
	"CREATE INDEX packages_name ON packages(name COLLATE NOCASE);"
+
	"CREATE INDEX packages_uid_nocase ON packages(name COLLATE NOCASE, origin COLLATE NOCASE);"
+
	"CREATE INDEX packages_version_nocase ON packages(name COLLATE NOCASE, version);"
+
	"CREATE INDEX packages_uid ON packages(name, origin);"
+
	"CREATE INDEX packages_version ON packages(name, version);"
+
	"CREATE UNIQUE INDEX packages_digest ON packages(manifestdigest);"
+
	/* FTS search table */
+
	"CREATE VIRTUAL TABLE pkg_search USING fts4(id, name, origin);"
+

+
	"PRAGMA user_version=%d;"
+
	;
+

+
struct repo_changes {
+
	int version;		/* The repo schema this change applies to */
+
	int next_version;	/* The repo schema this change creates */
+
	const char *message;
+
	const char *sql;
+
};
+

+
/* How to upgrade an older repo to match what the current system
+
   expects */
+
static const struct repo_changes repo_upgrades[] = {
+
	{2001,
+
	 2002,
+
	 "Modify shlib tracking to add \'provided\' capability",
+

+
	 "CREATE TABLE %Q.pkg_shlibs_required ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id)"
+
		" ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
+
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
		"UNIQUE (package_id, shlib_id)"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_shlibs_provided ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id)"
+
		" ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
+
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
		"UNIQUE (package_id, shlib_id)"
+
	 ");"
+
	 "INSERT INTO %Q.pkg_shlibs_required (package_id, shlib_id)"
+
		" SELECT package_id, shlib_id FROM %Q.pkg_shlibs;"
+
	 "DROP TABLE %Q.pkg_shlibs;"
+
	},
+
	{2002,
+
	 2003,
+
	 "Add abstract metadata capability",
+

+
	 "CREATE TABLE %Q.abstract ("
+
		"abstract_id INTEGER PRIMARY KEY,"
+
		"abstract TEXT NOT NULL UNIQUE"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_abstract ("
+
		"package_id INTERGER REFERENCES packages(id)"
+
		" ON DELETE CASCADE ON UPDATE RESTRICT,"
+
		"key_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
+
		" ON DELETE CASCADE ON UPDATE RESTRICT,"
+
		"value_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
+
		" ON DELETE CASCADE ON UPDATE RESTRICT"
+
	 ");"
+
	},
+
	{2003,
+
	 2004,
+
	"Add manifest digest field",
+

+
	"ALTER TABLE %Q.packages ADD COLUMN manifestdigest TEXT NULL;"
+
	"CREATE INDEX IF NOT EXISTS %Q.pkg_digest_id ON packages(origin, manifestdigest);"
+
	},
+
	{2004,
+
	 2005,
+
	 "Rename 'abstract metadata' to 'annotations'",
+

+
	 "CREATE TABLE %Q.annotation ("
+
	        "annotation_id INTEGER PRIMARY KEY,"
+
	        "annotation TEXT NOT NULL UNIQUE"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_annotation ("
+
	        "package_id INTEGER REFERENCES packages(id)"
+
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	        "tag_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
+
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	        "value_id INTEGER NOT NULL REFERENCES annotation(annotation_id)"
+
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	        "UNIQUE (package_id, tag_id)"
+
	 ");"
+
	 "INSERT INTO %Q.annotation (annotation_id, annotation)"
+
	        " SELECT abstract_id, abstract FROM %Q.abstract;"
+
	 "INSERT INTO %Q.pkg_annotation (package_id,tag_id,value_id)"
+
	        " SELECT package_id,key_id,value_id FROM %Q.pkg_abstract;"
+
	 "DROP TABLE pkg_abstract;"
+
	 "DROP TABLE abstract;"
+
	},
+
	{2005,
+
	 2006,
+
	 "Add capability to track option descriptions and defaults",
+

+
	 "CREATE TABLE %Q.option ("
+
		"option_id INTEGER PRIMARY KEY,"
+
		"option TEXT NOT NULL UNIQUE"
+
	 ");"
+
	 "CREATE TABLE %Q.option_desc ("
+
		"option_desc_id INTEGER PRIMARY KEY,"
+
		"option_desc TEXT NOT NULL UNIQUE"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_option ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"value TEXT NOT NULL,"
+
		"PRIMARY KEY(package_id, option_id)"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_option_desc ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"option_desc_id INTEGER NOT NULL "
+
			"REFERENCES option_desc(option_desc_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"PRIMARY KEY(package_id, option_id)"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_option_default ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option_id INTEGER NOT NULL REFERENCES option(option_id) "
+
			"ON DELETE RESTRICT ON UPDATE CASCADE,"
+
		"default_value TEXT NOT NULL,"
+
		"PRIMARY KEY(package_id, option_id)"
+
	 ");"
+
	 "INSERT INTO %Q.option (option) "
+
		"SELECT DISTINCT option FROM %Q.options;"
+
	 "INSERT INTO %Q.pkg_option(package_id, option_id, value) "
+
		"SELECT package_id, option_id, value "
+
		"FROM %Q.options oo JOIN %Q.option o "
+
			"ON (oo.option = o.option);"
+
	 "DROP TABLE %Q.options;",
+
	},
+
	{2006,
+
	 2007,
+
	 "Add conflicts and provides",
+

+
	"CREATE TABLE %Q.pkg_conflicts ("
+
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "conflict_id INTEGER NOT NULL,"
+
	    "UNIQUE(package_id, conflict_id)"
+
	");"
+
	"CREATE TABLE %Q.provides("
+
	"    id INTEGER PRIMARY KEY,"
+
	"    provide TEXT NOT NULL"
+
	");"
+
	"CREATE TABLE %Q.pkg_provides ("
+
	    "package_id INTEGER NOT NULL REFERENCES packages(id)"
+
	    "  ON DELETE CASCADE ON UPDATE CASCADE,"
+
	    "provide_id INTEGER NOT NULL REFERENCES provides(id)"
+
	    "  ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
	    "UNIQUE(package_id, provide_id)"
+
	");"
+
	},
+
	{2007,
+
	 2008,
+
	 "Add FTS index",
+

+
	 "CREATE VIRTUAL TABLE %Q.pkg_search USING fts4(id, name, origin);"
+
	 "INSERT INTO %Q.pkg_search SELECT id, name || '-' || version, origin FROM %Q.packages;"
+
	 "CREATE INDEX %Q.packages_origin ON packages(origin COLLATE NOCASE);"
+
	 "CREATE INDEX %Q.packages_name ON packages(name COLLATE NOCASE);"
+
	},
+
	{2008,
+
	 2009,
+
	 "Optimize indicies",
+

+
	 "CREATE INDEX IF NOT EXISTS %Q.packages_uid_nocase ON packages(name COLLATE NOCASE, origin COLLATE NOCASE);"
+
	 "CREATE INDEX IF NOT EXISTS %Q.packages_version_nocase ON packages(name COLLATE NOCASE, version);"
+
	 "CREATE INDEX IF NOT EXISTS %Q.packages_uid ON packages(name, origin);"
+
	 "CREATE INDEX IF NOT EXISTS %Q.packages_version ON packages(name, version);"
+
	 "CREATE UNIQUE INDEX IF NOT EXISTS %Q.packages_digest ON packages(manifestdigest);"
+
	},
+
	{2009,
+
	 2010,
+
	 "Add legacy digest field",
+

+
	 "ALTER TABLE %Q.packages ADD COLUMN olddigest TEXT NULL;"
+
	 "UPDATE %Q.packages SET olddigest=manifestdigest WHERE olddigest=NULL;"
+
	},
+
	/* Mark the end of the array */
+
	{ -1, -1, NULL, NULL, }
+

+
};
+

+
/* How to downgrade a newer repo to match what the current system
+
   expects */
+
static const struct repo_changes repo_downgrades[] = {
+
	{2010,
+
	 2009,
+
	 "Drop olddigest field",
+

+
	 "ALTER TABLE %Q.packages REMOVE COLUMN olddigest;"
+
	},
+
	{2009,
+
	 2008,
+
	 "Drop indicies",
+

+
	 "DROP INDEX %Q.packages_uid_nocase;"
+
	 "DROP INDEX %Q.packages_version_nocase;"
+
	 "DROP INDEX %Q.packages_uid;"
+
	 "DROP INDEX %Q.packages_version;"
+
	 "DROP INDEX %Q.packages_digest;"
+
	},
+
	{2008,
+
	 2007,
+
	 "Drop FTS index",
+

+
	 "DROP TABLE %Q.pkg_search;"
+
	},
+
	{2007,
+
	 2006,
+
	 "Revert conflicts and provides creation",
+

+
	 "DROP TABLE %Q.pkg_provides;"
+
	 "DROP TABLE %Q.provides;"
+
	 "DROP TABLE %Q.conflicts;"
+
	},
+
	{2006,
+
	 2005,
+
	 "Revert addition of extra options related data",
+

+
	 "CREATE TABLE %Q.options ("
+
		"package_id INTEGER REFERENCES packages(id) "
+
			"ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"option TEXT,"
+
		"value TEXT,"
+
		"PRIMARY KEY(package_id,option)"
+
	 ");"
+
	 "INSERT INTO %Q.options (package_id, option, value) "
+
		 "SELECT package_id, option, value "
+
		"FROM %Q.pkg_option JOIN %Q.option USING(option_id);"
+
	 "DROP TABLE pkg_option;"
+
	 "DROP TABLE pkg_option_default;"
+
	 "DROP TABLE option;"
+
	 "DROP TABLE pkg_option_desc;"
+
	 "DROP TABLE option_desc;",
+
	},
+
	{2005,
+
	 2004,
+
	 "Revert rename of 'abstract metadata' to 'annotations'",
+

+
	 "CREATE TABLE %Q.abstract ("
+
	        "abstract_id INTEGER PRIMARY KEY,"
+
	        "abstract TEXT NOT NULL UNIQUE"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_abstract ("
+
	        "package_id INTEGER REFERENCES packages(id)"
+
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	        "key_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
+
	        " ON DELETE CASCADE ON UPDATE RESTRICT,"
+
	        "value_id INTEGER NOT NULL REFERENCES abstract(abstract_id)"
+
	        " ON DELETE CASCADE ON UPDATE RESTRICT"
+
	 ");"
+
	 "INSERT INTO %Q.abstract (abstract_id, abstract)"
+
	        " SELECT annotation_id, annotation FROM %Q.annotation;"
+
	 "INSERT INTO %Q.pkg_abstract (package_id,key_id,value_id)"
+
	        " SELECT package_id,tag_id,value_id FROM %Q.pkg_annotation;"
+
	 "DROP TABLE %Q.pkg_annotation;"
+
	 "DROP TABLE %Q.annotation;"
+
	},
+
	{2004,
+
	 2003,
+
	 "Drop manifest digest index",
+

+
	 "DROP INDEX %Q.pkg_digest_id;"
+
	},
+
	{2003,
+
	 2002,
+
	 "Drop abstract metadata",
+

+
	 "DROP TABLE %Q.pkg_abstract;"
+
	 "DROP TABLE %Q.abstract;"
+
	},
+
	{2002,
+
	 2001,
+
	 "Drop \'shlibs provided\' but retain \'shlibs required\'",
+

+
	 "CREATE TABLE %Q.pkg_shlibs_required ("
+
		"package_id INTEGER NOT NULL REFERENCES packages(id)"
+
		" ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"shlib_id INTEGER NOT NULL REFERENCES shlibs(id)"
+
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
		"UNIQUE (package_id, shlib_id)"
+
	 ");"
+
	 "CREATE TABLE %Q.pkg_shlibs ("
+
		"package_id INTEGER REFERENCES packages(id)"
+
		" ON DELETE CASCADE ON UPDATE CASCADE,"
+
		"shlib_id INTEGER REFERENCES shlibs(id)"
+
		" ON DELETE RESTRICT ON UPDATE RESTRICT,"
+
		"PRIMARY KEY (package_id, shlib_id)"
+
	 ");"
+
	 "INSERT INTO %Q.pkg_shlibs (package_id, shlib_id)"
+
		" SELECT package_id, shlib_id FROM %Q.pkg_shlibs_required;"
+
	 "DELETE FROM %Q.shlibs WHERE id NOT IN"
+
		" (SELECT shlib_id FROM %Q.pkg_shlibs);"
+
	 "DROP TABLE %Q.pkg_shlibs_provided;"
+
	 "DROP TABLE %Q.pkg_shlibs_required;"
+
	},
+

+

+
	/* Mark the end of the array */
+
	{ -1, -1, NULL, NULL, }
+

+
};
+

+
/* The package repo schema major revision */
+
#define REPO_SCHEMA_MAJOR 2
+

+
/* The package repo schema minor revision.
+
   Minor schema changes don't prevent older pkgng
+
   versions accessing the repo. */
+
#define REPO_SCHEMA_MINOR 10
+

+
/* REPO_SCHEMA_VERSION=2007 */
+
#define REPO_SCHEMA_VERSION (REPO_SCHEMA_MAJOR * 1000 + REPO_SCHEMA_MINOR)
+

+
typedef enum _sql_prstmt_index {
+
	PKG = 0,
+
	DEPS,
+
	CAT1,
+
	CAT2,
+
	LIC1,
+
	LIC2,
+
	OPT1,
+
	OPT2,
+
	SHLIB1,
+
	SHLIB_REQD,
+
	SHLIB_PROV,
+
	ANNOTATE1,
+
	ANNOTATE2,
+
	EXISTS,
+
	VERSION,
+
	DELETE,
+
	FTS_APPEND,
+
	PRSTMT_LAST,
+
} sql_prstmt_index;
+

+
static sql_prstmt sql_prepared_statements[PRSTMT_LAST] = {
+
	[PKG] = {
+
		NULL,
+
		"INSERT INTO packages ("
+
		"origin, name, version, comment, desc, arch, maintainer, www, "
+
		"prefix, pkgsize, flatsize, licenselogic, cksum, path, manifestdigest, olddigest"
+
		")"
+
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16)",
+
		"TTTTTTTTTIIITTTT",
+
	},
+
	[DEPS] = {
+
		NULL,
+
		"INSERT INTO deps (origin, name, version, package_id) "
+
		"VALUES (?1, ?2, ?3, ?4)",
+
		"TTTI",
+
	},
+
	[CAT1] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO categories(name) VALUES(?1)",
+
		"T",
+
	},
+
	[CAT2] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_categories(package_id, category_id) "
+
		"VALUES (?1, (SELECT id FROM categories WHERE name = ?2))",
+
		"IT",
+
	},
+
	[LIC1] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO licenses(name) VALUES(?1)",
+
		"T",
+
	},
+
	[LIC2] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_licenses(package_id, license_id) "
+
		"VALUES (?1, (SELECT id FROM licenses WHERE name = ?2))",
+
		"IT",
+
	},
+
	[OPT1] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO option(option) "
+
		"VALUES (?1)",
+
		"T",
+
	},
+
	[OPT2] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_option (option_id, value, package_id) "
+
		"VALUES (( SELECT option_id FROM option WHERE option = ?1), ?2, ?3)",
+
		"TTI",
+
	},
+
	[SHLIB1] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO shlibs(name) VALUES(?1)",
+
		"T",
+
	},
+
	[SHLIB_REQD] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_shlibs_required(package_id, shlib_id) "
+
		"VALUES (?1, (SELECT id FROM shlibs WHERE name = ?2))",
+
		"IT",
+
	},
+
	[SHLIB_PROV] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_shlibs_provided(package_id, shlib_id) "
+
		"VALUES (?1, (SELECT id FROM shlibs WHERE name = ?2))",
+
		"IT",
+
	},
+
	[EXISTS] = {
+
		NULL,
+
		"SELECT count(*) FROM packages WHERE cksum=?1",
+
		"T",
+
	},
+
	[ANNOTATE1] = {
+
		NULL,
+
		"INSERT OR IGNORE INTO annotation(annotation) "
+
		"VALUES (?1)",
+
		"T",
+
	},
+
	[ANNOTATE2] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_annotation(package_id, tag_id, value_id) "
+
		"VALUES (?1,"
+
		" (SELECT annotation_id FROM annotation WHERE annotation=?2),"
+
		" (SELECT annotation_id FROM annotation WHERE annotation=?3))",
+
		"ITT",
+
	},
+
	[VERSION] = {
+
		NULL,
+
		"SELECT version FROM packages WHERE origin=?1",
+
		"T",
+
	},
+
	[DELETE] = {
+
		NULL,
+
		"DELETE FROM packages WHERE origin=?1;"
+
		"DELETE FROM pkg_search WHERE origin=?1;",
+
		"TT",
+
	},
+
	[FTS_APPEND] = {
+
		NULL,
+
		"INSERT OR ROLLBACK INTO pkg_search(id, name, origin) "
+
		"VALUES (?1, ?2 || '-' || ?3, ?4);",
+
		"ITTT"
+
	}
+
	/* PRSTMT_LAST */
+
};
+

+
#endif /* INIT_PRIVATE_H_ */
added libpkg/repo/binary/common.c
@@ -0,0 +1,72 @@
+
/* Copyright (c) 2014, Vsevolod Stakhov
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 *       * Redistributions of source code must retain the above copyright
+
 *         notice, this list of conditions and the following disclaimer.
+
 *       * Redistributions in binary form must reproduce the above copyright
+
 *         notice, this list of conditions and the following disclaimer in the
+
 *         documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include <stdlib.h>
+
#include <stdio.h>
+
#include <stdbool.h>
+
#include <string.h>
+

+
#include <sqlite3.h>
+

+
#include "pkg.h"
+
#include "private/event.h"
+
#include "private/pkg.h"
+
#include "private/pkgdb.h"
+
#include "private/utils.h"
+
#include "binary_private.h"
+

+
int
+
pkg_repo_binary_run_prstatement(sql_prstmt_index s, ...)
+
{
+
	int retcode;	/* Returns SQLITE error code */
+
	va_list ap;
+
	sqlite3_stmt *stmt;
+
	int i;
+
	const char *argtypes;
+

+
	stmt = STMT(s);
+
	argtypes = sql_prepared_statements[s].argtypes;
+

+
	sqlite3_reset(stmt);
+

+
	va_start(ap, s);
+

+
	for (i = 0; argtypes[i] != '\0'; i++)
+
	{
+
		switch (argtypes[i]) {
+
		case 'T':
+
			sqlite3_bind_text(stmt, i + 1, va_arg(ap, const char*),
+
			    -1, SQLITE_STATIC);
+
			break;
+
		case 'I':
+
			sqlite3_bind_int64(stmt, i + 1, va_arg(ap, int64_t));
+
			break;
+
		}
+
	}
+

+
	va_end(ap);
+

+
	retcode = sqlite3_step(stmt);
+

+
	return (retcode);
+
}
added libpkg/repo/binary/init.c
@@ -0,0 +1,241 @@
+
/* Copyright (c) 2014, Vsevolod Stakhov
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 *       * Redistributions of source code must retain the above copyright
+
 *         notice, this list of conditions and the following disclaimer.
+
 *       * Redistributions in binary form must reproduce the above copyright
+
 *         notice, this list of conditions and the following disclaimer in the
+
 *         documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include <sys/param.h>
+
#include <sys/mount.h>
+

+
#include <assert.h>
+
#include <errno.h>
+
#include <regex.h>
+
#include <grp.h>
+
#include <stdlib.h>
+
#include <stdio.h>
+
#include <stdbool.h>
+
#include <string.h>
+
#include <unistd.h>
+
#include <libgen.h>
+

+
#include <sqlite3.h>
+

+
#include "pkg.h"
+
#include "private/event.h"
+
#include "private/pkg.h"
+
#include "private/pkgdb.h"
+
#include "private/utils.h"
+
#include "binary.h"
+
#include "binary_private.h"
+

+
static void
+
sqlite_file_exists(sqlite3_context *ctx, int argc, sqlite3_value **argv)
+
{
+
	char	 fpath[MAXPATHLEN];
+
	sqlite3	*db = sqlite3_context_db_handle(ctx);
+
	char	*path = dirname(sqlite3_db_filename(db, "main"));
+
	char	 cksum[SHA256_DIGEST_LENGTH * 2 +1];
+

+
	if (argc != 2) {
+
		sqlite3_result_error(ctx, "file_exists needs two argument", -1);
+
		return;
+
	}
+

+
	snprintf(fpath, sizeof(fpath), "%s/%s", path, sqlite3_value_text(argv[0]));
+

+
	if (access(fpath, R_OK) == 0) {
+
		sha256_file(fpath, cksum);
+
		if (strcmp(cksum, sqlite3_value_text(argv[1])) == 0)
+
			sqlite3_result_int(ctx, 1);
+
		else
+
			sqlite3_result_int(ctx, 0);
+
	} else {
+
		sqlite3_result_int(ctx, 0);
+
	}
+
}
+

+
static int
+
pkg_repo_binary_get_user_version(sqlite3 *sqlite, const char *database, int *reposcver)
+
{
+
	sqlite3_stmt *stmt;
+
	int retcode;
+
	char sql[BUFSIZ];
+
	const char *fmt = "PRAGMA %Q.user_version";
+

+
	assert(database != NULL);
+

+
	sqlite3_snprintf(sizeof(sql), sql, fmt, database);
+

+
	if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
+
		ERROR_SQLITE(sqlite, sql);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (sqlite3_step(stmt) == SQLITE_ROW) {
+
		*reposcver = sqlite3_column_int(stmt, 0);
+
		retcode = EPKG_OK;
+
	} else {
+
		*reposcver = -1;
+
		retcode = EPKG_FATAL;
+
	}
+
	sqlite3_finalize(stmt);
+
	return (retcode);
+
}
+

+
static int
+
pkg_repo_binary_init_prstatements(sqlite3 *sqlite)
+
{
+
	sql_prstmt_index i, last;
+
	int ret;
+

+
	last = PRSTMT_LAST;
+

+
	for (i = 0; i < last; i++) {
+
		ret = sqlite3_prepare_v2(sqlite, SQL(i), -1, &STMT(i), NULL);
+
		if (ret != SQLITE_OK) {
+
			ERROR_SQLITE(sqlite, SQL(i));
+
			return (EPKG_FATAL);
+
		}
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
void
+
pkg_repo_binary_finalize_prstatements(void)
+
{
+
	sql_prstmt_index i, last;
+

+
	last = PRSTMT_LAST;
+

+
	for (i = 0; i < last; i++)
+
	{
+
		if (STMT(i) != NULL) {
+
			sqlite3_finalize(STMT(i));
+
			STMT(i) = NULL;
+
		}
+
	}
+
	return;
+
}
+

+
int
+
pkg_repo_binary_open(const char *repodb, bool force, sqlite3 **sqlite,
+
	bool *incremental)
+
{
+
	bool db_not_open;
+
	int reposcver;
+
	int retcode = EPKG_OK;
+

+
	if (access(repodb, R_OK) == 0)
+
		*incremental = true;
+
	else
+
		*incremental = false;
+

+
	sqlite3_initialize();
+
	db_not_open = true;
+
	while (db_not_open) {
+
		if (sqlite3_open(repodb, sqlite) != SQLITE_OK) {
+
			sqlite3_shutdown();
+
			return (EPKG_FATAL);
+
		}
+

+
		db_not_open = false;
+

+
		/* If the schema is too old, or we're forcing a full
+
			   update, then we cannot do an incremental update.
+
			   Delete the existing repo, and promote this to a
+
			   full update */
+
		if (!*incremental)
+
			continue;
+
		retcode = pkg_repo_binary_get_user_version(*sqlite, "main", &reposcver);
+
		if (retcode != EPKG_OK)
+
			return (EPKG_FATAL);
+
		if (force || reposcver != REPO_SCHEMA_VERSION) {
+
			if (reposcver != REPO_SCHEMA_VERSION)
+
				pkg_emit_error("re-creating repo to upgrade schema version "
+
						"from %d to %d", reposcver,
+
						REPO_SCHEMA_VERSION);
+
			sqlite3_close(*sqlite);
+
			unlink(repodb);
+
			*incremental = false;
+
			db_not_open = true;
+
		}
+
	}
+

+
	sqlite3_create_function(*sqlite, "file_exists", 2, SQLITE_ANY, NULL,
+
	    sqlite_file_exists, NULL, NULL);
+

+
	if (!*incremental) {
+
		retcode = sql_exec(*sqlite, initsql, REPO_SCHEMA_VERSION);
+
		if (retcode != EPKG_OK)
+
			return (retcode);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_repo_binary_init(struct pkg_repo *repo)
+
{
+
	int retcode = EPKG_OK;
+
	sqlite3 *sqlite;
+

+
	retcode = sql_exec(sqlite, "PRAGMA synchronous=default");
+
	if (retcode != EPKG_OK)
+
		return (retcode);
+

+
	retcode = sql_exec(sqlite, "PRAGMA foreign_keys=on");
+
	if (retcode != EPKG_OK)
+
		return (retcode);
+

+
	retcode = pkg_repo_binary_init_prstatements(sqlite);
+
	if (retcode != EPKG_OK)
+
		return (retcode);
+

+
	repo->priv = sqlite;
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_repo_binary_close(struct pkg_repo *repo, bool commit)
+
{
+
	int retcode = EPKG_OK;
+
	sqlite3 *sqlite = PRIV_GET(repo);
+

+
	if (sqlite == NULL)
+
		return (retcode);
+

+
	if (commit) {
+
		if (pkgdb_transaction_commit(sqlite, NULL) != SQLITE_OK)
+
			retcode = EPKG_FATAL;
+
	}
+
	else {
+
		if (pkgdb_transaction_rollback(sqlite, NULL) != SQLITE_OK)
+
				retcode = EPKG_FATAL;
+
	}
+

+
	pkg_repo_binary_finalize_prstatements();
+
	sqlite3_free(sqlite);
+

+
	repo->priv = NULL;
+

+
	return (retcode);
+
}
modified libpkg/repo/binary/update.c
@@ -49,7 +49,7 @@


static int
-
pkg_repo_register(struct pkg_repo *repo, sqlite3 *sqlite)
+
pkg_repo_binary_register(struct pkg_repo *repo, sqlite3 *sqlite)
{
	sqlite3_stmt *stmt;
	const char sql[] = ""
@@ -85,7 +85,7 @@ pkg_repo_register(struct pkg_repo *repo, sqlite3 *sqlite)
}

static int
-
pkg_repo_add_from_manifest(char *buf, const char *origin, const char *digest,
+
pkg_repo_binary_add_from_manifest(char *buf, const char *origin, const char *digest,
		long offset, sqlite3 *sqlite,
		struct pkg_manifest_key **keys, struct pkg **p, bool is_legacy,
		struct pkg_repo *repo)
@@ -153,7 +153,7 @@ struct pkg_increment_task_item {
};

static void
-
pkg_repo_update_increment_item_new(struct pkg_increment_task_item **head, const char *origin,
+
pkg_repo_binary_update_item_new(struct pkg_increment_task_item **head, const char *origin,
		const char *digest, long offset, long length)
{
	struct pkg_increment_task_item *item;
@@ -170,7 +170,7 @@ pkg_repo_update_increment_item_new(struct pkg_increment_task_item **head, const
}

static void __unused
-
pkg_repo_parse_conflicts_file(FILE *f, sqlite3 *sqlite)
+
pkg_repo_binary_parse_conflicts(FILE *f, sqlite3 *sqlite)
{
	size_t linecap = 0;
	ssize_t linelen;
@@ -207,7 +207,7 @@ pkg_repo_parse_conflicts_file(FILE *f, sqlite3 *sqlite)
}

static int
-
pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mtime)
+
pkg_repo_binary_update_incremental(const char *name, struct pkg_repo *repo, time_t *mtime)
{
	FILE *fmanifest = NULL, *fdigests = NULL /*, *fconflicts = NULL*/;
	sqlite3 *sqlite = NULL;
@@ -235,7 +235,7 @@ pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mti
		new_repo = false;

	pkg_debug(1, "Pkgrepo, begin incremental update of '%s'", name);
-
	if ((rc = pkgdb_repo_open(name, false, &sqlite, &reuse_repo)) != EPKG_OK) {
+
	if ((rc = pkg_repo_binary_open(name, false, &sqlite, &reuse_repo)) != EPKG_OK) {
		return (EPKG_FATAL);
	}

@@ -245,11 +245,11 @@ pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mti
		*mtime = 0;
	}

-
	if ((rc = pkgdb_repo_init(sqlite)) != EPKG_OK) {
+
	if ((rc = pkg_repo_binary_init(sqlite)) != EPKG_OK) {
		goto cleanup;
	}

-
	if ((rc = pkg_repo_register(repo, sqlite)) != EPKG_OK)
+
	if ((rc = pkg_repo_binary_register(repo, sqlite)) != EPKG_OK)
		goto cleanup;

	it = pkgdb_repo_origins(sqlite);
@@ -313,7 +313,7 @@ pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mti
	while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
		pkg_get(pkg, PKG_ORIGIN, &origin, legacy_repo ? PKG_OLD_DIGEST : PKG_DIGEST,
				&digest);
-
		pkg_repo_update_increment_item_new(&ldel, origin, digest, 4, 0);
+
		pkg_repo_binary_update_item_new(&ldel, origin, digest, 4, 0);
	}

	pkg_debug(1, "Pkgrepo, reading new packagesite.yaml for '%s'", name);
@@ -356,7 +356,7 @@ pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mti
		HASH_FIND_STR(ldel, origin, item);
		if (item == NULL) {
			added++;
-
			pkg_repo_update_increment_item_new(&ladd, origin, digest, num_offset,
+
			pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset,
					num_length);
		} else {
			if (strcmp(digest, item->digest) == 0) {
@@ -371,7 +371,7 @@ pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mti
				HASH_DEL(ldel, item);
				free(item);
				item = NULL;
-
				pkg_repo_update_increment_item_new(&ladd, origin, digest,
+
				pkg_repo_binary_update_item_new(&ladd, origin, digest,
						num_offset, num_length);
				updated++;
			}
@@ -424,12 +424,12 @@ pkg_repo_update_incremental(const char *name, struct pkg_repo *repo, time_t *mti
		pkg_emit_progress_tick(++hash_it, pushed);
		if (rc == EPKG_OK) {
			if (item->length != 0) {
-
				rc = pkg_repo_add_from_manifest(map + item->offset, item->origin,
+
				rc = pkg_repo_binary_add_from_manifest(map + item->offset, item->origin,
				    item->digest, item->length, sqlite, &keys, &pkg, legacy_repo,
				    repo);
			}
			else {
-
				rc = pkg_repo_add_from_manifest(map + item->offset, item->origin,
+
				rc = pkg_repo_binary_add_from_manifest(map + item->offset, item->origin,
				    item->digest, len - item->offset, sqlite, &keys, &pkg,
				    legacy_repo, repo);
			}
@@ -452,7 +452,7 @@ cleanup:
			rc = EPKG_FATAL;
	}

-
	pkgdb_repo_finalize_statements();
+
	pkg_repo_binary_finalize_prstatements();

	if (rc == EPKG_OK)
		sql_exec(sqlite, "DROP TABLE repo_update;");
@@ -477,7 +477,7 @@ cleanup:
}

int
-
pkg_repo_update_binary_pkgs(struct pkg_repo *repo, bool force)
+
pkg_repo_binary_update(struct pkg_repo *repo, bool force)
{
	char filepath[MAXPATHLEN];

@@ -569,7 +569,7 @@ pkg_repo_update_binary_pkgs(struct pkg_repo *repo, bool force)
		}
	}

-
	res = pkg_repo_update_incremental(filepath, repo, &t);
+
	res = pkg_repo_binary_update_incremental(filepath, repo, &t);
	if (res != EPKG_OK && res != EPKG_UPTODATE) {
		pkg_emit_notice("Unable to find catalogs");
		goto cleanup;