Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_databaseIsUnmoved.c458 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* Prototypes for internal functions used by the tests */8extern Pager *sqlite3BtreePager(Btree*);9extern int test_databaseIsUnmoved(Pager*);10 11/*12** Test VFS infrastructure to intercept SQLITE_FCNTL_HAS_MOVED.13*/14 15static const char *gTestVfsName = "testvfs";16static sqlite3_vfs *gOrigVfs = NULL;17static sqlite3_vfs gTestVfs;        /* registered VFS object */18static int gVfsRegistered = 0;19 20/* Mode for HAS_MOVED behavior:21**   0 -> return SQLITE_NOTFOUND22**   1 -> return SQLITE_OK, *(int*)pArg = 0 (not moved)23**   2 -> return SQLITE_OK, *(int*)pArg = 1 (moved)24**   3 -> return SQLITE_IOERR25**  -1 -> fall through to underlying xFileControl26*/27static int gHasMovedMode = -1;28 29/* Per-file wrapper */30typedef struct TestFile TestFile;31struct TestFile {32  sqlite3_file base;             /* must be first */33  sqlite3_file *pReal;           /* underlying real file */34  sqlite3_io_methods *pMeth;     /* per-file io_methods we own */35};36 37/* Forward declarations of file method wrappers */38static int tfClose(sqlite3_file*);39static int tfRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);40static int tfWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);41static int tfTruncate(sqlite3_file*, sqlite3_int64 size);42static int tfSync(sqlite3_file*, int flags);43static int tfFileSize(sqlite3_file*, sqlite3_int64 *pSize);44static int tfLock(sqlite3_file*, int);45static int tfUnlock(sqlite3_file*, int);46static int tfCheckReservedLock(sqlite3_file*, int *pResOut);47static int tfFileControl(sqlite3_file*, int op, void *pArg);48static int tfSectorSize(sqlite3_file*);49static int tfDeviceCharacteristics(sqlite3_file*);50/* iVersion >= 2 */51static int tfShmMap(sqlite3_file*, int, int, int, void volatile**);52static int tfShmLock(sqlite3_file*, int, int, int);53static void tfShmBarrier(sqlite3_file*);54static int tfShmUnmap(sqlite3_file*, int);55/* iVersion >= 3 */56static int tfFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);57static int tfUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);58 59static void tfInitIoMethods(TestFile *tf){60  sqlite3_io_methods const *rm = tf->pReal->pMethods;61  sqlite3_io_methods *m = (sqlite3_io_methods*)sqlite3_malloc(sizeof(*m));62  TEST_ASSERT_NOT_NULL(m);63  memset(m, 0, sizeof(*m));64  m->iVersion = rm->iVersion;65  m->xClose = tfClose;66  m->xRead = tfRead;67  m->xWrite = tfWrite;68  m->xTruncate = tfTruncate;69  m->xSync = tfSync;70  m->xFileSize = tfFileSize;71  m->xLock = tfLock;72  m->xUnlock = tfUnlock;73  m->xCheckReservedLock = tfCheckReservedLock;74  m->xFileControl = tfFileControl;75  m->xSectorSize = tfSectorSize;76  m->xDeviceCharacteristics = tfDeviceCharacteristics;77  if( rm->iVersion >= 2 ){78    m->xShmMap = tfShmMap;79    m->xShmLock = tfShmLock;80    m->xShmBarrier = tfShmBarrier;81    m->xShmUnmap = tfShmUnmap;82  }83  if( rm->iVersion >= 3 ){84    m->xFetch = tfFetch;85    m->xUnfetch = tfUnfetch;86  }87  tf->base.pMethods = m;88  tf->pMeth = m;89}90 91/* File method wrappers: mostly pass-through to underlying */92static int tfClose(sqlite3_file *pFile){93  TestFile *tf = (TestFile*)pFile;94  int rc = tf->pReal->pMethods->xClose(tf->pReal);95  sqlite3_free(tf->pReal);96  tf->pReal = NULL;97  if( tf->pMeth ){ sqlite3_free(tf->pMeth); tf->pMeth = NULL; }98  return rc;99}100static int tfRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite3_int64 iOfst){101  TestFile *tf = (TestFile*)pFile;102  return tf->pReal->pMethods->xRead(tf->pReal, zBuf, iAmt, iOfst);103}104static int tfWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite3_int64 iOfst){105  TestFile *tf = (TestFile*)pFile;106  return tf->pReal->pMethods->xWrite(tf->pReal, zBuf, iAmt, iOfst);107}108static int tfTruncate(sqlite3_file *pFile, sqlite3_int64 size){109  TestFile *tf = (TestFile*)pFile;110  return tf->pReal->pMethods->xTruncate(tf->pReal, size);111}112static int tfSync(sqlite3_file *pFile, int flags){113  TestFile *tf = (TestFile*)pFile;114  return tf->pReal->pMethods->xSync(tf->pReal, flags);115}116static int tfFileSize(sqlite3_file *pFile, sqlite3_int64 *pSize){117  TestFile *tf = (TestFile*)pFile;118  return tf->pReal->pMethods->xFileSize(tf->pReal, pSize);119}120static int tfLock(sqlite3_file *pFile, int eLock){121  TestFile *tf = (TestFile*)pFile;122  return tf->pReal->pMethods->xLock(tf->pReal, eLock);123}124static int tfUnlock(sqlite3_file *pFile, int eLock){125  TestFile *tf = (TestFile*)pFile;126  return tf->pReal->pMethods->xUnlock(tf->pReal, eLock);127}128static int tfCheckReservedLock(sqlite3_file *pFile, int *pResOut){129  TestFile *tf = (TestFile*)pFile;130  return tf->pReal->pMethods->xCheckReservedLock(tf->pReal, pResOut);131}132static int tfFileControl(sqlite3_file *pFile, int op, void *pArg){133  TestFile *tf = (TestFile*)pFile;134  if( op==SQLITE_FCNTL_HAS_MOVED ){135    if( gHasMovedMode==0 ){136      return SQLITE_NOTFOUND;137    }else if( gHasMovedMode==1 ){138      if( pArg ) *(int*)pArg = 0;139      return SQLITE_OK;140    }else if( gHasMovedMode==2 ){141      if( pArg ) *(int*)pArg = 1;142      return SQLITE_OK;143    }else if( gHasMovedMode==3 ){144      return SQLITE_IOERR;145    }146  }147  return tf->pReal->pMethods->xFileControl(tf->pReal, op, pArg);148}149static int tfSectorSize(sqlite3_file *pFile){150  TestFile *tf = (TestFile*)pFile;151  return tf->pReal->pMethods->xSectorSize(tf->pReal);152}153static int tfDeviceCharacteristics(sqlite3_file *pFile){154  TestFile *tf = (TestFile*)pFile;155  return tf->pReal->pMethods->xDeviceCharacteristics(tf->pReal);156}157static int tfShmMap(sqlite3_file *pFile, int iPg, int pgsz, int isWrite, void volatile **pp){158  TestFile *tf = (TestFile*)pFile;159  sqlite3_io_methods const *rm = tf->pReal->pMethods;160  if( rm->iVersion<2 || rm->xShmMap==0 ) return SQLITE_OK;161  return rm->xShmMap(tf->pReal, iPg, pgsz, isWrite, pp);162}163static int tfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){164  TestFile *tf = (TestFile*)pFile;165  sqlite3_io_methods const *rm = tf->pReal->pMethods;166  if( rm->iVersion<2 || rm->xShmLock==0 ) return SQLITE_OK;167  return rm->xShmLock(tf->pReal, ofst, n, flags);168}169static void tfShmBarrier(sqlite3_file *pFile){170  TestFile *tf = (TestFile*)pFile;171  sqlite3_io_methods const *rm = tf->pReal->pMethods;172  if( rm->iVersion>=2 && rm->xShmBarrier ) rm->xShmBarrier(tf->pReal);173}174static int tfShmUnmap(sqlite3_file *pFile, int delFlag){175  TestFile *tf = (TestFile*)pFile;176  sqlite3_io_methods const *rm = tf->pReal->pMethods;177  if( rm->iVersion<2 || rm->xShmUnmap==0 ) return SQLITE_OK;178  return rm->xShmUnmap(tf->pReal, delFlag);179}180static int tfFetch(sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp){181  TestFile *tf = (TestFile*)pFile;182  sqlite3_io_methods const *rm = tf->pReal->pMethods;183  if( rm->iVersion<3 || rm->xFetch==0 ) { *pp = 0; return SQLITE_OK; }184  return rm->xFetch(tf->pReal, iOfst, iAmt, pp);185}186static int tfUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){187  TestFile *tf = (TestFile*)pFile;188  sqlite3_io_methods const *rm = tf->pReal->pMethods;189  if( rm->iVersion<3 || rm->xUnfetch==0 ) return SQLITE_OK;190  return rm->xUnfetch(tf->pReal, iOfst, p);191}192 193/* VFS wrappers */194static int tvfsOpen(sqlite3_vfs* pVfs, const char *zName, sqlite3_file *pFile,195                    int flags, int *pOutFlags){196  TestFile *tf = (TestFile*)pFile;197  memset(tf, 0, sizeof(*tf));198  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;199  tf->pReal = (sqlite3_file*)sqlite3_malloc(orig->szOsFile);200  TEST_ASSERT_NOT_NULL(tf->pReal);201  memset(tf->pReal, 0, orig->szOsFile);202  int rc = orig->xOpen(orig, zName, tf->pReal, flags, pOutFlags);203  if( rc==SQLITE_OK ){204    tfInitIoMethods(tf);205  }else{206    sqlite3_free(tf->pReal);207    tf->pReal = NULL;208  }209  return rc;210}211static int tvfsDelete(sqlite3_vfs* pVfs, const char *zName, int syncDir){212  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;213  return orig->xDelete(orig, zName, syncDir);214}215static int tvfsAccess(sqlite3_vfs* pVfs, const char *zName, int flags, int *pRes){216  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;217  return orig->xAccess(orig, zName, flags, pRes);218}219static int tvfsFullPathname(sqlite3_vfs* pVfs, const char *zName, int nOut, char *zOut){220  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;221  return orig->xFullPathname(orig, zName, nOut, zOut);222}223static void *tvfsDlOpen(sqlite3_vfs* pVfs, const char *zFilename){224  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;225  return orig->xDlOpen(orig, zFilename);226}227static void tvfsDlError(sqlite3_vfs* pVfs, int nByte, char *zErrMsg){228  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;229  orig->xDlError(orig, nByte, zErrMsg);230}231static void (*tvfsDlSym(sqlite3_vfs* pVfs, void *p, const char *zSym))(void){232  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;233  return orig->xDlSym(orig, p, zSym);234}235static void tvfsDlClose(sqlite3_vfs* pVfs, void *pHandle){236  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;237  orig->xDlClose(orig, pHandle);238}239static int tvfsRandomness(sqlite3_vfs* pVfs, int nByte, char *zOut){240  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;241  return orig->xRandomness(orig, nByte, zOut);242}243static int tvfsSleep(sqlite3_vfs* pVfs, int microseconds){244  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;245  return orig->xSleep(orig, microseconds);246}247static int tvfsCurrentTime(sqlite3_vfs* pVfs, double *pTime){248  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;249  return orig->xCurrentTime(orig, pTime);250}251static int tvfsGetLastError(sqlite3_vfs* pVfs, int a, char *b){252  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;253  if( orig->xGetLastError ) return orig->xGetLastError(orig, a, b);254  return 0;255}256static int tvfsCurrentTimeInt64(sqlite3_vfs* pVfs, sqlite3_int64 *pNow){257  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;258  if( orig->iVersion>=2 && orig->xCurrentTimeInt64 ){259    return orig->xCurrentTimeInt64(orig, pNow);260  }261  double r; int rc = orig->xCurrentTime(orig, &r);262  if( rc==SQLITE_OK ) *pNow = (sqlite3_int64)(r*86400000.0);263  return rc;264}265static int tvfsSetSystemCall(sqlite3_vfs* pVfs, const char *zName, sqlite3_syscall_ptr pFunc){266  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;267  if( orig->iVersion>=3 && orig->xSetSystemCall ) return orig->xSetSystemCall(orig, zName, pFunc);268  return SQLITE_OK;269}270static sqlite3_syscall_ptr tvfsGetSystemCall(sqlite3_vfs* pVfs, const char *zName){271  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;272  if( orig->iVersion>=3 && orig->xGetSystemCall ) return orig->xGetSystemCall(orig, zName);273  return 0;274}275static const char *tvfsNextSystemCall(sqlite3_vfs* pVfs, const char *zName){276  sqlite3_vfs *orig = (sqlite3_vfs*)pVfs->pAppData;277  if( orig->iVersion>=3 && orig->xNextSystemCall ) return orig->xNextSystemCall(orig, zName);278  return 0;279}280 281static void registerTestVfs(void){282  if( gVfsRegistered ) return;283  gOrigVfs = sqlite3_vfs_find(NULL);284  TEST_ASSERT_NOT_NULL(gOrigVfs);285  memset(&gTestVfs, 0, sizeof(gTestVfs));286  gTestVfs.iVersion = gOrigVfs->iVersion;287  gTestVfs.szOsFile = sizeof(TestFile);288  gTestVfs.mxPathname = gOrigVfs->mxPathname;289  gTestVfs.zName = gTestVfsName;290  gTestVfs.pAppData = gOrigVfs; /* stash original in pAppData */291  gTestVfs.xOpen = tvfsOpen;292  gTestVfs.xDelete = tvfsDelete;293  gTestVfs.xAccess = tvfsAccess;294  gTestVfs.xFullPathname = tvfsFullPathname;295  gTestVfs.xDlOpen = tvfsDlOpen;296  gTestVfs.xDlError = tvfsDlError;297  gTestVfs.xDlSym = tvfsDlSym;298  gTestVfs.xDlClose = tvfsDlClose;299  gTestVfs.xRandomness = tvfsRandomness;300  gTestVfs.xSleep = tvfsSleep;301  gTestVfs.xCurrentTime = tvfsCurrentTime;302  gTestVfs.xGetLastError = tvfsGetLastError;303  if( gTestVfs.iVersion>=2 ){304    gTestVfs.xCurrentTimeInt64 = tvfsCurrentTimeInt64;305  }306  if( gTestVfs.iVersion>=3 ){307    gTestVfs.xSetSystemCall = tvfsSetSystemCall;308    gTestVfs.xGetSystemCall = tvfsGetSystemCall;309    gTestVfs.xNextSystemCall = tvfsNextSystemCall;310  }311  int rc = sqlite3_vfs_register(&gTestVfs, 0);312  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);313  gVfsRegistered = 1;314}315 316static void unregisterTestVfs(void){317  if( gVfsRegistered ){318    sqlite3_vfs_unregister(&gTestVfs);319    gVfsRegistered = 0;320  }321}322 323/* Utility helpers */324static void exec_sql(sqlite3 *db, const char *sql){325  char *zErr = 0;326  int rc = sqlite3_exec(db, sql, 0, 0, &zErr);327  if( rc!=SQLITE_OK ){328    printf("SQL error: %s\n", zErr ? zErr : "(null)");329  }330  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);331  sqlite3_free(zErr);332}333 334static Pager* getPagerForDb(sqlite3 *db, int iDb){335  if( db->aDb[iDb].pBt==0 ){336    /* Force opening the btree */337    exec_sql(db, "SELECT 1");338  }339  TEST_ASSERT_NOT_NULL(db->aDb[iDb].pBt);340  return sqlite3BtreePager(db->aDb[iDb].pBt);341}342 343static sqlite3* openWithTestVfs(const char *zFile){344  registerTestVfs();345  sqlite3 *db = 0;346  int rc = sqlite3_open_v2(zFile, &db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, gTestVfsName);347  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);348  TEST_ASSERT_NOT_NULL(db);349  return db;350}351 352/* Unity setup/teardown */353void setUp(void) {354  gHasMovedMode = -1;355}356void tearDown(void) {357  unregisterTestVfs();358}359 360/* Tests */361 362/* Intercept: xFileControl returns SQLITE_NOTFOUND => databaseIsUnmoved() => SQLITE_OK */363void test_databaseIsUnmoved_has_moved_notfound_returns_ok(void){364  sqlite3 *db = openWithTestVfs("unmoved_notfound.db");365  exec_sql(db, "PRAGMA journal_mode=DELETE;");366  exec_sql(db, "CREATE TABLE IF NOT EXISTS t(x);");367  exec_sql(db, "INSERT INTO t VALUES(1);");368  gHasMovedMode = 0; /* NOTFOUND */369  Pager *pPager = getPagerForDb(db, 0);370  int rc = test_databaseIsUnmoved(pPager);371  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);372  sqlite3_close(db);373  remove("unmoved_notfound.db");374  remove("unmoved_notfound.db-journal");375}376 377/* Intercept: xFileControl returns OK with bHasMoved==0 => SQLITE_OK */378void test_databaseIsUnmoved_ok_not_moved_returns_ok(void){379  sqlite3 *db = openWithTestVfs("unmoved_ok.db");380  exec_sql(db, "PRAGMA journal_mode=DELETE;");381  exec_sql(db, "CREATE TABLE IF NOT EXISTS t(x);");382  exec_sql(db, "INSERT INTO t VALUES(2);");383  gHasMovedMode = 1; /* OK, not moved */384  Pager *pPager = getPagerForDb(db, 0);385  int rc = test_databaseIsUnmoved(pPager);386  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);387  sqlite3_close(db);388  remove("unmoved_ok.db");389  remove("unmoved_ok.db-journal");390}391 392/* Intercept: xFileControl returns OK with bHasMoved==1 => SQLITE_READONLY_DBMOVED */393void test_databaseIsUnmoved_ok_moved_returns_dbmoved(void){394  sqlite3 *db = openWithTestVfs("unmoved_moved.db");395  exec_sql(db, "PRAGMA journal_mode=DELETE;");396  exec_sql(db, "CREATE TABLE IF NOT EXISTS t(x);");397  exec_sql(db, "INSERT INTO t VALUES(3);");398  gHasMovedMode = 2; /* OK, moved */399  Pager *pPager = getPagerForDb(db, 0);400  int rc = test_databaseIsUnmoved(pPager);401  TEST_ASSERT_EQUAL_INT(SQLITE_READONLY_DBMOVED, rc);402  sqlite3_close(db);403  remove("unmoved_moved.db");404  remove("unmoved_moved.db-journal");405}406 407/* Intercept: xFileControl returns error (SQLITE_IOERR) => passthrough */408void test_databaseIsUnmoved_error_passthrough(void){409  sqlite3 *db = openWithTestVfs("unmoved_error.db");410  exec_sql(db, "PRAGMA journal_mode=DELETE;");411  exec_sql(db, "CREATE TABLE IF NOT EXISTS t(x);");412  exec_sql(db, "INSERT INTO t VALUES(4);");413  gHasMovedMode = 3; /* IOERR */414  Pager *pPager = getPagerForDb(db, 0);415  int rc = test_databaseIsUnmoved(pPager);416  TEST_ASSERT_EQUAL_INT(SQLITE_IOERR, rc);417  sqlite3_close(db);418  remove("unmoved_error.db");419  remove("unmoved_error.db-journal");420}421 422/* Early return: tempFile => SQLITE_OK. Use a TEMP or :memory: database. */423void test_databaseIsUnmoved_tempfile_returns_ok(void){424  sqlite3 *db = NULL;425  int rc = sqlite3_open(":memory:", &db);426  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);427  exec_sql(db, "CREATE TABLE tmem(x);");428  Pager *pPager = getPagerForDb(db, 0);429  rc = test_databaseIsUnmoved(pPager);430  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);431  sqlite3_close(db);432}433 434/* Early return: dbSize==0 => SQLITE_OK, even if VFS would say moved */435void test_databaseIsUnmoved_dbsize_zero_returns_ok(void){436  sqlite3 *db = openWithTestVfs("unmoved_empty.db");437  /* Do not write anything to keep the database size at 0 pages. */438  /* Force opening the btree without writes */439  exec_sql(db, "SELECT count(*) FROM sqlite_master;");440  gHasMovedMode = 2; /* would claim "moved" if consulted */441  Pager *pPager = getPagerForDb(db, 0);442  int rc = test_databaseIsUnmoved(pPager);443  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);444  sqlite3_close(db);445  remove("unmoved_empty.db");446  remove("unmoved_empty.db-journal");447}448 449int main(void){450  UNITY_BEGIN();451  RUN_TEST(test_databaseIsUnmoved_has_moved_notfound_returns_ok);452  RUN_TEST(test_databaseIsUnmoved_ok_not_moved_returns_ok);453  RUN_TEST(test_databaseIsUnmoved_ok_moved_returns_dbmoved);454  RUN_TEST(test_databaseIsUnmoved_error_passthrough);455  RUN_TEST(test_databaseIsUnmoved_tempfile_returns_ok);456  RUN_TEST(test_databaseIsUnmoved_dbsize_zero_returns_ok);457  return UNITY_END();458}