AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Wrapper provided by the module for static function */6void test_autoIncrementEnd(Parse *pParse);7 8static sqlite3 *gDb = NULL;9 10/* Helpers to create and cleanup test state */11 12static void initParseWithVdbe(sqlite3 *db, Parse *pParse){13 memset(pParse, 0, sizeof(*pParse));14 pParse->db = db;15 pParse->pVdbe = sqlite3VdbeCreate(db);16 TEST_ASSERT_NOT_NULL_MESSAGE(pParse->pVdbe, "sqlite3VdbeCreate returned NULL");17}18 19static Table* installSeqTable(sqlite3 *db, int iDb, const char *zName, int tnum, int nNVCol, Table **ppOld){20 Schema *pSchema = db->aDb[iDb].pSchema;21 /* Save old pointer to restore later */22 if( ppOld ) *ppOld = pSchema->pSeqTab;23 24 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));25 TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "Failed to allocate Table");26 pTab->zName = sqlite3DbStrDup(db, zName ? zName : "sqlite_sequence");27 TEST_ASSERT_NOT_NULL_MESSAGE(pTab->zName, "Failed to allocate table name");28 pTab->tnum = tnum;29#if defined(SQLITE_OMIT_VIRTUALTABLE)30 /* nothing */31#endif32 /* Ensure table has rowid (default flags=0 implies HasRowid true) */33 /* Many SQLite versions have both nCol and nNVCol; only nNVCol is used by the code under test. */34#ifdef offsetof35 /* Try to set nCol if present to avoid uninitialized state, but do not depend on it. */36#endif37 pTab->nNVCol = nNVCol; /* used by sqlite3OpenTable when HasRowid(pTab) is true */38 pSchema->pSeqTab = pTab;39 return pTab;40}41 42static void uninstallSeqTable(sqlite3 *db, int iDb, Table *pOld){43 Schema *pSchema = db->aDb[iDb].pSchema;44 Table *pNew = pSchema->pSeqTab;45 pSchema->pSeqTab = pOld;46 if( pNew ){47 if( pNew->zName ) sqlite3DbFree(db, pNew->zName);48 sqlite3DbFree(db, pNew);49 }50}51 52static AutoincInfo* makeAutoinc(sqlite3 *db, int iDb, int regCtr, AutoincInfo *pNext){53 AutoincInfo *p = (AutoincInfo*)sqlite3DbMallocZero(db, sizeof(AutoincInfo));54 TEST_ASSERT_NOT_NULL_MESSAGE(p, "Allocation of AutoincInfo failed");55 p->iDb = iDb;56 p->regCtr = regCtr;57 p->pNext = pNext;58 return p;59}60 61void setUp(void) {62 int rc = sqlite3_open(":memory:", &gDb);63 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");64}65 66void tearDown(void) {67 if( gDb ){68 sqlite3_close(gDb);69 gDb = NULL;70 }71}72 73/* Test: No pAinc entries -> no VDBE ops emitted */74void test_autoIncrementEnd_no_entries(void){75 Parse parse;76 initParseWithVdbe(gDb, &parse);77 78 int nOpBefore = parse.pVdbe->nOp;79 TEST_ASSERT_EQUAL_INT(0, nOpBefore);80 81 parse.pAinc = NULL;82 test_autoIncrementEnd(&parse);83 84 int nOpAfter = parse.pVdbe->nOp;85 TEST_ASSERT_EQUAL_INT(nOpBefore, nOpAfter);86 87 sqlite3VdbeDelete(parse.pVdbe);88}89 90/* Test: Single AutoincInfo entry -> verify full emitted opcode pattern */91void test_autoIncrementEnd_single_entry_ops(void){92 Parse parse;93 initParseWithVdbe(gDb, &parse);94 95 /* Install a sqlite_sequence-like table in the main schema */96 Table *pOld = NULL;97 int iDb = 0;98 int tnum = 1234;99 int nNVCol = 2;100 Table *pSeq = installSeqTable(gDb, iDb, "sqlite_sequence", tnum, nNVCol, &pOld);101 102 /* Prepare AutoincInfo */103 int memId = 10; /* arbitrary register base */104 parse.pAinc = makeAutoinc(gDb, iDb, memId, NULL);105 106 int base = parse.pVdbe->nOp;107 test_autoIncrementEnd(&parse);108 Vdbe *v = parse.pVdbe;109 110 /* Expect exactly 7 ops emitted: Le, OpenWrite, and the 5-op list */111 TEST_ASSERT_EQUAL_INT(base + 7, v->nOp);112 113 VdbeOp *op = v->aOp;114 115 /* 0: OP_Le memId+2, base+7, memId */116 TEST_ASSERT_EQUAL_INT(OP_Le, op[base+0].opcode);117 TEST_ASSERT_EQUAL_INT(memId+2, op[base+0].p1);118 TEST_ASSERT_EQUAL_INT(base+7, op[base+0].p2);119 TEST_ASSERT_EQUAL_INT(memId, op[base+0].p3);120 121 /* 1: OP_OpenWrite cursor 0, tnum, iDb */122 TEST_ASSERT_EQUAL_INT(OP_OpenWrite, op[base+1].opcode);123 TEST_ASSERT_EQUAL_INT(0, op[base+1].p1);124 TEST_ASSERT_EQUAL_INT(tnum, op[base+1].p2);125 TEST_ASSERT_EQUAL_INT(iDb, op[base+1].p3);126 127 /* 2..6: the fixed list with patched fields */128 /* 2: OP_NotNull p1=memId+1 p2=2 */129 TEST_ASSERT_EQUAL_INT(OP_NotNull, op[base+2].opcode);130 TEST_ASSERT_EQUAL_INT(memId+1, op[base+2].p1);131 TEST_ASSERT_EQUAL_INT(2, op[base+2].p2);132 133 /* 3: OP_NewRowid p2=memId+1 */134 TEST_ASSERT_EQUAL_INT(OP_NewRowid, op[base+3].opcode);135 TEST_ASSERT_EQUAL_INT(memId+1, op[base+3].p2);136 137 /* 4: OP_MakeRecord p1=memId-1 p3=iRec (unknown temp reg) */138 TEST_ASSERT_EQUAL_INT(OP_MakeRecord, op[base+4].opcode);139 TEST_ASSERT_EQUAL_INT(memId-1, op[base+4].p1);140 int iRec = op[base+4].p3;141 TEST_ASSERT_TRUE_MESSAGE(iRec>0, "Temp register (iRec) should be >0");142 143 /* 5: OP_Insert p2=iRec p3=memId+1 p5 has OPFLAG_APPEND */144 TEST_ASSERT_EQUAL_INT(OP_Insert, op[base+5].opcode);145 TEST_ASSERT_EQUAL_INT(iRec, op[base+5].p2);146 TEST_ASSERT_EQUAL_INT(memId+1, op[base+5].p3);147 TEST_ASSERT_TRUE_MESSAGE((op[base+5].p5 & OPFLAG_APPEND)!=0, "OP_Insert should have OPFLAG_APPEND");148 149 /* 6: OP_Close cursor 0 */150 TEST_ASSERT_EQUAL_INT(OP_Close, op[base+6].opcode);151 TEST_ASSERT_EQUAL_INT(0, op[base+6].p1);152 153 /* Cleanup */154 sqlite3DbFree(gDb, parse.pAinc);155 uninstallSeqTable(gDb, iDb, pOld);156 sqlite3VdbeDelete(parse.pVdbe);157}158 159/* Test: Two AutoincInfo entries -> verify two sequences appended correctly */160void test_autoIncrementEnd_two_entries(void){161 Parse parse;162 initParseWithVdbe(gDb, &parse);163 164 Table *pOld = NULL;165 int iDb = 0;166 int tnum = 2222;167 int nNVCol = 3;168 Table *pSeq = installSeqTable(gDb, iDb, "sqlite_sequence", tnum, nNVCol, &pOld);169 170 /* Create two linked AutoincInfo nodes with different regCtr values */171 AutoincInfo *p2 = makeAutoinc(gDb, iDb, 30, NULL);172 AutoincInfo *p1 = makeAutoinc(gDb, iDb, 20, p2);173 parse.pAinc = p1;174 175 int base = parse.pVdbe->nOp;176 test_autoIncrementEnd(&parse);177 Vdbe *v = parse.pVdbe;178 179 /* Expect 14 ops total (7 per entry) */180 TEST_ASSERT_EQUAL_INT(base + 14, v->nOp);181 182 /* Validate first block (memId=20) */183 {184 int memId = 20;185 int b = base;186 TEST_ASSERT_EQUAL_INT(OP_Le, v->aOp[b+0].opcode);187 TEST_ASSERT_EQUAL_INT(memId+2, v->aOp[b+0].p1);188 TEST_ASSERT_EQUAL_INT(b+7, v->aOp[b+0].p2);189 TEST_ASSERT_EQUAL_INT(memId, v->aOp[b+0].p3);190 191 TEST_ASSERT_EQUAL_INT(OP_OpenWrite, v->aOp[b+1].opcode);192 TEST_ASSERT_EQUAL_INT(tnum, v->aOp[b+1].p2);193 TEST_ASSERT_EQUAL_INT(iDb, v->aOp[b+1].p3);194 195 TEST_ASSERT_EQUAL_INT(OP_NotNull, v->aOp[b+2].opcode);196 TEST_ASSERT_EQUAL_INT(memId+1, v->aOp[b+2].p1);197 TEST_ASSERT_EQUAL_INT(2, v->aOp[b+2].p2);198 199 TEST_ASSERT_EQUAL_INT(OP_NewRowid, v->aOp[b+3].opcode);200 TEST_ASSERT_EQUAL_INT(memId+1, v->aOp[b+3].p2);201 202 TEST_ASSERT_EQUAL_INT(OP_MakeRecord, v->aOp[b+4].opcode);203 TEST_ASSERT_EQUAL_INT(memId-1, v->aOp[b+4].p1);204 int iRec1 = v->aOp[b+4].p3;205 206 TEST_ASSERT_EQUAL_INT(OP_Insert, v->aOp[b+5].opcode);207 TEST_ASSERT_EQUAL_INT(iRec1, v->aOp[b+5].p2);208 TEST_ASSERT_EQUAL_INT(memId+1, v->aOp[b+5].p3);209 TEST_ASSERT_TRUE((v->aOp[b+5].p5 & OPFLAG_APPEND)!=0);210 211 TEST_ASSERT_EQUAL_INT(OP_Close, v->aOp[b+6].opcode);212 TEST_ASSERT_EQUAL_INT(0, v->aOp[b+6].p1);213 }214 215 /* Validate second block (memId=30) */216 {217 int memId = 30;218 int b = base + 7;219 TEST_ASSERT_EQUAL_INT(OP_Le, v->aOp[b+0].opcode);220 TEST_ASSERT_EQUAL_INT(memId+2, v->aOp[b+0].p1);221 TEST_ASSERT_EQUAL_INT(b+7, v->aOp[b+0].p2);222 TEST_ASSERT_EQUAL_INT(memId, v->aOp[b+0].p3);223 224 TEST_ASSERT_EQUAL_INT(OP_OpenWrite, v->aOp[b+1].opcode);225 TEST_ASSERT_EQUAL_INT(tnum, v->aOp[b+1].p2);226 TEST_ASSERT_EQUAL_INT(iDb, v->aOp[b+1].p3);227 228 TEST_ASSERT_EQUAL_INT(OP_NotNull, v->aOp[b+2].opcode);229 TEST_ASSERT_EQUAL_INT(memId+1, v->aOp[b+2].p1);230 TEST_ASSERT_EQUAL_INT(2, v->aOp[b+2].p2);231 232 TEST_ASSERT_EQUAL_INT(OP_NewRowid, v->aOp[b+3].opcode);233 TEST_ASSERT_EQUAL_INT(memId+1, v->aOp[b+3].p2);234 235 TEST_ASSERT_EQUAL_INT(OP_MakeRecord, v->aOp[b+4].opcode);236 TEST_ASSERT_EQUAL_INT(memId-1, v->aOp[b+4].p1);237 int iRec2 = v->aOp[b+4].p3;238 239 TEST_ASSERT_EQUAL_INT(OP_Insert, v->aOp[b+5].opcode);240 TEST_ASSERT_EQUAL_INT(iRec2, v->aOp[b+5].p2);241 TEST_ASSERT_EQUAL_INT(memId+1, v->aOp[b+5].p3);242 TEST_ASSERT_TRUE((v->aOp[b+5].p5 & OPFLAG_APPEND)!=0);243 244 TEST_ASSERT_EQUAL_INT(OP_Close, v->aOp[b+6].opcode);245 TEST_ASSERT_EQUAL_INT(0, v->aOp[b+6].p1);246 }247 248 /* Cleanup */249 sqlite3DbFree(gDb, p2);250 sqlite3DbFree(gDb, p1);251 uninstallSeqTable(gDb, iDb, pOld);252 sqlite3VdbeDelete(parse.pVdbe);253}254 255int main(void){256 UNITY_BEGIN();257 RUN_TEST(test_autoIncrementEnd_no_entries);258 RUN_TEST(test_autoIncrementEnd_single_entry_ops);259 RUN_TEST(test_autoIncrementEnd_two_entries);260 return UNITY_END();261}