github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/cd-service/pkg/sqlitestore/sqlite.c (about) 1 /*This file is part of kuberpult. 2 3 Kuberpult is free software: you can redistribute it and/or modify 4 it under the terms of the Expat(MIT) License as published by 5 the Free Software Foundation. 6 7 Kuberpult is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 MIT License for more details. 11 12 You should have received a copy of the MIT License 13 along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>. 14 15 Copyright 2023 freiheit.com*/ 16 #include <git2.h> 17 #include <git2/sys/odb_backend.h> 18 #include <sqlite3.h> 19 #include <string.h> 20 #include "sqlite.h" 21 22 typedef struct { 23 git_odb_backend parent; 24 sqlite3 *db; 25 sqlite3_stmt *read; 26 sqlite3_stmt *write; 27 sqlite3_stmt *read_header; 28 } kp_backend; 29 30 int kp_backend__read_header(size_t *len_out, git_otype *type_out, git_odb_backend *_backend, const git_oid *oid) 31 { 32 kp_backend *backend = (kp_backend *)_backend; 33 if( sqlite3_bind_text(backend->read_header, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) != SQLITE_OK) { 34 sqlite3_reset(backend->read_header); 35 return GIT_ERROR; 36 } 37 if (sqlite3_step(backend->read_header) == SQLITE_ROW) { 38 *type_out = (git_otype)sqlite3_column_int(backend->read_header, 0); 39 *len_out = (size_t)sqlite3_column_int(backend->read_header, 1); 40 sqlite3_reset(backend->read_header); 41 return GIT_OK; 42 } else { 43 sqlite3_reset(backend->read_header); 44 return GIT_ENOTFOUND; 45 } 46 } 47 48 int kp_backend__read(void **data_out, size_t *len_out, git_otype *type_out, git_odb_backend *_backend, const git_oid *oid) 49 { 50 kp_backend *backend = (kp_backend *)_backend; 51 int error = GIT_ERROR; 52 53 if (sqlite3_bind_text(backend->read, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) != SQLITE_OK) { 54 sqlite3_reset(backend->read); 55 return GIT_ERROR; 56 } 57 if (sqlite3_step(backend->read) == SQLITE_ROW) { 58 *type_out = (git_otype)sqlite3_column_int(backend->read, 0); 59 *len_out = (size_t)sqlite3_column_int(backend->read, 1); 60 *data_out = malloc(*len_out); 61 62 if (*data_out == NULL) { 63 giterr_set_oom(); 64 sqlite3_reset(backend->read); 65 return GIT_ERROR; 66 } else { 67 memcpy(*data_out, sqlite3_column_blob(backend->read, 2), *len_out); 68 sqlite3_reset(backend->read); 69 return GIT_OK; 70 } 71 } else { 72 sqlite3_reset(backend->read); 73 return GIT_ENOTFOUND; 74 } 75 76 } 77 78 int kp_backend__read_prefix(git_oid *out_oid, void **data_out, size_t *len_out, git_otype *type_out, git_odb_backend *_backend, 79 const git_oid *short_oid, size_t len) { 80 if (len >= GIT_OID_HEXSZ) { 81 int error = kp_backend__read(data_out, len_out, type_out, _backend, short_oid); 82 if (error == GIT_OK) 83 git_oid_cpy(out_oid, short_oid); 84 85 return error; 86 } 87 return GIT_ERROR; 88 } 89 90 int kp_backend__exists(git_odb_backend *_backend, const git_oid *oid) 91 { 92 kp_backend *backend; 93 int found; 94 95 96 backend = (kp_backend *)_backend; 97 found = 0; 98 99 if (sqlite3_bind_text(backend->read_header, 1, (char *)oid->id, 20, SQLITE_TRANSIENT) == SQLITE_OK) { 100 if (sqlite3_step(backend->read_header) == SQLITE_ROW) { 101 found = 1; 102 } 103 } 104 105 sqlite3_reset(backend->read_header); 106 return found; 107 } 108 109 110 int kp_backend__write(git_odb_backend *_backend, const git_oid *id, const void *data, size_t len, git_otype type) 111 { 112 int error; 113 kp_backend *backend; 114 115 116 backend = (kp_backend *)_backend; 117 118 error = SQLITE_ERROR; 119 120 if (sqlite3_bind_text(backend->write, 1, (char *)id->id, 20, SQLITE_TRANSIENT) == SQLITE_OK && 121 sqlite3_bind_int(backend->write, 2, (int)type) == SQLITE_OK && 122 sqlite3_bind_int(backend->write, 3, len) == SQLITE_OK && 123 sqlite3_bind_blob(backend->write, 4, data, len, SQLITE_TRANSIENT) == SQLITE_OK) { 124 error = sqlite3_step(backend->write); 125 } 126 127 sqlite3_reset(backend->write); 128 return (error == SQLITE_DONE) ? GIT_OK : GIT_ERROR; 129 } 130 131 132 void kp_backend__free(git_odb_backend *_backend) 133 { 134 kp_backend *backend; 135 backend = (kp_backend *)_backend; 136 137 sqlite3_finalize(backend->read); 138 sqlite3_finalize(backend->read_header); 139 sqlite3_finalize(backend->write); 140 sqlite3_close(backend->db); 141 142 free(backend); 143 } 144 145 static int create_table_if_not_exists(sqlite3 *db) 146 { 147 return sqlite3_exec(db, 148 "CREATE TABLE IF NOT EXISTS 'odb' (" 149 "'oid' CHARACTER(20) PRIMARY KEY NOT NULL," 150 "'type' INTEGER NOT NULL," 151 "'size' INTEGER NOT NULL," 152 "'data' BLOB);", NULL, NULL, NULL); 153 } 154 155 static int init_statements(kp_backend *backend) 156 { 157 int error = SQLITE_ERROR; 158 error = sqlite3_prepare_v2(backend->db, 159 "SELECT type, size, data FROM 'odb' WHERE oid = ?;" 160 , -1, &backend->read, NULL); 161 if( error != SQLITE_OK ){ 162 return error; 163 } 164 error = sqlite3_prepare_v2(backend->db, 165 "SELECT type, size FROM 'odb' WHERE oid = ?;", 166 -1, &backend->read_header, NULL); 167 if( error != SQLITE_OK ){ 168 return error; 169 } 170 return sqlite3_prepare_v2(backend->db, 171 "INSERT OR IGNORE INTO 'odb' VALUES (?, ?, ?, ?);", 172 -1, &backend->write, NULL); 173 } 174 175 int kp_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db, const char **err_out) 176 { 177 int error = SQLITE_ERROR; 178 kp_backend *backend = calloc(1, sizeof(kp_backend)); 179 if (backend == NULL) { 180 giterr_set_oom(); 181 return SQLITE_ERROR; 182 } 183 184 error = sqlite3_open(sqlite_db, &backend->db); 185 if (error != SQLITE_OK){ 186 *err_out = sqlite3_errmsg(backend->db); 187 kp_backend__free((git_odb_backend *)backend); 188 return error; 189 } 190 191 error = create_table_if_not_exists(backend->db); 192 if (error != SQLITE_OK){ 193 *err_out = sqlite3_errmsg(backend->db); 194 kp_backend__free((git_odb_backend *)backend); 195 return error; 196 } 197 198 error = init_statements(backend); 199 if (error != SQLITE_OK) { 200 *err_out = sqlite3_errmsg(backend->db); 201 kp_backend__free((git_odb_backend *)backend); 202 return error; 203 } 204 205 backend->parent.version = GIT_ODB_BACKEND_VERSION; 206 backend->parent.read = &kp_backend__read; 207 backend->parent.read_prefix = &kp_backend__read_prefix; 208 backend->parent.read_header = &kp_backend__read_header; 209 backend->parent.write = &kp_backend__write; 210 backend->parent.exists = &kp_backend__exists; 211 backend->parent.free = &kp_backend__free; 212 213 *backend_out = (git_odb_backend *)backend; 214 return SQLITE_OK; 215 }