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  }