LCOV - code coverage report
Current view: top level - sql/storage/bat - bat_logger.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 241 737 32.7 %
Date: 2024-12-19 20:05:57 Functions: 22 23 95.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "bat_logger.h"
      15             : #include "bat_utils.h"
      16             : #include "sql_types.h" /* EC_POS */
      17             : #include "gdk_logger_internals.h"
      18             : #include "mutils.h"
      19             : 
      20             : #define CATALOG_JUL2021 52300   /* first in Jul2021 */
      21             : #define CATALOG_JAN2022 52301   /* first in Jan2022 */
      22             : #define CATALOG_SEP2022 52302   /* first in Sep2022 */
      23             : 
      24             : /* Note, CATALOG version 52300 is the first one where the basic system
      25             :  * tables (the ones created in store.c) have fixed and unchangeable
      26             :  * ids. */
      27             : 
      28             : /* return GDK_SUCCEED if we can handle the upgrade from oldversion to
      29             :  * newversion */
      30             : static gdk_return
      31           8 : bl_preversion(sqlstore *store, int oldversion, int newversion)
      32             : {
      33           8 :         (void)newversion;
      34             : 
      35             : #ifdef CATALOG_JUL2021
      36           8 :         if (oldversion == CATALOG_JUL2021) {
      37             :                 /* upgrade to default releases */
      38           0 :                 store->catalog_version = oldversion;
      39           0 :                 return GDK_SUCCEED;
      40             :         }
      41             : #endif
      42             : 
      43             : #ifdef CATALOG_JAN2022
      44           8 :         if (oldversion == CATALOG_JAN2022) {
      45             :                 /* upgrade to default releases */
      46           0 :                 store->catalog_version = oldversion;
      47           0 :                 return GDK_SUCCEED;
      48             :         }
      49             : #endif
      50             : 
      51             : #ifdef CATALOG_SEP2022
      52           8 :         if (oldversion == CATALOG_SEP2022) {
      53             :                 /* upgrade to default releases */
      54           8 :                 store->catalog_version = oldversion;
      55           8 :                 return GDK_SUCCEED;
      56             :         }
      57             : #endif
      58             : 
      59             :         return GDK_FAIL;
      60             : }
      61             : 
      62             : #if defined CATALOG_JUL2021 || defined CATALOG_JAN2022
      63             : /* replace a column in a system table with a new column
      64             :  * colid is the SQL id for the column, oldcolid is the BAT id of the
      65             :  * to-be-replaced BAT */
      66             : static gdk_return
      67           0 : replace_bat(logger *lg, int colid, BAT *newcol)
      68             : {
      69           0 :         gdk_return rc;
      70           0 :         newcol = BATsetaccess(newcol, BAT_READ);
      71           0 :         if (newcol == NULL)
      72             :                 return GDK_FAIL;
      73           0 :         if ((rc = BAThash(lg->catalog_id)) == GDK_SUCCEED) {
      74           0 :                 BATiter cii = bat_iterator_nolock(lg->catalog_id);
      75           0 :                 BUN p;
      76           0 :                 MT_rwlock_rdlock(&cii.b->thashlock);
      77           0 :                 HASHloop_int(cii, cii.b->thash, p, &colid) {
      78           0 :                         if (BUNfnd(lg->dcatalog, &(oid){(oid)p}) == BUN_NONE) {
      79           0 :                                 if (BUNappend(lg->dcatalog, &(oid){(oid)p}, true) != GDK_SUCCEED ||
      80           0 :                                         BUNreplace(lg->catalog_lid, (oid) p, &(lng){0}, false) != GDK_SUCCEED) {
      81           0 :                                         MT_rwlock_rdunlock(&cii.b->thashlock);
      82           0 :                                         return GDK_FAIL;
      83             :                                 }
      84           0 :                                 break;
      85             :                         }
      86             :                 }
      87           0 :                 MT_rwlock_rdunlock(&cii.b->thashlock);
      88           0 :                 if ((rc = BUNappend(lg->catalog_id, &colid, true)) == GDK_SUCCEED &&
      89           0 :                         (rc = BUNappend(lg->catalog_bid, &newcol->batCacheid, true)) == GDK_SUCCEED &&
      90           0 :                         (rc = BUNappend(lg->catalog_lid, &lng_nil, false)) == GDK_SUCCEED &&
      91           0 :                         (rc = BUNappend(lg->catalog_cnt, &(lng){BATcount(newcol)}, false)) == GDK_SUCCEED) {
      92           0 :                         BBPretain(newcol->batCacheid);
      93             :                 }
      94             :         }
      95             :         return rc;
      96             : }
      97             : #endif
      98             : 
      99             : static BAT *
     100         184 : log_temp_descriptor(log_bid b)
     101             : {
     102         184 :         if (b <= 0)
     103             :                 return NULL;
     104         184 :         return temp_descriptor(b);
     105             : }
     106             : 
     107             : #if defined CATALOG_JAN2022 || defined CATALOG_SEP2022
     108             : static gdk_return
     109          16 : tabins(logger *lg, ...)
     110             : {
     111          16 :         va_list va;
     112          16 :         int cid;
     113          16 :         const void *cval;
     114          16 :         gdk_return rc;
     115          16 :         BAT *b;
     116             : 
     117          16 :         va_start(va, lg);
     118          16 :         BATiter cni = bat_iterator(lg->catalog_id);
     119         192 :         while ((cid = va_arg(va, int)) != 0) {
     120         176 :                 cval = va_arg(va, void *);
     121         352 :                 if ((b = log_temp_descriptor(log_find_bat(lg, cid))) == NULL) {
     122             :                         rc = GDK_FAIL;
     123             :                         break;
     124             :                 }
     125         176 :                 rc = BUNappend(b, cval, true);
     126         176 :                 if (rc == GDK_SUCCEED) {
     127         176 :                         BUN p;
     128         176 :                         MT_rwlock_rdlock(&cni.b->thashlock);
     129         188 :                         HASHloop_int(cni, cni.b->thash, p, &cid) {
     130         176 :                                 if (BUNfnd(lg->dcatalog, &(oid){p}) == BUN_NONE) {
     131         176 :                                         rc = BUNreplace(lg->catalog_cnt, p, &(lng){BATcount(b)}, false);
     132         176 :                                         break;
     133             :                                 }
     134             :                         }
     135         176 :                         MT_rwlock_rdunlock(&cni.b->thashlock);
     136             :                 }
     137         176 :                 bat_destroy(b);
     138         176 :                 if (rc != GDK_SUCCEED)
     139             :                         break;
     140             :         }
     141          16 :         bat_iterator_end(&cni);
     142          16 :         va_end(va);
     143          16 :         return rc;
     144             : }
     145             : #endif
     146             : 
     147             : static gdk_return
     148           8 : bl_postversion(void *Store, logger *lg)
     149             : {
     150           8 :         sqlstore *store = Store;
     151           8 :         gdk_return rc;
     152             : 
     153             : #ifdef CATALOG_JUL2021
     154           8 :         if (store->catalog_version <= CATALOG_JUL2021) {
     155             :                 /* change the language attribute in sys.functions for sys.env,
     156             :                  * sys.var, and sys.db_users from SQL to MAL */
     157             : 
     158             :                 /* sys.functions i.e. deleted rows */
     159           0 :                 BAT *del_funcs = log_temp_descriptor(log_find_bat(lg, 2016));
     160           0 :                 if (del_funcs == NULL)
     161           0 :                         return GDK_FAIL;
     162           0 :                 BAT *func_tid = BATmaskedcands(0, BATcount(del_funcs), del_funcs, false);
     163           0 :                 bat_destroy(del_funcs);
     164             :                 /* sys.functions.schema_id */
     165           0 :                 BAT *func_schem = log_temp_descriptor(log_find_bat(lg, 2026));
     166           0 :                 if (func_tid == NULL || func_schem == NULL) {
     167           0 :                         bat_destroy(func_tid);
     168           0 :                         bat_destroy(func_schem);
     169           0 :                         return GDK_FAIL;
     170             :                 }
     171             :                 /* select * from sys.functions where schema_id = 2000 */
     172           0 :                 BAT *cands = BATselect(func_schem, func_tid, &(int) {2000}, NULL, true, true, false);
     173           0 :                 bat_destroy(func_schem);
     174           0 :                 if (cands == NULL) {
     175           0 :                         bat_destroy(func_tid);
     176           0 :                         return GDK_FAIL;
     177             :                 }
     178             :                 /* the functions we need to change */
     179           0 :                 BAT *funcs = COLnew(0, TYPE_str, 3, TRANSIENT);
     180           0 :                 if (funcs == NULL ||
     181           0 :                         BUNappend(funcs, "db_users", false) != GDK_SUCCEED ||
     182           0 :                         BUNappend(funcs, "env", false) != GDK_SUCCEED ||
     183           0 :                         BUNappend(funcs, "var", false) != GDK_SUCCEED) {
     184           0 :                         bat_destroy(cands);
     185           0 :                         bat_destroy(funcs);
     186           0 :                         bat_destroy(func_tid);
     187           0 :                         return GDK_FAIL;
     188             :                 }
     189             :                 /* sys.functions.name */
     190           0 :                 BAT *func_name = log_temp_descriptor(log_find_bat(lg, 2018));
     191           0 :                 if (func_name == NULL) {
     192           0 :                         bat_destroy(cands);
     193           0 :                         bat_destroy(funcs);
     194           0 :                         bat_destroy(func_tid);
     195           0 :                         return GDK_FAIL;
     196             :                 }
     197             :                 /* select * from sys.functions where schema_id = 2000 and name in (...) */
     198           0 :                 BAT *b = BATintersect(func_name, funcs, cands, NULL, false, false, 3);
     199           0 :                 bat_destroy(cands);
     200           0 :                 bat_destroy(func_name);
     201           0 :                 bat_destroy(funcs);
     202           0 :                 cands = b;
     203           0 :                 if (cands == NULL) {
     204           0 :                         bat_destroy(func_tid);
     205           0 :                         return GDK_FAIL;
     206             :                 }
     207             :                 /* sys.functions.language */
     208           0 :                 BAT *func_lang = log_temp_descriptor(log_find_bat(lg, 2021));
     209           0 :                 if (func_lang == NULL) {
     210           0 :                         bat_destroy(cands);
     211           0 :                         bat_destroy(func_tid);
     212           0 :                         return GDK_FAIL;
     213             :                 }
     214             :                 /* select * from sys.functions where schema_id = 2000 and name in (...)
     215             :                  * and language = FUNC_LANG_SQL */
     216           0 :                 b = BATselect(func_lang, cands, &(int) {FUNC_LANG_SQL}, NULL, true, true, false);
     217           0 :                 bat_destroy(cands);
     218           0 :                 cands = b;
     219           0 :                 if (cands == NULL) {
     220           0 :                         bat_destroy(func_lang);
     221           0 :                         bat_destroy(func_tid);
     222           0 :                         return GDK_FAIL;
     223             :                 }
     224           0 :                 b = BATconstant(0, TYPE_int, &(int) {FUNC_LANG_MAL}, BATcount(cands), TRANSIENT);
     225           0 :                 if (b == NULL) {
     226           0 :                         bat_destroy(func_lang);
     227           0 :                         bat_destroy(cands);
     228           0 :                         bat_destroy(func_tid);
     229           0 :                         return GDK_FAIL;
     230             :                 }
     231           0 :                 rc = GDK_FAIL;
     232           0 :                 BAT *b2 = COLcopy(func_lang, func_lang->ttype, true, PERSISTENT);
     233           0 :                 if (b2 == NULL ||
     234           0 :                         BATreplace(b2, cands, b, false) != GDK_SUCCEED) {
     235           0 :                         bat_destroy(b2);
     236           0 :                         bat_destroy(cands);
     237           0 :                         bat_destroy(b);
     238           0 :                         bat_destroy(func_tid);
     239           0 :                         bat_destroy(func_lang);
     240           0 :                         return GDK_FAIL;
     241             :                 }
     242           0 :                 bat_destroy(b);
     243           0 :                 bat_destroy(cands);
     244             : 
     245             :                 /* additionally, update the language attribute for entries
     246             :                  * that were declared using "EXTERNAL NAME" to be MAL functions
     247             :                  * instead of SQL functions (a problem that seems to have
     248             :                  * occurred in ancient databases) */
     249             : 
     250             :                 /* sys.functions.func */
     251           0 :                 BAT *func_func = log_temp_descriptor(log_find_bat(lg, 2019));
     252           0 :                 if (func_func == NULL) {
     253           0 :                         bat_destroy(func_tid);
     254           0 :                         bat_destroy(b2);
     255           0 :                         return GDK_FAIL;
     256             :                 }
     257           0 :                 cands = BATselect(func_lang, func_tid, &(int){FUNC_LANG_SQL}, NULL, true, true, false);
     258           0 :                 bat_destroy(func_lang);
     259           0 :                 bat_destroy(func_tid);
     260           0 :                 if (cands == NULL) {
     261           0 :                         bat_destroy(b2);
     262           0 :                         bat_destroy(func_func);
     263           0 :                         return GDK_FAIL;
     264             :                 }
     265           0 :                 struct canditer ci;
     266           0 :                 canditer_init(&ci, func_func, cands);
     267           0 :                 BATiter ffi = bat_iterator_nolock(func_func);
     268           0 :                 for (BUN p = 0; p < ci.ncand; p++) {
     269           0 :                         oid o = canditer_next(&ci);
     270           0 :                         const char *f = BUNtvar(ffi, o - func_func->hseqbase);
     271           0 :                         const char *e;
     272           0 :                         if (!strNil(f) &&
     273           0 :                                 (e = strstr(f, "external")) != NULL &&
     274           0 :                                 e > f && isspace((unsigned char) e[-1]) && isspace((unsigned char) e[8]) && strncmp(e + 9, "name", 4) == 0 && isspace((unsigned char) e[13]) &&
     275           0 :                                 BUNreplace(b2, o, &(int){FUNC_LANG_MAL}, false) != GDK_SUCCEED) {
     276           0 :                                 bat_destroy(b2);
     277           0 :                                 bat_destroy(func_func);
     278           0 :                                 return GDK_FAIL;
     279             :                         }
     280             :                 }
     281           0 :                 rc = replace_bat(lg, 2021, b2);
     282           0 :                 bat_destroy(b2);
     283           0 :                 if (rc != GDK_SUCCEED)
     284             :                         return rc;
     285             :         }
     286           8 :         if (store->catalog_version <= CATALOG_JUL2021) {
     287             :                 /* change the side_effects attribute in sys.functions for
     288             :                  * selected functions */
     289             : 
     290             :                 /* sys.functions i.e. deleted rows */
     291           0 :                 BAT *del_funcs = log_temp_descriptor(log_find_bat(lg, 2016));
     292           0 :                 if (del_funcs == NULL)
     293           0 :                         return GDK_FAIL;
     294           0 :                 BAT *func_tid = BATmaskedcands(0, BATcount(del_funcs), del_funcs, false);
     295           0 :                 bat_destroy(del_funcs);
     296             :                 /* sys.functions.schema_id */
     297           0 :                 BAT *func_schem = log_temp_descriptor(log_find_bat(lg, 2026));
     298           0 :                 if (func_tid == NULL || func_schem == NULL) {
     299           0 :                         bat_destroy(func_tid);
     300           0 :                         bat_destroy(func_schem);
     301           0 :                         return GDK_FAIL;
     302             :                 }
     303             :                 /* select * from sys.functions where schema_id = 2000 */
     304           0 :                 BAT *cands = BATselect(func_schem, func_tid, &(int) {2000}, NULL, true, true, false);
     305           0 :                 bat_destroy(func_schem);
     306           0 :                 bat_destroy(func_tid);
     307           0 :                 if (cands == NULL) {
     308             :                         return GDK_FAIL;
     309             :                 }
     310             :                 /* sys.functions.side_effect */
     311           0 :                 BAT *func_se = log_temp_descriptor(log_find_bat(lg, 2023));
     312           0 :                 if (func_se == NULL) {
     313           0 :                         bat_destroy(cands);
     314           0 :                         return GDK_FAIL;
     315             :                 }
     316             :                 /* make a copy that we can modify */
     317           0 :                 BAT *b = COLcopy(func_se, func_se->ttype, true, PERSISTENT);
     318           0 :                 bat_destroy(func_se);
     319           0 :                 if (b == NULL) {
     320           0 :                         bat_destroy(cands);
     321           0 :                         return GDK_FAIL;
     322             :                 }
     323           0 :                 func_se = b;
     324             :                 /* sys.functions.func */
     325           0 :                 BAT *func_func = log_temp_descriptor(log_find_bat(lg, 2019));
     326           0 :                 if (func_func == NULL) {
     327           0 :                         bat_destroy(cands);
     328           0 :                         bat_destroy(func_se);
     329           0 :                         return GDK_FAIL;
     330             :                 }
     331             :                 /* the functions we need to change to FALSE */
     332           0 :                 BAT *funcs = COLnew(0, TYPE_str, 1, TRANSIENT);
     333           0 :                 if (funcs == NULL ||
     334           0 :                         BUNappend(funcs, "sqlrand", false) != GDK_SUCCEED) {
     335           0 :                         bat_destroy(cands);
     336           0 :                         bat_destroy(func_se);
     337           0 :                         bat_destroy(func_func);
     338           0 :                         bat_destroy(funcs);
     339           0 :                         return GDK_FAIL;
     340             :                 }
     341             :                 /* select * from sys.functions where schema_id = 2000 and func in (...) */
     342           0 :                 b = BATintersect(func_func, funcs, cands, NULL, false, false, 1);
     343           0 :                 bat_destroy(funcs);
     344           0 :                 if (b == NULL) {
     345           0 :                         bat_destroy(cands);
     346           0 :                         bat_destroy(func_se);
     347           0 :                         bat_destroy(func_func);
     348           0 :                         return GDK_FAIL;
     349             :                 }
     350             :                 /* while we're at it, also change sys.env and sys.db_users to
     351             :                  * being without side effect (legacy from ancient databases) */
     352             :                 /* sys.functions.name */
     353           0 :                 BAT *func_name = log_temp_descriptor(log_find_bat(lg, 2018));
     354           0 :                 if (func_name == NULL) {
     355           0 :                         bat_destroy(cands);
     356           0 :                         bat_destroy(func_se);
     357           0 :                         bat_destroy(func_func);
     358           0 :                         bat_destroy(b);
     359           0 :                         return GDK_FAIL;
     360             :                 }
     361           0 :                 BAT *b2 = BATselect(func_name, cands, "env", NULL, true, true, false);
     362           0 :                 if (b2 == NULL || BATappend(b, b2, NULL, false) != GDK_SUCCEED) {
     363           0 :                         bat_destroy(cands);
     364           0 :                         bat_destroy(func_se);
     365           0 :                         bat_destroy(func_func);
     366           0 :                         bat_destroy(b);
     367           0 :                         bat_destroy(func_name);
     368           0 :                         bat_destroy(b2);
     369           0 :                         return GDK_FAIL;
     370             :                 }
     371           0 :                 bat_destroy(b2);
     372           0 :                 b2 = BATselect(func_name, cands, "db_users", NULL, true, true, false);
     373           0 :                 bat_destroy(func_name);
     374           0 :                 if (b2 == NULL || BATappend(b, b2, NULL, false) != GDK_SUCCEED) {
     375           0 :                         bat_destroy(cands);
     376           0 :                         bat_destroy(func_se);
     377           0 :                         bat_destroy(func_func);
     378           0 :                         bat_destroy(b);
     379           0 :                         bat_destroy(b2);
     380           0 :                         return GDK_FAIL;
     381             :                 }
     382           0 :                 bat_destroy(b2);
     383             : 
     384           0 :                 BAT *vals = BATconstant(0, TYPE_bit, &(bit) {FALSE}, BATcount(b), TRANSIENT);
     385           0 :                 if (vals == NULL) {
     386           0 :                         bat_destroy(cands);
     387           0 :                         bat_destroy(func_se);
     388           0 :                         bat_destroy(func_func);
     389           0 :                         bat_destroy(b);
     390           0 :                         return GDK_FAIL;
     391             :                 }
     392           0 :                 rc = BATreplace(func_se, b, vals, false);
     393           0 :                 bat_destroy(b);
     394           0 :                 bat_destroy(vals);
     395           0 :                 if (rc != GDK_SUCCEED) {
     396           0 :                         bat_destroy(cands);
     397           0 :                         bat_destroy(func_se);
     398           0 :                         bat_destroy(func_func);
     399           0 :                         return GDK_FAIL;
     400             :                 }
     401             :                 /* the functions we need to change to TRUE */
     402           0 :                 funcs = COLnew(0, TYPE_str, 5, TRANSIENT);
     403           0 :                 if (funcs == NULL ||
     404           0 :                         BUNappend(funcs, "copy_from", false) != GDK_SUCCEED ||
     405           0 :                         BUNappend(funcs, "next_value", false) != GDK_SUCCEED ||
     406           0 :                         BUNappend(funcs, "update_schemas", false) != GDK_SUCCEED ||
     407           0 :                         BUNappend(funcs, "update_tables", false) != GDK_SUCCEED) {
     408           0 :                         bat_destroy(cands);
     409           0 :                         bat_destroy(func_se);
     410           0 :                         bat_destroy(func_func);
     411           0 :                         bat_destroy(funcs);
     412           0 :                         return GDK_FAIL;
     413             :                 }
     414             :                 /* select * from sys.functions where schema_id = 2000 and func in (...) */
     415           0 :                 b = BATintersect(func_func, funcs, cands, NULL, false, false, 7);
     416           0 :                 bat_destroy(funcs);
     417           0 :                 bat_destroy(cands);
     418           0 :                 bat_destroy(func_func);
     419           0 :                 if (b == NULL) {
     420           0 :                         bat_destroy(func_se);
     421           0 :                         return GDK_FAIL;
     422             :                 }
     423           0 :                 vals = BATconstant(0, TYPE_bit, &(bit) {TRUE}, BATcount(b), TRANSIENT);
     424           0 :                 if (vals == NULL) {
     425           0 :                         bat_destroy(func_se);
     426           0 :                         bat_destroy(b);
     427           0 :                         return GDK_FAIL;
     428             :                 }
     429           0 :                 rc = BATreplace(func_se, b, vals, false);
     430           0 :                 bat_destroy(b);
     431           0 :                 bat_destroy(vals);
     432           0 :                 if (rc != GDK_SUCCEED) {
     433           0 :                         bat_destroy(func_se);
     434           0 :                         return GDK_FAIL;
     435             :                 }
     436             :                 /* replace old column with modified copy */
     437           0 :                 rc = replace_bat(lg, 2023, func_se);
     438           0 :                 bat_destroy(func_se);
     439           0 :                 if (rc != GDK_SUCCEED)
     440             :                         return rc;
     441             :         }
     442           8 :         if (store->catalog_version <= CATALOG_JUL2021) {
     443             :                 /* upgrade some columns in sys.sequences:
     444             :                  * if increment is zero, set it to one (see ChangeLog);
     445             :                  * if increment is greater than zero and maxvalue is zero,
     446             :                  * set maxvalue to GDK_lng_max;
     447             :                  * if increment is less than zero and minvalue is zero,
     448             :                  * set minvalue to GDK_lng_min */
     449             : 
     450             :                 /* sys.sequences i.e. deleted rows */
     451           0 :                 BAT *del_seqs = log_temp_descriptor(log_find_bat(lg, 2037));
     452           0 :                 if (del_seqs == NULL)
     453           0 :                         return GDK_FAIL;
     454           0 :                 BAT *seq_tid = BATmaskedcands(0, BATcount(del_seqs), del_seqs, false);
     455           0 :                 bat_destroy(del_seqs);
     456           0 :                 BAT *seq_min = log_temp_descriptor(log_find_bat(lg, 2042)); /* sys.sequences.minvalue */
     457           0 :                 BAT *seq_max = log_temp_descriptor(log_find_bat(lg, 2043)); /* sys.sequences.maxvalue */
     458           0 :                 BAT *seq_inc = log_temp_descriptor(log_find_bat(lg, 2044)); /* sys.sequences.increment */
     459           0 :                 if (seq_tid == NULL || seq_min == NULL || seq_max == NULL || seq_inc == NULL) {
     460           0 :                         bat_destroy(seq_tid);
     461           0 :                         bat_destroy(seq_min);
     462           0 :                         bat_destroy(seq_max);
     463           0 :                         bat_destroy(seq_inc);
     464           0 :                         return GDK_FAIL;
     465             :                 }
     466             :                 /* select * from sys.sequences where increment = 0 */
     467           0 :                 BAT *inczero = BATselect(seq_inc, seq_tid, &(lng){0}, NULL, false, true, false);
     468           0 :                 if (inczero == NULL) {
     469           0 :                         bat_destroy(seq_tid);
     470           0 :                         bat_destroy(seq_min);
     471           0 :                         bat_destroy(seq_max);
     472           0 :                         bat_destroy(seq_inc);
     473           0 :                         return GDK_FAIL;
     474             :                 }
     475           0 :                 if (BATcount(inczero) > 0) {
     476           0 :                         BAT *b = BATconstant(0, TYPE_lng, &(lng) {1}, BATcount(inczero), TRANSIENT);
     477           0 :                         if (b == NULL) {
     478           0 :                                 bat_destroy(seq_tid);
     479           0 :                                 bat_destroy(seq_min);
     480           0 :                                 bat_destroy(seq_max);
     481           0 :                                 bat_destroy(seq_inc);
     482           0 :                                 bat_destroy(inczero);
     483           0 :                                 return GDK_FAIL;
     484             :                         }
     485           0 :                         BAT *b2 = COLcopy(seq_inc, seq_inc->ttype, true, PERSISTENT);
     486           0 :                         rc = GDK_FAIL;
     487           0 :                         if (b2 == NULL)
     488           0 :                                 rc = BATreplace(b2, inczero, b, false);
     489           0 :                         bat_destroy(b);
     490           0 :                         if (rc != GDK_SUCCEED) {
     491           0 :                                 bat_destroy(b2);
     492           0 :                                 bat_destroy(seq_tid);
     493           0 :                                 bat_destroy(seq_min);
     494           0 :                                 bat_destroy(seq_max);
     495           0 :                                 bat_destroy(seq_inc);
     496           0 :                                 bat_destroy(inczero);
     497           0 :                                 return GDK_FAIL;
     498             :                         }
     499           0 :                         rc = replace_bat(lg, 2044, b2);
     500           0 :                         bat_destroy(seq_inc);
     501           0 :                         seq_inc = b2;
     502           0 :                         if (rc != GDK_SUCCEED) {
     503           0 :                                 bat_destroy(seq_tid);
     504           0 :                                 bat_destroy(seq_min);
     505           0 :                                 bat_destroy(seq_max);
     506           0 :                                 bat_destroy(seq_inc);
     507           0 :                                 bat_destroy(inczero);
     508           0 :                                 return rc;
     509             :                         }
     510             :                 }
     511           0 :                 bat_destroy(inczero);
     512             :                 /* select * from sys.sequences where increment > 0 */
     513           0 :                 BAT *incpos = BATselect(seq_inc, seq_tid, &(lng){0}, &lng_nil, false, true, false);
     514           0 :                 bat_destroy(seq_inc);
     515           0 :                 if (incpos == NULL) {
     516           0 :                         bat_destroy(seq_tid);
     517           0 :                         bat_destroy(seq_min);
     518           0 :                         bat_destroy(seq_max);
     519           0 :                         return GDK_FAIL;
     520             :                 }
     521             :                 /* select * from sys.sequences where increment > 0 and maxvalue = 0 */
     522           0 :                 BAT *cands = BATselect(seq_max, incpos, &(lng) {0}, NULL, true, true, false);
     523           0 :                 bat_destroy(incpos);
     524           0 :                 if (cands == NULL) {
     525           0 :                         bat_destroy(seq_tid);
     526           0 :                         bat_destroy(seq_min);
     527           0 :                         bat_destroy(seq_max);
     528           0 :                         return GDK_FAIL;
     529             :                 }
     530           0 :                 if (BATcount(cands) > 0) {
     531           0 :                         BAT *b = BATconstant(0, TYPE_lng, &(lng){GDK_lng_max}, BATcount(cands), TRANSIENT);
     532           0 :                         BAT *b2 = COLcopy(seq_max, seq_max->ttype, true, PERSISTENT);
     533           0 :                         rc = GDK_FAIL;
     534           0 :                         if (b != NULL && b2 != NULL)
     535           0 :                                 rc = BATreplace(b2, cands, b, false);
     536           0 :                         bat_destroy(b);
     537           0 :                         if (rc == GDK_SUCCEED)
     538           0 :                                 rc = replace_bat(lg, 2043, b2);
     539           0 :                         bat_destroy(b2);
     540           0 :                         if (rc != GDK_SUCCEED) {
     541           0 :                                 bat_destroy(cands);
     542           0 :                                 bat_destroy(seq_tid);
     543           0 :                                 bat_destroy(seq_min);
     544           0 :                                 bat_destroy(seq_max);
     545           0 :                                 return rc;
     546             :                         }
     547             :                 }
     548           0 :                 bat_destroy(seq_max);
     549           0 :                 bat_destroy(cands);
     550             :                 /* select * from sys.sequences where increment < 0 */
     551           0 :                 BAT *incneg = BATselect(seq_inc, seq_tid, &lng_nil, &(lng){0}, false, true, false);
     552           0 :                 bat_destroy(seq_tid);
     553             :                 /* select * from sys.sequences where increment < 0 and minvalue = 0 */
     554           0 :                 cands = BATselect(seq_min, incneg, &(lng) {0}, NULL, true, true, false);
     555           0 :                 bat_destroy(incneg);
     556           0 :                 if (cands == NULL) {
     557           0 :                         bat_destroy(seq_min);
     558           0 :                         return GDK_FAIL;
     559             :                 }
     560           0 :                 if (BATcount(cands) > 0) {
     561           0 :                         BAT *b = BATconstant(0, TYPE_lng, &(lng){GDK_lng_min}, BATcount(cands), TRANSIENT);
     562           0 :                         BAT *b2 = COLcopy(seq_min, seq_min->ttype, true, PERSISTENT);
     563           0 :                         rc = GDK_FAIL;
     564           0 :                         if (b != NULL && b2 != NULL)
     565           0 :                                 rc = BATreplace(b2, cands, b, false);
     566           0 :                         bat_destroy(b);
     567           0 :                         if (rc == GDK_SUCCEED)
     568           0 :                                 rc = replace_bat(lg, 2042, b2);
     569           0 :                         bat_destroy(b2);
     570           0 :                         if (rc != GDK_SUCCEED) {
     571           0 :                                 bat_destroy(cands);
     572           0 :                                 bat_destroy(seq_min);
     573           0 :                                 return rc;
     574             :                         }
     575             :                 }
     576           0 :                 bat_destroy(seq_min);
     577           0 :                 bat_destroy(cands);
     578             :         }
     579             : #endif
     580             : 
     581             : #ifdef CATALOG_JAN2022
     582           8 :         if (store->catalog_version <= CATALOG_JAN2022) {
     583             :                 /* GRANT SELECT ON sys.db_user_info TO monetdb;
     584             :                  * except the grantor is 0 instead of user monetdb
     585             :                  *
     586             :                  * we need to find the IDs of the sys.db_user_info table and of
     587             :                  * the sys.privileges table and its columns since none of these
     588             :                  * have fixed IDs */
     589           0 :                 BAT *b = log_temp_descriptor(log_find_bat(lg, 2067)); /* sys._tables */
     590           0 :                 if (b == NULL)
     591           0 :                         return GDK_FAIL;
     592           0 :                 BAT *del_tabs = BATmaskedcands(0, BATcount(b), b, false);
     593           0 :                 bat_destroy(b);
     594           0 :                 if (del_tabs == NULL)
     595             :                         return GDK_FAIL;
     596           0 :                 b = log_temp_descriptor(log_find_bat(lg, 2076)); /* sys._columns */
     597           0 :                 if (b == NULL) {
     598           0 :                         bat_destroy(del_tabs);
     599           0 :                         return GDK_FAIL;
     600             :                 }
     601           0 :                 BAT *del_cols = BATmaskedcands(0, BATcount(b), b, false);
     602           0 :                 bat_destroy(b);
     603           0 :                 b = log_temp_descriptor(log_find_bat(lg, 2070)); /* sys._tables.schema_id */
     604           0 :                 if (del_cols == NULL || b == NULL) {
     605           0 :                         bat_destroy(del_cols);
     606           0 :                         bat_destroy(b);
     607           0 :                         bat_destroy(del_tabs);
     608           0 :                         return GDK_FAIL;
     609             :                 }
     610           0 :                 BAT *cands = BATselect(b, del_tabs, &(int) {2000}, NULL, true, true, false);
     611           0 :                 bat_destroy(b);
     612           0 :                 bat_destroy(del_tabs);
     613             :                 /* cands contains undeleted rows from sys._tables for tables in
     614             :                  * sys schema */
     615           0 :                 BAT *tabnme = log_temp_descriptor(log_find_bat(lg, 2069)); /* sys._tables.name */
     616           0 :                 if (cands == NULL || tabnme == NULL) {
     617           0 :                         bat_destroy(cands);
     618           0 :                         bat_destroy(tabnme);
     619           0 :                         bat_destroy(del_cols);
     620           0 :                         return GDK_FAIL;
     621             :                 }
     622           0 :                 b = BATselect(tabnme, cands, "db_user_info", NULL, true, true, false);
     623           0 :                 if (b == NULL) {
     624           0 :                         bat_destroy(cands);
     625           0 :                         bat_destroy(tabnme);
     626           0 :                         bat_destroy(del_cols);
     627           0 :                         return GDK_FAIL;
     628             :                 }
     629           0 :                 oid dbpos = BUNtoid(b, 0);
     630           0 :                 bat_destroy(b);
     631           0 :                 b = BATselect(tabnme, cands, "privileges", NULL, true, true, false);
     632           0 :                 bat_destroy(tabnme);
     633           0 :                 bat_destroy(cands);
     634           0 :                 BAT *tabid = log_temp_descriptor(log_find_bat(lg, 2068)); /* sys._tables.id */
     635           0 :                 if (b == NULL || tabid == NULL) {
     636           0 :                         bat_destroy(b);
     637           0 :                         bat_destroy(tabid);
     638           0 :                         bat_destroy(del_cols);
     639           0 :                         return GDK_FAIL;
     640             :                 }
     641           0 :                 int dbid = ((int *) tabid->theap->base)[dbpos];
     642           0 :                 int prid = ((int *) tabid->theap->base)[BUNtoid(b, 0)];
     643           0 :                 BAT *coltid = log_temp_descriptor(log_find_bat(lg, 2082)); /* sys._columns.table_id */
     644           0 :                 if (coltid == NULL) {
     645           0 :                         bat_destroy(b);
     646           0 :                         bat_destroy(del_cols);
     647           0 :                         bat_destroy(tabid);
     648           0 :                         return GDK_FAIL;
     649             :                 }
     650           0 :                 BAT *b1;
     651           0 :                 rc = BATjoin(&b1, NULL, coltid, tabid, del_cols, b, false, 5);
     652           0 :                 bat_destroy(coltid);
     653           0 :                 bat_destroy(tabid);
     654           0 :                 bat_destroy(del_cols);
     655           0 :                 bat_destroy(b);
     656           0 :                 BAT *colnr = log_temp_descriptor(log_find_bat(lg, 2085)); /* sys._columns.number */
     657           0 :                 BAT *colid = log_temp_descriptor(log_find_bat(lg, 2077)); /* sys._columns.id */
     658           0 :                 if (rc != GDK_SUCCEED || colnr == NULL || colid == NULL) {
     659           0 :                         if (rc == GDK_SUCCEED)
     660           0 :                                 bat_destroy(b1);
     661           0 :                         bat_destroy(colnr);
     662           0 :                         bat_destroy(colid);
     663           0 :                         return GDK_FAIL;
     664             :                 }
     665             :                 int privids[5];
     666           0 :                 for (int i = 0; i < 5; i++) {
     667           0 :                         oid p = BUNtoid(b1, i);
     668           0 :                         privids[((int *) colnr->theap->base)[p]] = ((int *) colid->theap->base)[p];
     669             :                 }
     670           0 :                 bat_destroy(b1);
     671           0 :                 bat_destroy(colnr);
     672           0 :                 bat_destroy(colid);
     673           0 :                 rc = tabins(lg,
     674           0 :                                         prid, &(msk) {false}, /* sys.privileges */
     675             :                                         privids[0], &dbid, /* sys.privileges.obj_id */
     676           0 :                                         privids[1], &(int) {USER_MONETDB}, /* sys.privileges.auth_id */
     677           0 :                                         privids[2], &(int) {PRIV_SELECT}, /* sys.privileges.privileges */
     678           0 :                                         privids[3], &(int) {0}, /* sys.privileges.grantor */
     679           0 :                                         privids[4], &(int) {0}, /* sys.privileges.grantee */
     680             :                                         0);
     681           0 :                 if (rc != GDK_SUCCEED)
     682             :                         return rc;
     683             :         }
     684             : #endif
     685             : 
     686             : #ifdef CATALOG_SEP2022
     687           8 :         if (store->catalog_version <= CATALOG_SEP2022) {
     688             :                         /* new STRING column sys.keys.check */
     689           8 :                         BAT *b = log_temp_descriptor(log_find_bat(lg, 2088)); /* sys.keys.id */
     690           8 :                         if (b == NULL)
     691           0 :                                 return GDK_FAIL;
     692           8 :                         BAT *check = BATconstant(b->hseqbase, TYPE_str, ATOMnilptr(TYPE_str), BATcount(b), PERSISTENT);
     693           8 :                         bat_destroy(b);
     694           8 :                         if (check == NULL)
     695             :                                 return GDK_FAIL;
     696          16 :                         if ((check = BATsetaccess(check, BAT_READ)) == NULL ||
     697             :                                 /* 2165 is sys.keys.check */
     698          16 :                                 BUNappend(lg->catalog_id, &(int) {2165}, true) != GDK_SUCCEED ||
     699          16 :                                 BUNappend(lg->catalog_bid, &check->batCacheid, true) != GDK_SUCCEED ||
     700          16 :                                 BUNappend(lg->catalog_lid, &lng_nil, false) != GDK_SUCCEED ||
     701           8 :                                 BUNappend(lg->catalog_cnt, &(lng){BATcount(check)}, false) != GDK_SUCCEED
     702             :                                 ) {
     703           0 :                                 bat_destroy(check);
     704           0 :                                 return GDK_FAIL;
     705             :                         }
     706           8 :                         BBPretain(check->batCacheid);
     707           8 :                         bat_destroy(check);
     708             : 
     709           8 :                         if (tabins(lg,
     710           8 :                                            2076, &(msk) {false},    /* sys._columns */
     711             :                                            /* 2165 is sys.keys.check */
     712           8 :                                            2077, &(int) {2165},             /* sys._columns.id */
     713             :                                            2078, "check",                     /* sys._columns.name */
     714             :                                            2079, "varchar",                   /* sys._columns.type */
     715           8 :                                            2080, &(int) {2048},             /* sys._columns.type_digits */
     716           8 :                                            2081, &(int) {0},                /* sys._columns.type_scale */
     717             :                                            /* 2087 is sys.keys */
     718           8 :                                            2082, &(int) {2087},             /* sys._columns.table_id */
     719             :                                            2083, str_nil,                       /* sys._columns.default */
     720           8 :                                            2084, &(bit) {TRUE},             /* sys._columns.null */
     721           8 :                                            2085, &(int) {6},                /* sys._columns.number */
     722             :                                            2086, str_nil,                       /* sys._columns.storage */
     723             :                                            0) != GDK_SUCCEED)
     724           0 :                                 return GDK_FAIL;
     725           8 :                         if (tabins(lg,
     726           8 :                                            2076, &(msk) {false},    /* sys._columns */
     727             :                                            /* 2166 is tmp.keys.check */
     728           8 :                                            2077, &(int) {2166},             /* sys._columns.id */
     729             :                                            2078, "check",                     /* sys._columns.name */
     730             :                                            2079, "varchar",                   /* sys._columns.type */
     731           8 :                                            2080, &(int) {2048},             /* sys._columns.type_digits */
     732           8 :                                            2081, &(int) {0},                /* sys._columns.type_scale */
     733             :                                            /* 2135 is tmp.keys */
     734           8 :                                            2082, &(int) {2135},             /* sys._columns.table_id */
     735             :                                            2083, str_nil,                       /* sys._columns.default */
     736           8 :                                            2084, &(bit) {TRUE},             /* sys._columns.null */
     737           8 :                                            2085, &(int) {6},                /* sys._columns.number */
     738             :                                            2086, str_nil,                       /* sys._columns.storage */
     739             :                                            0) != GDK_SUCCEED)
     740           0 :                                 return GDK_FAIL;
     741             :         }
     742             : #endif
     743             : 
     744             :         return GDK_SUCCEED;
     745             : }
     746             : 
     747             : static int
     748         332 : bl_create(sqlstore *store, int debug, const char *logdir, int cat_version)
     749             : {
     750         332 :         if (store->logger)
     751             :                 return LOG_ERR;
     752         332 :         store->logger = log_create(debug, "sql", logdir, cat_version, (preversionfix_fptr)&bl_preversion, (postversionfix_fptr)&bl_postversion, store);
     753         332 :         if (store->logger)
     754             :                 return LOG_OK;
     755             :         return LOG_ERR;
     756             : }
     757             : 
     758             : static void
     759         331 : bl_destroy(sqlstore *store)
     760             : {
     761         331 :         logger *l = store->logger;
     762             : 
     763         331 :         store->logger = NULL;
     764         331 :         if (l)
     765         331 :                 log_destroy(l);
     766         331 : }
     767             : 
     768             : static int
     769        2833 : bl_flush(sqlstore *store, lng save_id)
     770             : {
     771        2833 :         if (store->logger)
     772        2833 :                 return log_flush(store->logger, save_id) == GDK_SUCCEED ? LOG_OK : LOG_ERR;
     773             :         return LOG_OK;
     774             : }
     775             : 
     776             : static int
     777       13994 : bl_activate(sqlstore *store)
     778             : {
     779       13994 :         if (store->logger)
     780       13994 :                 return log_activate(store->logger) == GDK_SUCCEED ? LOG_OK : LOG_ERR;
     781             :         return LOG_OK;
     782             : }
     783             : 
     784             : static int
     785       16451 : bl_changes(sqlstore *store)
     786             : {
     787       16451 :         return (int) MIN(log_changes(store->logger), GDK_int_max);
     788             : }
     789             : 
     790             : static int
     791         463 : bl_get_sequence(sqlstore *store, int seq, lng *id)
     792             : {
     793         463 :         return log_sequence(store->logger, seq, id);
     794             : }
     795             : 
     796             : static int
     797         332 : bl_log_isnew(sqlstore *store)
     798             : {
     799         332 :         logger *bat_logger = store->logger;
     800         332 :         if (BATcount(bat_logger->catalog_bid) > 10) {
     801         106 :                 return 0;
     802             :         }
     803             :         return 1;
     804             : }
     805             : 
     806             : static int
     807       62494 : bl_tstart(sqlstore *store, bool flush, ulng *log_file_id)
     808             : {
     809       62494 :         return log_tstart(store->logger, flush, log_file_id) == GDK_SUCCEED ? LOG_OK : LOG_ERR;
     810             : }
     811             : 
     812             : static int
     813       62493 : bl_tend(sqlstore *store)
     814             : {
     815       62493 :         return log_tend(store->logger) == GDK_SUCCEED ? LOG_OK : LOG_ERR;
     816             : }
     817             : 
     818             : static int
     819       62493 : bl_tflush(sqlstore *store, ulng log_file_id, ulng commit_ts)
     820             : {
     821       62493 :         return log_tflush(store->logger, log_file_id, commit_ts) == GDK_SUCCEED ? LOG_OK : LOG_ERR;
     822             : }
     823             : 
     824             : static int
     825        6901 : bl_sequence(sqlstore *store, int seq, lng id)
     826             : {
     827        6901 :         return log_tsequence(store->logger, seq, id) == GDK_SUCCEED ? LOG_OK : LOG_ERR;
     828             : }
     829             : 
     830             : /* Write a plan entry to copy part of the given file.
     831             :  * That part of the file must remain unchanged until the plan is executed.
     832             :  */
     833             : static gdk_return __attribute__((__warn_unused_result__))
     834        1029 : snapshot_lazy_copy_file(stream *plan, const char *name, uint64_t extent)
     835             : {
     836        1029 :         if (mnstr_printf(plan, "c %" PRIu64 " %s\n", extent, name) < 0) {
     837           0 :                 GDKerror("%s", mnstr_peek_error(plan));
     838           0 :                 return GDK_FAIL;
     839             :         }
     840             :         return GDK_SUCCEED;
     841             : }
     842             : 
     843             : /* Write a plan entry to write the current contents of the given file.
     844             :  * The contents are included in the plan so the source file is allowed to
     845             :  * change in the mean time.
     846             :  */
     847             : static gdk_return __attribute__((__warn_unused_result__))
     848          10 : snapshot_immediate_copy_file(stream *plan, const char *path, const char *name)
     849             : {
     850          10 :         gdk_return ret = GDK_FAIL;
     851          10 :         const size_t bufsize = 64 * 1024;
     852          10 :         struct stat statbuf;
     853          10 :         char *buf = NULL;
     854          10 :         stream *s = NULL;
     855          10 :         size_t to_copy;
     856             : 
     857          10 :         if (MT_stat(path, &statbuf) < 0) {
     858           0 :                 GDKsyserror("stat failed on %s", path);
     859           0 :                 goto end;
     860             :         }
     861          10 :         to_copy = (size_t) statbuf.st_size;
     862             : 
     863          10 :         s = open_rstream(path);
     864          10 :         if (!s) {
     865           0 :                 GDKerror("%s", mnstr_peek_error(NULL));
     866           0 :                 goto end;
     867             :         }
     868             : 
     869          10 :         buf = GDKmalloc(bufsize);
     870          10 :         if (!buf) {
     871           0 :                 GDKerror("GDKmalloc failed");
     872           0 :                 goto end;
     873             :         }
     874             : 
     875          10 :         if (mnstr_printf(plan, "w %zu %s\n", to_copy, name) < 0) {
     876           0 :                 GDKerror("%s", mnstr_peek_error(plan));
     877           0 :                 goto end;
     878             :         }
     879             : 
     880          20 :         while (to_copy > 0) {
     881          10 :                 size_t chunk = (to_copy <= bufsize) ? to_copy : bufsize;
     882          10 :                 ssize_t bytes_read = mnstr_read(s, buf, 1, chunk);
     883          10 :                 if (bytes_read < 0) {
     884           0 :                         GDKerror("Reading bytes of component %s failed: %s", path, mnstr_peek_error(s));
     885           0 :                         goto end;
     886          10 :                 } else if (bytes_read < (ssize_t) chunk) {
     887           0 :                         GDKerror("Read only %zu/%zu bytes of component %s: %s", (size_t) bytes_read, chunk, path, mnstr_peek_error(s));
     888           0 :                         goto end;
     889             :                 }
     890             : 
     891          10 :                 ssize_t bytes_written = mnstr_write(plan, buf, 1, chunk);
     892          10 :                 if (bytes_written < 0) {
     893           0 :                         GDKerror("Writing to plan failed: %s", mnstr_peek_error(plan));
     894           0 :                         goto end;
     895          10 :                 } else if (bytes_written < (ssize_t) chunk) {
     896           0 :                         GDKerror("write to plan truncated");
     897           0 :                         goto end;
     898             :                 }
     899          10 :                 to_copy -= chunk;
     900             :         }
     901             : 
     902             :         ret = GDK_SUCCEED;
     903          10 : end:
     904          10 :         GDKfree(buf);
     905          10 :         if (s)
     906          10 :                 close_stream(s);
     907          10 :         return ret;
     908             : }
     909             : 
     910             : /* Add plan entries for all relevant files in the Write Ahead Log */
     911             : static gdk_return __attribute__((__warn_unused_result__))
     912           5 : snapshot_wal(logger *bat_logger, stream *plan, const char *db_dir)
     913             : {
     914           5 :         char log_file[FILENAME_MAX];
     915           5 :         int len;
     916             : 
     917           5 :         len = snprintf(log_file, sizeof(log_file), "%s/%s%s", db_dir, bat_logger->dir, LOGFILE);
     918           5 :         if (len == -1 || (size_t)len >= sizeof(log_file)) {
     919           0 :                 GDKerror("Could not open %s, filename is too large", log_file);
     920           0 :                 return GDK_FAIL;
     921             :         }
     922           5 :         if (snapshot_immediate_copy_file(plan, log_file, log_file + strlen(db_dir) + 1) != GDK_SUCCEED)
     923             :                 return GDK_FAIL;
     924             : 
     925          14 :         for (ulng id = bat_logger->saved_id+1; id <= bat_logger->id; id++) {
     926           9 :                 struct stat statbuf;
     927             : 
     928           9 :                 len = snprintf(log_file, sizeof(log_file), "%s/%s%s." LLFMT, db_dir, bat_logger->dir, LOGFILE, id);
     929           9 :                 if (len == -1 || (size_t)len >= sizeof(log_file)) {
     930           0 :                         GDKerror("Could not open %s, filename is too large", log_file);
     931           0 :                         return GDK_FAIL;
     932             :                 }
     933           9 :                 if (MT_stat(log_file, &statbuf) == 0) {
     934           9 :                         if (snapshot_lazy_copy_file(plan, log_file + strlen(db_dir) + 1, statbuf.st_size) != GDK_SUCCEED)
     935             :                                 return GDK_FAIL;
     936             :                 } else {
     937           0 :                         GDKerror("Could not open %s", log_file);
     938           0 :                         return GDK_FAIL;
     939             :                 }
     940             :         }
     941             :         return GDK_SUCCEED;
     942             : }
     943             : 
     944             : static gdk_return __attribute__((__warn_unused_result__))
     945        1600 : snapshot_heap(stream *plan, const char *db_dir, bat batid, const char *filename, const char *suffix, uint64_t extent)
     946             : {
     947        1600 :         char path1[FILENAME_MAX];
     948        1600 :         char path2[FILENAME_MAX];
     949        1600 :         const size_t offset = strlen(db_dir) + 1;
     950        1600 :         struct stat statbuf;
     951        1600 :         int len;
     952             : 
     953        1600 :         if (extent == 0) {
     954             :                 /* nothing to copy */
     955             :                 return GDK_SUCCEED;
     956             :         }
     957             :         // first check the backup dir
     958        1020 :         len = snprintf(path1, FILENAME_MAX, "%s/%s/%o.%s", db_dir, BAKDIR, (int) batid, suffix);
     959        1020 :         if (len == -1 || len >= FILENAME_MAX) {
     960           0 :                 path1[FILENAME_MAX - 1] = '\0';
     961           0 :                 GDKerror("Could not open %s, filename is too large", path1);
     962           0 :                 return GDK_FAIL;
     963             :         }
     964        1020 :         if (MT_stat(path1, &statbuf) == 0) {
     965           0 :                 return snapshot_lazy_copy_file(plan, path1 + offset, extent);
     966             :         }
     967        1020 :         if (errno != ENOENT) {
     968           0 :                 GDKsyserror("Error stat'ing %s", path1);
     969           0 :                 return GDK_FAIL;
     970             :         }
     971             : 
     972             :         // then check the regular location
     973        1020 :         len = snprintf(path2, FILENAME_MAX, "%s/%s/%s.%s", db_dir, BATDIR, filename, suffix);
     974        1020 :         if (len == -1 || len >= FILENAME_MAX) {
     975           0 :                 path2[FILENAME_MAX - 1] = '\0';
     976           0 :                 GDKerror("Could not open %s, filename is too large", path2);
     977           0 :                 return GDK_FAIL;
     978             :         }
     979        1020 :         if (MT_stat(path2, &statbuf) == 0) {
     980        1020 :                 return snapshot_lazy_copy_file(plan, path2 + offset, extent);
     981             :         }
     982           0 :         if (errno != ENOENT) {
     983           0 :                 GDKsyserror("Error stat'ing %s", path2);
     984           0 :                 return GDK_FAIL;
     985             :         }
     986             : 
     987           0 :         GDKerror("One of %s and %s must exist", path1, path2);
     988           0 :         return GDK_FAIL;
     989             : }
     990             : 
     991             : /* Add plan entries for all persistent BATs by looping over the BBP.dir.
     992             :  * Also include the BBP.dir itself.
     993             :  */
     994             : static gdk_return __attribute__((__warn_unused_result__))
     995           5 : snapshot_bats(stream *plan, const char *db_dir)
     996             : {
     997           5 :         char bbpdir[FILENAME_MAX];
     998           5 :         FILE *fp = NULL;
     999           5 :         int len;
    1000           5 :         gdk_return ret = GDK_FAIL;
    1001           5 :         int lineno = 0;
    1002           5 :         bat bbpsize = 0;
    1003           5 :         lng logno;
    1004           5 :         unsigned bbpversion;
    1005             : 
    1006           5 :         len = snprintf(bbpdir, FILENAME_MAX, "%s/%s/%s", db_dir, BAKDIR, "BBP.dir");
    1007           5 :         if (len == -1 || len >= FILENAME_MAX) {
    1008           0 :                 GDKerror("Could not open %s, filename is too large", bbpdir);
    1009           0 :                 return GDK_FAIL;
    1010             :         }
    1011           5 :         ret = snapshot_immediate_copy_file(plan, bbpdir, bbpdir + strlen(db_dir) + 1);
    1012           5 :         if (ret != GDK_SUCCEED)
    1013             :                 return ret;
    1014             : 
    1015             :         // Open the catalog and parse the header
    1016           5 :         fp = fopen(bbpdir, "r");
    1017           5 :         if (fp == NULL) {
    1018           0 :                 GDKerror("Could not open %s for reading: %s", bbpdir, mnstr_peek_error(NULL));
    1019           0 :                 return GDK_FAIL;
    1020             :         }
    1021           5 :         bbpversion = BBPheader(fp, &lineno, &bbpsize, &logno, false);
    1022           5 :         if (bbpversion == 0)
    1023           0 :                 goto end;
    1024           5 :         assert(bbpversion == GDKLIBRARY);
    1025             : 
    1026        1260 :         for (;;) {
    1027        1265 :                 BAT b;
    1028        1265 :                 Heap h;
    1029        1265 :                 Heap vh;
    1030        1265 :                 vh = h = (Heap) {
    1031             :                         .free = 0,
    1032             :                 };
    1033        1265 :                 b = (BAT) {
    1034             :                         .theap = &h,
    1035             :                         .tvheap = &vh,
    1036             :                 };
    1037        1265 :                 char *options;
    1038        1265 :                 char filename[sizeof(BBP_physical(0))];
    1039        1265 :                 char batname[129];
    1040             : #ifdef GDKLIBRARY_HASHASH
    1041        1265 :                 int hashash;
    1042             : #endif
    1043             : 
    1044        1265 :                 switch (BBPreadBBPline(fp, bbpversion, &lineno, &b,
    1045             : #ifdef GDKLIBRARY_HASHASH
    1046             :                                                            &hashash,
    1047             : #endif
    1048             :                                                            batname, filename, &options)) {
    1049           5 :                 case 0:
    1050             :                         /* end of file */
    1051           5 :                         fclose(fp);
    1052           5 :                         return GDK_SUCCEED;
    1053             :                 case 1:
    1054             :                         /* successfully read an entry */
    1055        1260 :                         break;
    1056           0 :                 default:
    1057             :                         /* error */
    1058           0 :                         fclose(fp);
    1059           0 :                         return GDK_FAIL;
    1060             :                 }
    1061             : #ifdef GDKLIBRARY_HASHASH
    1062        1260 :                 assert(hashash == 0);
    1063             : #endif
    1064        1260 :                 if (ATOMvarsized(b.ttype)) {
    1065         340 :                         ret = snapshot_heap(plan, db_dir, b.batCacheid, filename, "theap", b.tvheap->free);
    1066         340 :                         if (ret != GDK_SUCCEED)
    1067           0 :                                 goto end;
    1068             :                 }
    1069        1260 :                 ret = snapshot_heap(plan, db_dir, b.batCacheid, filename, BATtailname(&b), b.theap->free);
    1070        1260 :                 if (ret != GDK_SUCCEED)
    1071           0 :                         goto end;
    1072             :         }
    1073             : 
    1074           0 : end:
    1075           0 :         if (fp) {
    1076           0 :                 fclose(fp);
    1077             :         }
    1078           0 :         return ret;
    1079             : }
    1080             : 
    1081             : static gdk_return __attribute__((__warn_unused_result__))
    1082           5 : snapshot_vaultkey(stream *plan, const char *db_dir)
    1083             : {
    1084           5 :         char path[FILENAME_MAX];
    1085           5 :         struct stat statbuf;
    1086             : 
    1087           5 :         int len = snprintf(path, FILENAME_MAX, "%s/.vaultkey", db_dir);
    1088           5 :         if (len == -1 || len >= FILENAME_MAX) {
    1089           0 :                 path[FILENAME_MAX - 1] = '\0';
    1090           0 :                 GDKerror("Could not open %s, filename is too large", path);
    1091           0 :                 return GDK_FAIL;
    1092             :         }
    1093           5 :         if (MT_stat(path, &statbuf) == 0) {
    1094           0 :                 return snapshot_lazy_copy_file(plan, ".vaultkey", statbuf.st_size);
    1095             :         }
    1096           5 :         if (errno == ENOENT) {
    1097             :                 // No .vaultkey? Fine.
    1098             :                 return GDK_SUCCEED;
    1099             :         }
    1100             : 
    1101           0 :         GDKsyserror("Error stat'ing %s", path);
    1102           0 :         return GDK_FAIL;
    1103             : }
    1104             : 
    1105             : static gdk_return
    1106           5 : bl_snapshot(sqlstore *store, stream *plan)
    1107             : {
    1108           5 :         logger *bat_logger = store->logger;
    1109           5 :         gdk_return ret;
    1110           5 :         char *db_dir = NULL;
    1111           5 :         size_t db_dir_len;
    1112             : 
    1113             :         // Farm 0 is always the persistent farm.
    1114           5 :         db_dir = GDKfilepath(0, NULL, "", NULL);
    1115           5 :         if (db_dir == NULL)
    1116             :                 return GDK_FAIL;
    1117           5 :         db_dir_len = strlen(db_dir);
    1118           5 :         if (db_dir[db_dir_len - 1] == DIR_SEP)
    1119           5 :                 db_dir[db_dir_len - 1] = '\0';
    1120             : 
    1121          10 :         if (mnstr_printf(plan, "%s\n", db_dir) < 0 ||
    1122             :                 // Please monetdbd
    1123           5 :                 mnstr_printf(plan, "w 0 .uplog\n") < 0) {
    1124           0 :                 GDKerror("%s", mnstr_peek_error(plan));
    1125           0 :                 ret = GDK_FAIL;
    1126           0 :                 goto end;
    1127             :         }
    1128             : 
    1129           5 :         ret = snapshot_vaultkey(plan, db_dir);
    1130           5 :         if (ret != GDK_SUCCEED)
    1131           0 :                 goto end;
    1132             : 
    1133           5 :         ret = snapshot_bats(plan, db_dir);
    1134           5 :         if (ret != GDK_SUCCEED)
    1135           0 :                 goto end;
    1136             : 
    1137           5 :         ret = snapshot_wal(bat_logger, plan, db_dir);
    1138           5 :         if (ret != GDK_SUCCEED)
    1139             :                 goto end;
    1140             : 
    1141             :         ret = GDK_SUCCEED;
    1142           5 : end:
    1143           5 :         GDKfree(db_dir);
    1144           5 :         return ret;
    1145             : }
    1146             : 
    1147             : void
    1148         332 : bat_logger_init( logger_functions *lf )
    1149             : {
    1150         332 :         lf->create = bl_create;
    1151         332 :         lf->destroy = bl_destroy;
    1152         332 :         lf->flush = bl_flush;
    1153         332 :         lf->activate = bl_activate;
    1154         332 :         lf->changes = bl_changes;
    1155         332 :         lf->get_sequence = bl_get_sequence;
    1156         332 :         lf->log_isnew = bl_log_isnew;
    1157         332 :         lf->log_tstart = bl_tstart;
    1158         332 :         lf->log_tend = bl_tend;
    1159         332 :         lf->log_tflush = bl_tflush;
    1160         332 :         lf->log_tsequence = bl_sequence;
    1161         332 :         lf->get_snapshot_files = bl_snapshot;
    1162         332 : }

Generated by: LCOV version 1.14