LCOV - code coverage report
Current view: top level - samples/techempower - database.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 65 200 32.5 %
Date: 2023-04-18 16:19:03 Functions: 9 17 52.9 %

          Line data    Source code
       1             : /*
       2             :  * lwan - web server
       3             :  * Copyright (c) 2014 L. A. F. Pereira <l@tia.mat.br>
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU General Public License
       7             :  * as published by the Free Software Foundation; either version 2
       8             :  * of the License, or any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
      18             :  * USA.
      19             :  */
      20             : 
      21             : #include <string.h>
      22             : #include <mysql.h>
      23             : #include <sqlite3.h>
      24             : #include <stddef.h>
      25             : #include <stdlib.h>
      26             : #include <stdarg.h>
      27             : 
      28             : #include "database.h"
      29             : #include "lwan-status.h"
      30             : 
      31             : struct db_stmt {
      32             :     bool (*bind)(const struct db_stmt *stmt,
      33             :                  struct db_row *rows,
      34             :                  size_t n_rows);
      35             :     bool (*step)(const struct db_stmt *stmt, const char *signature, va_list ap);
      36             :     void (*finalize)(struct db_stmt *stmt);
      37             : };
      38             : 
      39             : struct db {
      40             :     void (*disconnect)(struct db *db);
      41             :     struct db_stmt *(*prepare)(const struct db *db,
      42             :                                const char *sql,
      43             :                                const size_t sql_len);
      44             : };
      45             : 
      46             : /* MySQL */
      47             : 
      48             : struct db_mysql {
      49             :     struct db base;
      50             :     MYSQL *con;
      51             : };
      52             : 
      53             : struct db_stmt_mysql {
      54             :     struct db_stmt base;
      55             :     MYSQL_STMT *stmt;
      56             :     MYSQL_BIND *param_bind;
      57             :     MYSQL_BIND *result_bind;
      58             :     bool must_execute_again;
      59             : };
      60             : 
      61           0 : static bool db_stmt_bind_mysql(const struct db_stmt *stmt,
      62             :                                struct db_row *rows,
      63             :                                size_t n_rows)
      64             : {
      65           0 :     struct db_stmt_mysql *stmt_mysql = (struct db_stmt_mysql *)stmt;
      66             : 
      67           0 :     stmt_mysql->must_execute_again = true;
      68             : 
      69           0 :     if (!stmt_mysql->param_bind) {
      70           0 :         stmt_mysql->param_bind = calloc(n_rows, sizeof(MYSQL_BIND));
      71           0 :         if (!stmt_mysql->param_bind)
      72           0 :             return false;
      73             :     } else {
      74           0 :         mysql_stmt_reset(stmt_mysql->stmt);
      75             :     }
      76             : 
      77           0 :     for (size_t row = 0; row < n_rows && rows[row].kind; row++) {
      78           0 :         MYSQL_BIND *param = &stmt_mysql->param_bind[row];
      79             : 
      80           0 :         switch (rows[row].kind) {
      81           0 :         case 's':
      82           0 :             param->buffer_type = MYSQL_TYPE_STRING;
      83           0 :             param->buffer = rows[row].u.s;
      84           0 :             break;
      85           0 :         case 'i':
      86           0 :             param->buffer_type = MYSQL_TYPE_LONG;
      87           0 :             param->buffer = &rows[row].u.i;
      88           0 :             break;
      89           0 :         default:
      90           0 :             return false;
      91             :         }
      92             : 
      93           0 :         param->is_null = false;
      94           0 :         param->length = 0;
      95             :     }
      96             : 
      97           0 :     return !mysql_stmt_bind_param(stmt_mysql->stmt, stmt_mysql->param_bind);
      98             : }
      99             : 
     100           0 : static bool db_stmt_step_mysql(const struct db_stmt *stmt,
     101             :                                const char *signature,
     102             :                                va_list ap)
     103             : {
     104           0 :     struct db_stmt_mysql *stmt_mysql = (struct db_stmt_mysql *)stmt;
     105             : 
     106           0 :     if (stmt_mysql->must_execute_again) {
     107           0 :         stmt_mysql->must_execute_again = false;
     108           0 :         if (mysql_stmt_execute(stmt_mysql->stmt))
     109           0 :             return false;
     110             :     }
     111             : 
     112           0 :     if (!stmt_mysql->result_bind) {
     113           0 :         if (*signature == '\0')
     114           0 :             return false;
     115             : 
     116           0 :         stmt_mysql->result_bind =
     117           0 :             calloc(strlen(signature), sizeof(*stmt_mysql->result_bind));
     118           0 :         if (!stmt_mysql->result_bind)
     119           0 :             return false;
     120             : 
     121           0 :         free(stmt_mysql->param_bind);
     122           0 :         stmt_mysql->param_bind = NULL;
     123             : 
     124           0 :         MYSQL_BIND *result = stmt_mysql->result_bind;
     125           0 :         for (size_t r = 0; signature[r]; r++) {
     126           0 :             switch (signature[r]) {
     127           0 :             case 's':
     128           0 :                 result[r].buffer_type = MYSQL_TYPE_STRING;
     129           0 :                 result[r].buffer = va_arg(ap, char *);
     130           0 :                 result[r].buffer_length = va_arg(ap, size_t);
     131           0 :                 break;
     132           0 :             case 'i':
     133           0 :                 result[r].buffer_type = MYSQL_TYPE_LONG;
     134           0 :                 result[r].buffer = va_arg(ap, long *);
     135           0 :                 result[r].buffer_length = 0;
     136           0 :                 break;
     137           0 :             default:
     138           0 :                 goto out;
     139             :             }
     140             : 
     141           0 :             result[r].is_null = false;
     142             :         }
     143             : 
     144           0 :         if (mysql_stmt_bind_result(stmt_mysql->stmt, result))
     145           0 :             goto out;
     146             :     }
     147             : 
     148           0 :     return mysql_stmt_fetch(stmt_mysql->stmt) == 0;
     149             : 
     150           0 : out:
     151           0 :     free(stmt_mysql->result_bind);
     152           0 :     stmt_mysql->result_bind = NULL;
     153             : 
     154           0 :     return false;
     155             : }
     156             : 
     157           0 : static void db_stmt_finalize_mysql(struct db_stmt *stmt)
     158             : {
     159           0 :     struct db_stmt_mysql *stmt_mysql = (struct db_stmt_mysql *)stmt;
     160             : 
     161           0 :     mysql_stmt_close(stmt_mysql->stmt);
     162           0 :     free(stmt_mysql->result_bind);
     163           0 :     free(stmt_mysql->param_bind);
     164           0 :     free(stmt_mysql);
     165           0 : }
     166             : 
     167             : static struct db_stmt *
     168           0 : db_prepare_mysql(const struct db *db, const char *sql, const size_t sql_len)
     169             : {
     170           0 :     const struct db_mysql *db_mysql = (const struct db_mysql *)db;
     171           0 :     struct db_stmt_mysql *stmt_mysql = malloc(sizeof(*stmt_mysql));
     172             : 
     173           0 :     if (!stmt_mysql)
     174           0 :         return NULL;
     175             : 
     176           0 :     stmt_mysql->stmt = mysql_stmt_init(db_mysql->con);
     177           0 :     if (!stmt_mysql->stmt)
     178           0 :         goto out_free_stmt;
     179             : 
     180           0 :     if (mysql_stmt_prepare(stmt_mysql->stmt, sql, sql_len))
     181           0 :         goto out_close_stmt;
     182             : 
     183           0 :     stmt_mysql->base.bind = db_stmt_bind_mysql;
     184           0 :     stmt_mysql->base.step = db_stmt_step_mysql;
     185           0 :     stmt_mysql->base.finalize = db_stmt_finalize_mysql;
     186           0 :     stmt_mysql->result_bind = NULL;
     187           0 :     stmt_mysql->param_bind = NULL;
     188           0 :     stmt_mysql->must_execute_again = true;
     189             : 
     190           0 :     return (struct db_stmt *)stmt_mysql;
     191             : 
     192           0 : out_close_stmt:
     193           0 :     mysql_stmt_close(stmt_mysql->stmt);
     194           0 : out_free_stmt:
     195           0 :     free(stmt_mysql);
     196             : 
     197           0 :     return NULL;
     198             : }
     199             : 
     200           0 : static void db_disconnect_mysql(struct db *db)
     201             : {
     202           0 :     struct db_mysql *db_mysql = (struct db_mysql *)db;
     203             : 
     204           0 :     mysql_close(db_mysql->con);
     205           0 :     free(db);
     206           0 : }
     207             : 
     208           0 : struct db *db_connect_mysql(const char *host,
     209             :                             const char *user,
     210             :                             const char *pass,
     211             :                             const char *database)
     212             : {
     213           0 :     struct db_mysql *db_mysql = malloc(sizeof(*db_mysql));
     214             : 
     215           0 :     if (!db_mysql)
     216           0 :         return NULL;
     217             : 
     218           0 :     db_mysql->con = mysql_init(NULL);
     219           0 :     if (!db_mysql->con) {
     220           0 :         free(db_mysql);
     221           0 :         return NULL;
     222             :     }
     223             : 
     224           0 :     if (!mysql_real_connect(db_mysql->con, host, user, pass, database, 0, NULL,
     225             :                             0))
     226           0 :         goto error;
     227             : 
     228           0 :     if (mysql_set_character_set(db_mysql->con, "utf8"))
     229           0 :         goto error;
     230             : 
     231           0 :     db_mysql->base.disconnect = db_disconnect_mysql;
     232           0 :     db_mysql->base.prepare = db_prepare_mysql;
     233             : 
     234           0 :     return (struct db *)db_mysql;
     235             : 
     236           0 : error:
     237           0 :     mysql_close(db_mysql->con);
     238           0 :     free(db_mysql);
     239           0 :     return NULL;
     240             : }
     241             : 
     242             : /* SQLite */
     243             : 
     244             : struct db_sqlite {
     245             :     struct db base;
     246             :     sqlite3 *sqlite;
     247             : };
     248             : 
     249             : struct db_stmt_sqlite {
     250             :     struct db_stmt base;
     251             :     sqlite3_stmt *sqlite;
     252             : };
     253             : 
     254        1115 : static bool db_stmt_bind_sqlite(const struct db_stmt *stmt,
     255             :                                 struct db_row *rows,
     256             :                                 size_t n_rows)
     257             : {
     258        1115 :     const struct db_stmt_sqlite *stmt_sqlite =
     259             :         (const struct db_stmt_sqlite *)stmt;
     260             : 
     261        1115 :     sqlite3_reset(stmt_sqlite->sqlite);
     262        1115 :     sqlite3_clear_bindings(stmt_sqlite->sqlite);
     263             : 
     264        2230 :     for (size_t row = 1; row <= n_rows; row++) {
     265        1115 :         const struct db_row *r = &rows[row - 1];
     266             :         int ret;
     267             : 
     268        1115 :         switch (r->kind) {
     269           0 :         case 's':
     270           0 :             ret = sqlite3_bind_text(stmt_sqlite->sqlite, (int)row, r->u.s, -1,
     271             :                                     NULL);
     272           0 :             break;
     273        1115 :         case 'i':
     274        1115 :             ret = sqlite3_bind_int(stmt_sqlite->sqlite, (int)row, r->u.i);
     275        1115 :             break;
     276           0 :         default:
     277           0 :             return false;
     278             :         }
     279             : 
     280        1115 :         if (ret != SQLITE_OK)
     281           0 :             return false;
     282             :     }
     283             : 
     284        1115 :     return true;
     285             : }
     286             : 
     287        1128 : static bool db_stmt_step_sqlite(const struct db_stmt *stmt,
     288             :                                 const char *signature,
     289             :                                 va_list ap)
     290             : {
     291        1128 :     const struct db_stmt_sqlite *stmt_sqlite =
     292             :         (const struct db_stmt_sqlite *)stmt;
     293             : 
     294        1128 :     if (sqlite3_step(stmt_sqlite->sqlite) != SQLITE_ROW)
     295           1 :         return false;
     296             : 
     297        3381 :     for (int r = 0; signature[r]; r++) {
     298        2254 :         switch (signature[r]) {
     299        2242 :         case 'i':
     300        2242 :             *va_arg(ap, long *) = sqlite3_column_int(stmt_sqlite->sqlite, r);
     301        2242 :             break;
     302          12 :         case 's': {
     303          12 :             char *out = va_arg(ap, char *);
     304          12 :             size_t bufsize = va_arg(ap, size_t);
     305             : 
     306          12 :             strncpy(out,
     307          12 :                     (const char *)sqlite3_column_text(stmt_sqlite->sqlite, r),
     308             :                     bufsize);
     309             : 
     310          12 :             break;
     311             :         }
     312           0 :         default:
     313           0 :             return false;
     314             :         }
     315             :     }
     316             : 
     317        1127 :     return true;
     318             : }
     319             : 
     320          10 : static void db_stmt_finalize_sqlite(struct db_stmt *stmt)
     321             : {
     322          10 :     struct db_stmt_sqlite *stmt_sqlite = (struct db_stmt_sqlite *)stmt;
     323             : 
     324          10 :     sqlite3_finalize(stmt_sqlite->sqlite);
     325          10 :     free(stmt_sqlite);
     326          10 : }
     327             : 
     328             : static struct db_stmt *
     329          10 : db_prepare_sqlite(const struct db *db, const char *sql, const size_t sql_len)
     330             : {
     331          10 :     const struct db_sqlite *db_sqlite = (const struct db_sqlite *)db;
     332          10 :     struct db_stmt_sqlite *stmt_sqlite = malloc(sizeof(*stmt_sqlite));
     333             : 
     334          10 :     if (!stmt_sqlite)
     335           0 :         return NULL;
     336             : 
     337          10 :     int ret = sqlite3_prepare_v2(db_sqlite->sqlite, sql, (int)sql_len,
     338             :                                  &stmt_sqlite->sqlite, NULL);
     339          10 :     if (ret != SQLITE_OK) {
     340           0 :         free(stmt_sqlite);
     341           0 :         return NULL;
     342             :     }
     343             : 
     344          10 :     stmt_sqlite->base.bind = db_stmt_bind_sqlite;
     345          10 :     stmt_sqlite->base.step = db_stmt_step_sqlite;
     346          10 :     stmt_sqlite->base.finalize = db_stmt_finalize_sqlite;
     347             : 
     348          10 :     return (struct db_stmt *)stmt_sqlite;
     349             : }
     350             : 
     351           0 : static void db_disconnect_sqlite(struct db *db)
     352             : {
     353           0 :     struct db_sqlite *db_sqlite = (struct db_sqlite *)db;
     354             : 
     355           0 :     sqlite3_close(db_sqlite->sqlite);
     356           0 :     free(db);
     357           0 : }
     358             : 
     359             : struct db *
     360           4 : db_connect_sqlite(const char *path, bool read_only, const char *pragmas[])
     361             : {
     362           4 :     struct db_sqlite *db_sqlite = malloc(sizeof(*db_sqlite));
     363             : 
     364           4 :     if (!db_sqlite)
     365           0 :         return NULL;
     366             : 
     367           4 :     int flags = read_only ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
     368           4 :     int ret = sqlite3_open_v2(path, &db_sqlite->sqlite, flags, NULL);
     369           4 :     if (ret != SQLITE_OK) {
     370           0 :         free(db_sqlite);
     371           0 :         return NULL;
     372             :     }
     373             : 
     374           4 :     if (pragmas) {
     375          16 :         for (size_t p = 0; pragmas[p]; p++)
     376          12 :             sqlite3_exec(db_sqlite->sqlite, pragmas[p], NULL, NULL, NULL);
     377             :     }
     378             : 
     379           4 :     db_sqlite->base.disconnect = db_disconnect_sqlite;
     380           4 :     db_sqlite->base.prepare = db_prepare_sqlite;
     381             : 
     382           4 :     return (struct db *)db_sqlite;
     383             : }
     384             : 
     385             : /* Generic */
     386             : 
     387             : inline bool
     388        1115 : db_stmt_bind(const struct db_stmt *stmt, struct db_row *rows, size_t n_rows)
     389             : {
     390        1115 :     return stmt->bind(stmt, rows, n_rows);
     391             : }
     392             : 
     393             : inline bool
     394        1128 : db_stmt_step(const struct db_stmt *stmt, const char *signature, ...)
     395             : {
     396             :     va_list ap;
     397             :     bool ret;
     398             : 
     399        1128 :     va_start(ap, signature);
     400        1128 :     ret = stmt->step(stmt, signature, ap);
     401        1128 :     va_end(ap);
     402             : 
     403        1128 :     return ret;
     404             : }
     405             : 
     406          10 : inline void db_stmt_finalize(struct db_stmt *stmt) { stmt->finalize(stmt); }
     407             : 
     408           0 : inline void db_disconnect(struct db *db) { db->disconnect(db); }
     409             : 
     410             : inline struct db_stmt *
     411          10 : db_prepare_stmt(const struct db *db, const char *sql, const size_t sql_len)
     412             : {
     413          10 :     return db->prepare(db, sql, sql_len);
     414             : }

Generated by: LCOV version 1.15-2-gb9d6727