AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5#include <stdlib.h>6 7static sqlite3 *gDb = NULL;8static Btree *gBtree = NULL;9 10static int open_memory_db(void){11 int rc = sqlite3_open(":memory:", &gDb);12 if( rc!=SQLITE_OK ) return rc;13 /* Main DB handle's Btree is in aDb[0] */14 gBtree = gDb->aDb[0].pBt;15 return SQLITE_OK;16}17 18static void close_db(void){19 if( gDb ){20 sqlite3_close(gDb);21 gDb = NULL;22 gBtree = NULL;23 }24}25 26/* Create a new intkey table and return its root page number */27static int create_intkey_table(Pgno *pRoot){28 int rc;29 TEST_ASSERT_NOT_NULL(gBtree);30 rc = sqlite3BtreeBeginTrans(gBtree, 1, 0);31 if( rc!=SQLITE_OK ) return rc;32 rc = sqlite3BtreeCreateTable(gBtree, pRoot, BTREE_INTKEY | BTREE_LEAFDATA);33 return rc;34}35 36static int open_cursor(Pgno root, int wr, BtCursor **ppCur){37 int rc;38 int n = sqlite3BtreeCursorSize();39 BtCursor *pCur = (BtCursor*)sqlite3_malloc(n);40 TEST_ASSERT_NOT_NULL_MESSAGE(pCur, "malloc cursor failed");41 sqlite3BtreeCursorZero(pCur);42 rc = sqlite3BtreeCursor(gBtree, root, wr?BTREE_WRCSR:0, NULL, pCur);43 if( rc!=SQLITE_OK ){44 sqlite3_free(pCur);45 return rc;46 }47 *ppCur = pCur;48 return SQLITE_OK;49}50 51static void close_cursor(BtCursor *pCur){52 if( pCur ){53 sqlite3BtreeCloseCursor(pCur);54 sqlite3_free(pCur);55 }56}57 58/* Insert n rows with rowids 1..n and small payload */59static int insert_rows(Pgno root, int nrow){60 int rc;61 BtCursor *pCur = NULL;62 rc = open_cursor(root, 1, &pCur);63 if( rc!=SQLITE_OK ) return rc;64 65 for(int i=1;i<=nrow;i++){66 const char payload[] = "x";67 BtreePayload x;68 memset(&x, 0, sizeof(x));69 x.pKey = NULL;70 x.nKey = (i64)i;71 x.pData = payload;72 x.nData = (int)sizeof(payload)-1;73 x.nZero = 0;74 rc = sqlite3BtreeInsert(pCur, &x, 0, 0);75 if( rc!=SQLITE_OK ){76 close_cursor(pCur);77 return rc;78 }79 }80 close_cursor(pCur);81 return SQLITE_OK;82}83 84/* Count rows by scanning the Btree */85static int count_rows(Pgno root, int *pCount){86 int rc;87 BtCursor *pCur = NULL;88 int cnt = 0;89 int res = 0;90 91 rc = open_cursor(root, 0, &pCur);92 if( rc!=SQLITE_OK ) return rc;93 94 rc = sqlite3BtreeFirst(pCur, &res);95 if( rc!=SQLITE_OK ){96 close_cursor(pCur);97 return rc;98 }99 if( res==0 ){100 /* valid at first row */101 cnt++;102 while( (rc = sqlite3BtreeNext(pCur, 0))==SQLITE_OK ){103 cnt++;104 }105 if( rc==SQLITE_DONE ) rc = SQLITE_OK;106 }107 close_cursor(pCur);108 *pCount = cnt;109 return rc;110}111 112void setUp(void){113 int rc = open_memory_db();114 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory db");115}116 117void tearDown(void){118 close_db();119}120 121void test_sqlite3BtreeClearTable_counts_and_empties(void){122 int rc;123 Pgno root = 0;124 i64 nChanged = -1;125 int cnt = -1;126 127 rc = create_intkey_table(&root);128 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);129 TEST_ASSERT_TRUE(root>1);130 131 rc = insert_rows(root, 10);132 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);133 134 /* Sanity check inserted rows */135 rc = count_rows(root, &cnt);136 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);137 TEST_ASSERT_EQUAL_INT(10, cnt);138 139 /* Clear the table */140 rc = sqlite3BtreeClearTable(gBtree, (int)root, &nChanged);141 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);142 TEST_ASSERT_EQUAL_INT64(10, nChanged);143 144 /* Verify table is empty using a Btree cursor */145 BtCursor *pCur = NULL;146 int res = -1;147 rc = open_cursor(root, 0, &pCur);148 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);149 rc = sqlite3BtreeFirst(pCur, &res);150 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);151 TEST_ASSERT_EQUAL_INT_MESSAGE(1, res, "Table should be empty after clear");152 close_cursor(pCur);153 154 /* Optional: commit the transaction cleanly */155 rc = sqlite3BtreeCommit(gBtree);156 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);157}158 159void test_sqlite3BtreeClearTable_empty_table(void){160 int rc;161 Pgno root = 0;162 i64 nChanged = -1;163 164 rc = create_intkey_table(&root);165 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);166 167 /* Verify empty */168 int cnt = 123;169 rc = count_rows(root, &cnt);170 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);171 TEST_ASSERT_EQUAL_INT(0, cnt);172 173 rc = sqlite3BtreeClearTable(gBtree, (int)root, &nChanged);174 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);175 TEST_ASSERT_EQUAL_INT64(0, nChanged);176 177 /* Still empty */178 int res = -1;179 BtCursor *pCur = NULL;180 rc = open_cursor(root, 0, &pCur);181 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);182 rc = sqlite3BtreeFirst(pCur, &res);183 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);184 TEST_ASSERT_EQUAL_INT(1, res);185 close_cursor(pCur);186 187 rc = sqlite3BtreeCommit(gBtree);188 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);189}190 191void test_sqlite3BtreeClearTable_incrblob_invalidation(void){192 int rc;193 Pgno root = 0;194 i64 nChanged = -1;195 196 rc = create_intkey_table(&root);197 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);198 rc = insert_rows(root, 1);199 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);200 201 /* Open a cursor positioned at rowid=1 and mark as incrblob */202 BtCursor *pCur = NULL;203 rc = open_cursor(root, 0, &pCur);204 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);205 int res = 0;206 /* Seek to rowid=1 */207 rc = sqlite3BtreeTableMoveto(pCur, 1, 0, &res);208 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);209 /* res==0 should indicate exact match (found) */210 TEST_ASSERT_EQUAL_INT(0, res);211 TEST_ASSERT_EQUAL_INT(CURSOR_VALID, pCur->eState);212 213 sqlite3BtreeIncrblobCursor(pCur);214 TEST_ASSERT_TRUE( (pCur->curFlags & BTCF_Incrblob)!=0 );215 216 /* Clear the whole table; should invalidate incrblob cursor(s) */217 rc = sqlite3BtreeClearTable(gBtree, (int)root, &nChanged);218 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);219 TEST_ASSERT_EQUAL_INT64(1, nChanged);220 221 /* Cursor should be invalid now */222 TEST_ASSERT_EQUAL_INT(CURSOR_INVALID, pCur->eState);223 close_cursor(pCur);224 225 rc = sqlite3BtreeCommit(gBtree);226 TEST_ASSERT_EQUAL_INT(rc, SQLITE_OK);227}228 229int main(void){230 UNITY_BEGIN();231 232 RUN_TEST(test_sqlite3BtreeClearTable_counts_and_empties);233 RUN_TEST(test_sqlite3BtreeClearTable_empty_table);234 RUN_TEST(test_sqlite3BtreeClearTable_incrblob_invalidation);235 236 return UNITY_END();237}