Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Refactor prepared statement code used for generating the repo.
Matthew Seaman committed 13 years ago
commit 4e80eaca070647e088233f93acae26a499e493be
parent afadb9550fd401e04e3a7bde4d3ee9388a8f1a64
1 file changed +284 -248
modified libpkg/pkg_repo.c
@@ -42,6 +42,110 @@
#include "private/utils.h"
#include "private/pkg.h"

+
typedef enum _sql_prstmt_index_t {
+
	PKG = 0,
+
	DEPS,
+
	CAT1,
+
	CAT2,
+
	LIC1,
+
	LIC2,
+
	OPTS,
+
	SHLIB1,
+
	SHLIB2,
+
	EXISTS,
+
	DELETE,
+
	PRSTMT_LAST
+
} sql_prstmt_index_t;
+

+
typedef struct _sql_prstmt_t {
+
	sqlite3_stmt *stmt;
+
	const char *sql;
+
	const char *argtypes;
+
} sql_prstmt_t;
+

+
#define STMT(x) (sql_prepared_statements[(x)].stmt)
+
#define SQL(x)  (sql_prepared_statements[(x)].sql)
+

+
static sql_prstmt_t sql_prepared_statements[PRSTMT_LAST] = {
+
	/* PKG */
+
	{
+
		NULL,
+
		"INSERT INTO packages ("
+
		"origin, name, version, comment, desc, arch, maintainer, www, "
+
		"prefix, pkgsize, flatsize, licenselogic, cksum, path"
+
		")"
+
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);",
+
		"TTTTTTTTTIIITT"
+
	},
+
	/* 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"
+
	},
+
	/* OPTS */
+
	{
+
		NULL,
+
		"INSERT OR ROLLBACK INTO options (option, value, package_id) "
+
		"VALUES (?1, ?2, ?3);",
+
		"TTI"
+
	},
+
	/* SHLIB1 */
+
	{
+
		NULL,
+
		"INSERT OR IGNORE INTO shlibs(name) VALUES(?1);",
+
		"T"
+
	},
+
	/* SHLIB2 */
+
	{
+
		NULL, 
+
		"INSERT OR ROLLBACK INTO pkg_shlibs(package_id, shlib_id) "
+
		"VALUES (?1, (SELECT id FROM shlibs WHERE name = ?2))",
+
		"IT"
+
	},
+
	/* EXISTS */
+
	{
+
		NULL,
+
		"SELECT count(*), cksum FROM packages WHERE path=?1",
+
		"T"
+
	},
+
	/* DELETE */
+
	{
+
		NULL,
+
		"DELETE FROM packages WHERE path=?1",
+
		"T"
+
	}
+
	/* PRSTMT_LAST */
+
};
+

int
pkg_repo_fetch(struct pkg *pkg)
{
@@ -152,46 +256,10 @@ file_exists(sqlite3_context *ctx, int argc, __unused sqlite3_value **argv)
			sqlite3_result_int(ctx, 0);
}

-
int
-
pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *data)
+
static int
+
initialize_repo(const char *repodb, bool incremental, sqlite3 **sqlite)
{
-
	FTS *fts = NULL;
-
	FTSENT *ent = NULL;
-

-
	struct pkg *pkg = NULL;
-
	struct pkg_dep *dep = NULL;
-
	struct pkg_category *category = NULL;
-
	struct pkg_license *license = NULL;
-
	struct pkg_option *option = NULL;
-
	struct pkg_shlib *shlib = NULL;
-
	struct sbuf *manifest = NULL;
-
	char *ext = NULL;
-

-
	sqlite3 *sqlite = NULL;
-
	sqlite3_stmt *stmt_deps = NULL;
-
	sqlite3_stmt *stmt_pkg = NULL;
-
	sqlite3_stmt *stmt_lic1 = NULL;
-
	sqlite3_stmt *stmt_lic2 = NULL;
-
	sqlite3_stmt *stmt_cat1 = NULL;
-
	sqlite3_stmt *stmt_cat2 = NULL;
-
	sqlite3_stmt *stmt_opts = NULL;
-
	sqlite3_stmt *stmt_shlib1 = NULL;
-
	sqlite3_stmt *stmt_shlib2 = NULL;
-

-
	int64_t package_id;
-
	char *errmsg = NULL;
	int retcode = EPKG_OK;
-
	char *pkg_path;
-
	char cksum[SHA256_DIGEST_LENGTH * 2 +1];
-
	bool incremental = false;
-
	int ret;
-

-
	char *repopath[2];
-
	char repodb[MAXPATHLEN + 1];
-
	char repopack[MAXPATHLEN + 1];
-

-
	struct archive *a = NULL;
-
	struct archive_entry *ae = NULL;

	const char initsql[] = ""
		"CREATE TABLE packages ("
@@ -255,26 +323,144 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
		");"
		"PRAGMA user_version=2;"
		;
-
	const char pkgsql[] = ""
-
		"INSERT INTO packages ("
-
				"origin, name, version, comment, desc, arch, "
-
				"maintainer, www, prefix, pkgsize, flatsize, licenselogic, cksum, path"
-
		")"
-
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);";
-
	const char depssql[] = ""
-
		"INSERT INTO deps (origin, name, version, package_id) "
-
		"VALUES (?1, ?2, ?3, ?4);";
-
	const char licsql[] = "INSERT OR IGNORE INTO licenses(name) VALUES(?1);";
-
	const char addlicsql[] = "INSERT OR ROLLBACK INTO pkg_licenses(package_id, license_id) "
-
		"VALUES (?1, (SELECT id FROM licenses WHERE name = ?2));";
-
	const char catsql[] = "INSERT OR IGNORE INTO categories(name) VALUES(?1);";
-
	const char addcatsql[] = "INSERT OR ROLLBACK INTO pkg_categories(package_id, category_id) "
-
		"VALUES (?1, (SELECT id FROM categories WHERE name = ?2));";
-
	const char addoption[] = "INSERT OR ROLLBACK INTO options (option, value, package_id) "
-
		"VALUES (?1, ?2, ?3);";
-
	const char shlibsql[] = "INSERT OR IGNORE INTO shlibs(name) VALUES(?1);";
-
	const char addshlibsql[] = "INSERT OR ROLLBACK INTO pkg_shlibs(package_id, shlib_id) "
-
		"VALUES (?1, (SELECT id FROM shlibs WHERE name = ?2))";
+

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

+
	sqlite3_create_function(*sqlite, "file_exists", 1, SQLITE_ANY, NULL, file_exists, NULL, NULL);
+
	if ((retcode = sql_exec(*sqlite, "PRAGMA synchronous=off;")) != EPKG_OK)
+
		return retcode;
+

+
	if ((retcode = sql_exec(*sqlite, "PRAGMA journal_mode=memory")) != EPKG_OK)
+
		return retcode;
+

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

+
	if ((retcode = sql_exec(*sqlite, "BEGIN TRANSACTION;")) != EPKG_OK)
+
		return retcode;
+

+
	/* remove everything that is not anymore in the repository */
+
	if (incremental) {
+
		sql_exec(*sqlite, "DELETE FROM packages WHERE NOT FILE_EXISTS(path);");
+
		sql_exec(*sqlite, "DELETE FROM deps WHERE package_id NOT IN (SELECT id FROM packages);");
+
		sql_exec(*sqlite, "DELETE FROM pkg_categories WHERE package_id NOT IN (SELECT id FROM packages);");
+
		sql_exec(*sqlite, "DELETE FROM categories WHERE id NOT IN (SELECT category_id FROM pkg_categories);");
+
		sql_exec(*sqlite, "DELETE FROM pkg_licenses WHERE package_id NOT IN (SELECT id FROM packages);");
+
		sql_exec(*sqlite, "DELETE FROM licenses WHERE id NOT IN (SELECT license_id FROM pkg_licenses);");
+
		sql_exec(*sqlite, "DELETE FROM options WHERE package_id NOT IN (SELECT id FROM packages);");
+
		sql_exec(*sqlite, "DELETE FROM pkg_shlibs WHERE package_id NOT IN (SELECT id FROM packages);");
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
initialize_prepared_statements(sqlite3 *sqlite)
+
{
+
	sql_prstmt_index_t i;
+
	int retcode = EPKG_OK;
+

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

+
static int
+
run_prepared_statement(sql_prstmt_index_t 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);
+
}
+

+
static void
+
finalize_prepared_statements(void)
+
{
+
	sql_prstmt_index_t i;
+

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

+
int
+
pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *data)
+
{
+
	FTS *fts = NULL;
+
	FTSENT *ent = NULL;
+

+
	struct pkg *pkg = NULL;
+
	struct pkg_dep *dep = NULL;
+
	struct pkg_category *category = NULL;
+
	struct pkg_license *license = NULL;
+
	struct pkg_option *option = NULL;
+
	struct pkg_shlib *shlib = NULL;
+
	struct sbuf *manifest = NULL;
+
	char *ext = NULL;
+

+
	sqlite3 *sqlite = NULL;
+

+
	int64_t package_id;
+
	char *errmsg = NULL;
+
	int retcode = EPKG_OK;
+
	char *pkg_path;
+
	char cksum[SHA256_DIGEST_LENGTH * 2 +1];
+
	bool incremental = false;
+
	int ret;
+

+
	char *repopath[2];
+
	char repodb[MAXPATHLEN + 1];
+
	char repopack[MAXPATHLEN + 1];
+

+
	struct archive *a = NULL;
+
	struct archive_entry *ae = NULL;

	if (!is_dir(path)) {
		pkg_emit_error("%s is not a directory", path);
@@ -284,6 +470,12 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
	repopath[0] = path;
	repopath[1] = NULL;

+
	if ((fts = fts_open(repopath, FTS_PHYSICAL, NULL)) == NULL) {
+
		pkg_emit_errno("fts_open", path);
+
		retcode = EPKG_FATAL;
+
		goto cleanup;
+
	}
+

	snprintf(repodb, sizeof(repodb), "%s/repo.sqlite", path);
	snprintf(repopack, sizeof(repopack), "%s/repo.txz", path);

@@ -310,96 +502,12 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
	if (access(repodb, F_OK) == 0)
		incremental = true;

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

-
	sqlite3_create_function(sqlite, "file_exists", 1, SQLITE_ANY, NULL, file_exists, NULL, NULL);
-
	if ((retcode = sql_exec(sqlite, "PRAGMA synchronous=off;")) != EPKG_OK)
-
		goto cleanup;
-

-
	if ((retcode = sql_exec(sqlite, "PRAGMA journal_mode=memory")) != EPKG_OK)
-
		goto cleanup;
-

-
	if (!incremental && (retcode = sql_exec(sqlite, initsql)) != EPKG_OK)
-
		goto cleanup;
-

-
	if ((retcode = sql_exec(sqlite, "BEGIN TRANSACTION;")) != EPKG_OK)
-
		goto cleanup;
-

-
	/* remove everything that is not anymore in the repository */
-
	if (incremental) {
-
		sql_exec(sqlite, "DELETE FROM packages WHERE NOT FILE_EXISTS(path);");
-
		sql_exec(sqlite, "DELETE FROM deps WHERE package_id NOT IN (SELECT id FROM packages);");
-
		sql_exec(sqlite, "DELETE FROM pkg_categories WHERE package_id NOT IN (SELECT id FROM packages);");
-
		sql_exec(sqlite, "DELETE FROM categories WHERE id NOT IN (SELECT category_id FROM pkg_categories);");
-
		sql_exec(sqlite, "DELETE FROM pkg_licenses WHERE package_id NOT IN (SELECT id FROM packages);");
-
		sql_exec(sqlite, "DELETE FROM licenses WHERE id NOT IN (SELECT license_id FROM pkg_licenses);");
-
		sql_exec(sqlite, "DELETE FROM options WHERE package_id NOT IN (SELECT id FROM packages);");
-
		sql_exec(sqlite, "DELETE FROM pkg_shlibs WHERE package_id NOT IN (SELECT id FROM packages);");
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, pkgsql, -1, &stmt_pkg, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, depssql, -1, &stmt_deps, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
+
	if ((retcode = initialize_repo(repodb, incremental, &sqlite))
+
	    != EPKG_OK)
		goto cleanup;
-
	}

-
	if (sqlite3_prepare_v2(sqlite, licsql, -1, &stmt_lic1, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
+
	if ((retcode = initialize_prepared_statements(sqlite)) != EPKG_OK)
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, addlicsql, -1, &stmt_lic2, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, addoption, -1, &stmt_opts, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if ((fts = fts_open(repopath, FTS_PHYSICAL, NULL)) == NULL) {
-
		pkg_emit_errno("fts_open", path);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, catsql, -1, &stmt_cat1, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, addcatsql, -1, &stmt_cat2, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, shlibsql, -1, &stmt_shlib1, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	if (sqlite3_prepare_v2(sqlite, addshlibsql, -1, &stmt_shlib2, NULL) != SQLITE_OK) {
-
		ERROR_SQLITE(sqlite);
-
		retcode = EPKG_FATAL;
-
		goto cleanup;
-
	}

	manifest = sbuf_new_auto();
	while ((ent = fts_read(fts)) != NULL) {
@@ -433,36 +541,18 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
			pkg_path++;

		sha256_file(ent->fts_accpath, cksum);
-
		/* do not add if package if already in base */
+
		/* do not add if package if already in repodb */
		if (incremental) {
-
			sqlite3_stmt *stmt;
-
			if (sqlite3_prepare_v2(sqlite, "select count(*), cksum from packages where path=?1;",
-
			        -1, &stmt, NULL) != SQLITE_OK) {
-
				goto cleanup;
-
			}
-
			sqlite3_bind_text(stmt, 1, pkg_path, -1, SQLITE_STATIC);
-

-
			if (sqlite3_step(stmt) != SQLITE_ROW) {
+
			if (run_prepared_statement(EXISTS, pkg_path) != SQLITE_ROW) {
				ERROR_SQLITE(sqlite);
				goto cleanup;
			}
-
			if (sqlite3_column_int(stmt, 0) > 0) {
-
				if (strcmp(sqlite3_column_text(stmt, 1), cksum) == 0) {
-
					sqlite3_finalize(stmt);
+
			if (sqlite3_column_int(STMT(EXISTS), 0) > 0) {
+
				if (strcmp(sqlite3_column_text(STMT(EXISTS), 1), cksum) == 0)
					continue;
-
				}
-

-
				sqlite3_finalize(stmt);
-
				if (sqlite3_prepare_v2(sqlite, "delete from packages where path=?1;",
-
							-1, &stmt, NULL) != SQLITE_OK) {
-
					goto cleanup;
-
				}

-
				sqlite3_bind_text(stmt, 1, pkg_path, -1, SQLITE_STATIC);
-
				sqlite3_step(stmt);
+
				run_prepared_statement(DELETE, pkg_path);
			}
-

-
			sqlite3_finalize(stmt);
		}

		if (pkg_open(&pkg, ent->fts_accpath, manifest) != EPKG_OK) {
@@ -478,22 +568,10 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
		    PKG_MAINTAINER, &maintainer, PKG_WWW, &www, PKG_PREFIX, &prefix,
		    PKG_FLATSIZE, &flatsize, PKG_LICENSE_LOGIC, &licenselogic);

-
		sqlite3_bind_text(stmt_pkg, 1, origin, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 2, name, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 3, version, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 4, comment, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 5, desc, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 6, arch, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 7, maintainer, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 8, www, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 9, prefix, -1, SQLITE_STATIC);
-
		sqlite3_bind_int64(stmt_pkg, 10, ent->fts_statp->st_size);
-
		sqlite3_bind_int64(stmt_pkg, 11, flatsize);
-
		sqlite3_bind_int64(stmt_pkg, 12, licenselogic);
-
		sqlite3_bind_text(stmt_pkg, 13, cksum, -1, SQLITE_STATIC);
-
		sqlite3_bind_text(stmt_pkg, 14, pkg_path, -1, SQLITE_STATIC);
-

-
		if ((ret = sqlite3_step(stmt_pkg)) != SQLITE_DONE) {
+
		if ((ret = run_prepared_statement(PKG, origin, name, version,
+
		    comment, desc, arch, maintainer, www, prefix,
+
		    ent->fts_statp->st_size, flatsize, licenselogic, cksum,
+
		    pkg_path)) != SQLITE_DONE) {
			if (ret == SQLITE_CONSTRAINT) {
				pkg_emit_error("Another package already provides %s", origin);
			} else {
@@ -502,99 +580,82 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
			retcode = EPKG_FATAL;
			goto cleanup;
		}
-
		sqlite3_reset(stmt_pkg);

		package_id = sqlite3_last_insert_rowid(sqlite);

		dep = NULL;
		while (pkg_deps(pkg, &dep) == EPKG_OK) {
-
			sqlite3_bind_text(stmt_deps, 1, pkg_dep_get(dep, PKG_DEP_ORIGIN), -1, SQLITE_STATIC);
-
			sqlite3_bind_text(stmt_deps, 2, pkg_dep_get(dep, PKG_DEP_NAME), -1, SQLITE_STATIC);
-
			sqlite3_bind_text(stmt_deps, 3, pkg_dep_get(dep, PKG_DEP_VERSION), -1, SQLITE_STATIC);
-
			sqlite3_bind_int64(stmt_deps, 4, package_id);
-

-
			if (sqlite3_step(stmt_deps) != SQLITE_DONE) {
+
			if (run_prepared_statement(DEPS, 
+
			    pkg_dep_get(dep, PKG_DEP_ORIGIN),
+
			    pkg_dep_get(dep, PKG_DEP_NAME),
+
			    pkg_dep_get(dep, PKG_DEP_VERSION),
+
			    package_id) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
-
			sqlite3_reset(stmt_deps);
		}

		category = NULL;
		while (pkg_categories(pkg, &category) == EPKG_OK) {
-
			sqlite3_bind_text(stmt_cat1, 1, pkg_category_name(category), -1, SQLITE_STATIC);
-
			sqlite3_bind_int64(stmt_cat2, 1, package_id);
-
			sqlite3_bind_text(stmt_cat2, 2, pkg_category_name(category), -1, SQLITE_STATIC);
-

-
			if (sqlite3_step(stmt_cat1) != SQLITE_DONE) {
+
			if (run_prepared_statement(CAT1,
+
			    pkg_category_name(category)) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}

-
			if (sqlite3_step(stmt_cat2) != SQLITE_DONE) {
+
			if (run_prepared_statement(CAT2, package_id,
+
			    pkg_category_name(category)) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
-
			sqlite3_reset(stmt_cat1);
-
			sqlite3_reset(stmt_cat2);
		}

		license = NULL;
		while (pkg_licenses(pkg, &license) == EPKG_OK) {
-
			sqlite3_bind_text(stmt_lic1, 1, pkg_license_name(license), -1, SQLITE_STATIC);
-
			sqlite3_bind_int64(stmt_lic2, 1, package_id);
-
			sqlite3_bind_text(stmt_lic2, 2, pkg_license_name(license), -1, SQLITE_STATIC);
-

-
			if (sqlite3_step(stmt_lic1) != SQLITE_DONE) {
+
			if (run_prepared_statement(LIC1,
+
			    pkg_license_name(license)) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}

-
			if (sqlite3_step(stmt_lic2) != SQLITE_DONE) {
+
			if (run_prepared_statement(LIC2, package_id,
+
			    pkg_license_name(license)) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
-
			sqlite3_reset(stmt_lic1);
-
			sqlite3_reset(stmt_lic2);
		}
		option = NULL;
		while (pkg_options(pkg, &option) == EPKG_OK) {
-
			sqlite3_bind_text(stmt_opts, 1, pkg_option_opt(option), -1, SQLITE_STATIC);
-
			sqlite3_bind_text(stmt_opts, 2, pkg_option_value(option), -1, SQLITE_STATIC);
-
			sqlite3_bind_int64(stmt_opts, 3, package_id);
-

-
			if (sqlite3_step(stmt_opts) != SQLITE_DONE) {
+
			if (run_prepared_statement(OPTS,
+
			    pkg_option_opt(option),
+
			    pkg_option_value(option),
+
			    package_id) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
-
			sqlite3_reset(stmt_opts);
		}

		shlib = NULL;
		while (pkg_shlibs(pkg, &shlib) == EPKG_OK) {
-
			sqlite3_bind_text(stmt_shlib1, 1, pkg_shlib_name(shlib), -1, SQLITE_STATIC);
-
			sqlite3_bind_int64(stmt_shlib2, 1, package_id);
-
			sqlite3_bind_text(stmt_shlib2, 2, pkg_shlib_name(shlib), -1, SQLITE_STATIC);
-

-
			if (sqlite3_step(stmt_shlib1) != SQLITE_DONE) {
+
			if (run_prepared_statement(SHLIB1,
+
			    pkg_shlib_name(shlib)) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}

-
			if (sqlite3_step(stmt_shlib2) != SQLITE_DONE) {
+
			if (run_prepared_statement(SHLIB2, package_id,
+
			    pkg_shlib_name(shlib)) != SQLITE_DONE) {
				ERROR_SQLITE(sqlite);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
-
			sqlite3_reset(stmt_shlib1);
-
			sqlite3_reset(stmt_shlib2);
		}
	}

@@ -610,32 +671,7 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
	if (pkg != NULL)
		pkg_free(pkg);

-
	if (stmt_pkg != NULL)
-
		sqlite3_finalize(stmt_pkg);
-

-
	if (stmt_deps != NULL)
-
		sqlite3_finalize(stmt_deps);
-

-
	if (stmt_cat1 != NULL)
-
		sqlite3_finalize(stmt_cat1);
-

-
	if (stmt_cat2 != NULL)
-
		sqlite3_finalize(stmt_cat2);
-

-
	if (stmt_lic1 != NULL)
-
		sqlite3_finalize(stmt_lic1);
-

-
	if (stmt_lic2 != NULL)
-
		sqlite3_finalize(stmt_lic2);
-

-
	if (stmt_opts != NULL)
-
		sqlite3_finalize(stmt_opts);
-

-
	if (stmt_shlib1 != NULL)
-
		sqlite3_finalize(stmt_shlib1);
-

-
	if (stmt_shlib2 != NULL)
-
		sqlite3_finalize(stmt_shlib2);
+
	finalize_prepared_statements();

	if (sqlite != NULL)
		sqlite3_close(sqlite);