Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Refactor prepared statement code used for generating the repo.
Matthew Seaman committed 13 years ago
commit 4e80eaca070647e088233f93acae26a499e493be
parent afadb95
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);