Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_delete_sqlite3GenerateRowIndexDelete.c302 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7 8/* Unity setup/teardown */9void setUp(void) {10  /* no-op */11}12void tearDown(void) {13  /* no-op */14}15 16/* Helper: execute SQL and assert success */17static void exec_sql_ok(sqlite3 *db, const char *sql){18  char *err = 0;19  int rc = sqlite3_exec(db, sql, 0, 0, &err);20  if( rc!=SQLITE_OK ){21    fprintf(stderr, "SQL error: %s\nWhile executing: %s\n", err?err:"(null)", sql);22  }23  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);24  if( err ) sqlite3_free(err);25}26 27/* Helper: count indexes and collect them in enumeration order (pTab->pIndex order) */28static int collectIndexes(Table *pTab, Index ***ppArr){29  int n = 0;30  Index *p;31  for(p=pTab->pIndex; p; p=p->pNext) n++;32  if( ppArr ){33    Index **arr = (Index**)sqlite3_malloc(sizeof(Index*)*n);34    TEST_ASSERT_NOT_NULL(arr);35    int i=0;36    for(p=pTab->pIndex; p; p=p->pNext){37      arr[i++] = p;38    }39    *ppArr = arr;40  }41  return n;42}43 44/* Helper: collect OP_IdxDelete ops in order */45static int collectIdxDeleteOps(Vdbe *v, VdbeOp ***ppOps){46  int n = 0;47  for(int i=0; i<v->nOp; i++){48    if( v->aOp[i].opcode==OP_IdxDelete ) n++;49  }50  if( ppOps ){51    VdbeOp **arr = (VdbeOp**)sqlite3_malloc(sizeof(VdbeOp*)*n);52    TEST_ASSERT_NOT_NULL(arr);53    int j=0;54    for(int i=0; i<v->nOp; i++){55      if( v->aOp[i].opcode==OP_IdxDelete ){56        arr[j++] = &v->aOp[i];57      }58    }59    *ppOps = arr;60  }61  return n;62}63 64/* Test 1: Rowid table; expect one OP_IdxDelete per index with correct P1/P3/P5 */65static void test_sqlite3GenerateRowIndexDelete_rowid_table_basic(void){66  sqlite3 *db = 0;67  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));68 69  /* Create a rowid table with:70     - Unique NOT NULL index on (a,b)71     - Normal index on (c)72     - Partial index on (b) WHERE c IS NOT NULL73  */74  exec_sql_ok(db, "CREATE TABLE t1(a NOT NULL, b NOT NULL, c);");75  exec_sql_ok(db, "CREATE UNIQUE INDEX t1_ab_u ON t1(a,b);");76  exec_sql_ok(db, "CREATE INDEX t1_c ON t1(c);");77  exec_sql_ok(db, "CREATE INDEX t1_b_partial ON t1(b) WHERE c IS NOT NULL;");78 79  Table *pTab = sqlite3FindTable(db, "t1", "main");80  TEST_ASSERT_NOT_NULL(pTab);81 82  Index **idxArr = 0;83  int nIdx = collectIndexes(pTab, &idxArr);84  TEST_ASSERT_TRUE(nIdx >= 3); /* We created 3 indexes */85 86  Parse sParse;87  memset(&sParse, 0, sizeof(sParse));88  sParse.db = db;89  sParse.pVdbe = sqlite3VdbeCreate(db);90  TEST_ASSERT_NOT_NULL(sParse.pVdbe);91 92  int iDataCur = 1;93  int iIdxCur = 5;94  int *aRegIdx = 0; /* delete all indexes */95  int iIdxNoSeek = -1;96 97  sqlite3GenerateRowIndexDelete(&sParse, pTab, iDataCur, iIdxCur, aRegIdx, iIdxNoSeek);98 99  Vdbe *v = sParse.pVdbe;100  VdbeOp **ops = 0;101  int nDel = collectIdxDeleteOps(v, &ops);102 103  /* All indexes should be targeted (no PK for rowid tables) */104  TEST_ASSERT_EQUAL_INT(nIdx, nDel);105 106  /* Validate each OP_IdxDelete's P1, P3, and P5 */107  for(int i=0; i<nDel; i++){108    Index *pIdx = idxArr[i];109    VdbeOp *op = ops[i];110    TEST_ASSERT_EQUAL_INT(iIdxCur + i, op->p1);111    /* P3 is nKeyCol if uniqNotNull, else nColumn */112    int expectedP3 = pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn;113    TEST_ASSERT_EQUAL_INT(expectedP3, op->p3);114    TEST_ASSERT_EQUAL_INT(1, op->p5); /* Should cause error if not found */115  }116 117  sqlite3_free(ops);118  sqlite3_free(idxArr);119  sqlite3VdbeDelete(sParse.pVdbe);120  sqlite3_close(db);121}122 123/* Test 2: aRegIdx filtering: skip one index (where aRegIdx[i]==0) */124static void test_sqlite3GenerateRowIndexDelete_respects_aRegIdx(void){125  sqlite3 *db = 0;126  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));127 128  exec_sql_ok(db, "CREATE TABLE t2(a NOT NULL, b NOT NULL, c);");129  exec_sql_ok(db, "CREATE UNIQUE INDEX t2_ab_u ON t2(a,b);");130  exec_sql_ok(db, "CREATE INDEX t2_c ON t2(c);");131  exec_sql_ok(db, "CREATE INDEX t2_b ON t2(b);");132 133  Table *pTab = sqlite3FindTable(db, "t2", "main");134  TEST_ASSERT_NOT_NULL(pTab);135 136  Index **idxArr = 0;137  int nIdx = collectIndexes(pTab, &idxArr);138  TEST_ASSERT_TRUE(nIdx >= 3);139 140  int *aRegIdx = (int*)sqlite3_malloc(sizeof(int)*nIdx);141  TEST_ASSERT_NOT_NULL(aRegIdx);142  /* Allow all except skip the middle one (iSkip) */143  int iSkip = (nIdx>=2) ? 1 : 0;144  for(int i=0;i<nIdx;i++) aRegIdx[i] = (i==iSkip) ? 0 : 1;145 146  Parse ps;147  memset(&ps, 0, sizeof(ps));148  ps.db = db;149  ps.pVdbe = sqlite3VdbeCreate(db);150  TEST_ASSERT_NOT_NULL(ps.pVdbe);151 152  int iDataCur = 2;153  int iIdxCur = 10;154  int iIdxNoSeek = -1;155 156  sqlite3GenerateRowIndexDelete(&ps, pTab, iDataCur, iIdxCur, aRegIdx, iIdxNoSeek);157 158  VdbeOp **ops = 0;159  int nDel = collectIdxDeleteOps(ps.pVdbe, &ops);160  TEST_ASSERT_EQUAL_INT(nIdx - 1, nDel);161 162  /* Build expectation: all indexes except iSkip */163  int j = 0;164  for(int i=0; i<nIdx; i++){165    if( i==iSkip ) continue;166    Index *pIdx = idxArr[i];167    VdbeOp *op = ops[j++];168    TEST_ASSERT_EQUAL_INT(iIdxCur + i, op->p1);169    int expectedP3 = pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn;170    TEST_ASSERT_EQUAL_INT(expectedP3, op->p3);171    TEST_ASSERT_EQUAL_INT(1, op->p5);172  }173 174  sqlite3_free(ops);175  sqlite3_free(aRegIdx);176  sqlite3_free(idxArr);177  sqlite3VdbeDelete(ps.pVdbe);178  sqlite3_close(db);179}180 181/* Test 3: iIdxNoSeek skip: ensure selected cursor is skipped */182static void test_sqlite3GenerateRowIndexDelete_respects_iIdxNoSeek(void){183  sqlite3 *db = 0;184  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));185 186  exec_sql_ok(db, "CREATE TABLE t3(a, b, c);");187  exec_sql_ok(db, "CREATE INDEX t3_a ON t3(a);");188  exec_sql_ok(db, "CREATE INDEX t3_b ON t3(b);");189  exec_sql_ok(db, "CREATE INDEX t3_c ON t3(c);");190 191  Table *pTab = sqlite3FindTable(db, "t3", "main");192  TEST_ASSERT_NOT_NULL(pTab);193 194  Index **idxArr = 0;195  int nIdx = collectIndexes(pTab, &idxArr);196  TEST_ASSERT_TRUE(nIdx >= 3);197 198  Parse ps;199  memset(&ps, 0, sizeof(ps));200  ps.db = db;201  ps.pVdbe = sqlite3VdbeCreate(db);202  TEST_ASSERT_NOT_NULL(ps.pVdbe);203 204  int iDataCur = 3;205  int iIdxCur = 20;206 207  /* Choose to skip the last enumerated index */208  int iSkip = nIdx - 1;209  int iIdxNoSeek = iIdxCur + iSkip;210 211  sqlite3GenerateRowIndexDelete(&ps, pTab, iDataCur, iIdxCur, 0, iIdxNoSeek);212 213  VdbeOp **ops = 0;214  int nDel = collectIdxDeleteOps(ps.pVdbe, &ops);215  TEST_ASSERT_EQUAL_INT(nIdx - 1, nDel);216 217  int j = 0;218  for(int i=0; i<nIdx; i++){219    if( i==iSkip ) continue;220    Index *pIdx = idxArr[i];221    VdbeOp *op = ops[j++];222    TEST_ASSERT_EQUAL_INT(iIdxCur + i, op->p1);223    int expectedP3 = pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn;224    TEST_ASSERT_EQUAL_INT(expectedP3, op->p3);225    TEST_ASSERT_EQUAL_INT(1, op->p5);226  }227 228  sqlite3_free(ops);229  sqlite3_free(idxArr);230  sqlite3VdbeDelete(ps.pVdbe);231  sqlite3_close(db);232}233 234/* Test 4: WITHOUT ROWID table: ensure PRIMARY KEY index is skipped */235static void test_sqlite3GenerateRowIndexDelete_wo_rowid_skips_pk(void){236  sqlite3 *db = 0;237  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));238 239  exec_sql_ok(db, "CREATE TABLE w1(a, b, c, PRIMARY KEY(a,b)) WITHOUT ROWID;");240  exec_sql_ok(db, "CREATE INDEX w1_c ON w1(c);");241  exec_sql_ok(db, "CREATE UNIQUE INDEX w1_b_u ON w1(b);");242 243  Table *pTab = sqlite3FindTable(db, "w1", "main");244  TEST_ASSERT_NOT_NULL(pTab);245 246  /* Ensure HasRowid is false */247  TEST_ASSERT_FALSE( HasRowid(pTab) );248 249  Index **idxArr = 0;250  int nIdx = collectIndexes(pTab, &idxArr);251  TEST_ASSERT_TRUE(nIdx >= 2);252 253  Index *pPk = sqlite3PrimaryKeyIndex(pTab);254  TEST_ASSERT_NOT_NULL(pPk);255 256  Parse ps;257  memset(&ps, 0, sizeof(ps));258  ps.db = db;259  ps.pVdbe = sqlite3VdbeCreate(db);260  TEST_ASSERT_NOT_NULL(ps.pVdbe);261 262  int iDataCur = 100;  /* choose values different from iIdxCur to avoid assertion */263  int iIdxCur = 200;264 265  sqlite3GenerateRowIndexDelete(&ps, pTab, iDataCur, iIdxCur, 0, -1);266 267  VdbeOp **ops = 0;268  int nDel = collectIdxDeleteOps(ps.pVdbe, &ops);269 270  /* We expect one OP_IdxDelete per non-PK index */271  int nNonPk = 0;272  for(int i=0; i<nIdx; i++){273    if( idxArr[i] != pPk ) nNonPk++;274  }275  TEST_ASSERT_EQUAL_INT(nNonPk, nDel);276 277  /* Validate that only non-PK indexes are targeted and P1/P3/P5 are correct */278  int j = 0;279  for(int i=0; i<nIdx; i++){280    Index *pIdx = idxArr[i];281    if( pIdx==pPk ) continue;282    VdbeOp *op = ops[j++];283    TEST_ASSERT_EQUAL_INT(iIdxCur + i, op->p1);284    int expectedP3 = pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn;285    TEST_ASSERT_EQUAL_INT(expectedP3, op->p3);286    TEST_ASSERT_EQUAL_INT(1, op->p5);287  }288 289  sqlite3_free(ops);290  sqlite3_free(idxArr);291  sqlite3VdbeDelete(ps.pVdbe);292  sqlite3_close(db);293}294 295int main(void){296  UNITY_BEGIN();297  RUN_TEST(test_sqlite3GenerateRowIndexDelete_rowid_table_basic);298  RUN_TEST(test_sqlite3GenerateRowIndexDelete_respects_aRegIdx);299  RUN_TEST(test_sqlite3GenerateRowIndexDelete_respects_iIdxNoSeek);300  RUN_TEST(test_sqlite3GenerateRowIndexDelete_wo_rowid_skips_pk);301  return UNITY_END();302}