summary refs log tree commit diff
diff options
context:
space:
mode:
authorTerin Stock <terinjokes@gmail.com>2022-04-25 00:17:08 -0700
committerTerin Stock <terinjokes@gmail.com>2022-04-25 00:17:08 -0700
commitf9cfa54ff8c9bb44258666d96bc0fd5b65f27f18 (patch)
treefb04df85f37d141daed46a81e7e46780461f870d
parent00bfbfb0db1fcf863e34d946e324ebc5cdb8d1ea (diff)
init-db: create sqlite database 2.36
When creating a new repository, create a SQLite3 database in the git
directory. This database currently stores objects, refs, and the HEAD
pointer.

The upstream implementation mixes filesystem and system checks,
configuration updating, template copying, and creating the "objects" and
"refs" directories. A future revision of this patch should split this
logic apart such that the SQLite3 implementation can omit these directories.
-rw-r--r--builtin/init-db.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 546f9c595e..922a514084 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -11,6 +11,9 @@
 #include "parse-options.h"
 #include "worktree.h"
 
+#include <sqlite3.h>
+#include <string.h>
+
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
 #endif
@@ -381,6 +384,18 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
 	}
 }
 
+#if defined(USE_SQLITE)
+static char *get_sqlite_dbname(const char *gitdir)
+{
+	struct strbuf path = STRBUF_INIT;
+
+	strbuf_addstr(&path, gitdir);
+	strbuf_addstr(&path, "/git.sqlite");
+
+	return strbuf_detach(&path, NULL);
+}
+#endif
+
 int init_db(const char *git_dir, const char *real_git_dir,
 	    const char *template_dir, int hash, const char *initial_branch,
 	    unsigned int flags)
@@ -455,6 +470,84 @@ int init_db(const char *git_dir, const char *real_git_dir,
 		git_config_set("receive.denyNonFastforwards", "true");
 	}
 
+#if defined(USE_SQLITE)
+	sqlite3 *db;
+	int rc;
+	char *errMsg;
+	char *dbname;
+	char *ref;
+
+	dbname = get_sqlite_dbname(git_dir);
+
+	rc = sqlite3_open(dbname, &db);
+	if (rc) {
+		die(_("can't open database: %s"), sqlite3_errmsg(db));
+	}
+
+	// TODO: read sqlite options from gitconfig.
+	rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA foreign_keys = ON;", NULL, NULL, &errMsg);
+	if (rc != SQLITE_OK) {
+		printf(_("SQL Error: %s\n"), errMsg);
+		sqlite3_free(errMsg);
+		die("sql error!");
+	}
+
+	if (!reinit) {
+		rc = sqlite3_exec(db, "CREATE TABLE objects(hash BLOB PRIMARY KEY NOT NULL, \
+						    content BLOB NOT NULL); \
+			       CREATE TABLE refs(name STRING PRIMARY KEY NOT NULL, \
+						 hash BLOB NOT NULL, \
+						 FOREIGN KEY(hash) REFERENCES objects(hash)); \
+			       CREATE TABLE head(id INTEGER PRIMARY KEY CHECK (id = 0), \
+						 head BLOB)", NULL, NULL, &errMsg);
+		if (rc != SQLITE_OK) {
+			printf(_("SQL Error: %s\n"), errMsg);
+			sqlite3_free(errMsg);
+			die("sql error!");
+		}
+
+		if (!initial_branch)
+			initial_branch = git_default_branch_name(flags & INIT_DB_QUIET);
+
+		ref = xstrfmt("refs/heads/%s", initial_branch);
+		if (check_refname_format(ref, 0) < 0)
+			die(_("invalid initial branch name: '%s'"),
+			    initial_branch);
+
+		sqlite3_stmt *stmt;
+		rc = sqlite3_prepare_v2(db, "REPLACE INTO head(id, head) VALUES (0, ?)", -1, &stmt, NULL);
+		if (rc != SQLITE_OK) {
+			printf(_("[%d] SQL Error: %s\n"), __LINE__, errMsg);
+			sqlite3_free(errMsg);
+			die("sql error!");
+		}
+
+		rc = sqlite3_bind_text(stmt, 1, ref, strlen(ref)+1, free);
+		if (rc != SQLITE_OK) {
+			printf(_("[%d] SQL Error: %s\n"), __LINE__, errMsg);
+			sqlite3_free(errMsg);
+			die("sql error!");
+		}
+
+		rc = sqlite3_step(stmt);
+		if (rc != SQLITE_DONE) {
+			printf(_("[%d] SQL Error: %s\n"), __LINE__, errMsg);
+			sqlite3_free(errMsg);
+			die("sql error!");
+		}
+
+		rc = sqlite3_finalize(stmt);
+		if (rc != SQLITE_OK) {
+			printf(_("[%d] SQL Error: %s\n"), __LINE__, errMsg);
+			sqlite3_free(errMsg);
+			die("sql error!");
+		}
+	}
+
+	sqlite3_close(db);
+	free(dbname);
+#endif
+
 	if (!(flags & INIT_DB_QUIET)) {
 		int len = strlen(git_dir);